]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/Undo.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / tools / radiant / Undo.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "qe3.h"
33 #include "Radiant.h"
34
35 /*
36
37   QERadiant Undo/Redo
38
39
40 basic setup:
41
42 <-g_undolist---------g_lastundo> <---map data---> <-g_lastredo---------g_redolist->
43
44
45   undo/redo on the world_entity is special, only the epair changes are remembered
46   and the world entity never gets deleted.
47
48   FIXME: maybe reset the Undo system at map load
49                  maybe also reset the entityId at map load
50 */
51
52 typedef struct undo_s
53 {
54         double time;                            //time operation was performed
55         int id;                                         //every undo has an unique id
56         int done;                                       //true when undo is build
57         char *operation;                        //name of the operation
58         brush_t brushlist;                      //deleted brushes
59         entity_t entitylist;            //deleted entities
60         struct undo_s *prev, *next;     //next and prev undo in list
61 } undo_t;
62
63 undo_t *g_undolist;                                             //first undo in the list
64 undo_t *g_lastundo;                                             //last undo in the list
65 undo_t *g_redolist;                                             //first redo in the list
66 undo_t *g_lastredo;                                             //last undo in list
67 int g_undoMaxSize = 64;                                 //maximum number of undos
68 int g_undoSize = 0;                                             //number of undos in the list
69 int g_undoMaxMemorySize = 2*1024*1024;  //maximum undo memory (default 2 MB)
70 int g_undoMemorySize = 0;                               //memory size of undo buffer
71 int g_undoId = 1;                                               //current undo ID (zero is invalid id)
72 int g_redoId = 1;                                               //current redo ID (zero is invalid id)
73
74
75 /*
76 =============
77 Undo_MemorySize
78 =============
79 */
80 int Undo_MemorySize(void)
81 {
82         /*
83         int size;
84         undo_t *undo;
85         brush_t *pBrush;
86         entity_t *pEntity;
87
88         size = 0;
89         for (undo = g_undolist; undo; undo = undo->next)
90         {
91                 for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pBrush->next)
92                 {
93                         size += Brush_MemorySize(pBrush);
94                 }
95                 for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pEntity->next)
96                 {
97                         size += Entity_MemorySize(pEntity);
98                 }
99                 size += sizeof(undo_t);
100         }
101         return size;
102         */
103         return g_undoMemorySize;
104 }
105
106 /*
107 =============
108 Undo_ClearRedo
109 =============
110 */
111 void Undo_ClearRedo(void)
112 {
113         undo_t *redo, *nextredo;
114         brush_t *pBrush, *pNextBrush;
115         entity_t *pEntity, *pNextEntity;
116
117         for (redo = g_redolist; redo; redo = nextredo)
118         {
119                 nextredo = redo->next;
120                 for (pBrush = redo->brushlist.next ; pBrush != NULL && pBrush != &redo->brushlist ; pBrush = pNextBrush)
121                 {
122                         pNextBrush = pBrush->next;
123                         Brush_Free(pBrush);
124                 }
125                 for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = pNextEntity)
126                 {
127                         pNextEntity = pEntity->next;
128                         Entity_Free(pEntity);
129                 }
130                 Mem_Free(redo);
131         }
132         g_redolist = NULL;
133         g_lastredo = NULL;
134         g_redoId = 1;
135 }
136
137 /*
138 =============
139 Undo_Clear
140
141   Clears the undo buffer.
142 =============
143 */
144 void Undo_Clear(void)
145 {
146         undo_t *undo, *nextundo;
147         brush_t *pBrush, *pNextBrush;
148         entity_t *pEntity, *pNextEntity;
149
150         Undo_ClearRedo();
151         for (undo = g_undolist; undo; undo = nextundo)
152         {
153                 nextundo = undo->next;
154                 for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush)
155                 {
156                         pNextBrush = pBrush->next;
157                         g_undoMemorySize -= Brush_MemorySize(pBrush);
158                         Brush_Free(pBrush);
159                 }
160                 for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity)
161                 {
162                         pNextEntity = pEntity->next;
163                         g_undoMemorySize -= Entity_MemorySize(pEntity);
164                         Entity_Free(pEntity);
165                 }
166                 g_undoMemorySize -= sizeof(undo_t);
167                 Mem_Free(undo);
168         }
169         g_undolist = NULL;
170         g_lastundo = NULL;
171         g_undoSize = 0;
172         g_undoMemorySize = 0;
173         g_undoId = 1;
174 }
175
176 /*
177 =============
178 Undo_SetMaxSize
179 =============
180 */
181 void Undo_SetMaxSize(int size)
182 {
183         Undo_Clear();
184         if (size < 1) g_undoMaxSize = 1;
185         else g_undoMaxSize = size;
186 }
187
188 /*
189 =============
190 Undo_GetMaxSize
191 =============
192 */
193 int Undo_GetMaxSize(void)
194 {
195         return g_undoMaxSize;
196 }
197
198 /*
199 =============
200 Undo_SetMaxMemorySize
201 =============
202 */
203 void Undo_SetMaxMemorySize(int size)
204 {
205         Undo_Clear();
206         if (size < 1024) g_undoMaxMemorySize = 1024;
207         else g_undoMaxMemorySize = size;
208 }
209
210 /*
211 =============
212 Undo_GetMaxMemorySize
213 =============
214 */
215 int Undo_GetMaxMemorySize(void)
216 {
217         return g_undoMaxMemorySize;
218 }
219
220 /*
221 =============
222 Undo_FreeFirstUndo
223 =============
224 */
225 void Undo_FreeFirstUndo(void)
226 {
227         undo_t *undo;
228         brush_t *pBrush, *pNextBrush;
229         entity_t *pEntity, *pNextEntity;
230
231         //remove the oldest undo from the undo buffer
232         undo = g_undolist;
233         g_undolist = g_undolist->next;
234         g_undolist->prev = NULL;
235         //
236         for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush)
237         {
238                 pNextBrush = pBrush->next;
239                 g_undoMemorySize -= Brush_MemorySize(pBrush);
240                 Brush_Free(pBrush);
241         }
242         for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity)
243         {
244                 pNextEntity = pEntity->next;
245                 g_undoMemorySize -= Entity_MemorySize(pEntity);
246                 Entity_Free(pEntity);
247         }
248         g_undoMemorySize -= sizeof(undo_t);
249         Mem_Free(undo);
250         g_undoSize--;
251 }
252
253 /*
254 =============
255 Undo_GeneralStart
256 =============
257 */
258 void Undo_GeneralStart(char *operation)
259 {
260         undo_t *undo;
261         brush_t *pBrush;
262         entity_t *pEntity;
263
264
265         if (g_lastundo)
266         {
267                 if (!g_lastundo->done)
268                 {
269                         common->Printf("Undo_Start: WARNING last undo not finished.\n");
270                 }
271         }
272
273         undo = (undo_t *) Mem_ClearedAlloc(sizeof(undo_t));
274         if (!undo) return;
275         memset(undo, 0, sizeof(undo_t));
276         undo->brushlist.next = &undo->brushlist;
277         undo->brushlist.prev = &undo->brushlist;
278         undo->entitylist.next = &undo->entitylist;
279         undo->entitylist.prev = &undo->entitylist;
280         if (g_lastundo) g_lastundo->next = undo;
281         else g_undolist = undo;
282         undo->prev = g_lastundo;
283         undo->next = NULL;
284         g_lastundo = undo;
285         
286         undo->time = Sys_DoubleTime();
287         //
288         if (g_undoId > g_undoMaxSize * 2) g_undoId = 1;
289         if (g_undoId <= 0) g_undoId = 1;
290         undo->id = g_undoId++;
291         undo->done = false;
292         undo->operation = operation;
293         //reset the undo IDs of all brushes using the new ID
294         for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next)
295         {
296                 if (pBrush->undoId == undo->id)
297                 {
298                         pBrush->undoId = 0;
299                 }
300         }
301         for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next)
302         {
303                 if (pBrush->undoId == undo->id)
304                 {
305                         pBrush->undoId = 0;
306                 }
307         }
308         //reset the undo IDs of all entities using thew new ID
309         for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next)
310         {
311                 if (pEntity->undoId == undo->id)
312                 {
313                         pEntity->undoId = 0;
314                 }
315         }
316         g_undoMemorySize += sizeof(undo_t);
317         g_undoSize++;
318         //undo buffer is bound to a max
319         if (g_undoSize > g_undoMaxSize)
320         {
321                 Undo_FreeFirstUndo();
322         }
323 }
324
325 /*
326 =============
327 Undo_BrushInUndo
328 =============
329 */
330 int Undo_BrushInUndo(undo_t *undo, brush_t *brush)
331 {
332         brush_t *b;
333
334         for (b = undo->brushlist.next; b != &undo->brushlist; b = b->next)
335         {
336                 if (b == brush) return true;
337         }
338         return false;
339 }
340
341 /*
342 =============
343 Undo_EntityInUndo
344 =============
345 */
346 int Undo_EntityInUndo(undo_t *undo, entity_t *ent)
347 {
348         entity_t *e;
349
350         for (e = undo->entitylist.next; e != &undo->entitylist; e = e->next)
351         {
352                 if (e == ent) return true;
353         }
354         return false;
355 }
356
357 /*
358 =============
359 Undo_Start
360 =============
361 */
362 void Undo_Start(char *operation)
363 {
364         Undo_ClearRedo();
365         Undo_GeneralStart(operation);
366 }
367
368 /*
369 =============
370 Undo_AddBrush
371 =============
372 */
373 void Undo_AddBrush(brush_t *pBrush)
374 {
375         if (!g_lastundo)
376         {
377                 Sys_Status("Undo_AddBrushList: no last undo.\n");
378                 return;
379         }
380         if (g_lastundo->entitylist.next != &g_lastundo->entitylist)
381         {
382                 Sys_Status("Undo_AddBrushList: WARNING adding brushes after entity.\n");
383         }
384         //if the brush is already in the undo
385         if (Undo_BrushInUndo(g_lastundo, pBrush))
386                 return;
387         //clone the brush
388         brush_t* pClone = Brush_FullClone(pBrush);
389         //save the ID of the owner entity
390         pClone->ownerId = pBrush->owner->entityId;
391
392         if (pBrush->owner && !(pBrush->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN)) {
393                 Undo_AddEntity(pBrush->owner);
394         }
395
396         //save the old undo ID for previous undos
397         pClone->undoId = pBrush->undoId;
398         Brush_AddToList (pClone, &g_lastundo->brushlist);
399         //
400         g_undoMemorySize += Brush_MemorySize(pClone);
401 }
402
403 /*
404 =============
405 Undo_AddBrushList
406 =============
407 */
408 void Undo_AddBrushList(brush_t *brushlist)
409 {
410         brush_t *pBrush;
411
412         if (!g_lastundo)
413         {
414                 Sys_Status("Undo_AddBrushList: no last undo.\n");
415                 return;
416         }
417         if (g_lastundo->entitylist.next != &g_lastundo->entitylist)
418         {
419                 Sys_Status("Undo_AddBrushList: WARNING adding brushes after entity.\n");
420         }
421         //copy the brushes to the undo
422         for (pBrush = brushlist->next ; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next)
423         {
424                 //if the brush is already in the undo
425                 if (Undo_BrushInUndo(g_lastundo, pBrush))
426                         continue;
427                 //clone the brush
428                 brush_t* pClone = Brush_FullClone(pBrush);
429                 //save the ID of the owner entity
430                 pClone->ownerId = pBrush->owner->entityId;
431                 //save the old undo ID from previous undos
432                 pClone->undoId = pBrush->undoId;
433
434                 if ( pBrush->owner && pBrush->owner != world_entity ) {
435                         Undo_AddEntity(pBrush->owner);
436                 }
437
438
439                 Brush_AddToList (pClone, &g_lastundo->brushlist);
440                 //
441                 g_undoMemorySize += Brush_MemorySize(pClone);
442         }
443 }
444
445 /*
446 =============
447 Undo_EndBrush
448 =============
449 */
450 void Undo_EndBrush(brush_t *pBrush)
451 {
452         if (!g_lastundo)
453         {
454                 //Sys_Status("Undo_End: no last undo.\n");
455                 return;
456         }
457         if (g_lastundo->done)
458         {
459                 //Sys_Status("Undo_End: last undo already finished.\n");
460                 return;
461         }
462         pBrush->undoId = g_lastundo->id;
463 }
464
465 /*
466 =============
467 Undo_EndBrushList
468 =============
469 */
470 void Undo_EndBrushList(brush_t *brushlist)
471 {
472         if (!g_lastundo)
473         {
474                 //Sys_Status("Undo_End: no last undo.\n");
475                 return;
476         }
477         if (g_lastundo->done)
478         {
479                 //Sys_Status("Undo_End: last undo already finished.\n");
480                 return;
481         }
482         for (brush_t* pBrush = brushlist->next; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next)
483         {
484                 pBrush->undoId = g_lastundo->id;
485         }
486 }
487
488 /*
489 =============
490 Undo_AddEntity
491 =============
492 */
493 void Undo_AddEntity(entity_t *entity)
494 {
495         entity_t* pClone;
496
497         if (!g_lastundo)
498         {
499                 Sys_Status("Undo_AddEntity: no last undo.\n");
500                 return;
501         }
502         //if the entity is already in the undo
503         if (Undo_EntityInUndo(g_lastundo, entity))
504                 return;
505         //clone the entity
506         pClone = Entity_Clone(entity);
507         //NOTE: Entity_Clone adds the entity to the entity list
508         //              so we remove it from that list here
509         Entity_RemoveFromList(pClone);
510         //save the old undo ID for previous undos
511         pClone->undoId = entity->undoId;
512         //save the entity ID (we need a full clone)
513         pClone->entityId = entity->entityId;
514         //
515         Entity_AddToList(pClone, &g_lastundo->entitylist);
516         //
517         g_undoMemorySize += Entity_MemorySize(pClone);
518 }
519
520 /*
521 =============
522 Undo_EndEntity
523 =============
524 */
525 void Undo_EndEntity(entity_t *entity)
526 {
527         if (!g_lastundo)
528         {
529                 //Sys_Status("Undo_End: no last undo.\n");
530                 return;
531         }
532         if (g_lastundo->done)
533         {
534                 //Sys_Status("Undo_End: last undo already finished.\n");
535                 return;
536         }
537         if (entity == world_entity)
538         {
539                 //Sys_Status("Undo_AddEntity: undo on world entity.\n");
540                 //NOTE: we never delete the world entity when undoing an operation
541                 //              we only transfer the epairs
542                 return;
543         }
544         entity->undoId = g_lastundo->id;
545 }
546
547 /*
548 =============
549 Undo_End
550 =============
551 */
552 void Undo_End(void)
553 {
554         if (!g_lastundo)
555         {
556                 //Sys_Status("Undo_End: no last undo.\n");
557                 return;
558         }
559         if (g_lastundo->done)
560         {
561                 //Sys_Status("Undo_End: last undo already finished.\n");
562                 return;
563         }
564         g_lastundo->done = true;
565
566         //undo memory size is bound to a max
567         while (g_undoMemorySize > g_undoMaxMemorySize)
568         {
569                 //always keep one undo
570                 if (g_undolist == g_lastundo) break;
571                 Undo_FreeFirstUndo();
572         }
573         //
574         //Sys_Status("undo size = %d, undo memory = %d\n", g_undoSize, g_undoMemorySize);
575 }
576
577 /*
578 =============
579 Undo_Undo
580 =============
581 */
582 void Undo_Undo(void)
583 {
584         undo_t *undo, *redo;
585         brush_t *pBrush, *pNextBrush;
586         entity_t *pEntity, *pNextEntity, *pUndoEntity;
587
588         if (!g_lastundo)
589         {
590                 Sys_Status("Nothing left to undo.\n");
591                 return;
592         }
593         if (!g_lastundo->done)
594         {
595                 Sys_Status("Undo_Undo: WARNING: last undo not yet finished!\n");
596         }
597         // get the last undo
598         undo = g_lastundo;
599         if (g_lastundo->prev) g_lastundo->prev->next = NULL;
600         else g_undolist = NULL;
601         g_lastundo = g_lastundo->prev;
602
603         //allocate a new redo
604         redo = (undo_t *) Mem_ClearedAlloc(sizeof(undo_t));
605         if (!redo) return;
606         memset(redo, 0, sizeof(undo_t));
607         redo->brushlist.next = &redo->brushlist;
608         redo->brushlist.prev = &redo->brushlist;
609         redo->entitylist.next = &redo->entitylist;
610         redo->entitylist.prev = &redo->entitylist;
611         if (g_lastredo) g_lastredo->next = redo;
612         else g_redolist = redo;
613         redo->prev = g_lastredo;
614         redo->next = NULL;
615         g_lastredo = redo;
616         redo->time = Sys_DoubleTime();
617         redo->id = g_redoId++;
618         redo->done = true;
619         redo->operation = undo->operation;
620
621         //reset the redo IDs of all brushes using the new ID
622         for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next)
623         {
624                 if (pBrush->redoId == redo->id)
625                 {
626                         pBrush->redoId = 0;
627                 }
628         }
629         for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next)
630         {
631                 if (pBrush->redoId == redo->id)
632                 {
633                         pBrush->redoId = 0;
634                 }
635         }
636         //reset the redo IDs of all entities using thew new ID
637         for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next)
638         {
639                 if (pEntity->redoId == redo->id)
640                 {
641                         pEntity->redoId = 0;
642                 }
643         }
644
645         // remove current selection
646         Select_Deselect();
647         // move "created" brushes to the redo
648         for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush=pNextBrush)
649         {
650                 pNextBrush = pBrush->next;
651                 if (pBrush->undoId == undo->id)
652                 {
653                         //Brush_Free(pBrush);
654                         //move the brush to the redo
655                         Brush_RemoveFromList(pBrush);
656                         Brush_AddToList(pBrush, &redo->brushlist);
657                         //make sure the ID of the owner is stored
658                         pBrush->ownerId = pBrush->owner->entityId;
659                         //unlink the brush from the owner entity
660                         Entity_UnlinkBrush(pBrush);
661                 }
662         }
663         // move "created" entities to the redo
664         for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity)
665         {
666                 pNextEntity = pEntity->next;
667                 if (pEntity->undoId == undo->id)
668                 {
669                         // check if this entity is in the undo
670                         for (pUndoEntity = undo->entitylist.next; pUndoEntity != NULL && pUndoEntity != &undo->entitylist; pUndoEntity = pUndoEntity->next)
671                         {
672                                 // move brushes to the undo entity
673                                 if (pUndoEntity->entityId == pEntity->entityId)
674                                 {
675                                         pUndoEntity->brushes.next = pEntity->brushes.next;
676                                         pUndoEntity->brushes.prev = pEntity->brushes.prev;
677                                         pEntity->brushes.next = &pEntity->brushes;
678                                         pEntity->brushes.prev = &pEntity->brushes;
679                                 }
680                         }
681                         //
682                         //Entity_Free(pEntity);
683                         //move the entity to the redo
684                         Entity_RemoveFromList(pEntity);
685                         Entity_AddToList(pEntity, &redo->entitylist);
686                 }
687         }
688         // add the undo entities back into the entity list
689         for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = undo->entitylist.next)
690         {
691                 g_undoMemorySize -= Entity_MemorySize(pEntity);
692                 //if this is the world entity
693                 if (pEntity->entityId == world_entity->entityId)
694                 {
695                         //free the epairs of the world entity
696                         Entity_FreeEpairs(world_entity);
697                         //set back the original epairs
698                         world_entity->epairs = pEntity->epairs;
699                         //free the world_entity clone that stored the epairs
700                         Entity_Free(pEntity);
701                 }
702                 else
703                 {
704                         Entity_RemoveFromList(pEntity);
705                         Entity_AddToList(pEntity, &entities);
706                         pEntity->redoId = redo->id;
707                 }
708         }
709         // add the undo brushes back into the selected brushes
710         for (pBrush = undo->brushlist.next; pBrush != NULL && pBrush != &undo->brushlist; pBrush = undo->brushlist.next)
711         {
712                 g_undoMemorySize -= Brush_MemorySize(pBrush);
713                 Brush_RemoveFromList(pBrush);
714         Brush_AddToList(pBrush, &active_brushes);
715                 for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next)
716                 {
717                         if (pEntity->entityId == pBrush->ownerId)
718                         {
719                                 Entity_LinkBrush(pEntity, pBrush);
720                                 break;
721                         }
722                 }
723                 //if the brush is not linked then it should be linked into the world entity
724                 if (pEntity == NULL || pEntity == &entities)
725                 {
726                         Entity_LinkBrush(world_entity, pBrush);
727                 }
728                 //build the brush
729                 //Brush_Build(pBrush);
730                 Select_Brush(pBrush);
731                 pBrush->redoId = redo->id;
732     }
733         //
734         common->Printf("%s undone.\n", undo->operation);
735         // free the undo
736         g_undoMemorySize -= sizeof(undo_t);
737         Mem_Free(undo);
738         g_undoSize--;
739         g_undoId--;
740         if (g_undoId <= 0) g_undoId = 2 * g_undoMaxSize;
741         //
742
743         Sys_BeginWait();
744         brush_t *b, *next;
745         for (b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next) {
746                 next = b->next;
747                 Brush_Build( b, true, false, false );
748         }
749         for (b = selected_brushes.next ; b != NULL && b != &selected_brushes ; b=next) {
750                 next = b->next;
751                 Brush_Build( b, true, false, false );
752         }
753         Sys_EndWait();
754
755     g_bScreenUpdates = true; 
756     Sys_UpdateWindows(W_ALL);
757 }
758
759 /*
760 =============
761 Undo_Redo
762 =============
763 */
764 void Undo_Redo(void)
765 {
766         undo_t *redo;
767         brush_t *pBrush, *pNextBrush;
768         entity_t *pEntity, *pNextEntity, *pRedoEntity;
769
770         if (!g_lastredo)
771         {
772                 Sys_Status("Nothing left to redo.\n");
773                 return;
774         }
775         if (g_lastundo)
776         {
777                 if (!g_lastundo->done)
778                 {
779                         Sys_Status("WARNING: last undo not finished.\n");
780                 }
781         }
782         // get the last redo
783         redo = g_lastredo;
784         if (g_lastredo->prev) g_lastredo->prev->next = NULL;
785         else g_redolist = NULL;
786         g_lastredo = g_lastredo->prev;
787         //
788         Undo_GeneralStart(redo->operation);
789         // remove current selection
790         Select_Deselect();
791         // move "created" brushes back to the last undo
792         for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pNextBrush)
793         {
794                 pNextBrush = pBrush->next;
795                 if (pBrush->redoId == redo->id)
796                 {
797                         //move the brush to the undo
798                         Brush_RemoveFromList(pBrush);
799                         Brush_AddToList(pBrush, &g_lastundo->brushlist);
800                         g_undoMemorySize += Brush_MemorySize(pBrush);
801                         pBrush->ownerId = pBrush->owner->entityId;
802                         Entity_UnlinkBrush(pBrush);
803                 }
804         }
805         // move "created" entities back to the last undo
806         for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity)
807         {
808                 pNextEntity = pEntity->next;
809                 if (pEntity->redoId == redo->id)
810                 {
811                         // check if this entity is in the redo
812                         for (pRedoEntity = redo->entitylist.next; pRedoEntity != NULL && pRedoEntity != &redo->entitylist; pRedoEntity = pRedoEntity->next)
813                         {
814                                 // move brushes to the redo entity
815                                 if (pRedoEntity->entityId == pEntity->entityId)
816                                 {
817                                         pRedoEntity->brushes.next = pEntity->brushes.next;
818                                         pRedoEntity->brushes.prev = pEntity->brushes.prev;
819                                         pEntity->brushes.next = &pEntity->brushes;
820                                         pEntity->brushes.prev = &pEntity->brushes;
821                                 }
822                         }
823                         //
824                         //Entity_Free(pEntity);
825                         //move the entity to the redo
826                         Entity_RemoveFromList(pEntity);
827                         Entity_AddToList(pEntity, &g_lastundo->entitylist);
828                         g_undoMemorySize += Entity_MemorySize(pEntity);
829                 }
830         }
831         // add the undo entities back into the entity list
832         for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = redo->entitylist.next)
833         {
834                 //if this is the world entity
835                 if (pEntity->entityId == world_entity->entityId)
836                 {
837                         //free the epairs of the world entity
838                         Entity_FreeEpairs(world_entity);
839                         //set back the original epairs
840                         world_entity->epairs = pEntity->epairs;
841                         //free the world_entity clone that stored the epairs
842                         Entity_Free(pEntity);
843                 }
844                 else
845                 {
846                         Entity_RemoveFromList(pEntity);
847                         Entity_AddToList(pEntity, &entities);
848                 }
849         }
850         // add the redo brushes back into the selected brushes
851         for (pBrush = redo->brushlist.next; pBrush != NULL && pBrush != &redo->brushlist; pBrush = redo->brushlist.next)
852         {
853                 Brush_RemoveFromList(pBrush);
854         Brush_AddToList(pBrush, &active_brushes);
855                 for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next)
856                 {
857                         if (pEntity->entityId == pBrush->ownerId)
858                         {
859                                 Entity_LinkBrush(pEntity, pBrush);
860                                 break;
861                         }
862                 }
863                 //if the brush is not linked then it should be linked into the world entity
864                 if (pEntity == NULL || pEntity == &entities)
865                 {
866                         Entity_LinkBrush(world_entity, pBrush);
867                 }
868                 //build the brush
869                 //Brush_Build(pBrush);
870                 Select_Brush(pBrush);
871     }
872         //
873         Undo_End();
874         //
875         common->Printf("%s redone.\n", redo->operation);
876         //
877         g_redoId--;
878         // free the undo
879         Mem_Free(redo);
880         //
881     g_bScreenUpdates = true; 
882     Sys_UpdateWindows(W_ALL);
883 }
884
885 /*
886 =============
887 Undo_RedoAvailable
888 =============
889 */
890 int Undo_RedoAvailable(void)
891 {
892         if (g_lastredo) return true;
893         return false;
894 }
895
896 /*
897 =============
898 Undo_UndoAvailable
899 =============
900 */
901 int Undo_UndoAvailable(void)
902 {
903         if (g_lastundo)
904         {
905                 if (g_lastundo->done)
906                         return true;
907         }
908         return false;
909 }