doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Undo.cpp
Go to the documentation of this file.
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;
158  Brush_Free(pBrush);
159  }
160  for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity)
161  {
162  pNextEntity = pEntity->next;
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 */
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 */
194 {
195  return g_undoMaxSize;
196 }
197 
198 /*
199 =============
200 Undo_SetMaxMemorySize
201 =============
202 */
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 */
216 {
217  return g_undoMaxMemorySize;
218 }
219 
220 /*
221 =============
222 Undo_FreeFirstUndo
223 =============
224 */
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;
240  Brush_Free(pBrush);
241  }
242  for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity)
243  {
244  pNextEntity = pEntity->next;
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 */
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
320  {
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 */
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 */
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  //
401 }
402 
403 /*
404 =============
405 Undo_AddBrushList
406 =============
407 */
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  //
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 */
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 */
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  //
518 }
519 
520 /*
521 =============
522 Undo_EndEntity
523 =============
524 */
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
568  {
569  //always keep one undo
570  if (g_undolist == g_lastundo) break;
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  {
692  //if this is the world entity
693  if (pEntity->entityId == world_entity->entityId)
694  {
695  //free the epairs of the 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  {
713  Brush_RemoveFromList(pBrush);
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  {
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  //
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);
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);
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
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);
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  {
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 */
891 {
892  if (g_lastredo) return true;
893  return false;
894 }
895 
896 /*
897 =============
898 Undo_UndoAvailable
899 =============
900 */
902 {
903  if (g_lastundo)
904  {
905  if (g_lastundo->done)
906  return true;
907  }
908  return false;
909 }
int entityId
Definition: EditorEntity.h:36
brush_t * Brush_FullClone(brush_t *b)
void Undo_AddBrushList(brush_t *brushlist)
Definition: Undo.cpp:408
void WINAPI Sys_UpdateWindows(int nBits)
Definition: MainFrm.cpp:3974
entity_t * world_entity
Definition: EditorMap.cpp:49
int Undo_EntityInUndo(undo_t *undo, entity_t *ent)
Definition: Undo.cpp:346
void Entity_FreeEpairs(entity_t *e)
brush_t selected_brushes
Definition: EditorMap.cpp:40
void Entity_Free(entity_t *e)
brush_t brushlist
Definition: Undo.cpp:58
brush_t active_brushes
Definition: EditorMap.cpp:39
void Entity_UnlinkBrush(brush_t *b)
struct undo_s * next
Definition: Undo.cpp:60
int Undo_RedoAvailable(void)
Definition: Undo.cpp:890
void Undo_FreeFirstUndo(void)
Definition: Undo.cpp:225
void Undo_EndBrush(brush_t *pBrush)
Definition: Undo.cpp:450
void Sys_Status(const char *psz, int part)
Definition: Radiant.cpp:465
void Undo_Redo(void)
Definition: Undo.cpp:764
void Brush_Free(brush_t *b, bool bRemoveNode)
int undoId
Definition: EditorEntity.h:36
double time
Definition: Undo.cpp:54
undo_t * g_undolist
Definition: Undo.cpp:63
int Undo_GetMaxMemorySize(void)
Definition: Undo.cpp:215
void Undo_Start(char *operation)
Definition: Undo.cpp:362
int g_undoMaxSize
Definition: Undo.cpp:67
brush_t brushes
Definition: EditorEntity.h:35
void Brush_Build(brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool updateLights)
void Undo_EndEntity(entity_t *entity)
Definition: Undo.cpp:525
void Undo_Undo(void)
Definition: Undo.cpp:582
int g_undoMemorySize
Definition: Undo.cpp:70
struct undo_s undo_t
int Undo_UndoAvailable(void)
Definition: Undo.cpp:901
void Brush_AddToList(brush_t *b, brush_t *list)
idCommon * common
Definition: Common.cpp:206
char * operation
Definition: Undo.cpp:57
struct entity_s * prev
Definition: EditorEntity.h:34
#define NULL
Definition: Lib.h:88
struct entity_s * next
Definition: EditorEntity.h:34
int id
Definition: Undo.cpp:55
void Undo_ClearRedo(void)
Definition: Undo.cpp:111
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
void Brush_RemoveFromList(brush_t *b)
entity_t * Entity_Clone(entity_t *e)
int g_undoId
Definition: Undo.cpp:71
virtual void Printf(const char *fmt,...) id_attribute((format(printf
undo_t * g_redolist
Definition: Undo.cpp:65
int Brush_MemorySize(brush_t *b)
int Undo_GetMaxSize(void)
Definition: Undo.cpp:193
void Undo_Clear(void)
Definition: Undo.cpp:144
int g_undoSize
Definition: Undo.cpp:68
void Undo_AddEntity(entity_t *entity)
Definition: Undo.cpp:493
void Entity_RemoveFromList(entity_t *e)
GLubyte GLubyte b
Definition: glext.h:4662
int g_redoId
Definition: Undo.cpp:72
int done
Definition: Undo.cpp:56
void Entity_LinkBrush(entity_t *e, brush_t *b)
int redoId
Definition: EditorEntity.h:36
void Undo_EndBrushList(brush_t *brushlist)
Definition: Undo.cpp:470
void Undo_AddBrush(brush_t *pBrush)
Definition: Undo.cpp:373
GLsizeiptr size
Definition: glext.h:3112
entity_t entities
Definition: EditorMap.cpp:47
entity_t entitylist
Definition: Undo.cpp:59
int Undo_MemorySize(void)
Definition: Undo.cpp:80
void Undo_End(void)
Definition: Undo.cpp:552
idDict epairs
Definition: EditorEntity.h:42
void * Mem_ClearedAlloc(const int size)
Definition: Heap.cpp:1149
bool g_bScreenUpdates
Definition: MainFrm.cpp:77
void Undo_SetMaxSize(int size)
Definition: Undo.cpp:181
void Entity_AddToList(entity_t *e, entity_t *list)
struct undo_s * prev
Definition: Undo.cpp:60
int Undo_BrushInUndo(undo_t *undo, brush_t *brush)
Definition: Undo.cpp:330
undo_t * g_lastredo
Definition: Undo.cpp:66
int Entity_MemorySize(entity_t *e)
void Undo_GeneralStart(char *operation)
Definition: Undo.cpp:258
undo_t * g_lastundo
Definition: Undo.cpp:64
void Undo_SetMaxMemorySize(int size)
Definition: Undo.cpp:203
int g_undoMaxMemorySize
Definition: Undo.cpp:69
Definition: Undo.cpp:52