summaryrefslogtreecommitdiff
path: root/undo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'undo.cpp')
-rw-r--r--undo.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/undo.cpp b/undo.cpp
new file mode 100644
index 0000000..7858f8d
--- /dev/null
+++ b/undo.cpp
@@ -0,0 +1,146 @@
+// get ready for some MLG...
+
+// These get four things pushed together: the address of what's being
+// changed, what type the data is, the original data, and the type again.
+// The type is encoded twice so we always know how big the data is whether
+// we're undoing or redoing.
+// We need to encode data that's able to go from A -> B as well as B -> A. Thus
+// for the ints I encode the difference instead of just whatever the last value
+// was. Strings currently just stores both.
+void Action_Change_Commit(memory *Memory, void *OriginalData, void *NewData, action_change_type ActionChange)
+{
+ void *UndoEntry = AllocateMemory(Memory, sizeof(void *), P_UndoBuffer);
+ *(ptrsize *)UndoEntry = (ptrsize)OriginalData;
+ void *Data = AllocateMemory(Memory, sizeof(action_change_type), P_UndoBuffer);
+ *(action_change_type *)Data = ActionChange;
+ switch (ActionChange)
+ {
+ case action_change_u16:
+ {
+ uint16 OriginalValue = *(uint16 *)OriginalData;
+ uint16 NewValue = *(uint16 *)NewData;
+ uint16 Difference = NewValue - OriginalValue;
+ void *Data = AllocateMemory(Memory, sizeof(uint16), P_UndoBuffer);
+ *(uint16 *)Data = Difference;
+ *(uint16 *)OriginalData = *(uint16 *)NewData;
+ } break;
+ case action_change_i16:
+ {
+ int16 OriginalValue = *(int16 *)OriginalData;
+ int16 NewValue = *(int16 *)NewData;
+ int16 Difference = NewValue - OriginalValue;
+ void *Data = AllocateMemory(Memory, sizeof(int16), P_UndoBuffer);
+ *(int16 *)Data = Difference;
+ *(int16 *)OriginalData = *(int16 *)NewData;
+ } break;
+ case action_change_u32:
+ {
+ uint32 OriginalValue = *(uint32 *)OriginalData;
+ uint32 NewValue = *(uint32 *)NewData;
+ uint32 Difference = NewValue - OriginalValue;
+ void *Data = AllocateMemory(Memory, sizeof(uint32), P_UndoBuffer);
+ *(uint32 *)Data = Difference;
+ *(uint32 *)OriginalData = *(uint32 *)NewData;
+ } break;
+ case action_change_i32:
+ {
+ int32 OriginalValue = *(int32 *)OriginalData;
+ int32 NewValue = *(int32 *)NewData;
+ int32 Difference = NewValue - OriginalValue;
+ void *Data = AllocateMemory(Memory, sizeof(int32), P_UndoBuffer);
+ *(int32 *)Data = Difference;
+ *(int32 *)OriginalData = *(int32 *)NewData;
+ } break;
+ case action_change_r32:
+ {
+ real32 OriginalValue = *(real32 *)OriginalData;
+ real32 NewValue = *(real32 *)NewData;
+ real32 Difference = NewValue - OriginalValue;
+ void *Data = AllocateMemory(Memory, sizeof(real32), P_UndoBuffer);
+ *(real32 *)Data = Difference;
+ *(real32 *)OriginalData = *(real32 *)NewData;
+ } break;
+ case action_change_u64:
+ {
+ uint64 OriginalValue = *(uint64 *)OriginalData;
+ uint64 NewValue = *(uint64 *)NewData;
+ uint64 Difference = NewValue - OriginalValue;
+ void *Data = AllocateMemory(Memory, sizeof(uint64), P_UndoBuffer);
+ *(uint64 *)Data = Difference;
+ *(uint64 *)OriginalData = *(uint64 *)NewData;
+ } break;
+ case action_change_ptr:
+ {
+ ptrsize OriginalValue = *(ptrsize *)OriginalData;
+ ptrsize NewValue = *(ptrsize *)NewData;
+ ptrsize Difference = NewValue - OriginalValue;
+ void *Data = AllocateMemory(Memory, sizeof(ptrsize), P_UndoBuffer);
+ *(ptrsize *)Data = Difference;
+ *(ptrsize *)OriginalData = *(ptrsize *)NewData;
+ } break;
+ case action_change_string:
+ {
+ void *Data = AllocateMemory(Memory, STRING_SIZE, P_UndoBuffer);
+ CopyStrings(Data, OriginalData);
+ Data = AllocateMemory(Memory, STRING_SIZE, P_UndoBuffer);
+ CopyStrings(Data, NewData);
+ CopyStrings(OriginalData, NewData);
+ } break;
+ }
+ Data = AllocateMemory(Memory, sizeof(action_change_type), P_UndoBuffer);
+ *(action_change_type *)Data = ActionChange;
+}
+
+// TODO(fox): Maybe take the extra lines to separate the incrementing of the
+// address from the variable assignment to improve legibility.
+
+// The pointer is unwinded.
+void Action_Undo(memory *Memory) {
+ memory_table *Table = &Memory->Slot[P_UndoBuffer];
+ uint8 *LastPos = (uint8 *)Table->Address + Table->CurrentPosition;
+ action_change_type *ActionType = (action_change_type *)LastPos - 1;
+ uint8 *TableAddress;
+ switch (*ActionType)
+ {
+ case action_change_u16:
+ {
+ uint16 *Difference = (uint16 *)ActionType - 1;
+ TableAddress = (uint8 *)Difference - sizeof(ptrsize) - sizeof(action_change_type);
+ void *Address = (void *)*(ptrsize *)TableAddress;
+ *(uint16 *)Address -= *Difference;
+ } break;
+ case action_change_ptr:
+ {
+ ptrsize *Difference = (ptrsize *)ActionType - 1;
+ TableAddress = (uint8 *)Difference - sizeof(ptrsize) - sizeof(action_change_type);
+ void *Address = (void *)*(ptrsize *)TableAddress;
+ *(ptrsize *)Address -= *Difference;
+ } break;
+ }
+ Table->CurrentPosition = (TableAddress - (uint8 *)Table->Address);
+}
+
+// The pointer is rewinded.
+void Action_Redo(memory *Memory) {
+ memory_table *Table = &Memory->Slot[P_UndoBuffer];
+ uint8 *LastPos = (uint8 *)Table->Address + Table->CurrentPosition;
+ void *Address = (void *)*(ptrsize *)LastPos;
+ action_change_type *ActionType = (action_change_type *)(LastPos + sizeof(void *));
+ uint8 *TableAddress;
+ switch (*ActionType)
+ {
+ case action_change_u16:
+ {
+ uint16 *Difference = (uint16 *)(ActionType + 1);
+ TableAddress = (uint8 *)Difference + sizeof(uint16) + sizeof(action_change_type);
+ *(uint16 *)Address += *Difference;
+ } break;
+ case action_change_ptr:
+ {
+ ptrsize *Difference = (ptrsize *)(ActionType + 1);
+ TableAddress = (uint8 *)Difference + sizeof(ptrsize) + sizeof(action_change_type);
+ *(ptrsize *)Address += *Difference;
+ } break;
+ }
+ Table->CurrentPosition = (TableAddress - (uint8 *)Table->Address);
+}