Blender  V2.59
gpencil.c
Go to the documentation of this file.
00001 /*
00002  * $Id: gpencil.c 35247 2011-02-27 20:40:57Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2008, Blender Foundation
00021  * This is a new part of Blender
00022  *
00023  * Contributor(s): Joshua Leung
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <stdlib.h>
00036 #include <stddef.h>
00037 #include <math.h>
00038 
00039 #include "MEM_guardedalloc.h"
00040 
00041 #include "BLI_blenlib.h"
00042 #include "BLI_utildefines.h"
00043 
00044 #include "DNA_gpencil_types.h"
00045 
00046 #include "BKE_global.h"
00047 #include "BKE_gpencil.h"
00048 #include "BKE_library.h"
00049 #include "BKE_main.h"
00050 
00051 
00052 
00053 /* ************************************************** */
00054 /* GENERAL STUFF */
00055 
00056 /* --------- Memory Management ------------ */
00057 
00058 /* Free strokes belonging to a gp-frame */
00059 void free_gpencil_strokes (bGPDframe *gpf)
00060 {
00061         bGPDstroke *gps, *gpsn;
00062         
00063         /* error checking */
00064         if (gpf == NULL) return;
00065         
00066         /* free strokes */
00067         for (gps= gpf->strokes.first; gps; gps= gpsn) {
00068                 gpsn= gps->next;
00069                 
00070                 /* free stroke memory arrays, then stroke itself */
00071                 if (gps->points) MEM_freeN(gps->points);
00072                 BLI_freelinkN(&gpf->strokes, gps);
00073         }
00074 }
00075 
00076 /* Free all of a gp-layer's frames */
00077 void free_gpencil_frames (bGPDlayer *gpl)
00078 {
00079         bGPDframe *gpf, *gpfn;
00080         
00081         /* error checking */
00082         if (gpl == NULL) return;
00083         
00084         /* free frames */
00085         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
00086                 gpfn= gpf->next;
00087                 
00088                 /* free strokes and their associated memory */
00089                 free_gpencil_strokes(gpf);
00090                 BLI_freelinkN(&gpl->frames, gpf);
00091         }
00092 }
00093 
00094 /* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
00095 void free_gpencil_layers (ListBase *list) 
00096 {
00097         bGPDlayer *gpl, *gpln;
00098         
00099         /* error checking */
00100         if (list == NULL) return;
00101         
00102         /* delete layers*/
00103         for (gpl= list->first; gpl; gpl= gpln) {
00104                 gpln= gpl->next;
00105                 
00106                 /* free layers and their data */
00107                 free_gpencil_frames(gpl);
00108                 BLI_freelinkN(list, gpl);
00109         }
00110 }
00111 
00112 /* Free all of GPencil datablock's related data, but not the block itself */
00113 void free_gpencil_data (bGPdata *gpd)
00114 {
00115         /* free layers */
00116         free_gpencil_layers(&gpd->layers);
00117 }
00118 
00119 /* -------- Container Creation ---------- */
00120 
00121 /* add a new gp-frame to the given layer */
00122 bGPDframe *gpencil_frame_addnew (bGPDlayer *gpl, int cframe)
00123 {
00124         bGPDframe *gpf, *gf;
00125         short state=0;
00126         
00127         /* error checking */
00128         if ((gpl == NULL) || (cframe <= 0))
00129                 return NULL;
00130                 
00131         /* allocate memory for this frame */
00132         gpf= MEM_callocN(sizeof(bGPDframe), "bGPDframe");
00133         gpf->framenum= cframe;
00134         
00135         /* find appropriate place to add frame */
00136         if (gpl->frames.first) {
00137                 for (gf= gpl->frames.first; gf; gf= gf->next) {
00138                         /* check if frame matches one that is supposed to be added */
00139                         if (gf->framenum == cframe) {
00140                                 state= -1;
00141                                 break;
00142                         }
00143                         
00144                         /* if current frame has already exceeded the frame to add, add before */
00145                         if (gf->framenum > cframe) {
00146                                 BLI_insertlinkbefore(&gpl->frames, gf, gpf);
00147                                 state= 1;
00148                                 break;
00149                         }
00150                 }
00151         }
00152         
00153         /* check whether frame was added successfully */
00154         if (state == -1) {
00155                 MEM_freeN(gpf);
00156                 printf("Error: frame (%d) existed already for this layer \n", cframe);
00157         }
00158         else if (state == 0) {
00159                 /* add to end then! */
00160                 BLI_addtail(&gpl->frames, gpf);
00161         }
00162         
00163         /* return frame */
00164         return gpf;
00165 }
00166 
00167 /* add a new gp-layer and make it the active layer */
00168 bGPDlayer *gpencil_layer_addnew (bGPdata *gpd)
00169 {
00170         bGPDlayer *gpl;
00171         
00172         /* check that list is ok */
00173         if (gpd == NULL)
00174                 return NULL;
00175                 
00176         /* allocate memory for frame and add to end of list */
00177         gpl= MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
00178         
00179         /* add to datablock */
00180         BLI_addtail(&gpd->layers, gpl);
00181         
00182         /* set basic settings */
00183         gpl->color[3]= 0.9f;
00184         gpl->thickness = 3;
00185         
00186         /* auto-name */
00187         sprintf(gpl->info, "GP_Layer");
00188         BLI_uniquename(&gpd->layers, gpl, "GP_Layer", '.', offsetof(bGPDlayer, info[0]), sizeof(gpl->info));
00189         
00190         /* make this one the active one */
00191         gpencil_layer_setactive(gpd, gpl);
00192         
00193         /* return layer */
00194         return gpl;
00195 }
00196 
00197 /* add a new gp-datablock */
00198 bGPdata *gpencil_data_addnew (const char name[])
00199 {
00200         bGPdata *gpd;
00201         
00202         /* allocate memory for a new block */
00203         gpd= alloc_libblock(&G.main->gpencil, ID_GD, name);
00204         
00205         /* initial settings */
00206         gpd->flag = (GP_DATA_DISPINFO|GP_DATA_EXPAND);
00207         
00208         /* for now, stick to view is also enabled by default
00209          * since this is more useful...
00210          */
00211         gpd->flag |= GP_DATA_VIEWALIGN;
00212         
00213         return gpd;
00214 }
00215 
00216 /* -------- Data Duplication ---------- */
00217 
00218 /* make a copy of a given gpencil frame */
00219 bGPDframe *gpencil_frame_duplicate (bGPDframe *src)
00220 {
00221         bGPDstroke *gps, *gpsd;
00222         bGPDframe *dst;
00223         
00224         /* error checking */
00225         if (src == NULL)
00226                 return NULL;
00227                 
00228         /* make a copy of the source frame */
00229         dst= MEM_dupallocN(src);
00230         dst->prev= dst->next= NULL;
00231         
00232         /* copy strokes */
00233         dst->strokes.first = dst->strokes.last= NULL;
00234         for (gps= src->strokes.first; gps; gps= gps->next) {
00235                 /* make copy of source stroke, then adjust pointer to points too */
00236                 gpsd= MEM_dupallocN(gps);
00237                 gpsd->points= MEM_dupallocN(gps->points);
00238                 
00239                 BLI_addtail(&dst->strokes, gpsd);
00240         }
00241         
00242         /* return new frame */
00243         return dst;
00244 }
00245 
00246 /* make a copy of a given gpencil layer */
00247 bGPDlayer *gpencil_layer_duplicate (bGPDlayer *src)
00248 {
00249         bGPDframe *gpf, *gpfd;
00250         bGPDlayer *dst;
00251         
00252         /* error checking */
00253         if (src == NULL)
00254                 return NULL;
00255                 
00256         /* make a copy of source layer */
00257         dst= MEM_dupallocN(src);
00258         dst->prev= dst->next= NULL;
00259         
00260         /* copy frames */
00261         dst->frames.first= dst->frames.last= NULL;
00262         for (gpf= src->frames.first; gpf; gpf= gpf->next) {
00263                 /* make a copy of source frame */
00264                 gpfd= gpencil_frame_duplicate(gpf);
00265                 BLI_addtail(&dst->frames, gpfd);
00266                 
00267                 /* if source frame was the current layer's 'active' frame, reassign that too */
00268                 if (gpf == dst->actframe)
00269                         dst->actframe= gpfd;
00270         }
00271         
00272         /* return new layer */
00273         return dst;
00274 }
00275 
00276 /* make a copy of a given gpencil datablock */
00277 bGPdata *gpencil_data_duplicate (bGPdata *src)
00278 {
00279         bGPDlayer *gpl, *gpld;
00280         bGPdata *dst;
00281         
00282         /* error checking */
00283         if (src == NULL)
00284                 return NULL;
00285         
00286         /* make a copy of the base-data */
00287         dst= MEM_dupallocN(src);
00288         
00289         /* copy layers */
00290         dst->layers.first= dst->layers.last= NULL;
00291         for (gpl= src->layers.first; gpl; gpl= gpl->next) {
00292                 /* make a copy of source layer and its data */
00293                 gpld= gpencil_layer_duplicate(gpl);
00294                 BLI_addtail(&dst->layers, gpld);
00295         }
00296         
00297         /* return new */
00298         return dst;
00299 }
00300 
00301 /* -------- GP-Frame API ---------- */
00302 
00303 /* delete the last stroke of the given frame */
00304 void gpencil_frame_delete_laststroke (bGPDlayer *gpl, bGPDframe *gpf)
00305 {
00306         bGPDstroke *gps= (gpf) ? gpf->strokes.last : NULL;
00307         int cfra = (gpf) ? gpf->framenum : 0; /* assume that the current frame was not locked */
00308         
00309         /* error checking */
00310         if (ELEM(NULL, gpf, gps))
00311                 return;
00312         
00313         /* free the stroke and its data */
00314         MEM_freeN(gps->points);
00315         BLI_freelinkN(&gpf->strokes, gps);
00316         
00317         /* if frame has no strokes after this, delete it */
00318         if (gpf->strokes.first == NULL) {
00319                 gpencil_layer_delframe(gpl, gpf);
00320                 gpencil_layer_getframe(gpl, cfra, 0);
00321         }
00322 }
00323 
00324 /* -------- GP-Layer API ---------- */
00325 
00326 /* get the appropriate gp-frame from a given layer
00327  *      - this sets the layer's actframe var (if allowed to)
00328  *      - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
00329  */
00330 bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew)
00331 {
00332         bGPDframe *gpf = NULL;
00333         short found = 0;
00334         
00335         /* error checking */
00336         if (gpl == NULL) return NULL;
00337         if (cframe <= 0) cframe = 1;
00338         
00339         /* check if there is already an active frame */
00340         if (gpl->actframe) {
00341                 gpf= gpl->actframe;
00342                 
00343                 /* do not allow any changes to layer's active frame if layer is locked from changes
00344                  * or if the layer has been set to stay on the current frame
00345                  */
00346                 if (gpl->flag & (GP_LAYER_LOCKED|GP_LAYER_FRAMELOCK))
00347                         return gpf;
00348                 /* do not allow any changes to actframe if frame has painting tag attached to it */
00349                 if (gpf->flag & GP_FRAME_PAINT) 
00350                         return gpf;
00351                 
00352                 /* try to find matching frame */
00353                 if (gpf->framenum < cframe) {
00354                         for (; gpf; gpf= gpf->next) {
00355                                 if (gpf->framenum == cframe) {
00356                                         found= 1;
00357                                         break;
00358                                 }
00359                                 else if ((gpf->next) && (gpf->next->framenum > cframe)) {
00360                                         found= 1;
00361                                         break;
00362                                 }
00363                         }
00364                         
00365                         /* set the appropriate frame */
00366                         if (addnew) {
00367                                 if ((found) && (gpf->framenum == cframe))
00368                                         gpl->actframe= gpf;
00369                                 else
00370                                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
00371                         }
00372                         else if (found)
00373                                 gpl->actframe= gpf;
00374                         else
00375                                 gpl->actframe= gpl->frames.last;
00376                 }
00377                 else {
00378                         for (; gpf; gpf= gpf->prev) {
00379                                 if (gpf->framenum <= cframe) {
00380                                         found= 1;
00381                                         break;
00382                                 }
00383                         }
00384                         
00385                         /* set the appropriate frame */
00386                         if (addnew) {
00387                                 if ((found) && (gpf->framenum == cframe))
00388                                         gpl->actframe= gpf;
00389                                 else
00390                                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
00391                         }
00392                         else if (found)
00393                                 gpl->actframe= gpf;
00394                         else
00395                                 gpl->actframe= gpl->frames.first;
00396                 }
00397         }
00398         else if (gpl->frames.first) {
00399                 /* check which of the ends to start checking from */
00400                 const int first= ((bGPDframe *)(gpl->frames.first))->framenum;
00401                 const int last= ((bGPDframe *)(gpl->frames.last))->framenum;
00402                 
00403                 if (abs(cframe-first) > abs(cframe-last)) {
00404                         /* find gp-frame which is less than or equal to cframe */
00405                         for (gpf= gpl->frames.last; gpf; gpf= gpf->prev) {
00406                                 if (gpf->framenum <= cframe) {
00407                                         found= 1;
00408                                         break;
00409                                 }
00410                         }
00411                 }
00412                 else {
00413                         /* find gp-frame which is less than or equal to cframe */
00414                         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
00415                                 if (gpf->framenum <= cframe) {
00416                                         found= 1;
00417                                         break;
00418                                 }
00419                         }
00420                 }
00421                 
00422                 /* set the appropriate frame */
00423                 if (addnew) {
00424                         if ((found) && (gpf->framenum == cframe))
00425                                 gpl->actframe= gpf;
00426                         else
00427                                 gpl->actframe= gpencil_frame_addnew(gpl, cframe);
00428                 }
00429                 else if (found)
00430                         gpl->actframe= gpf;
00431                 else {
00432                         /* unresolved errogenous situation! */
00433                         printf("Error: cannot find appropriate gp-frame \n");
00434                         /* gpl->actframe should still be NULL */
00435                 }
00436         }
00437         else {
00438                 /* currently no frames (add if allowed to) */
00439                 if (addnew)
00440                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
00441                 else {
00442                         /* don't do anything... this may be when no frames yet! */
00443                         /* gpl->actframe should still be NULL */
00444                 }
00445         }
00446         
00447         /* return */
00448         return gpl->actframe;
00449 }
00450 
00451 /* delete the given frame from a layer */
00452 void gpencil_layer_delframe (bGPDlayer *gpl, bGPDframe *gpf)
00453 {
00454         /* error checking */
00455         if (ELEM(NULL, gpl, gpf))
00456                 return;
00457                 
00458         /* free the frame and its data */
00459         free_gpencil_strokes(gpf);
00460         BLI_freelinkN(&gpl->frames, gpf);
00461         gpl->actframe = NULL;
00462 }
00463 
00464 /* get the active gp-layer for editing */
00465 bGPDlayer *gpencil_layer_getactive (bGPdata *gpd)
00466 {
00467         bGPDlayer *gpl;
00468         
00469         /* error checking */
00470         if (ELEM(NULL, gpd, gpd->layers.first))
00471                 return NULL;
00472                 
00473         /* loop over layers until found (assume only one active) */
00474         for (gpl=gpd->layers.first; gpl; gpl=gpl->next) {
00475                 if (gpl->flag & GP_LAYER_ACTIVE)
00476                         return gpl;
00477         }
00478         
00479         /* no active layer found */
00480         return NULL;
00481 }
00482 
00483 /* set the active gp-layer */
00484 void gpencil_layer_setactive (bGPdata *gpd, bGPDlayer *active)
00485 {
00486         bGPDlayer *gpl;
00487         
00488         /* error checking */
00489         if (ELEM3(NULL, gpd, gpd->layers.first, active))
00490                 return;
00491                 
00492         /* loop over layers deactivating all */
00493         for (gpl=gpd->layers.first; gpl; gpl=gpl->next)
00494                 gpl->flag &= ~GP_LAYER_ACTIVE;
00495         
00496         /* set as active one */
00497         active->flag |= GP_LAYER_ACTIVE;
00498 }
00499 
00500 /* delete the active gp-layer */
00501 void gpencil_layer_delactive (bGPdata *gpd)
00502 {
00503         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
00504         
00505         /* error checking */
00506         if (ELEM(NULL, gpd, gpl)) 
00507                 return;
00508         
00509         /* free layer */        
00510         free_gpencil_frames(gpl);
00511         BLI_freelinkN(&gpd->layers, gpl);
00512 }
00513 
00514 /* ************************************************** */