Blender V2.61 - r43446

gpencil.c

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