Blender V2.61 - r43446
|
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 /* ************************************************** */