summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFox Caminiti <fox@foxcam.net>2022-10-05 23:49:41 -0400
committerFox Caminiti <fox@foxcam.net>2022-10-05 23:49:41 -0400
commita4c1e537b0cb2540535357d880e46f63b38c134f (patch)
treec9fafc32d0c9d2c37ba608b98ab76908d8850d8b
parentbc1335ebbf68c805a19303469bb49759296a645f (diff)
graph edits; arch rework
-rw-r--r--createcalls.cpp97
-rw-r--r--debug.h11
-rw-r--r--ffmpeg_backend.cpp44
-rw-r--r--main.cpp84
-rw-r--r--main.h355
-rw-r--r--memory.cpp53
-rw-r--r--memory.h64
-rw-r--r--my_imgui_internal_widgets.cpp30
-rw-r--r--my_imgui_internal_widgets.h2
-rw-r--r--my_imgui_widgets.cpp313
-rw-r--r--strings.cpp9
-rw-r--r--undo.h2
12 files changed, 617 insertions, 447 deletions
diff --git a/createcalls.cpp b/createcalls.cpp
index fb949a9..3bd13f8 100644
--- a/createcalls.cpp
+++ b/createcalls.cpp
@@ -1,29 +1,13 @@
-static void
-IncrementFrame(project_data *File, int16 Amount) {
- if ((File->CurrentFrame <= 0 && Amount < File->StartFrame) || (File->CurrentFrame >= File->EndFrame)) {
- File->CurrentFrame = 0;
- } else {
- File->CurrentFrame += Amount;
- }
-}
-
-static void
-PostMsg(project_state *State, char *msg)
-{
- State->MsgTime = 120;
- State->Msg = msg;
-}
static bool32
Source_Generate(project_data *File, project_state *State, memory *Memory, void *TempString)
{
- Assert(File->NumberOfSources < MAX_SOURCES);
- source *Source = &File->Source[File->NumberOfSources];
- bool32 IsVideo = 0;
-
- void *Path = String_GenerateFromChar(Memory, (char *)TempString);
+ Assert(File->Source_Count < MAX_SOURCES);
+ bool32 IsVideo = 0;
if (AV_IsFileSupported((char *)Path, &IsVideo)) {
+ block_source *Source =
+ uint16 = String_AddToFile(Memory, (char *)TempString);
if (IsVideo)
Source->SourceType = source_type_video;
else
@@ -36,12 +20,29 @@ Source_Generate(project_data *File, project_state *State, memory *Memory, void *
return 1;
} else {
void *Address = Memory_Rewind(Memory, STRING_SIZE, F_Strings);
- PostMsg(State, "File open fail...");
+ PostMsg(State, "File not supported...");
}
return 0;
}
+#if 0
+static void
+IncrementFrame(project_data *File, int16 Amount) {
+ if ((File->CurrentFrame <= 0 && Amount < File->StartFrame) || (File->CurrentFrame >= File->EndFrame)) {
+ File->CurrentFrame = 0;
+ } else {
+ File->CurrentFrame += Amount;
+ }
+}
+
+static void
+PostMsg(project_state *State, char *msg)
+{
+ State->MsgTime = 120;
+ State->Msg = msg;
+}
+
static property_channel
InitFloatProperty(char *Name, real32 Val, real32 ScrubVal, real32 MinVal = PROPERTY_REAL_MIN, real32 MaxVal = PROPERTY_REAL_MAX) {
property_channel Property = {};
@@ -294,9 +295,18 @@ LoadTestFootage(project_data *File, project_state *State, memory *Memory)
Source_Generate(File, State, Memory, SourceString);
Layer_CreateFromSource(File, State, Memory, &File->Source[0]);
- Keyframe_Insert(&File->Layer[0]->x, Memory, 00, -10);
- Keyframe_Insert(&File->Layer[0]->x, Memory, 01, 0);
- Keyframe_Insert(&File->Layer[0]->x, Memory, 05, 10);
+ Keyframe_Insert(&File->Layer[0]->x, Memory, 01, -10);
+ Keyframe_Insert(&File->Layer[0]->x, Memory, 10, -5);
+ Keyframe_Insert(&File->Layer[0]->x, Memory, 23, 0);
+ Keyframe_Insert(&File->Layer[0]->x, Memory, 34, 5);
+
+ for (int i = 0; i < 5; i++) {
+ keyframe *Keyframe = KeyframeLookup(&File->Layer[0]->x, i);
+ Keyframe->TangentLeft = V2(-3, 0);
+ Keyframe->TangentRight = V2(1.5, 0);
+ Keyframe->Type = bezier;
+ }
+
File->Layer[0]->x.IsToggled = true;
SelectLayer(File->Layer[0], State, 0);
// AddEffect(File->Layer[0], Memory, 1);
@@ -434,43 +444,4 @@ CreateDemoScene(project_data *File, project_state *State, memory *Memory)
Layer3->x.IsToggled = true;
Layer3->y.IsToggled = true;
}
-
-#if 0
-static void
-CreateGrid(project_data *File, memory *Memory) {
- uint16 Amount = 8;
- real32 XInc = File->Width / Amount;
- real32 YInc = File->Height / Amount;
- for (int16 j = 0; j < 8; j++) {
- for (int16 i = 0; i < 8; i++) {
- project_layer *Layer = CreateSolidLayer(File, Memory, 400, 400, V4(0.6, 0.3, 0.4, 1.0));
- Layer->x.CurrentValue.f = (XInc*i);
- Layer->y.CurrentValue.f = (XInc*j);
- Layer->opacity.CurrentValue.f = 0.25;
- Layer->StartFrame = 0;
- Layer->EndFrame = File->EndFrame;
- Keyframe_Insert(&Layer->rotation, Memory, i, 0);
- Keyframe_Insert(&Layer->rotation, Memory, 40+i, 360);
- }
- }
-}
#endif
-
-/*
-{
- Layer->RenderInfo = AllocateMemory(Memory, sizeof(source_image), P_SourceData);
- Layer->RenderInfo = AllocateMemory(Memory, sizeof(source_video), P_SourceData);
- source_image *Source = (source_image *)Layer->RenderInfo;
- Source->Raster = LoadImage(Memory, filename);
- Layer->EndFrame = File.EndFrame;
- Layer->x.CurrentValue.f = 1280/2;
- Layer->y.CurrentValue.f = 720/2;
- Layer->StartFrame = 0;
-
-
- Layer->x.CurrentValue.f = 1280/2;
- Layer->y.CurrentValue.f = 720/2;
- Layer->StartFrame = 0;
- Layer->EndFrame = File.EndFrame;
-}
-*/
diff --git a/debug.h b/debug.h
index 0e6c9b6..2514717 100644
--- a/debug.h
+++ b/debug.h
@@ -51,17 +51,6 @@ DebugWatchVar(char *Name, void *Address, valtype Type) {
Debug.Temp.WatchedProperties++;
}
-static void
-DebugPrintMemoryUsage(memory Memory)
-{
- for (int i = 0; i < 8; i++) {
- memory_table Table = Memory.Slot[i];
- printf("%s: %li bytes, %li kb\n", Table.Name, Table.CurrentPosition, Table.CurrentPosition / 1024);
- }
-}
-
-
-
#else
#define Assert(Expression)
diff --git a/ffmpeg_backend.cpp b/ffmpeg_backend.cpp
index 89c0c91..34abf35 100644
--- a/ffmpeg_backend.cpp
+++ b/ffmpeg_backend.cpp
@@ -112,7 +112,7 @@ void AV_Dealloc(av_info *AV)
av_frame_free(&AV->VideoFrame);
};
-void AV_Init(source *Source, av_info *AV, memory *Memory)
+void AV_Init(block_source *Source, av_info *AV, memory *Memory)
{
*AV = {};
@@ -197,21 +197,21 @@ void AV_Init(source *Source, av_info *AV, memory *Memory)
fprintf(stderr, "Libav error: (%s)\n", av_err2str(err));
}
- Source->Info.BytesPerPixel = 4;
- Source->Info.FPS = (real32)AV->VideoStream->r_frame_rate.num / AV->VideoStream->r_frame_rate.den;
- Source->Info.Width = AV->VideoCodecContext->width;
- Source->Info.Height = AV->VideoCodecContext->height;
+ Source->BytesPerPixel = 4;
+ Source->FPS = (real32)AV->VideoStream->r_frame_rate.num / AV->VideoStream->r_frame_rate.den;
+ Source->Width = AV->VideoCodecContext->width;
+ Source->Height = AV->VideoCodecContext->height;
};
-void AV_GetPTSAverage(source *Source, av_info *AV, int32 *err)
+void AV_GetPTSAverage(block_source *Source, av_info *AV, int32 *err)
{
// TODO(fox): This PTS average isn't exact and causes an occasional
// frame skip. See libav remarks in forum for more details.
if (AV->VideoStream->duration == 1) {
- Source->Info.AvgPTSPerFrame = 1;
+ Source->AvgPTSPerFrame = 1;
return;
}
@@ -234,13 +234,14 @@ void AV_GetPTSAverage(source *Source, av_info *AV, int32 *err)
}
}
- Source->Info.AvgPTSPerFrame = (real32)AvgPTSPerSecond / (int32)(FPS + 0.5f);
- printf("Avg PTS per sec: %.06f, Avg PTS per frame: %.06f\n", AvgPTSPerSecond, Source->Info.AvgPTSPerFrame);
+ Source->AvgPTSPerFrame = (real32)AvgPTSPerSecond / (int32)(FPS + 0.5f);
+ printf("Avg PTS per sec: %.06f, Avg PTS per frame: %.06f\n", AvgPTSPerSecond, Source->AvgPTSPerFrame);
av_seek_frame(AV->FileFormatContext, -1, 0, AVSEEK_FLAG_BACKWARD);
}
-cached_bitmap * AV_LoadStill(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory)
+#if 0
+cached_bitmap * AV_LoadStill(block_source *Source, layer_bitmap_info *BitmapInfo, memory *Memory)
{
av_info *AV = (av_info *)BitmapInfo->AVInfo;
int32 *CurrentlyRenderedFrame = &BitmapInfo->CurrentFrame;
@@ -254,9 +255,9 @@ cached_bitmap * AV_LoadStill(source *Source, layer_bitmap_info *BitmapInfo, memo
while (err >= 0) {
if (AV_TryFrame(AV, &err))
{
- uint16 Width = Source->Info.Width;
- uint16 Height = Source->Info.Height;
- uint16 BytesPerPixel = Source->Info.BytesPerPixel;
+ uint16 Width = Source->Width;
+ uint16 Height = Source->Height;
+ uint16 BytesPerPixel = Source->BytesPerPixel;
int32 Pitch = Width*BytesPerPixel;
cached_bitmap *Bitmap = Memory_RollingBitmap(Memory, Source, 0);
@@ -295,10 +296,10 @@ cached_bitmap * AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo,
int32 err = 0;
- if (!Source->Info.AvgPTSPerFrame) {
+ if (!Source->AvgPTSPerFrame) {
AV_GetPTSAverage(Source, AV, &err);
}
- Assert(Source->Info.AvgPTSPerFrame);
+ Assert(Source->AvgPTSPerFrame);
int32 FrameToSeek = TimelineFrame - BitmapInfo->FrameOffset;
if (*CurrentlyRenderedFrame == FrameToSeek || FrameToSeek < 0)
@@ -309,7 +310,7 @@ cached_bitmap * AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo,
// This function only seeks to the nearest "keyframe."
if (*CurrentlyRenderedFrame != FrameToSeek - 1) {
- int64 SeekSeconds = (int64)(FrameToSeek / (int32)(Source->Info.FPS + 0.5f) * AV_TIME_BASE);
+ int64 SeekSeconds = (int64)(FrameToSeek / (int32)(Source->FPS + 0.5f) * AV_TIME_BASE);
av_seek_frame(AV->FileFormatContext, -1, SeekSeconds, AVSEEK_FLAG_BACKWARD);
printf("Seek activated\n");
} else if (*CurrentlyRenderedFrame < 0) {
@@ -318,7 +319,7 @@ cached_bitmap * AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo,
*CurrentlyRenderedFrame = FrameToSeek;
- int64 SeekPTS = (int64)(Source->Info.AvgPTSPerFrame*FrameToSeek + 0.5f);
+ int64 SeekPTS = (int64)(Source->AvgPTSPerFrame*FrameToSeek + 0.5f);
while (err >= 0) {
if (AV_TryFrame(AV, &err)) {
@@ -332,7 +333,7 @@ cached_bitmap * AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo,
}
int64 Difference = AV->VideoFrame->pts - SeekPTS;
- if (abs(Difference) < Source->Info.AvgPTSPerFrame)
+ if (abs(Difference) < Source->AvgPTSPerFrame)
{
if (AV->PreviousPTS == -1) {
AV->PreviousPTS = AV->VideoFrame->pts;
@@ -342,9 +343,9 @@ cached_bitmap * AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo,
AV->PreviousPTS = AV->VideoFrame->pts;
}
- uint16 Width = Source->Info.Width;
- uint16 Height = Source->Info.Height;
- uint16 BytesPerPixel = Source->Info.BytesPerPixel;
+ uint16 Width = Source->Width;
+ uint16 Height = Source->Height;
+ uint16 BytesPerPixel = Source->BytesPerPixel;
int32 Pitch = Width*BytesPerPixel;
cached_bitmap *Bitmap = Memory_RollingBitmap(Memory, Source, FrameToSeek);
@@ -381,3 +382,4 @@ cached_bitmap * AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo,
}
return 0;
}
+#endif
diff --git a/main.cpp b/main.cpp
index 60504e1..9db6588 100644
--- a/main.cpp
+++ b/main.cpp
@@ -36,9 +36,12 @@
#include "defines.h"
#include "my_math.h"
#include "structs.h"
+
+#include "memory.h"
#include "main.h"
+
#include "debug.h"
-#include "functions.h"
+// #include "functions.h"
// #include "sharebuffer.h"
SDL_atomic_t CurrentEntry;
@@ -48,29 +51,32 @@ static bool32 IsRendering = false;
static instruction_mode InstructionMode = instruction_mode_scalar;
static uint32 RandomGlobalIncrement = 0;
-render_entry Entries[256];
+// render_entry Entries[256];
SDL_Thread *thread[8];
SDL_sem *Semaphore;
#include "memory.cpp"
+#include "strings.cpp"
+#include "createcalls.cpp"
+#include "ffmpeg_backend.cpp"
+#if 0
#include "effects.cpp"
#include "keyframes.cpp"
#include "layer.cpp"
-#include "strings.cpp"
#include "bezier.cpp"
#if THREADED
#include "threading.cpp"
#endif
#include "prenderer.cpp"
-#include "ffmpeg_backend.cpp"
#include "bitmap_calls.cpp"
-#include "createcalls.cpp"
#include "my_imgui_widgets.cpp"
#include "gl_calls.cpp"
#include "undo.cpp"
+#endif
+#if 0
static void
MainFunction(main_sdl *Main, memory *Memory,
project_state *State, project_data *File,
@@ -99,12 +105,13 @@ MainFunction(main_sdl *Main, memory *Memory,
State->UpdateKeyframes = false;
QueueCurrentFrame(File, CompBuffer, State);
}
+#endif
int main(int argc, char *argv[]) {
global_memory GlobalMemory = {};
- GlobalMemory.Size = ((uint64)4 * 1024 * 1024 * 1024);
+ GlobalMemory.Size = ((uint64)1 * 1024 * 1024 * 1024);
GlobalMemory.CurrentPosition = 0;
#if WINDOWS
@@ -120,23 +127,19 @@ int main(int argc, char *argv[]) {
memory Memory = {};
+ Memory_InitTable(&GlobalMemory, &Memory, 1 * 1024 * 1024, P_AVInfo, "Image/video headers");
+ Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_UndoBuffer, "Undo buffer");
+ Memory_InitTable(&GlobalMemory, &Memory, 1 * 1024 * 1024, P_MiscCache, "Misc persistent");
- InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_AVInfo, "Image/video headers");
- InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_VectorPoints, "Vector Points");
- InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_UndoBuffer, "Undo buffer");
- InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_MiscCache, "Misc cache");
-
- InitMemoryTable(&GlobalMemory, &Memory, 15 * 1024 * 1024, F_Layers, "Layers");
- InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Effects, "Effects");
- InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Keyframes, "Keyframe blocks");
- InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Strings, "Strings");
-
- InitMemoryTable(&GlobalMemory, &Memory, (uint64)200 * 1024 * 1024, B_LayerBitmaps, "Layer buffer");
- InitMemoryTable(&GlobalMemory, &Memory, (uint64)200 * 1024 * 1024, B_LoadedBitmaps, "Loaded bitmap buffer");
+ Memory_InitTable(&GlobalMemory, &Memory, sizeof(project_data), F_File, "File", sizeof(project_data));
+ Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Precomps, "Precomps", sizeof(block_composition));
+ // Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Layers, "Layers");
+ Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Sources, "Sources", sizeof(block_source));
+ // Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Effects, "Effects");
+ // Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Keyframes, "Keyframe blocks");
+ Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Strings, "Strings");
- Memory.Scratch = AllocateMemory(&Memory, (uint64)64*1024*1024, B_LayerBitmaps);
-
- project_state State = {};
+ // Memory_InitTable(&GlobalMemory, &Memory, (uint64)200 * 1024 * 1024, B_CachedBitmaps, "Cached bitmap buffer");
#if ARM
InstructionMode = instruction_mode_neon;
@@ -149,14 +152,21 @@ int main(int argc, char *argv[]) {
}
#endif
- project_data File = {};
- File.Width = 1920;
- File.Height = 1080;
- File.NumberOfFrames = 120;
- File.FPS = 24;
- File.CurrentFrame = 1;
- File.StartFrame = 0;
- File.EndFrame = 100;
+ project_state *State = (project_state *)Memory.Slot[P_MiscCache].Address;
+ project_data *File = (project_data *)Memory_Block_AllocateAddress(&Memory, F_File);
+ block_composition *MainComp = (block_composition *)Memory_Block_AllocateAddress(&Memory, F_Precomps);
+
+ MainComp->Width = 1280;
+ MainComp->Height = 720;
+ MainComp->FPS = 24;
+ MainComp->BytesPerPixel = 4;
+
+ MainComp->Frame_Count = 48;
+ MainComp->Frame_End = 48;
+
+ Source_Generate(File, State, Memory, "../asset/a.jpg");
+
+#if 0
#if DEBUG
@@ -296,7 +306,7 @@ int main(int argc, char *argv[]) {
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
- ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable;
+ ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableSetMousePos;
(void)io;
// NOTE(fox): Instead of constructing the position of the windows on
@@ -344,11 +354,23 @@ int main(int argc, char *argv[]) {
State.IsRunning = false;
}
+ if (UI.WantSetPos) {
+ ImGui::GetIO().WantSetMousePos = true;
+ io.MousePos = UI.SetPos;
+ }
+
ImGui_ImplOpenGL3_NewFrame();
+
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
+ if (UI.WantSetPos) {
+ ImGui_WrapMouseFinish(&UI, io.MousePos);
+ io.MouseDelta = {};
+ UI.WantSetPos = false;
+ }
+
if (!io.WantCaptureKeyboard)
ImGui_ProcessInputs(&File, &State, &CompBuffer, &Memory, &UI, io);
@@ -427,5 +449,7 @@ int main(int argc, char *argv[]) {
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
SDL_Quit();
+#endif
+
return 0;
}
diff --git a/main.h b/main.h
index 30025b3..1c9a69b 100644
--- a/main.h
+++ b/main.h
@@ -8,119 +8,6 @@ enum instruction_mode {
#endif
};
-enum memory_table_list {
-
- // F = file attributes
- // P = persistent data, but not file-based
- // B = cached data, often cleared
-
- P_AVInfo,
- P_VectorPoints,
- P_UndoBuffer,
- P_MiscCache,
-
- // The structs that these four blocks correspond to (project_layer, effect,
- // keyframe_block, char[STRING_SIZE]) are guranteed equal size.
- F_Layers,
- F_Effects,
- F_Keyframes,
- F_Strings,
-
- B_LayerBitmaps,
- B_LoadedBitmaps,
-};
-
-struct memory_table {
- char *Name;
- void *Address;
- uint64 CurrentPosition;
- uint64 Size;
- uint32 NumberOfPointers;
- uint32 PointerIndex;
-};
-
-struct global_memory {
- void *Address;
- uint64 CurrentPosition;
- uint64 Size;
-};
-
-struct source;
-
-struct cached_bitmap {
- source *SourceOwner; // Which source it belongs to. Currently used to dereference the bitmap.
- void *Data; // Unpacked data loaded from the source file.
- uint32 Frame; // What frame it is.
-};
-
-struct action_shift_data {
- void *StartingAddress;
- uint32 Size;
- uint16 NumberOf;
- uint16 Index;
- int16 Direction;
-};
-
-enum action_type {
- action_type_change_u16,
- action_type_change_i16,
- action_type_change_u32,
- action_type_change_i32,
- action_type_change_r32,
- action_type_change_u64,
- action_type_change_ptr,
- action_type_change_string,
- action_type_shift_keyframe,
- action_type_shift_bezier,
- action_type_shift,
- action_type_storedata
-};
-
-enum action_entry_type {
- action_entry_layerinit,
- action_entry_default
-};
-
-struct action_entry {
- char *Name;
- action_entry_type Type;
- void *ExtraPointer;
- uint16 NumberOfActions;
-};
-
-struct action_entries {
- action_entry Entry[1024];
- uint16 Index;
- uint16 NumberOfEntries;
-};
-
-struct memory {
- memory_table Slot[16];
- cached_bitmap Bitmap[4096];
- void *Scratch; // 64 MB of data
- action_entries Action;
-};
-
-struct property_channel;
-struct project_layer;
-
-enum keyframe_type
-{
- linear,
- bezier,
- hold
-};
-
-// NOTE(fox): One val slot holds 16 bytes of data.
-
-enum var_type
-{
- type_real,
- type_color,
- type_blendmode
-};
-
-
static char* BlendmodeNames[] = {
"Normal",
"Multiply",
@@ -153,57 +40,72 @@ enum blend_mode
};
-union val {
- v4 col;
- real32 f;
- blend_mode blendmode;
+enum interpolation_type
+{
+ interpolation_type_linear,
+ interpolation_type_bezier,
+ interpolation_type_hold
};
-struct keyframe {
- val Value;
- // NOTE(fox): Frame values are relative to the layer's FrameOffset! This is
- // done to reduce the footprint of layer moving in the undo tree.
- int32 FrameNumber;
- keyframe_type Type;
- bool32 IsSelected;
- // The X coordinate for the tangent is in keyframes, and the Y is in units.
- // Probably should think of something smarter.
- v2 TangentLeft;
- v2 TangentRight;
- // NOTE(fox): We need some sort of unique constant to give to ImGui in
- // order for dragging to work.
- uint32 ImguiID;
+struct bezier_point {
+ v2 Pos[3];
+ interpolation_type Type;
+ uint16 ImguiID;
+ uint8 IsSelected;
};
-struct keyframe_block {
- keyframe Keyframe[MAX_KEYFRAMES_PER_BLOCK];
+struct block_bezier {
+ uint8 Occupied;
+ bezier_point Point[MAX_KEYFRAMES_PER_BLOCK];
};
-struct property_channel {
- char *Name;
- keyframe_block *KeyframeBlock[MAX_KEYFRAME_BLOCKS];
- uint16 NumberOfKeyframeBlocks;
- uint16 NumberOfSelectedKeyframes;
- uint16 NumberOfTotalKeyframes;
- val CurrentValue;
- val MaxVal;
- val MinVal;
- val ScrubVal; // increment when dragging on sliders, etc.
- var_type VarType;
+struct project_state
+{
+ bool32 UpdateKeyframes = 1;
+ bool32 UpdateFrame = 1; // only refreshes frame; set UpdateKeyframes to update animation
+ bool32 DebugDisableCache = 1;
- bool32 IsToggled;
+ // tool Tool = tool_default;
+ // pen_state Pen = {};
+
+ bool32 IsRunning = 1;
+ bool32 IsPlaying;
+
+ int16 MostRecentlySelectedLayer = -1;
+ // selection_type RecentSelectionType = selection_none;
+
+ bool32 IsInteracting;
+ real32 InteractCache[6];
+ // interact_type InteractType;
+
+ int32 MsgTime; // currently in "frames"
+ char *Msg;
+
+ ImGuiTextFilter filter; // This filter API is pretty ballin'.
+ bool32 RerouteEffects; // Allows shift+space hotkey to gain focus on the effects panel.
};
-struct property_header
+struct project_data
{
- char *Name;
- val Value;
- var_type VarType;
- val MinVal;
- val MaxVal;
+ uint8 Occupied;
+ uint16 Layer_Count;
+ uint16 Source_Count;
+ uint16 PrincipalCompIndex;
};
-// Information about a particular file.
+struct block_composition
+{
+ uint8 Occupied;
+ uint16 Width;
+ uint16 Height;
+ uint16 FPS;
+ uint16 BytesPerPixel;
+
+ uint32 Frame_Count;
+ int32 Frame_Current;
+ int32 Frame_Start;
+ int32 Frame_End;
+};
enum source_type {
source_type_none,
@@ -211,10 +113,11 @@ enum source_type {
source_type_image
};
-// Probably best to consider source_info a part of the file data so we don't
-// have to re-check each source on every project load. (except for AVInfo)
+struct block_source
+{
+ uint8 Occupied;
-struct source_info {
+ uint16 Block_String_Index;
// Image and video
uint16 Width;
uint16 Height;
@@ -223,15 +126,41 @@ struct source_info {
// Video only
real32 FPS;
real32 AvgPTSPerFrame; // set by Libav
-};
-struct source {
- char *Path;
source_type SourceType;
- source_info Info;
};
-// Bitmaps from files are loaded into these temporary cache blocks.
+struct property_header
+{
+ char *Name;
+ real32 DefaultVal;
+ real32 MinVal;
+ real32 MaxVal;
+};
+
+struct property_channel {
+ char *Name;
+ uint16 Block_Bezier_Index[MAX_KEYFRAME_BLOCKS];
+ uint16 Block_Bezier_Count;
+ uint16 Keyframe_Count;
+
+ real32 CurrentValue;
+ real32 MaxVal;
+ real32 MinVal;
+ real32 ScrubVal; // increment when dragging on sliders, etc.
+
+ bool32 IsToggled;
+};
+
+
+
+#if 0
+
+struct cached_bitmap {
+ uint32 SourceIndex; // Which source it belongs to. Currently used to dereference the bitmap.
+ void *Data; // Unpacked data loaded from the source file.
+ uint32 Frame; // What frame it is.
+};
struct gl_effect_layer {
bool32 Initialized;
@@ -250,16 +179,15 @@ struct layer_bitmap_info {
gl_effect_layer Test;
gl_effect_layer TestM;
- // TODO(fox): Find a better place to store this. Either give effects a more
- // fleshed-out API to add things to a struct like this or integrate into ImGui.
- void *HistogramVals; // 256*5 floats (all channel average + RGBA).
- uint16 LevelsSelector; // Which channel is currently active
-
// Video only
int32 CurrentFrame = -1; // The last frame number rendered to the bitmap. -1 gurantees a load upon layer creation.
void *AVInfo; // Internal data containing current frame info
};
+
+// Bitmaps from files are loaded into these temporary cache blocks.
+
+
// NOTE(fox): I use the term "comp" (composition) to mean the canvas that is
// being rendered to, since it's what I'm used to from AE.
struct comp_buffer {
@@ -347,51 +275,6 @@ struct project_layer {
};
-// NOTE(fox): I have no idea how people normally do selection; currently I'm
-// treating it more "immediate." Instead of updating a selection state as
-// things are selected, I'm just calling functions that go through all the
-// layers and keyframes to look for the IsSelected bool. If this causes
-// lag I'll switch it to the former.
-
-struct temp_layer_list {
- int16 LayerIndex[MAX_LAYERS];
-};
-
-struct temp_keyframe_list {
- keyframe *SelectedKeyframe[50];
- uint16 Amount;
-};
-
-struct project_data
-{
- uint16 Width;
- uint16 Height;
- uint16 FPS;
- uint32 NumberOfFrames;
- int32 StartFrame;
- int32 EndFrame;
- int32 CurrentFrame;
-
- // NOTE(fox): Currently I'm handling layer sorting by just saying that
- // their order in memory is the order of the index and manually moving
- // their positions.
-
- project_layer *Layer[MAX_LAYERS];
- uint16 NumberOfSelectedLayers;
- uint16 NumberOfLayers;
-
- source Source[MAX_SOURCES];
- uint32 SourceSelected;
- uint16 NumberOfSources;
-};
-
-enum transforms_hotkey_interact {
- sliding_position,
- sliding_anchorpoint,
- sliding_scale,
- sliding_rotation
-};
-
struct main_sdl
{
SDL_Texture *Texture;
@@ -426,37 +309,13 @@ struct pen_state {
bool32 IsActive;
};
-struct project_state
+enum interact_type
{
- bool32 UpdateKeyframes = 1;
- bool32 UpdateFrame = 1; // only refreshes frame; set UpdateKeyframes to update animation
- bool32 DebugDisableCache = 1;
+ interact_type_keyframe_move,
+ interact_type_keyframe_rotate,
+ interact_type_keyframe_scale
+}
- tool Tool = tool_default;
- pen_state Pen = {};
-
- uint16 LayersToRender[MAX_LAYERS];
- uint16 NumberOfLayersToRender;
-
- bool32 IsRunning = 1;
- bool32 IsPlaying;
- bool32 DemoButton = 1;
- bool32 GridButton = 1;
-
- uint16 NumberOfSelectedLayers;
- int16 MostRecentlySelectedLayer = -1; // convenience for the properties panel
- selection_type RecentSelectionType = selection_none;
-
- bool32 IsInteracting;
- real32 InteractCache[4]; // we need to store the initial position in order to record it in the undo tree
- transforms_hotkey_interact TransformsHotkeyInteract;
-
- int32 MsgTime; // currently in "frames"
- char *Msg;
-
- ImGuiTextFilter filter; // This filter API is pretty ballin'.
- bool32 RerouteEffects; // Allows shift+space hotkey to gain focus on the effects panel.
-};
struct brush_tool
{
@@ -489,16 +348,21 @@ struct ui
// Under 1 is zoomed in!
real32 TimelinePercentZoomed = 1.0f;
- real32 TimelinePercentOffset = 0.0f;
+ real32 TimelinePercentOffset = 0.3f;
- real32 Default_Y_TimelinePercentZoomed = 2.0f;
- real32 Default_Y_TimelinePercentOffset = 0.5f;
+ real32 Default_Y_TimelinePercentZoomed = 1.2f;
+ real32 Default_Y_TimelinePercentOffset = 0.0f;
real32 Y_TimelinePercentZoomed;
real32 Y_TimelinePercentOffset;
bool32 IsDragging;
+ bool32 IsTransforming;
+ int32 Wrap_X = 0;
+ int32 Wrap_Y = 0;
real32 TempVal;
+ real32 TempVal_X;
+ real32 OldVal[4];
real32 Y_MaxVal;
real32 Y_MinVal;
@@ -506,6 +370,11 @@ struct ui
real32 Display_Y_MaxVal;
real32 Display_Y_MinVal;
+ bool32 WantSetPos = false;
+ ImVec2 SetPos;
+ real32 InitPos;
+ int32 WrapDirection;
+
// Note that I don't use "zoom" to mean the scale in relation to the
// original (i.e. default = 1.0f); it's the literal screen size in pixels
// of the composition in the UI.
@@ -622,3 +491,5 @@ struct render_entry {
rectangle RenderRegion;
};
+#endif
+
diff --git a/memory.cpp b/memory.cpp
index 85c6610..27ac266 100644
--- a/memory.cpp
+++ b/memory.cpp
@@ -1,18 +1,58 @@
-
static void
-InitMemoryTable(global_memory *GlobalMemory, memory *Memory, uint64 Size, memory_table_list TableName, char *Name) {
+Memory_InitTable(global_memory *GlobalMemory, memory *Memory, uint64 Size, memory_table_list TableName, char *Name, uint64 Block_ElementSize = 0) {
memory_table *Table = &Memory->Slot[TableName];
Table->Name = Name;
Table->Address = (ptrsize *)((uint8 *)GlobalMemory->Address + GlobalMemory->CurrentPosition);
Table->Size = Size;
+ Table->Block_ElementSize = Block_ElementSize;
GlobalMemory->CurrentPosition += Size;
}
-// NOTE(fox): Currently memory acts like simple stack that can only grow forwards.
-// Undos/deletes create "holes." Once someone undos/deletes enough to trigger
-// the limit or we start caring more about space, I'll revamp the system to
-// keep track of free holes and allow those to be returned.
+void Memory_Zero(uint8 *Address_Write, uint64 Size)
+{
+ uint64 i = 0;
+ while (i < Size) {
+ *(Address_Write + i) = 0;
+ i++;
+ }
+}
+
+static uint32
+Memory_Block_AllocateNew(memory *Memory, memory_table_list TableName)
+{
+ memory_table *Table = &Memory->Slot[TableName];
+ Assert(Table->Block_ElementSize != 0);
+ bool32 Empty = 0;
+ uint32 Index = 0;
+ uint8 *Address_Playhead = (uint8 *)Table->Address;
+ while (*Address_Playhead != 0) {
+ Address_Playhead += Table->Block_ElementSize;
+ Index++;
+ }
+ Memory_Zero(Address_Playhead, Table->Block_ElementSize);
+ *Address_Playhead = 1;
+
+ return Index;
+}
+
+static void *
+Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 Index)
+{
+ memory_table *Table = &Memory->Slot[TableName];
+ Assert(Table->Block_ElementSize != 0);
+ uint8 *Address = (uint8 *)Table->Address + (Table->Block_ElementSize * Index);
+ Assert(*Address == 1);
+ return (void *)Address;
+}
+static void *
+Memory_Block_AllocateAddress(memory *Memory, memory_table_list TableName)
+{
+ uint16 FileIndex = Memory_Block_AllocateNew(Memory, TableName);
+ return Memory_Block_AddressAtIndex(Memory, F_File, FileIndex);
+}
+
+#if 0
static void*
AllocateMemory(memory *Memory, uint64 Size, memory_table_list TableName) {
void *Address;
@@ -174,3 +214,4 @@ Memory_RollingBitmap(memory *Memory, source *Source, uint32 FrameToSeek)
Debug_Memory_Assert_Cohesion(Memory, Table);
return Bitmap;
}
+#endif
diff --git a/memory.h b/memory.h
new file mode 100644
index 0000000..47c737e
--- /dev/null
+++ b/memory.h
@@ -0,0 +1,64 @@
+enum memory_table_list {
+
+ P_AVInfo,
+ P_UndoBuffer,
+ P_MiscCache,
+
+ F_File,
+ F_Precomps,
+ F_Layers,
+ F_Sources,
+ F_Properties,
+ F_Keyframes,
+ F_Effects,
+ F_Nodes,
+ F_Strings,
+
+ B_CachedBitmaps,
+};
+
+struct memory_table {
+ char *Name;
+ void *Address;
+ uint64 Size;
+ uint32 Block_ElementSize;
+};
+
+struct global_memory {
+ void *Address;
+ uint64 CurrentPosition;
+ uint64 Size;
+};
+
+enum history_action_type {
+ action_type_swap,
+ action_type_shift
+};
+
+struct history_action {
+ memory_table_list TableName;
+ history_action_type Type;
+ uint64 Size;
+ uint64 ByteOffset;
+ uint64 ShiftAmount; // Only for type_shift
+ int16 Direction; // Only for type_shift
+};
+
+struct history_entry {
+ char *Name;
+ uint16 NumberOfActions;
+};
+
+struct history_entry_list {
+ history_entry Entry[256];
+ history_action Action[1024];
+ uint16 NumberOfEntries;
+ uint16 EntryPlayhead;
+};
+
+struct memory {
+ memory_table Slot[16];
+ history_entry_list History;
+ bool32 IsFileSaved;
+};
+
diff --git a/my_imgui_internal_widgets.cpp b/my_imgui_internal_widgets.cpp
index d398ca1..1c16b65 100644
--- a/my_imgui_internal_widgets.cpp
+++ b/my_imgui_internal_widgets.cpp
@@ -1,13 +1,41 @@
#include "my_imgui_internal_widgets.h"
-
#include "imgui.h"
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include "imgui_internal.h"
+// In the regular call (GetMouseDragDelta) after the threshold is passed for
+// the first time, it returns true on every delta change even if you call
+// ResetMouseDragDelta, which makes routines like changing the frame number
+// every time the mouse is dragged past a certain distance not work how you'd
+// expect. This function uses the actual mouse delta instead of the stored
+// "max" value.
+ImVec2 ImGui::GetLocalMouseDragDelta(ImGuiMouseButton button, float lock_threshold)
+{
+ ImGuiContext& g = *GImGui;
+ IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
+ ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[button]) : ImVec2(0.0f, 0.0f);
+ if (lock_threshold < 0.0f)
+ lock_threshold = g.IO.MouseDragThreshold;
+ if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
+ if (ImLengthSqr(delta_from_click_pos) >= lock_threshold * lock_threshold)
+ if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button]))
+ return g.IO.MousePos - g.IO.MouseClickedPos[button];
+ return ImVec2(0.0f, 0.0f);
+}
+
+// To make the above scenario work we also have to be able to subtract from the
+// delta; simply resetting it will cause misalignment from the mouse.
+void ImGui::SetLocalMouseDragDelta(ImGuiMouseButton button, ImVec2 DeltaOffset)
+{
+ ImGuiContext& g = *GImGui;
+ IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
+ g.IO.MouseClickedPos[button] += DeltaOffset;
+}
+
// A modded version of ScalarSlider allowing for the minimum and maximum parts
// of the slider to be draggable by two other buttons. p_mid is from range -1
// to 1, and s_min and max are from 0-1.
diff --git a/my_imgui_internal_widgets.h b/my_imgui_internal_widgets.h
index 52fdc74..2841c2d 100644
--- a/my_imgui_internal_widgets.h
+++ b/my_imgui_internal_widgets.h
@@ -6,6 +6,8 @@
// NOTE(fox): Appending to the standard ImGui namespace so I don't have to convert all the functions to ImGui::Function()
namespace ImGui {
+ IMGUI_API ImVec2 GetLocalMouseDragDelta(ImGuiMouseButton button, float lock_threshold);
+ IMGUI_API void SetLocalMouseDragDelta(ImGuiMouseButton button, ImVec2 DeltaOffset);
IMGUI_API bool SliderLevels(const char* label, const char* label2, const char* label3, void* p_data, void* p_min, void* p_max);
IMGUI_API bool TestLine(ImVec2 P1, ImVec2 P2);
IMGUI_API bool BezierInteractive(ImVec2 p0, ImVec2 p1, ImVec2 p2, ImVec2 p3);
diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp
index d237b3c..a688283 100644
--- a/my_imgui_widgets.cpp
+++ b/my_imgui_widgets.cpp
@@ -72,6 +72,59 @@ ImGui_KeyframeDragging(project_data *File, project_state *State, ui *UI, propert
}
}
+// NOTE(fox): We have to do a bit of hackery here to tell how many times the
+// mouse has been wrapped during a drag, since it doesn't seem like we can rely
+// on SDL_WarpMouseGlobal to update on the first frame of a WantSetPos request.
+
+static void
+ImGui_WrapMouse(ui *UI, ImVec2 MousePos, ImVec2 Min, ImVec2 Max, int Direction = 3)
+{
+ if (Direction & 1) {
+ if (MousePos.x < Min.x) {
+ UI->WantSetPos = true;
+ UI->SetPos = ImVec2(Max.x - 5, MousePos.y);
+ UI->InitPos = MousePos.x;
+ UI->WrapDirection = 0;
+ }
+ if (MousePos.x > Max.x) {
+ UI->WantSetPos = true;
+ UI->SetPos = ImVec2(Min.x + 5, MousePos.y);
+ UI->InitPos = MousePos.x;
+ UI->WrapDirection = 1;
+ }
+ }
+ if (Direction & 2) {
+ if (MousePos.y < Min.y) {
+ UI->WantSetPos = true;
+ UI->SetPos = ImVec2(MousePos.x, Max.y - 5);
+ UI->InitPos = MousePos.y;
+ UI->WrapDirection = 2;
+ }
+ if (MousePos.y > Max.y) {
+ UI->WantSetPos = true;
+ UI->SetPos = ImVec2(MousePos.x, Min.y + 5);
+ UI->InitPos = MousePos.y;
+ UI->WrapDirection = 3;
+ }
+ }
+}
+
+static void
+ImGui_WrapMouseFinish(ui *UI, ImVec2 MousePos)
+{
+ if (UI->WrapDirection == 0) {
+ if (MousePos.x < UI->InitPos) UI->Wrap_X--;
+ } else if (UI->WrapDirection == 1) {
+ if (MousePos.x > UI->InitPos) UI->Wrap_X++;
+ } else if (UI->WrapDirection == 2) {
+ if (MousePos.y < UI->InitPos) UI->Wrap_Y--;
+ } else if (UI->WrapDirection == 3) {
+ if (MousePos.y > UI->InitPos) UI->Wrap_Y++;
+ } else {
+ Assert(0);
+ }
+}
+
static void
ImGui_InteractSliderProperty(project_state *State, memory *Memory, property_channel *Property)
{
@@ -256,24 +309,6 @@ ImGui_TimelineIncrementDraw(project_data *File, ui *UI, ImDrawList *draw_list,
RightmostEdge = true;
}
}
-
-#if 0
- x = -0.25;
- bool32 LeftmostEdge = false;
- while (!LeftmostEdge) {
- ImVec2 Min = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize + x*TimelineZoomSize, TimelineStartingPos.y);
- ImVec2 Max = ImVec2(Min.x + 2, WindowMaxAbs.y);
- if (Min.x > TimelineAbsolutePos.x) {
- draw_list->AddLine(Min, Max, LineColor);
- char buf2[6];
- sprintf(buf2, "%.2f", x);
- draw_list->AddText(ImVec2(Min.x, TimelineAbsolutePos.y), IM_COL32(200, 200, 200, 130), buf2);
- x -= 0.25;
- } else {
- LeftmostEdge = true;
- }
- }
-#endif
}
static void
@@ -325,37 +360,6 @@ ImGui_TimelineIncrementDraw2(project_data *File, ImDrawList *draw_list, real32 M
LeftmostEdge = true;
}
}
-#if 0
- while (!RightmostEdge) {
- ImVec2 Min = ImVec2(TimelineAbsolutePos.x, TimelineAbsolutePos.y + TimelineZoomSize + TimelineMoveSize - x*TimelineZoomSize);
- ImVec2 Max = ImVec2(TimelineAbsolutePos.x + TimelineSizeWithBorder.x, Min.y + 2);
- if (Min.y > TimelineAbsolutePos.y) {
- draw_list->AddLine(Min, Max, LineColor);
- char buf2[6];
- sprintf(buf2, "%.2f", (x / Increment) + MinVal_Y);
- draw_list->AddText(ImVec2(TimelineAbsolutePos.x, Min.y), IM_COL32(200, 200, 200, 130), buf2);
- x += Increment;
- } else {
- RightmostEdge = true;
- }
- }
-
- x = -Increment;
- bool32 LeftmostEdge = false;
- while (!LeftmostEdge) {
- ImVec2 Min = ImVec2(TimelineAbsolutePos.x, TimelineAbsolutePos.y + TimelineZoomSize + TimelineMoveSize - x*TimelineZoomSize);
- ImVec2 Max = ImVec2(TimelineAbsolutePos.x + TimelineSizeWithBorder.x, Min.y + 2);
- if (Min.y < TimelineAbsolutePos.y + TimelineSizeWithBorder.y) {
- draw_list->AddLine(Min, Max, LineColor);
- char buf2[6];
- sprintf(buf2, "%.2f", (x / Increment) + MinVal_Y);
- draw_list->AddText(ImVec2(TimelineAbsolutePos.x, Min.y), IM_COL32(200, 200, 200, 130), buf2);
- x -= Increment;
- } else {
- LeftmostEdge = true;
- }
- }
-#endif
}
static void
@@ -1175,6 +1179,13 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
sprintf(buf2, "%.2i:%.2i", File->CurrentFrame / File->FPS, File->CurrentFrame % File->FPS);
ImGui::Text(buf2);
/*
+ if (UI->IsDragging) {
+ ImGui::SameLine();
+ sprintf(buf2, "X: %.3f, Y: %.3f",
+ ImGui::Text(buf2);
+ }
+ */
+ /*
ImGui::Button("V", TopbarButtonSize); ImGui::SameLine();
ImGui::Button("V", TopbarButtonSize); ImGui::SameLine();
ImGui::Button("V", TopbarButtonSize); ImGui::SameLine();
@@ -1259,6 +1270,11 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
MinVal_Y = (Keyframe->Value.f < MinVal_Y) ? Keyframe->Value.f : MinVal_Y;
}
+ keyframe *FirstKeyframe = KeyframeLookup(Property, 0);
+ keyframe *LastKeyframe = KeyframeLookup(Property, Property->NumberOfTotalKeyframes - 1);
+ real32 MinVal_X = (Layer->BitmapInfo.FrameOffset + FirstKeyframe->FrameNumber);
+ real32 MaxVal_X = (Layer->BitmapInfo.FrameOffset + LastKeyframe->FrameNumber);
+
UI->Y_MaxVal = MaxVal_Y;
UI->Y_MinVal = MinVal_Y;
@@ -1275,39 +1291,72 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
DebugWatchVar("offset: ", &Y_TimelinePercentOffset, d_float);
DebugWatchVar("zoom: ", &Y_TimelinePercentZoomed, d_float);
+ real32 Ratio_Graph_X = (MaxVal_X - MinVal_X) / File->NumberOfFrames;
+ real32 TimelineZoomSize = TimelineSizeWithBorder.x / UI->TimelinePercentZoomed;
+ real32 TimelineMoveSize = TimelineSizeWithBorder.x * UI->TimelinePercentOffset / UI->TimelinePercentZoomed;
+ real32 Y_TimelineZoomSize = TimelineSizeWithBorder.y / Y_TimelinePercentZoomed;
+ real32 Y_TimelineMoveSize = TimelineSizeWithBorder.y * Y_TimelinePercentOffset / Y_TimelinePercentZoomed;
+
for (int b = 0; b < Property->NumberOfTotalKeyframes; b++) {
ImGui::PushID(b);
- real32 TimelineZoomSize = TimelineSizeWithBorder.x / UI->TimelinePercentZoomed;
- real32 TimelineMoveSize = TimelineSizeWithBorder.x * UI->TimelinePercentOffset / UI->TimelinePercentZoomed;
- real32 Y_TimelineZoomSize = TimelineSizeWithBorder.y / Y_TimelinePercentZoomed;
- real32 Y_TimelineMoveSize = TimelineSizeWithBorder.y * Y_TimelinePercentOffset / Y_TimelinePercentZoomed;
keyframe *Keyframe = KeyframeLookup(Property, b);
// Only used for drawing the bezier.
- keyframe *NextKeyframe = (b != Property->NumberOfTotalKeyframes - 1) ? KeyframeLookup(Property, b) : NULL;
+ keyframe *NextKeyframe = (b != Property->NumberOfTotalKeyframes - 1) ? KeyframeLookup(Property, b + 1) : NULL;
- real32 Ratio_X = (real32)(Layer->BitmapInfo.FrameOffset + Keyframe->FrameNumber) / File->NumberOfFrames;
- real32 Ratio_Y = (Keyframe->Value.f - MinVal_Y) / (MaxVal_Y - MinVal_Y);
+ real32 Increment_X = (real32)1 / File->NumberOfFrames;
+ real32 UI_FrameDistance = Increment_X*TimelineZoomSize;
- ImVec2 KeyframePos = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize + Ratio_X*TimelineZoomSize,
- TimelineAbsolutePos.y + Y_TimelineMoveSize + (1.0f - Ratio_Y)*Y_TimelineZoomSize);
- ImGui::SetCursorScreenPos(KeyframePos);
+ int32 Keyframe_X = (Layer->BitmapInfo.FrameOffset + Keyframe->FrameNumber);
+ real32 Keyframe_Y = Keyframe->Value.f;
+
+ real32 Ratio_X_Mid = (real32)Keyframe_X / File->NumberOfFrames;
+ real32 Ratio_Y_Mid = (Keyframe_Y - MinVal_Y) / (MaxVal_Y - MinVal_Y);
+
+ ImVec2 KeyframePos_Mid = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize + Ratio_X_Mid*TimelineZoomSize,
+ TimelineAbsolutePos.y + Y_TimelineMoveSize + (1.0f - Ratio_Y_Mid)*Y_TimelineZoomSize);
+
+ ImGui::SetCursorScreenPos(KeyframePos_Mid);
ImGui::Button("##keyframe", ImVec2(FontHeight, FontHeight));
+ if (ImGui::IsItemHovered() && ImGui::IsKeyPressed(ImGuiKey_R)) {
+ UI->TempVal = Keyframe->Value.f;
+ UI->TempVal_X = Keyframe->FrameNumber;
+ }
+
if (ImGui::IsItemActivated()) {
UI->IsDragging = true;
UI->TempVal = Keyframe->Value.f;
+ UI->TempVal_X = Keyframe->FrameNumber;
}
if ((ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1)))
{
- real32 MouseDeltaRatio = -io.MouseDelta.y / TimelineSizeWithBorder.y * Y_TimelinePercentZoomed;
- if (io.KeyShift)
- Ratio_Y = (real32)((int32)(Ratio_Y * 1000) / 10) / 100;
- real32 Test = ((MaxVal_Y - MinVal_Y) * (Ratio_Y + MouseDeltaRatio)) + MinVal_Y;
- DebugWatchVar("RatioY", &Ratio_Y, d_float);
- DebugWatchVar("NewRatioY", &UI->Y_MaxVal, d_float);
- Keyframe->Value.f = Test;
+ ImVec2 DragDelta = ImGui::GetMouseDragDelta();
+ DragDelta = DragDelta + (ImVec2(UI->Wrap_X, UI->Wrap_Y) * TimelineSize);
+ DebugWatchVar("DragX", &DragDelta.x, d_float);
+ DebugWatchVar("DragY", &DragDelta.y, d_float);
+ DebugWatchVar("Wrap_X", &UI->Wrap_X, d_int);
+ DebugWatchVar("Wrap_Y", &UI->Wrap_Y, d_int);
+ real32 MouseDeltaRatio = -DragDelta.y / TimelineSizeWithBorder.y * Y_TimelinePercentZoomed;
+ ImVec2 Increment = ImVec2(DragDelta.x / UI_FrameDistance, ((MaxVal_Y - MinVal_Y) * MouseDeltaRatio));
+
+ // The plus 0.5 * X_Direction is for making the frame jump happen
+ // when the cursor is between two frames rather than when passing one.
+ real32 X_Direction = (Increment.x > 0) ? fabsf(Increment.x) / Increment.x : 0;
+
+ Keyframe->FrameNumber = UI->TempVal_X + (int32)(Increment.x + 0.5*X_Direction);
+ Keyframe->Value.f = UI->TempVal + Increment.y;
+
+ if (io.KeyShift) {
+ bool32 RestrainAxis = (fabsf(DragDelta.x) > fabsf(DragDelta.y));
+ if (RestrainAxis) {
+ Keyframe->Value.f = UI->TempVal;
+ } else {
+ Keyframe->FrameNumber = UI->TempVal_X;
+ }
+ }
+ ImGui_WrapMouse(UI, io.MousePos, TimelineAbsolutePos, TimelineAbsolutePos + TimelineSizeWithBorder);
}
// TODO(fox): This is kind of a mess. I built the graph around the
@@ -1317,7 +1366,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
if (ImGui::IsItemDeactivated()) {
if ((UI->TempVal >= MaxVal_Y) || Keyframe->Value.f == UI->Y_MaxVal) {
- real32 Min = ((Ratio_Y <= 0.0f) && (UI->TempVal >= MaxVal_Y)) ? MinVal_Y : UI->Y_MinVal;
+ real32 Min = ((Ratio_Y_Mid <= 0.0f) && (UI->TempVal >= MaxVal_Y)) ? MinVal_Y : UI->Y_MinVal;
real32 RealRatio_Y = (UI->Y_MaxVal - UI->Y_MinVal) / (MaxVal_Y - MinVal_Y);
UI->Y_TimelinePercentZoomed = UI->Y_TimelinePercentZoomed / RealRatio_Y;
UI->Y_TimelinePercentOffset = (1.0f/RealRatio_Y + UI->Y_TimelinePercentOffset/RealRatio_Y - 1.0f);
@@ -1327,6 +1376,67 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
UI->Y_TimelinePercentZoomed = UI->Y_TimelinePercentZoomed / (1 - RealRatio_Y);
}
UI->IsDragging = false;
+ UI->Wrap_X = 0;
+ UI->Wrap_Y = 0;
+ }
+
+ ImU32 col = ImGui::GetColorU32(ImGuiCol_ScrollbarGrab);
+
+ ImVec2 Handle_Pos[2] = {};
+
+ if (Keyframe->Type == bezier) {
+ ImVec2 Handle_Ratio[2] = {};
+
+ Handle_Ratio[0] = ImVec2((real32)(Keyframe_X + Keyframe->TangentLeft.x) / File->NumberOfFrames,
+ (Keyframe_Y + Keyframe->TangentLeft.y - MinVal_Y) / (MaxVal_Y - MinVal_Y));
+ Handle_Ratio[1] = ImVec2((real32)(Keyframe_X + Keyframe->TangentRight.x) / File->NumberOfFrames,
+ (Keyframe_Y + Keyframe->TangentRight.y - MinVal_Y) / (MaxVal_Y - MinVal_Y));
+
+ Handle_Pos[0] = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize + Handle_Ratio[0].x*TimelineZoomSize,
+ TimelineAbsolutePos.y + Y_TimelineMoveSize + (1.0f - Handle_Ratio[0].y)*Y_TimelineZoomSize);
+ Handle_Pos[1] = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize + Handle_Ratio[1].x*TimelineZoomSize,
+ TimelineAbsolutePos.y + Y_TimelineMoveSize + (1.0f - Handle_Ratio[1].y)*Y_TimelineZoomSize);
+
+ draw_list->AddLine(KeyframePos_Mid, Handle_Pos[0], col, 1.0f);
+ draw_list->AddLine(KeyframePos_Mid, Handle_Pos[1], col, 1.0f);
+
+ for (int i = 0; i < 2; i++) {
+ ImGui::SetCursorScreenPos(Handle_Pos[i]);
+ ImGui::Button((i == 0) ? "##keyframe_left" : "##keyframe_right", ImVec2(FontHeight, FontHeight));
+ v2 *Tangent = (i == 0) ? &Keyframe->TangentLeft : &Keyframe->TangentRight;
+
+ if (ImGui::IsItemActivated()) {
+ UI->IsDragging = true;
+ UI->TempVal_X = Tangent->x;
+ UI->TempVal = Tangent->y;
+ }
+
+ if ((ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1)))
+ {
+ ImVec2 DragDelta = ImGui::GetMouseDragDelta();
+ DragDelta = DragDelta + (ImVec2(UI->Wrap_X, UI->Wrap_Y) * TimelineSize);
+ ImVec2 MouseDeltaRatio = (ImVec2(1, -1) * DragDelta) / TimelineSizeWithBorder * ImVec2(UI->TimelinePercentZoomed / Ratio_Graph_X, Y_TimelinePercentZoomed);
+ real32 NewPos_X = ((MaxVal_X - MinVal_X) * MouseDeltaRatio.x);
+ real32 NewPos_Y = (io.KeyShift) ? 0 : ((MaxVal_Y - MinVal_Y) * MouseDeltaRatio.y);
+ *Tangent = V2(UI->TempVal_X, UI->TempVal) + V2(NewPos_X, NewPos_Y);
+ ImGui_WrapMouse(UI, io.MousePos, TimelineAbsolutePos, TimelineAbsolutePos + TimelineSizeWithBorder);
+ }
+
+ if (ImGui::IsItemDeactivated()) {
+ UI->IsDragging = false;
+ UI->Wrap_X = 0;
+ UI->Wrap_Y = 0;
+ }
+ }
+ }
+
+ if (NextKeyframe) {
+ real32 Ratio_X_2 = (real32)(Layer->BitmapInfo.FrameOffset + NextKeyframe->FrameNumber) / File->NumberOfFrames;
+ real32 Ratio_Y_2 = (NextKeyframe->Value.f - MinVal_Y) / (MaxVal_Y - MinVal_Y);
+
+ ImVec2 NextKeyframePos = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize + Ratio_X_2*TimelineZoomSize,
+ TimelineAbsolutePos.y + Y_TimelineMoveSize + (1.0f - Ratio_Y_2)*Y_TimelineZoomSize);
+ draw_list->AddLine(KeyframePos_Mid, NextKeyframePos, col, 1.0f);
}
ImGui::PopID();
@@ -1371,6 +1481,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
BarH_Offset = Min(BarH_Offset, TimelineSize.x - BarH_SizeUI - BarHandleSize*4);
ImVec2 BarH_PosUI = TimelineAbsolutePos + ImVec2(BarH_Offset, TimelineSize.y - BarThickness);
+ bool32 BarHeld = false;
ImGui::SetCursorScreenPos(BarH_PosUI);
ImGui::Button("##scrollbarleft", ImVec2(BarHandleSize, BarThickness));
@@ -1381,6 +1492,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
UI->TimelinePercentZoomed -= MouseDelta.x;
UI->TimelinePercentOffset -= MouseDelta.x;
}
+ BarHeld = true;
}
ImGui::SetCursorScreenPos(BarH_PosUI + ImVec2(BarHandleSize, 0));
@@ -1389,6 +1501,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))
{
UI->TimelinePercentOffset -= MouseDelta.x;
+ BarHeld = true;
}
ImGui::SetCursorScreenPos(BarH_PosUI + ImVec2(BarHandleSize, 0) + ImVec2(BarH_SizeUI, 0));
@@ -1399,6 +1512,11 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
if ((UI->TimelinePercentZoomed + MouseDelta.x) > BarMinZoom) {
UI->TimelinePercentZoomed += MouseDelta.x;
}
+ BarHeld = true;
+ }
+
+ if (BarHeld) {
+ ImGui_WrapMouse(UI, io.MousePos, TimelineAbsolutePos, TimelineAbsolutePos + TimelineSizeWithBorder, 1);
}
Assert(UI->TimelinePercentZoomed > BarMinZoom);
@@ -1423,6 +1541,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
BarV_Offset = Min(BarV_Offset, BarV_MaxSize - BarV_SizeUI - BarHandleSize*4);
ImVec2 BarV_PosUI = TimelineAbsolutePos + ImVec2(TimelineSize.x - BarThickness, BarV_Offset);
+ BarHeld = false;
ImGui::SetCursorScreenPos(BarV_PosUI);
ImGui::Button("##h-scrollbarleft", ImVec2(BarThickness, BarHandleSize));
@@ -1431,14 +1550,21 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
{
UI->Y_TimelinePercentZoomed -= MouseDelta.y;
UI->Y_TimelinePercentOffset -= MouseDelta.y;
+ BarHeld = true;
}
ImGui::SetCursorScreenPos(BarV_PosUI + ImVec2(0, BarHandleSize));
- ImGui::Button("##h-scrollbarhori", ImVec2(BarThickness, BarV_SizeUI));
+ ImGui::Button("##h-scrollbar", ImVec2(BarThickness, BarV_SizeUI));
+
+ if (ImGui::IsItemHovered() && io.MouseWheel)
+ {
+ UI->Y_TimelinePercentOffset -= io.MouseWheel/10;
+ }
if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))
{
UI->Y_TimelinePercentOffset -= MouseDelta.y;
+ BarHeld = true;
}
ImGui::SetCursorScreenPos(BarV_PosUI + ImVec2(0, BarHandleSize) + ImVec2(0, BarV_SizeUI));
@@ -1447,15 +1573,58 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
if ((ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1)))
{
UI->Y_TimelinePercentZoomed += MouseDelta.y;
+ BarHeld = true;
}
UI->Y_TimelinePercentZoomed = Max(UI->Y_TimelinePercentZoomed, 0.01);
+ if (BarHeld) {
+ ImGui_WrapMouse(UI, io.MousePos, TimelineAbsolutePos, TimelineAbsolutePos + TimelineSizeWithBorder, 2);
+ }
+
draw_list->PopClipRect();
ImGui::PopClipRect();
ImGui::PopStyleVar();
+ if (io.MouseWheel) {
+ // NOTE(fox): Change this if any other action is added when hovering over the bar area.
+ bool32 BarHovering_H = TestRectangle(TimelineAbsolutePos + ImVec2(0, TimelineSize.y - BarThickness),
+ TimelineAbsolutePos + ImVec2(TimelineSize.x, TimelineSize.y),
+ io.MousePos);
+ bool32 BarHovering_V = TestRectangle(TimelineAbsolutePos + ImVec2(TimelineSize.x - BarThickness, 0),
+ TimelineAbsolutePos + ImVec2(TimelineSize.x, TimelineSize.y),
+ io.MousePos);
+ if (BarHovering_H && io.MouseWheel) {
+ UI->TimelinePercentOffset -= io.MouseWheel/15;
+ } else if (BarHovering_V && io.MouseWheel) {
+ UI->Y_TimelinePercentOffset -= io.MouseWheel/15;
+ } else {
+ real32 Increment = 0.1;
+ bool32 Direction = (io.MouseWheel > 0) ? 1 : -1;
+ real32 Offset = (io.MousePos.y - (TimelineAbsolutePos.y + Y_TimelineMoveSize)) / Y_TimelineZoomSize;
+ real32 X_Offset = (io.MousePos.x - (TimelineAbsolutePos.x + TimelineMoveSize)) / TimelineZoomSize;
+ DebugWatchVar("X Offset", &X_Offset, d_float);
+ if (io.KeyShift) {
+ UI->Y_TimelinePercentOffset += Increment*Direction;
+ } else if (io.KeyCtrl) {
+ UI->TimelinePercentOffset += Increment*Direction*0.3;
+ } else {
+ if (Direction == 1) {
+ UI->Y_TimelinePercentZoomed -= (UI->Y_TimelinePercentZoomed * Increment);
+ UI->Y_TimelinePercentOffset -= (UI->Y_TimelinePercentOffset * Increment) + Offset*Increment;
+ UI->TimelinePercentZoomed -= (UI->TimelinePercentZoomed * Increment);
+ UI->TimelinePercentOffset -= (UI->TimelinePercentOffset * Increment) + X_Offset*Increment;
+ } else {
+ UI->Y_TimelinePercentOffset = ((UI->Y_TimelinePercentOffset + Offset*Increment) / (1.0f - Increment));
+ UI->Y_TimelinePercentZoomed = (UI->Y_TimelinePercentZoomed / (1.0f - Increment));
+ UI->TimelinePercentOffset = ((UI->TimelinePercentOffset + X_Offset*Increment) / (1.0f - Increment));
+ UI->TimelinePercentZoomed = (UI->TimelinePercentZoomed / (1.0f - Increment));
+ }
+ }
+ }
+ }
+
// General timeline interaction
ImGui::SetCursorScreenPos(TimelineAbsolutePos);
@@ -1550,14 +1719,20 @@ ImGui_ProcessInputs(project_data *File, project_state *State, comp_buffer *CompB
// ImGui::SaveIniSettingsToDisk("asda");
#endif
if (ImGui::IsKeyPressed(ImGuiKey_R)) {
+ /*
UI->Y_TimelinePercentZoomed = UI->Default_Y_TimelinePercentZoomed;
UI->Y_TimelinePercentOffset = UI->Default_Y_TimelinePercentOffset;
keyframe *Keyframe = KeyframeLookup(&File->Layer[0]->x, 0);
Keyframe->Value.f = -10;
Keyframe = KeyframeLookup(&File->Layer[0]->x, 1);
- Keyframe->Value.f = 0;
+ Keyframe->Value.f = -5;
Keyframe = KeyframeLookup(&File->Layer[0]->x, 2);
+ Keyframe->Value.f = 0;
+ Keyframe = KeyframeLookup(&File->Layer[0]->x, 3);
+ Keyframe->Value.f = 5;
+ Keyframe = KeyframeLookup(&File->Layer[0]->x, 4);
Keyframe->Value.f = 10;
+ */
}
if (ImGui::IsKeyPressed(ImGuiKey_D)) {
diff --git a/strings.cpp b/strings.cpp
index 6caedd0..b8560d1 100644
--- a/strings.cpp
+++ b/strings.cpp
@@ -23,14 +23,15 @@ CopyStrings(void *Dest, void *Data)
}
}
-static void *
-String_GenerateFromChar(memory *Memory, char *Char)
+static uint16
+String_AddToFile(memory *Memory, char *Char)
{
- void *Address = AllocateMemory(Memory, STRING_SIZE, F_Strings);
+ uint16 FileIndex = Memory_Block_AllocateNew(Memory, F_Strings);
+ void *Address = Memory_Block_AddressAtIndex(Memory, F_Strings, FileIndex);
uint16 i = 0;
while (Char[i] != '\0') {
*((char *)Address + i) = Char[i];
i++;
}
- return Address;
+ return FileIndex;
}
diff --git a/undo.h b/undo.h
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/undo.h
@@ -0,0 +1,2 @@
+
+