Blender V2.61 - r43446
|
00001 /* 00002 * 00003 * Undo system for painting and sculpting. 00004 * 00005 * ***** BEGIN GPL LICENSE BLOCK ***** 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU General Public License 00009 * as published by the Free Software Foundation; either version 2 00010 * of the License, or (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program; if not, write to the Free Software Foundation, 00019 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00020 * 00021 * ***** END GPL LICENSE BLOCK ***** 00022 */ 00023 00029 #include <stdlib.h> 00030 #include <string.h> 00031 00032 #include "MEM_guardedalloc.h" 00033 00034 #include "BLI_listbase.h" 00035 #include "BLI_utildefines.h" 00036 #include "BLI_string.h" 00037 00038 #include "DNA_userdef_types.h" 00039 00040 00041 #include "BKE_context.h" 00042 #include "BKE_global.h" 00043 00044 #include "ED_sculpt.h" 00045 00046 #include "paint_intern.h" 00047 00048 #define MAXUNDONAME 64 00049 00050 typedef struct UndoElem { 00051 struct UndoElem *next, *prev; 00052 char name[MAXUNDONAME]; 00053 uintptr_t undosize; 00054 00055 ListBase elems; 00056 00057 UndoRestoreCb restore; 00058 UndoFreeCb free; 00059 } UndoElem; 00060 00061 typedef struct UndoStack { 00062 int type; 00063 ListBase elems; 00064 UndoElem *current; 00065 } UndoStack; 00066 00067 static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL}; 00068 static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL}; 00069 00070 /* Generic */ 00071 00072 static void undo_restore(bContext *C, UndoStack *UNUSED(stack), UndoElem *uel) 00073 { 00074 if(uel && uel->restore) 00075 uel->restore(C, &uel->elems); 00076 } 00077 00078 static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel) 00079 { 00080 if(uel && uel->free) { 00081 uel->free(&uel->elems); 00082 BLI_freelistN(&uel->elems); 00083 } 00084 } 00085 00086 static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free) 00087 { 00088 UndoElem *uel; 00089 int nr; 00090 00091 /* Undo push is split up in begin and end, the reason is that as painting 00092 * happens more tiles/nodes are added to the list, and at the very end we 00093 * know how much memory the undo used to remove old undo elements */ 00094 00095 /* remove all undos after (also when stack->current==NULL) */ 00096 while(stack->elems.last != stack->current) { 00097 uel= stack->elems.last; 00098 undo_elem_free(stack, uel); 00099 BLI_freelinkN(&stack->elems, uel); 00100 } 00101 00102 /* make new */ 00103 stack->current= uel= MEM_callocN(sizeof(UndoElem), "undo file"); 00104 uel->restore= restore; 00105 uel->free= free; 00106 BLI_addtail(&stack->elems, uel); 00107 00108 /* name can be a dynamic string */ 00109 BLI_strncpy(uel->name, name, sizeof(uel->name)); 00110 00111 /* limit amount to the maximum amount*/ 00112 nr= 0; 00113 uel= stack->elems.last; 00114 while(uel) { 00115 nr++; 00116 if(nr==U.undosteps) break; 00117 uel= uel->prev; 00118 } 00119 if(uel) { 00120 while(stack->elems.first!=uel) { 00121 UndoElem *first= stack->elems.first; 00122 undo_elem_free(stack, first); 00123 BLI_freelinkN(&stack->elems, first); 00124 } 00125 } 00126 } 00127 00128 static void undo_stack_push_end(UndoStack *stack) 00129 { 00130 UndoElem *uel; 00131 uintptr_t totmem, maxmem; 00132 00133 if(U.undomemory != 0) { 00134 /* limit to maximum memory (afterwards, we can't know in advance) */ 00135 totmem= 0; 00136 maxmem= ((uintptr_t)U.undomemory)*1024*1024; 00137 00138 uel= stack->elems.last; 00139 while(uel) { 00140 totmem+= uel->undosize; 00141 if(totmem>maxmem) break; 00142 uel= uel->prev; 00143 } 00144 00145 if(uel) { 00146 while(stack->elems.first!=uel) { 00147 UndoElem *first= stack->elems.first; 00148 undo_elem_free(stack, first); 00149 BLI_freelinkN(&stack->elems, first); 00150 } 00151 } 00152 } 00153 } 00154 00155 static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name) 00156 { 00157 UndoElem *undo; 00158 00159 if(step==1) { 00160 if(stack->current==NULL); 00161 else { 00162 if(!name || strcmp(stack->current->name, name) == 0) { 00163 if(G.f & G_DEBUG) printf("undo %s\n", stack->current->name); 00164 undo_restore(C, stack, stack->current); 00165 stack->current= stack->current->prev; 00166 return 1; 00167 } 00168 } 00169 } 00170 else if(step==-1) { 00171 if((stack->current!=NULL && stack->current->next==NULL) || stack->elems.first==NULL); 00172 else { 00173 if(!name || strcmp(stack->current->name, name) == 0) { 00174 undo= (stack->current && stack->current->next)? stack->current->next: stack->elems.first; 00175 undo_restore(C, stack, undo); 00176 stack->current= undo; 00177 if(G.f & G_DEBUG) printf("redo %s\n", undo->name); 00178 return 1; 00179 } 00180 } 00181 } 00182 00183 return 0; 00184 } 00185 00186 static void undo_stack_free(UndoStack *stack) 00187 { 00188 UndoElem *uel; 00189 00190 for(uel=stack->elems.first; uel; uel=uel->next) 00191 undo_elem_free(stack, uel); 00192 00193 BLI_freelistN(&stack->elems); 00194 stack->current= NULL; 00195 } 00196 00197 /* Exported Functions */ 00198 00199 void undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free) 00200 { 00201 if(type == UNDO_PAINT_IMAGE) 00202 undo_stack_push_begin(&ImageUndoStack, name, restore, free); 00203 else if(type == UNDO_PAINT_MESH) 00204 undo_stack_push_begin(&MeshUndoStack, name, restore, free); 00205 } 00206 00207 ListBase *undo_paint_push_get_list(int type) 00208 { 00209 if(type == UNDO_PAINT_IMAGE) { 00210 if(ImageUndoStack.current) 00211 return &ImageUndoStack.current->elems; 00212 } 00213 else if(type == UNDO_PAINT_MESH) { 00214 if(MeshUndoStack.current) 00215 return &MeshUndoStack.current->elems; 00216 } 00217 00218 return NULL; 00219 } 00220 00221 void undo_paint_push_count_alloc(int type, int size) 00222 { 00223 if(type == UNDO_PAINT_IMAGE) 00224 ImageUndoStack.current->undosize += size; 00225 else if(type == UNDO_PAINT_MESH) 00226 MeshUndoStack.current->undosize += size; 00227 } 00228 00229 void undo_paint_push_end(int type) 00230 { 00231 if(type == UNDO_PAINT_IMAGE) 00232 undo_stack_push_end(&ImageUndoStack); 00233 else if(type == UNDO_PAINT_MESH) 00234 undo_stack_push_end(&MeshUndoStack); 00235 } 00236 00237 int ED_undo_paint_step(bContext *C, int type, int step, const char *name) 00238 { 00239 if(type == UNDO_PAINT_IMAGE) 00240 return undo_stack_step(C, &ImageUndoStack, step, name); 00241 else if(type == UNDO_PAINT_MESH) 00242 return undo_stack_step(C, &MeshUndoStack, step, name); 00243 00244 return 0; 00245 } 00246 00247 int ED_undo_paint_valid(int type, const char *name) 00248 { 00249 UndoStack *stack; 00250 00251 if(type == UNDO_PAINT_IMAGE) 00252 stack= &ImageUndoStack; 00253 else if(type == UNDO_PAINT_MESH) 00254 stack= &MeshUndoStack; 00255 else 00256 return 0; 00257 00258 if(stack->current==NULL); 00259 else { 00260 if(name && strcmp(stack->current->name, name) == 0) 00261 return 1; 00262 else 00263 return stack->elems.first != stack->elems.last; 00264 } 00265 return 0; 00266 } 00267 00268 void ED_undo_paint_free(void) 00269 { 00270 undo_stack_free(&ImageUndoStack); 00271 undo_stack_free(&MeshUndoStack); 00272 } 00273