summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--createcalls.cpp389
-rw-r--r--debug.h2
-rw-r--r--defines.h1
-rw-r--r--functions.h14
-rw-r--r--gl_calls.cpp14
-rw-r--r--imgui_ops.h10
-rw-r--r--main.cpp211
-rw-r--r--main.h135
-rw-r--r--memory.cpp77
-rw-r--r--memory.h3
-rw-r--r--my_imgui_widgets.cpp1056
-rw-r--r--prenderer.cpp176
12 files changed, 1781 insertions, 307 deletions
diff --git a/createcalls.cpp b/createcalls.cpp
index 5c569fb..c018eaa 100644
--- a/createcalls.cpp
+++ b/createcalls.cpp
@@ -6,12 +6,45 @@ PostMsg(project_state *State, char *msg)
}
static uint16
+Source_Generate_Blank(project_data *File, project_state *State, memory *Memory, uint16 Width, uint16 Height, uint16 BytesPerPixel)
+{
+ Assert(File->Source_Count < MAX_SOURCES);
+ uint16 Index = Memory_Block_AllocateNew(Memory, F_Sources);
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Index);
+ Source->Occupied = 1;
+ Source->Width = Width;
+ Source->Height = Height;
+ Source->BytesPerPixel= BytesPerPixel;
+ Source->Type = source_type_principal;
+ Source->Bitmap_Index = Memory_Block_PrincipalBitmap_AllocateNew(File, State, Memory);
+ Source->Path_String_Index = String_AddToFile(Memory, "test");
+ // History_Action_Swap(Memory, F_File, sizeof(File->Source_Count), &File->Source_Count);
+ File->Source_Count++;
+ return Index;
+}
+
+static bool32 Source_IsFileSupported(char *Path, bool32 *IsVideo) {
+ return stbi_info(Path, NULL, NULL, NULL);
+ // AV_IsFileSupported(Path, IsVideo)
+}
+
+static void
+Source_Delete(project_data *File, memory *Memory, uint32 Index)
+{
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Index);
+ History_Action_Block_Swap(Memory, F_Sources, Source);
+ Source->Occupied = 0;
+ History_Action_Swap(Memory, F_File, sizeof(File->Source_Count), &File->Source_Count);
+ File->Source_Count--;
+}
+
+static int16
Source_Generate(project_data *File, project_state *State, memory *Memory, void *TempString)
{
Assert(File->Source_Count < MAX_SOURCES);
bool32 IsVideo = 0;
- if (AV_IsFileSupported((char *)TempString, &IsVideo)) {
+ if (Source_IsFileSupported((char *)TempString, &IsVideo)) {
uint16 Index = Memory_Block_AllocateNew(Memory, F_Sources);
block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Index);
History_Entry_Commit(Memory, "Add source");
@@ -19,10 +52,8 @@ Source_Generate(project_data *File, project_state *State, memory *Memory, void *
Source->Occupied = 1;
Source->Path_String_Index = String_AddToFile(Memory, (char *)TempString);
- if (IsVideo)
- Source->Type = source_type_video;
- else
- Source->Type = source_type_image;
+ Assert(!IsVideo);
+ Source->Type = source_type_file;
History_Action_Swap(Memory, F_File, sizeof(File->Source_Count), &File->Source_Count);
File->Source_Count++;
@@ -109,6 +140,7 @@ Keyframe_Interact_Evaluate(memory *Memory, project_state *State, uint8 IsSelecte
}
}
+/*
static void
Layer_Interact_Evaluate(memory *Memory, project_state *State, uint16 Layer_Index_Physical, sorted_comp_info SortedCompInfo, sorted_layer *SortedLayerInfo,
int32 *Frame_Start, int32 *Frame_End, real32 *Vertical_Offset)
@@ -146,8 +178,26 @@ Layer_Interact_Evaluate(memory *Memory, project_state *State, uint16 Layer_Index
*Frame_End += (int32)(State->Interact_Offset[0] * Side[1]);
if (*Frame_End <= *Frame_Start)
*Frame_End = *Frame_Start + 1;
+ } else if (State->Interact_Active == interact_type_viewport_transform) {
+ int i = SortedCompInfo.LayerCount - 1;
+ while (i >= 0) {
+ sorted_layer SortEntry = SortedLayerInfo[i];
+ uint32 Index_Physical = SortEntry.Block_Layer_Index;
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical);
+ i--;
+ }
}
}
+*/
+
+static void
+Layer_Select(memory *Memory, project_state *State, int32 i)
+{
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
+ Layer->IsSelected = true;
+ State->MostRecentlySelectedLayer = i;
+ // State->RecentSelectionType = selection_layer;
+}
// TODO(fox): Precomps!
void Layer_DeselectAll(memory *Memory, uint32 LayerCount) {
@@ -158,6 +208,15 @@ void Layer_DeselectAll(memory *Memory, uint32 LayerCount) {
}
}
+void Source_DeselectAll(project_data *File, memory *Memory)
+{
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Sources, File->Source_Count, &h, &c, &i)) {
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, i);
+ Source->IsSelected = 0;
+ }
+}
+
static sorted_layer *
Layer_GetSortedArray(sorted_layer *LayerArrayStart, sorted_comp_info *SortedCompStart, uint32 TargetComp)
{
@@ -169,6 +228,35 @@ Layer_GetSortedArray(sorted_layer *LayerArrayStart, sorted_comp_info *SortedComp
return LayerArrayStart + LayerOffset;
}
+int32 Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, uint16 PrincipalIndex)
+{
+ block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, PrincipalIndex);
+ sorted_comp_info SortedCompInfo = SortedCompArray[PrincipalIndex];
+ sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, PrincipalIndex);
+ int32 LayerIndex = -1;
+ // for (int i = 0; i < SortedCompInfo.LayerCount; i++) {
+ for (int i = SortedCompInfo.LayerCount - 1; i >= 0; i--) {
+ sorted_layer SortEntry = SortedLayerInfo[i];
+ uint32 Index_Physical = SortEntry.Block_Layer_Index;
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical);
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+ layer_transforms T = Layer_GetTransforms(Layer);
+ v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, UI->TempZoomRatio);
+ if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && !Layer->IsSelected)
+ {
+ LayerIndex = Index_Physical;
+ break;
+ }
+ // if (Layer->IsPrecomp) {
+ // Layer_RecursiveDeselect(Memory, SortedCompArray, SortedLayerArray, TargetIndex, Layer->Block_Source_Index);
+ // }
+ // if (Layer->Block_Composition_Index != TargetIndex) {
+ // Layer->IsSelected = false;
+ // }
+ }
+ return LayerIndex;
+}
+
void Layer_RecursiveDeselect(memory *Memory, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, uint16 TargetIndex, uint16 PrincipalIndex)
{
block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, PrincipalIndex);
@@ -187,16 +275,35 @@ void Layer_RecursiveDeselect(memory *Memory, sorted_comp_info *SortedCompArray,
}
}
-void Layer_SortAll(memory *Memory, sorted_layer *LayerArrayStart, sorted_comp_info *CompStart, uint32 LayerCount, uint32 CompCount)
+void Layer_Sort_CheckPrev(memory *Memory, int i, int Direction, sorted_layer *SortedLayerInfo, sorted_comp_info SortedCompInfo, int *EntriesPassed, sorted_layer *LayerEntry)
{
- for (uint32 i = 0; i < LayerCount; i++) {
+ int PrevOffsetIndex = i + Direction + (*EntriesPassed * Direction);
+ bool32 OutOfBounds = (Direction > 0) ? (PrevOffsetIndex > (SortedCompInfo.LayerCount - 1)) : (PrevOffsetIndex < 0);
+ if (!OutOfBounds) {
+ sorted_layer *PrevLayerEntry = &SortedLayerInfo[PrevOffsetIndex];
+ // block_layer *PrevLayer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, PrevLayerEntry->Block_Layer_Index);
+ // real32 PrevOffset = PrevLayer->Vertical_Offset;
+ real32 PrevOffset = PrevLayerEntry->SortedOffset;
+ if (PrevOffset == (LayerEntry->SortedOffset - Direction)) {
+ LayerEntry->SortedOffset -= Direction;
+ (*EntriesPassed)++;
+ Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerInfo, SortedCompInfo, EntriesPassed, LayerEntry);
+ }
+ }
+}
+
+
+void Layer_SortAll(project_data *File, project_state *State, memory *Memory, sorted_layer *LayerArrayStart, sorted_comp_info *CompStart, uint32 LayerCount, uint32 CompCount)
+{
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) {
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
Assert(Layer->Block_Composition_Index < CompCount);
CompStart[Layer->Block_Composition_Index].LayerCount++;
}
- for (uint32 i = 0; i < LayerCount; i++) {
- // SortedLayerArray->Block_Layer_Index = 0;
+ h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) {
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
sorted_comp_info *SortedCompInfo = &CompStart[Layer->Block_Composition_Index];
sorted_layer *SortedLayerInfo = Layer_GetSortedArray(LayerArrayStart, CompStart, Layer->Block_Composition_Index);
@@ -218,19 +325,63 @@ void Layer_SortAll(memory *Memory, sorted_layer *LayerArrayStart, sorted_comp_in
}
sorted_layer *LayerEntry = SortedLayerInfo + SortedIndex_Playhead;
LayerEntry->Block_Layer_Index = i;
+ LayerEntry->SortedOffset = Layer->Vertical_Offset;
SortedCompInfo->CurrentSortIndex++;
}
- // Assert(CompStart[0].LayerCount == 3);
- // Assert(CompStart[1].LayerCount == 2);
- // Assert(LayerArrayStart[0].Block_Layer_Index == 0);
- // Assert(LayerArrayStart[1].Block_Layer_Index == 2);
- // Assert(LayerArrayStart[2].Block_Layer_Index == 4);
- // Assert(LayerArrayStart[4].Block_Layer_Index == 1);
- // Assert(LayerArrayStart[5].Block_Layer_Index == 3);
+ if (State->Interact_Active == interact_type_layer_move) {
+ int32 Offset = (int32)State->Interact_Offset[1];
+ bool32 Direction = (Offset > 0) ? 1 : -1;
+ for (uint32 c = 0; c < CompCount; c++) {
+ sorted_comp_info *SortedCompInfo = &CompStart[c];
+ if (!SortedCompInfo->LayerCount)
+ continue;
+ sorted_layer *SortedLayerInfo = Layer_GetSortedArray(LayerArrayStart, CompStart, c);
+ int i = (Direction > 0) ? SortedCompInfo->LayerCount - 1 : 0;
+ bool32 Case = 1;
+ while (Case) {
+ int32 EntriesPassed = 0;
+ sorted_layer *LayerEntry = &SortedLayerInfo[i];
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, LayerEntry->Block_Layer_Index);
+ Assert(LayerEntry->SortedOffset == Layer->Vertical_Offset);
+ if (Layer->IsSelected) {
+ int32 SpacesToMove = Offset * Direction;
+ while (SpacesToMove) {
+ Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerInfo, *SortedCompInfo, &EntriesPassed, LayerEntry);
+ LayerEntry->SortedOffset -= Direction;
+ SpacesToMove--;
+ }
+ }
+ int b = 0;
+ while (b < EntriesPassed) {
+ sorted_layer *FrontEntry = &SortedLayerInfo[i+(b*Direction)];
+ sorted_layer *BackEntry = &SortedLayerInfo[i+((b+1)*Direction)];
+ sorted_layer Swap = *FrontEntry;
+ *FrontEntry = *BackEntry;
+ *BackEntry = Swap;
+ b++;
+ }
+ i -= Direction;
+ Case = (Direction > 0) ? (i >= 0) : (i < SortedCompInfo->LayerCount);
+ }
+ }
+ }
+}
+
+static void
+Layer_Delete(project_data *File, memory *Memory, uint32 Index)
+{
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index);
+ History_Action_Block_Swap(Memory, F_Layers, Layer);
+ Layer->Occupied = 0;
+ History_Action_Swap(Memory, F_File, sizeof(File->Layer_Count), &File->Layer_Count);
+ File->Layer_Count--;
}
block_layer * Layer_Init(project_data *File, memory *Memory)
{
+ if (File->Layer_Count + 1 > MAX_LAYERS) {
+ Assert(0);
+ }
block_layer *Layer = (block_layer *)Memory_Block_AllocateAddress(Memory, F_Layers);
History_Action_Block_Swap(Memory, F_Layers, Layer);
@@ -259,22 +410,210 @@ block_layer * Layer_Init(project_data *File, memory *Memory)
return Layer;
}
+void Source_UICreateButton(project_data *File, project_state *State, memory *Memory,
+ sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray)
+{
+ block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex);
+ sorted_comp_info *SortedCompInfo = &SortedCompArray[File->PrincipalCompIndex];
+ int32 TopOffset;
+ if (!File->Layer_Count) {
+ TopOffset = 11;
+ } else {
+ sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, File->PrincipalCompIndex);
+ block_layer *TopLayer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, SortedLayerInfo[SortedCompInfo->LayerCount - 1].Block_Layer_Index);
+ TopOffset = TopLayer->Vertical_Offset;
+ }
+ bool32 CommitAction = 0;
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Sources, File->Source_Count, &h, &c, &i)) {
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, i);
+ if (Source->IsSelected) {
+ if (!CommitAction) {
+ History_Entry_Commit(Memory, "Create layer from source");
+ CommitAction = 1;
+ }
+ block_layer *Layer = Layer_Init(File, Memory);
+ Layer->Block_Source_Index = i;
+ Layer->x.CurrentValue = Source->Width / 2;
+ Layer->y.CurrentValue = Source->Height / 2;
+ Layer->Vertical_Offset = TopOffset-1;
+ Layer->Frame_End = Comp->Frame_End;
+ TopOffset--;
+ }
+ State->UpdateFrame = true;
+ }
+ if (CommitAction)
+ History_Entry_End(Memory);
+ Source_DeselectAll(File, Memory);
+}
+
+
+// Helper for working with different bit depths.
+static render_byte_info
+Bitmap_ByteInfo(uint32 BytesPerPixel) {
+ render_byte_info Byte = {};
+ if (BytesPerPixel == 4) {
+ Byte.MaskPixel = 0xFF;
+ Byte.ByteOffset = 1;
+ Byte.Normalized = 1 / 255.0f;
+ Byte.Bits = 255;
+ } else if (BytesPerPixel == 8) {
+ Byte.MaskPixel = 0xFFFF;
+ Byte.ByteOffset = 2;
+ Byte.Normalized = 1 / 65535.0f;
+ Byte.Bits = 65535;
+ } else {
+ Byte.MaskPixel = 0xFFFFFFFF;
+ Byte.ByteOffset = 4;
+ Byte.Normalized = 1 / 4294967295.0f;
+ Byte.Bits = 4294967295;
+ Assert(0);
+ }
+ return Byte;
+}
+
+// TODO(fox): Make separate full-size bitmap that gets scaled on the GPU instead of this
static void
-Layer_CreateFromSource(project_data *File, project_state *State, memory *Memory, uint16 SourceIndex, int32 Frame_End)
+State_BindBrushTexture(memory *Memory, brush_state *Brush, uint32 BytesPerPixel)
{
- if (File->Layer_Count + 1 > MAX_LAYERS) {
- Assert(0);
+ GL_GenAndBindTexture(&Brush->GLTexture, Brush->Size, Brush->Size, BytesPerPixel, Brush->PaintBuffer);
+}
+
+static void
+Brush_CalcBitmapAlphaFromSize(memory *Memory, brush_state *Brush, uint32 BytesPerPixel)
+{
+ real32 BrushLength = Brush->Size;
+ real32 BrushCenter = BrushLength / 2;
+ real32 MaxLength = BrushCenter;
+ void *BrushAddress = Brush->PaintBuffer;
+
+ render_byte_info Byte = Bitmap_ByteInfo(BytesPerPixel);
+
+ for (int Y = 0; Y < (int)BrushLength; Y++) {
+ for (int X = 0; X < (int)BrushLength; X++) {
+ uint8 *PixelAddress = (uint8 *)BrushAddress + (Y * BytesPerPixel*(int)BrushLength) + (X * BytesPerPixel);
+ uint32 *R_DestAddress = (uint32 *)(PixelAddress + Byte.ByteOffset*0);
+ // uint32 *G_DestAddress = (uint32 *)(PixelAddress + Byte.ByteOffset*1);
+ // uint32 *B_DestAddress = (uint32 *)(PixelAddress + Byte.ByteOffset*2);
+ uint32 *A_DestAddress = (uint32 *)(PixelAddress + Byte.ByteOffset*3);
+ v2 Pos = V2(BrushCenter - X, BrushCenter - Y);
+ real32 L = sqrt(LengthSq(Pos));
+ real32 Gradient = Ceil(L, MaxLength) / MaxLength;
+ Gradient = pow(Gradient, Brush->Hardness);
+ *R_DestAddress = (*R_DestAddress & ~Byte.MaskPixel) | Byte.Bits; // brush preview is red
+ *A_DestAddress = (*A_DestAddress & ~Byte.MaskPixel) | (uint32)((1.0f - Gradient)*Byte.Bits);
+ }
}
- History_Entry_Commit(Memory,"Add layer from source");
- block_layer *Layer = Layer_Init(File, Memory);
- Layer->Block_Source_Index = SourceIndex;
- Layer->Frame_End = Frame_End;
- History_Entry_End(Memory);
+}
- State->UpdateFrame = true;
+// TODO(fox): We could merge this exactly with the standard rendering code.
+static void
+PaintTest(memory *Memory, block_source *Source, brush_state *Brush, void *Address, v2 LayerPos, uint32 BytesPerPixel, v4 Color)
+{
+ uint32 BrushLength = (uint32)Brush->Size;
+
+ rectangle RenderRegion = { 0, 0, Source->Width, Source->Height };
+ rectangle BrushPos = { (int32)(LayerPos.x - (BrushLength / 2)),
+ (int32)(LayerPos.y - (BrushLength / 2)),
+ (int32)(LayerPos.x + (BrushLength / 2)),
+ (int32)(LayerPos.y + (BrushLength / 2)) };
+ rectangle LayerBounds = ClipRectangle(BrushPos, RenderRegion);
+
+ if (BrushPos.Min.x < Brush->CacheBounds.Min.x)
+ Brush->CacheBounds.Min.x = BrushPos.Min.x;
+ if (BrushPos.Min.y < Brush->CacheBounds.Min.y)
+ Brush->CacheBounds.Min.y = BrushPos.Min.y;
+ if (BrushPos.Max.x > Brush->CacheBounds.Max.x)
+ Brush->CacheBounds.Max.x = BrushPos.Max.x;
+ if (BrushPos.Max.y > Brush->CacheBounds.Max.y)
+ Brush->CacheBounds.Max.y = BrushPos.Max.y;
+
+ uint32 LayerPitch = Source->Width*Source->BytesPerPixel;
+ uint32 BrushPitch = (int)BrushLength * BytesPerPixel;
+
+ render_byte_info LayerBits = Bitmap_ByteInfo(Source->BytesPerPixel);
+ render_byte_info BrushBits = Bitmap_ByteInfo(BytesPerPixel);
+
+ int32 ExtraX = 0;
+ int32 ExtraY = 0;
+ if (BrushPos.Min.x < 0) {
+ ExtraX = BrushPos.Min.x;
+ }
+ if (BrushPos.Min.y < 0) {
+ ExtraY = BrushPos.Min.y;
+ }
+
+ void *BrushBuffer = Brush->PaintBuffer;
+
+ // ImGui's color picker works in sRGB, so we need to convert to linear.
+ // real32 R_Brush = (Color.r >= 0.04045) ? pow((Color.r + 0.055) / (1 + 0.055), 2.4) : Color.r / 12.92;
+ // real32 G_Brush = (Color.g >= 0.04045) ? pow((Color.g + 0.055) / (1 + 0.055), 2.4) : Color.g / 12.92;
+ // real32 B_Brush = (Color.b >= 0.04045) ? pow((Color.b + 0.055) / (1 + 0.055), 2.4) : Color.b / 12.92;
+ // real32 A_Brush = (Color.a >= 0.04045) ? pow((Color.a + 0.055) / (1 + 0.055), 2.4) : Color.a / 12.92;
+ real32 R_Brush = Color.r;
+ real32 G_Brush = Color.g;
+ real32 B_Brush = Color.b;
+ real32 A_Brush = Color.a;
+
+ uint8 *BrushRow = (uint8 *)BrushBuffer;
+ for (int32 Y = LayerBounds.Min.y; Y < LayerBounds.Max.y; Y++) {
+ for (int32 X = LayerBounds.Min.x; X < LayerBounds.Max.x; X++) {
+
+ uint32 Offset = Y*LayerPitch + X*Source->BytesPerPixel;
+ uint8 *LayerPixel = (uint8 *)Address + Offset;
+
+ uint32 *R_DestAddress = (uint32 *)(LayerPixel + LayerBits.ByteOffset * 0);
+ uint32 *G_DestAddress = (uint32 *)(LayerPixel + LayerBits.ByteOffset * 1);
+ uint32 *B_DestAddress = (uint32 *)(LayerPixel + LayerBits.ByteOffset * 2);
+ uint32 *A_DestAddress = (uint32 *)(LayerPixel + LayerBits.ByteOffset * 3);
+
+ real32 R_Layer = (real32)(*R_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized;
+ real32 G_Layer = (real32)(*G_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized;
+ real32 B_Layer = (real32)(*B_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized;
+ real32 A_Layer = (real32)(*A_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized;
+
+ int32 TrueX = (X - LayerBounds.Min.x) - ExtraX;
+ int32 TrueY = (Y - LayerBounds.Min.y) - ExtraY;
+
+ // Assert(TrueX >= 0 && TrueX < BrushLength);
+ // Assert(TrueY >= 0 && TrueY < BrushLength);
+
+ uint8 *BrushPixel = (uint8 *)BrushBuffer + (TrueY * BrushPitch) + (TrueX * BytesPerPixel);
+
+ real32 Brush_BitmapAlpha = (real32)((*(uint32 *)(BrushPixel + BrushBits.ByteOffset*3)) & BrushBits.MaskPixel) * BrushBits.Normalized;
+
+ real32 BrushAlpha = Brush_BitmapAlpha * A_Brush;
+ real32 LayerAlpha = A_Layer;
+
+ real32 A_Blend = LayerAlpha + BrushAlpha;
+
+ real32 R_Blend = (R_Layer * (1.0f - BrushAlpha)) + (R_Brush * BrushAlpha);
+ real32 G_Blend = (G_Layer * (1.0f - BrushAlpha)) + (G_Brush * BrushAlpha);
+ real32 B_Blend = (B_Layer * (1.0f - BrushAlpha)) + (B_Brush * BrushAlpha);
+
+ /*
+ R_Blend = (R_Brush * (1.0f - LayerAlpha)) + (R_Blend * LayerAlpha);
+ G_Blend = (G_Brush * (1.0f - LayerAlpha)) + (G_Blend * LayerAlpha);
+ B_Blend = (B_Brush * (1.0f - LayerAlpha)) + (B_Blend * LayerAlpha);
+ */
+
+ Assert(R_Blend <= 1.0f);
+
+ uint32 R_Out = (uint32)(Normalize(R_Blend) * LayerBits.Bits);
+ uint32 G_Out = (uint32)(Normalize(G_Blend) * LayerBits.Bits);
+ uint32 B_Out = (uint32)(Normalize(B_Blend) * LayerBits.Bits);
+ uint32 A_Out = (uint32)(Normalize(A_Blend) * LayerBits.Bits);
+
+ *R_DestAddress = (*R_DestAddress & ~LayerBits.MaskPixel) | R_Out;
+ *G_DestAddress = (*G_DestAddress & ~LayerBits.MaskPixel) | G_Out;
+ *B_DestAddress = (*B_DestAddress & ~LayerBits.MaskPixel) | B_Out;
+ *A_DestAddress = (*A_DestAddress & ~LayerBits.MaskPixel) | A_Out;
+ }
+ }
}
+
#if 0
static void
IncrementFrame(project_data *File, int16 Amount) {
diff --git a/debug.h b/debug.h
index cac3d39..202eb20 100644
--- a/debug.h
+++ b/debug.h
@@ -27,7 +27,7 @@ struct debug_temp
struct project_debug
{
debug_temp Temp;
- bool32 ToggleWindow;
+ bool32 ToggleWindow = 1;
uint64 PixelCountTransparent;
uint64 PixelCountRendered;
uint64 PixelCountChecked;
diff --git a/defines.h b/defines.h
index ccadb78..f2d58f2 100644
--- a/defines.h
+++ b/defines.h
@@ -35,6 +35,7 @@ typedef uint64 ptrsize; // is there a compiler variable for 32 vs 64 bit like
#define MAX_PROPERTIES_PER_EFFECT 16
#define MAX_KEYFRAME_BLOCKS 64
#define MAX_KEYFRAMES_PER_BLOCK 32 // max keyframes on a single channel is 2048
+#define MAX_BITMAP_CHUNKS 64 // Up to 2048x2048-size textures
#define MAX_SELECTED_PROPERTIES 16
diff --git a/functions.h b/functions.h
index 07cfc25..d4a4cfa 100644
--- a/functions.h
+++ b/functions.h
@@ -1,10 +1,22 @@
-static bool32 AV_IsFileSupported(char *filename, bool32 *IsVideo);
+// static bool32 AV_IsFileSupported(char *filename, bool32 *IsVideo);
static void Arbitrary_WriteInto(uint8 *Address_Read, uint8 *Address_Write, uint64 Size);
static void Arbitrary_Zero(uint8 *Address_Write, uint64 Size);
static void Arbitrary_SwapData(memory *Memory, uint8 *Address_0, uint8 *Address_1, uint64 Size);
static void Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 ShiftAmount, int32 Direction);
+static v2 T_CompUVToLayerUV(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, v2 CompUV);
+
+static void Interact_Transform_Begin(project_data *File, memory *Memory, project_state *State, ImVec2 OGPos);
+
+static v2 Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, ui UI, ImVec2 ViewportMin, ImVec2 Point);
+static ImVec2 Layer_LocalToScreenSpace(project_state *State, block_layer *Layer, ui *UI, real32 SourceWidth, real32 SourceHeight, real32 CompWidth, real32 CompHeight, v2 Point);
+
+static void Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale);
+
+static layer_transforms Layer_GetTransforms(block_layer *Layer);
+void GL_GenAndBindTexture(GLuint *GLTexture, int Width, int Height, int BytesPerPixel, void *BufferAddress);
+
static real32 Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 X);
# if 0
diff --git a/gl_calls.cpp b/gl_calls.cpp
index b08615a..6f760b6 100644
--- a/gl_calls.cpp
+++ b/gl_calls.cpp
@@ -154,6 +154,20 @@ static void GL_InitDefaultVerts() {
glEnableVertexAttribArray(1);
}
+void
+GL_GenAndBindTexture(GLuint *GLTexture, int Width, int Height, int BytesPerPixel, void *BufferAddress)
+{
+ glGenTextures(1, GLTexture);
+ glBindTexture(GL_TEXTURE_2D, *GLTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ int ByteFlag = (BytesPerPixel == 4) ? GL_RGBA : GL_RGBA16;
+ int ByteFlag2 = (BytesPerPixel == 4) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
+ glTexImage2D(GL_TEXTURE_2D, 0, ByteFlag, Width, Height, 0, GL_RGBA, ByteFlag2, BufferAddress);
+}
+
#if 0
void
GL_InitTexture(gl_effect_layer *Test)
diff --git a/imgui_ops.h b/imgui_ops.h
index e2627ab..2bf6335 100644
--- a/imgui_ops.h
+++ b/imgui_ops.h
@@ -70,6 +70,16 @@ ImVec2 operator/(ImVec2 A, real32 B)
return Result;
}
+ImVec2 operator/(real32 A, ImVec2 B)
+{
+ ImVec2 Result;
+
+ Result.x = A / B.x;
+ Result.y = A / B.y;
+
+ return Result;
+}
+
inline bool32
IsRectTouching(ImVec2 Min1, ImVec2 Max1, ImVec2 Min2, ImVec2 Max2)
{
diff --git a/main.cpp b/main.cpp
index 7920727..0a5e9ed 100644
--- a/main.cpp
+++ b/main.cpp
@@ -66,7 +66,7 @@ static uint32 RandomGlobalIncrement = 0;
#include "threading.cpp"
#endif
#include "createcalls.cpp"
-#include "ffmpeg_backend.cpp"
+// #include "ffmpeg_backend.cpp"
#include "my_imgui_widgets.cpp"
#include "prenderer.cpp"
#include "gl_calls.cpp"
@@ -125,39 +125,36 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI,
UI->Warp_WantSetPos = false;
}
- ImGui::DockSpaceOverViewport();
-
if (!io.WantCaptureKeyboard)
ImGui_ProcessInputs(File, State, UI, Memory, io);
-#if 0
-
- ImGui_Viewport(File, &State, &UI, &Memory, CompBuffer, io, textureID);
-
- ImGui_File(&File, &State, &Memory, &UI, io);
-
- ImGui_EffectsPanel(&File, &State, &Memory, &UI, io);
-
- ImGui_PropertiesPanel(&File, &State, &UI, &Memory, io);
-
- // ImGui_Graph(&File, &State, &Memory, &UI, io);
-
-#if DEBUG
- ImGui_DebugUndoTree(&File, &Memory);
-#endif
-
-#endif
+ uint64 SortSize = (sizeof(sorted_comp_info) * File->Comp_Count) + (sizeof(sorted_layer) * File->Layer_Count);
+ void *SortedArray = Memory_PushScratch(Memory, SortSize);
+ Arbitrary_Zero((uint8 *)SortedArray, SortSize);
+ sorted_comp_info *SortedCompArray = (sorted_comp_info *)SortedArray;
+ sorted_layer *SortedLayerArray = (sorted_layer *)((uint8 *)SortedArray + (sizeof(sorted_comp_info) * File->Comp_Count));
+ Layer_SortAll(File, State, Memory, SortedLayerArray, SortedCompArray, File->Layer_Count, File->Comp_Count);
- ImGui_Viewport(File, State, UI, Memory, io, textureID);
- ImGui_Timeline(File, State, Memory, UI, io);
- ImGui_File(File, State, Memory, io);
+ ImGui::DockSpaceOverViewport();
if (Debug.ToggleWindow) {
ImGui::ShowDemoWindow();
ImGui_DebugMemoryViewer(Memory, State);
+ ImGui_DebugUndoTree(Memory, State);
}
- // ImGui::ShowDemoWindow();
+ // if (State->Initializing == 3)
+ // Source_UICreateButton(File, State, Memory, SortedCompArray, SortedLayerArray);
+
+
+ ImGui_Viewport(File, State, UI, Memory, io, textureID, SortedCompArray, SortedLayerArray);
+ ImGui_Timeline(File, State, Memory, UI, io, SortedCompArray, SortedLayerArray);
+ ImGui_File(File, State, Memory, io, SortedCompArray, SortedLayerArray);
+ ImGui_PropertiesPanel(File, State, UI, Memory, io);
+ ImGui_ColorPanel(File, State, UI, Memory, io);
+ ImGui_Menu(File, State, UI, Memory, io);
+
+ Memory_PopScratch(Memory, SortSize);
#if DEBUG
Debug.Temp = {};
#endif
@@ -165,20 +162,28 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI,
ImGui::EndFrame();
}
+static layer_transforms
+Layer_GetTransforms(block_layer *Layer) {
+ return { Layer->x.CurrentValue, Layer->y.CurrentValue, Layer->ax.CurrentValue, Layer->ay.CurrentValue, Layer->rotation.CurrentValue, Layer->scale.CurrentValue };
+}
+
static void *
Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, uint32 CompIndex)
{
block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex);
- cache_entry *Entry_Main = Memory_Cache_Search(State, Memory, State->Render.Entry, cache_entry_type_comp, CompIndex, State->Frame_Current);
+ cache_entry *Entry_Main = Memory_Cache_Search(State, Memory, cache_entry_type_comp, CompIndex, State->Frame_Current);
void *CompBuffer = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry_Main->Block_StartIndex);
+ uint64 Size = Comp->Width * Comp->Height * Comp->BytesPerPixel;
+ Arbitrary_Zero((uint8 *)CompBuffer, Size);
- if (Entry_Main->IsCached)
- return CompBuffer;
+ // if (Entry_Main->IsCached)
+ // return CompBuffer;
uint64 Comp_TimeStart = GetTime();
sorted_comp_info *SortedCompInfo = &SortedCompArray[CompIndex];
sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, CompIndex);
+
for (int i = 0; i < SortedCompInfo->LayerCount; i++) {
sorted_layer SortEntry = SortedLayerInfo[i];
uint32 Index_Physical = SortEntry.Block_Layer_Index;
@@ -190,33 +195,36 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io
void *BitmapAddress = NULL;
if (!Layer->IsPrecomp) {
block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
- cache_entry *Entry = Memory_Cache_Search(State, Memory, State->Render.Entry, cache_entry_type_source, Layer->Block_Source_Index, 0);
-
- Assert(Source->Type == source_type_image);
- if (!Entry->IsCached) {
- uint64 Src_TimeStart = GetTime();
- block_string *Name = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Source->Path_String_Index);
- int w = 0, h = 0;
- void *temp = stbi_load(Name->Char, &w, &h, NULL, 4);
- Source->Width = w;
- Source->Height = h;
- Source->BytesPerPixel = 4;
- uint64 Size = Source->Width * Source->Height * Source->BytesPerPixel;
- void *Source_Address = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex);
- Arbitrary_WriteInto((uint8 *)temp, (uint8 *)Source_Address, Size);
- stbi_image_free(temp);
- BitmapState->ToUpdate = false;
- BitmapState->CurrentFrame = 0;
- Entry->CycleTime = GetTime() - Src_TimeStart;
- Layer->x.CurrentValue = (Layer->Block_Source_Index == 0) ? 200 : Comp->Width/2;
- Layer->y.CurrentValue = Comp->Height/2;
- Entry->IsCached = true;
+ if (Source->Type == source_type_principal) {
+ BitmapAddress = Memory_Block_AddressAtIndex(Memory, F_PrincipalBitmaps, Source->Bitmap_Index);
+ } else {
+ cache_entry *Entry = Memory_Cache_Search(State, Memory, cache_entry_type_source, Layer->Block_Source_Index, 0);
+ if (!Entry->IsCached) {
+ uint64 Src_TimeStart = GetTime();
+ block_string *Name = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Source->Path_String_Index);
+ int w = 0, h = 0;
+ void *temp = stbi_load(Name->Char, &w, &h, NULL, 4);
+ Source->Width = w;
+ Source->Height = h;
+ Source->BytesPerPixel = 4;
+ uint64 Size = Source->Width * Source->Height * Source->BytesPerPixel;
+ void *Source_Address = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex);
+ Arbitrary_WriteInto((uint8 *)temp, (uint8 *)Source_Address, Size);
+ stbi_image_free(temp);
+ BitmapState->ToUpdate = false;
+ BitmapState->CurrentFrame = 0;
+ Entry->CycleTime = GetTime() - Src_TimeStart;
+ Layer->x.CurrentValue = Comp->Width/2;
+ Layer->y.CurrentValue = Comp->Height/2;
+ Entry->IsCached = true;
+ }
+ BitmapAddress = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex);
}
- BitmapAddress = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex);
+
} else {
block_composition *Precomp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index);
- cache_entry *Entry = Memory_Cache_Search(State, Memory, State->Render.Entry, cache_entry_type_comp, Layer->Block_Source_Index, State->Frame_Current);
+ cache_entry *Entry = Memory_Cache_Search(State, Memory, cache_entry_type_comp, Layer->Block_Source_Index, State->Frame_Current);
if (!Entry->IsCached) {
uint64 Src_TimeStart = GetTime();
Render_Comp(File, State, Memory, io, SortedCompArray, SortedLayerArray, Layer->Block_Source_Index);
@@ -307,7 +315,7 @@ Main_Renderer(project_data *File, project_state *State, memory *Memory, SDL_Wind
Arbitrary_Zero((uint8 *)SortedArray, SortSize);
sorted_comp_info *SortedCompArray = (sorted_comp_info *)SortedArray;
sorted_layer *SortedLayerArray = (sorted_layer *)((uint8 *)SortedArray + (sizeof(sorted_comp_info) * File->Comp_Count));
- Layer_SortAll(Memory, SortedLayerArray, SortedCompArray, File->Layer_Count, File->Comp_Count);
+ Layer_SortAll(File, State, Memory, SortedLayerArray, SortedCompArray, File->Layer_Count, File->Comp_Count);
void *MainCompBuffer = Render_Comp(File, State, Memory, io, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex);
@@ -343,6 +351,9 @@ int main(int argc, char *argv[]) {
0);
#endif
+ // 1 meg per block
+ BitmapBlockSize = 1024 * 1024;
+
memory Memory = {};
Memory_InitTable(&GlobalMemory, &Memory, 1 * 1024 * 1024, P_AVInfo, "Image/video headers");
@@ -355,10 +366,12 @@ int main(int argc, char *argv[]) {
Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Sources, "Sources", sizeof(block_source));
Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Bezier, "Bezier paths (keyframes, masks)", sizeof(block_bezier));
Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Strings, "Strings", sizeof(block_string));
+ Memory_InitTable(&GlobalMemory, &Memory, (uint64)50 * 1024 * 1024, F_PrincipalBitmaps, "Principal bitmap data", BitmapBlockSize);
Memory_InitTable(&GlobalMemory, &Memory, (uint64)64 * 1024 * 1024, B_ScratchSpace, "Scratch");
Memory_InitTable(&GlobalMemory, &Memory, (uint64)200 * 1024 * 1024, B_CachedBitmaps, "Cached bitmap buffer");
+
#if ARM
InstructionMode = instruction_mode_neon;
#else
@@ -370,21 +383,30 @@ int main(int argc, char *argv[]) {
}
#endif
+
project_state *State = (project_state *)Memory.Slot[P_MiscCache].Address;
*State = {};
project_data *File = (project_data *)Memory_Block_AllocateAddress(&Memory, F_File);
*File = {};
File->Occupied = 1;
+ State->Brush.PaintBuffer = Memory.Slot[B_ScratchSpace].Address;
+ uint64 ScratchPaintSize = 2048*2048*4;
+ Memory.ScratchPos += ScratchPaintSize;
+
ui UI = {};
UI.Test = ImDrawListSplitter();
+ // int ToolCount = (int)tool_count;
+ // for (int i = 0; i < ToolCount; i++) {
+ // glBindTexture(GL_TEXTURE_2D, textureID);
+ // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MainComp->Width, MainComp->Height, 0, GL_RGBA, ByteFlag2, MainCompBuffer);
+ // }
+
block_composition *MainComp = (block_composition *)Memory_Block_AllocateAddress(&Memory, F_Precomps);
- // MainComp->Width = 3840;
- // MainComp->Height = 2160;
- MainComp->Width = 1280;
- MainComp->Height = 720;
+ MainComp->Width = 1024;
+ MainComp->Height = 512;
MainComp->FPS = 24;
MainComp->BytesPerPixel = 4;
MainComp->Frame_Count = 48;
@@ -392,6 +414,9 @@ int main(int argc, char *argv[]) {
MainComp->Occupied = 1;
MainComp->Name_String_Index = String_AddToFile(&Memory, "Main comp");
+ File->Comp_Count = 1;
+
+ /*
block_composition *Comp2 = (block_composition *)Memory_Block_AllocateAddress(&Memory, F_Precomps);
Comp2->Width = 500;
Comp2->Height = 500;
@@ -401,16 +426,16 @@ int main(int argc, char *argv[]) {
Comp2->Frame_End = 48;
Comp2->Occupied = 1;
Comp2->Name_String_Index = String_AddToFile(&Memory, "Another comp");
+ */
- File->Comp_Count = 2;
-
- // 1 MB for 4, 2 MB for 8
- BitmapBlockSize = (MainComp->BytesPerPixel / 4) * 1024 * 1024;
+ File->Comp_Count = 1;
{
uint16 SourceIndex = Source_Generate(File, State, &Memory, (void *)"../asset/a.jpg");
block_source *Source = (block_source *)Memory_Block_AddressAtIndex(&Memory, F_Sources, 0);
+ Source->IsSelected = true;
+ /*
{
Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End);
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1);
@@ -480,30 +505,39 @@ int main(int argc, char *argv[]) {
Bezier3->Point[1].Occupied = true;
Bezier3->Point[2].Occupied = true;
}
- // {
- // Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End);
- // block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1);
- // Layer->Vertical_Offset = 1;
- // Layer->Col[0] = 1;
- // Layer->Col[1] = 0;
- // Layer->Col[2] = 0;
- // Layer->Block_Composition_Index = 1;
- // }
+ */
+ /*
+ {
+ Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End);
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1);
+ Layer->Vertical_Offset = 2;
+ Layer->IsSelected = true;
+ Layer->ColIndex = 2;
+ Layer->Block_Composition_Index = 0;
+ }
+ {
+ Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End);
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1);
+ Layer->Vertical_Offset = 5;
+ Layer->ColIndex = 0;
+ Layer->Block_Composition_Index = 0;
+ }
+ */
}
{
uint16 SourceIndex = Source_Generate(File, State, &Memory, (void *)"../asset/b.jpg");
block_source *Source = (block_source *)Memory_Block_AddressAtIndex(&Memory, F_Sources, 1);
-#if 0
+ Source->IsSelected = true;
+ /*
{
Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End);
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1);
- Layer->Vertical_Offset = 5;
- Layer->Col[0] = 0;
- Layer->Col[1] = 0;
- Layer->Col[2] = 1;
- Layer->Block_Composition_Index = 0;
Layer->IsSelected = true;
+ Layer->Vertical_Offset = 3;
+ Layer->ColIndex = 1;
+ Layer->Block_Composition_Index = 0;
+ // Layer->IsSelected = true;
property_channel *Property = &Layer->x;
Property->Block_Bezier_Index[0] = Memory_Block_AllocateNew(&Memory, F_Bezier);
@@ -545,21 +579,22 @@ int main(int argc, char *argv[]) {
Bezier2->Point[0].Occupied = true;
Bezier2->Point[1].Occupied = true;
}
-#endif
+ */
}
{
uint16 SourceIndex = Source_Generate(File, State, &Memory, (void *)"../asset/c.jpg");
block_source *Source = (block_source *)Memory_Block_AddressAtIndex(&Memory, F_Sources, 2);
- // {
- // Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End);
- // block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1);
- // Layer->Vertical_Offset = 0;
- // Layer->Col[0] = 0;
- // Layer->Col[1] = 1;
- // Layer->Col[2] = 0;
- // Layer->Block_Composition_Index = 1;
- // }
+ Source->IsSelected = true;
+ /*
+ {
+ Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End);
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1);
+ Layer->Vertical_Offset = 1;
+ Layer->ColIndex = 3;
+ Layer->Block_Composition_Index = 0;
+ }
+ */
// {
// Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End);
// block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1);
@@ -600,7 +635,6 @@ int main(int argc, char *argv[]) {
SDL_Init(SDL_INIT_VIDEO);
-
Semaphore = SDL_CreateSemaphore(0);
#if THREADED
@@ -703,8 +737,15 @@ int main(int argc, char *argv[]) {
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
+ Brush_CalcBitmapAlphaFromSize(&Memory, &State->Brush, 4);
+ State_BindBrushTexture(&Memory, &State->Brush, 4);
+
+
while (State->IsRunning)
{
+ // State->Interact_Active = interact_type_layer_move;
+ // State->Interact_Offset[1] = -3.0f;
+
Main_InputTest(File, State, &Memory, &UI, window, textureID);
if (State->IsPlaying) {
diff --git a/main.h b/main.h
index 7e07597..1b386ce 100644
--- a/main.h
+++ b/main.h
@@ -125,6 +125,7 @@ struct sorted_comp_info
struct sorted_layer
{
uint16 Block_Layer_Index;
+ real32 SortedOffset;
};
enum timeline_mode
@@ -144,10 +145,11 @@ struct ui
ImVec2 TimelinePercentZoomed;
ImVec2 TimelinePercentOffset;
- timeline_mode TimelineMode = timeline_mode_graph;
+ uint32 InteractTransformMode; // Whether a drag on the Shift+T UI is scale (1), rotation (2), or position (3).
+
+ timeline_mode TimelineMode;
bool32 BoxSelect;
- ImVec2 DragDelta_Prev; // TODO(fox): Make native ImGui?
focused_window FocusedWindow; // Convenience for adding window-specific hotkeys.
@@ -160,23 +162,27 @@ struct ui
real32 Warp_PositionInitial;
int32 Warp_Direction;
+ v4 Color = {1, 1, 1, 1};
+ v4 AltColor = {0, 0, 0, 1};
+ bool32 IsPrimary;
+
ImU32 LayerColors[16] = {
- 0x00050506,
- 0x00806754,
- 0x002d3f66,
- 0x0044546e,
- 0x00556780,
- 0x005d7392,
- 0x007e7b7e,
- 0x00828282,
- 0x00434344,
- 0x00AB8A71,
- 0x003C5588,
- 0x005B7193,
- 0x00728AAB,
- 0x007C9AC3,
- 0x00A9A5A8,
- 0x00c0c0c0
+ 0xff0000ff,
+ 0xff00ff00,
+ 0xffff0000,
+ 0xff44546e,
+ 0xff556780,
+ 0xff5d7392,
+ 0xff7e7b7e,
+ 0xff828282,
+ 0xff434344,
+ 0xffAB8A71,
+ 0xff3C5588,
+ 0xff5B7193,
+ 0xff728AAB,
+ 0xff7C9AC3,
+ 0xffA9A5A8,
+ 0xffc0c0c0
};
};
@@ -184,14 +190,70 @@ struct pen_state {
bool32 IsActive;
};
+enum brush_type
+{
+ brush_normal,
+ brush_wacky1,
+ brush_wacky2,
+ brush_wacky3,
+ brush_amount
+};
+
+char *BrushNames[brush_amount] = {
+ "brush_normal",
+ "brush_wacky1",
+ "brush_wacky2",
+ "brush_wacky3"
+};
+
+struct brush_state
+{
+ ImVec2 UIPos; // Initial position when ctrl is held
+ real32 Size = 15; // Maxes at 1024 for now
+ real32 Hardness = 1.0f; // From 1 to 100
+ real32 Spacing = 1.0f;
+ brush_type Type = brush_normal;
+ GLuint GLTexture;
+ void *PaintBuffer;
+ rectangle CacheBounds;
+};
+
enum interact_type
{
interact_type_none,
interact_type_layer_move,
interact_type_layer_timeadjust,
+ interact_type_viewport_transform,
interact_type_keyframe_move,
interact_type_keyframe_scale,
interact_type_keyframe_rotate,
+ interact_type_newlayer_paint
+};
+
+char *ToolName[] {
+ "Move",
+ "Crop",
+ "Brush",
+ "Pen"
+};
+
+enum tool {
+ tool_default,
+ tool_crop,
+ tool_brush,
+ tool_pen,
+ tool_count
+};
+
+struct interact_transform
+{
+ v2 Min;
+ v2 Max;
+ real32 Radians;
+ v2 Position;
+ real32 Scale = 1.0f;
+ ImVec2 OGPos;
+ uint32 TransformMode;
};
struct project_state
@@ -202,9 +264,13 @@ struct project_state
render_state Render;
- int32 Frame_Current;
- // tool Tool = tool_default;
+ int32 Frame_Current;
+ tool Tool = tool_default;
+ // GLuint ToolIconTex[(int)tool_count];
pen_state Pen = {};
+ brush_state Brush;
+
+ char DummyName2[512];
bool32 IsRunning = 1;
bool32 IsPlaying;
@@ -214,7 +280,7 @@ struct project_state
// selection_type RecentSelectionType = selection_none;
interact_type Interact_Active;
- real32 Interact_Offset[4];
+ real32 Interact_Offset[12];
void *Interact_Address;
int32 Initializing = 3;
@@ -253,25 +319,36 @@ struct block_composition
enum source_type {
source_type_none,
- source_type_video,
- source_type_image
+ source_type_principal,
+ source_type_file
+};
+
+struct layer_transforms
+{
+ real32 x;
+ real32 y;
+ real32 ax;
+ real32 ay;
+ real32 rotation;
+ real32 scale;
};
struct block_source
{
uint8 Occupied;
+ bool32 IsSelected;
+
uint16 Path_String_Index;
uint16 Name_String_Index;
- // Image and video
+
+ // Only used for type_principal
+ uint16 Bitmap_Index;
+
uint16 Width;
uint16 Height;
uint16 BytesPerPixel;
- // Video only
- real32 FPS;
- real32 AvgPTSPerFrame; // set by Libav
-
source_type Type;
};
@@ -353,7 +430,7 @@ struct block_layer {
real32 Vertical_Offset;
real32 Vertical_Height = 1;
- real32 Col[3];
+ uint16 ColIndex;
};
struct render_byte_info {
diff --git a/memory.cpp b/memory.cpp
index 3037eb0..6e70055 100644
--- a/memory.cpp
+++ b/memory.cpp
@@ -41,6 +41,58 @@ Memory_Block_AllocateAddress(memory *Memory, memory_table_list TableName)
return Memory_Block_AddressAtIndex(Memory, TableName, FileIndex);
}
+// IMPORTANT(fox): All block data has to start with a uint8 Occupied variable!
+static bool32
+Block_Loop(memory *Memory, memory_table_list TableName, uint32 TotalCount, int *HasIncremented, int *CurrentCount, int *Index)
+{
+ for (;;) {
+ if (*CurrentCount == TotalCount) {
+ return 0;
+ }
+ if (*HasIncremented) {
+ *HasIncremented = 0;
+ (*Index)++;
+ }
+ uint8 *Occupied = (uint8 *)Memory_Block_AddressAtIndex(Memory, TableName, *Index);
+ if (*Occupied) {
+ *HasIncremented = 1;
+ (*CurrentCount)++;
+ return 1;
+ }
+ (*Index)++;
+ Assert(*CurrentCount <= TotalCount);
+ Assert(*Index <= TotalCount*100); // This can get triggered normally if 100+ items are added and the first 99 in memory are deleted.
+ }
+ Assert(0);
+ return 0;
+}
+
+static uint32
+Memory_Block_PrincipalBitmap_AllocateNew(project_data *File, project_state *State, memory *Memory)
+{
+ uint32 LastVal = 0;
+ uint32 LastBlock = 0;
+ uint32 c = 0;
+ uint32 r = 0;
+ while (r < File->Source_Count) {
+ block_source Source = *(block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, c);
+ if (Source.Occupied != 0) {
+ LastBlock = (Source.Bitmap_Index > LastBlock) ? Source.Bitmap_Index : LastBlock;
+ LastVal = r;
+ r++;
+ }
+ c++;
+ }
+
+ block_source Source = *(block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, r);
+ uint32 BlockSize = ((Source.Width * Source.Height * Source.BytesPerPixel) / BitmapBlockSize) + 1;
+
+ uint32 Blocks_Max = Memory->Slot[B_CachedBitmaps].Size / BitmapBlockSize;
+ Assert(Blocks_Max > (LastBlock + BlockSize));
+ return LastBlock + BlockSize;
+
+}
+
static uint32
Memory_Block_Bitmap_AllocateNew(project_state *State, memory *Memory, cache_entry Entry, uint64 NewSize)
{
@@ -95,17 +147,37 @@ Memory_Block_Bitmap_AllocateNew(project_state *State, memory *Memory, cache_entr
}
+static void
+Memory_Cache_Invalidate(project_state *State, memory *Memory, cache_entry_type Type, uint32 TypeInfo, uint32 TypeInfo_Sub)
+{
+ cache_entry *EntryArray = State->Render.Entry;
+ int c = 0;
+ int count = Memory->EntryCount;
+ while (count != 0) {
+ if (EntryArray[c].Type == Type &&
+ EntryArray[c].TypeInfo == TypeInfo) {
+ EntryArray[c].IsOccupied = false;
+ Memory->EntryCount--;
+ }
+ c++;
+ count--;
+ }
+}
+
static cache_entry *
-Memory_Cache_Search(project_state *State, memory *Memory, cache_entry *EntryArray, cache_entry_type Type, uint32 TypeInfo, uint32 TypeInfo_Sub)
+Memory_Cache_Search(project_state *State, memory *Memory, cache_entry_type Type, uint32 TypeInfo, uint32 TypeInfo_Sub)
{
+ cache_entry *EntryArray = State->Render.Entry;
int c = 0;
- while (EntryArray[c].IsOccupied != 0) {
+ int count = Memory->EntryCount;
+ while (count != 0) {
if (EntryArray[c].Type == Type &&
EntryArray[c].TypeInfo == TypeInfo &&
EntryArray[c].TypeInfo_Sub == TypeInfo_Sub) {
return &EntryArray[c];
}
c++;
+ count--;
}
if (c != 0)
EntryArray[c].Block_StartIndex = Memory_Block_Bitmap_AllocateNew(State, Memory, EntryArray[c], 0);
@@ -113,6 +185,7 @@ Memory_Cache_Search(project_state *State, memory *Memory, cache_entry *EntryArra
EntryArray[c].Type = Type;
EntryArray[c].TypeInfo = TypeInfo;
EntryArray[c].TypeInfo_Sub = TypeInfo_Sub;
+ Memory->EntryCount++;
return &EntryArray[c];
}
diff --git a/memory.h b/memory.h
index 3148138..2067e16 100644
--- a/memory.h
+++ b/memory.h
@@ -12,9 +12,9 @@ enum memory_table_list {
F_Bezier,
F_Effects,
F_Strings,
+ F_PrincipalBitmaps,
B_ScratchSpace,
- // B_CachedBitmapInfo,
B_CachedBitmaps,
};
@@ -61,6 +61,7 @@ struct memory {
memory_table Slot[16];
history_entry_list History;
uint64 ScratchPos;
+ uint32 EntryCount;
bool32 IsFileSaved;
};
diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp
index c5a4049..e1e9ffc 100644
--- a/my_imgui_widgets.cpp
+++ b/my_imgui_widgets.cpp
@@ -4,6 +4,72 @@
#include "imgui_helper_widgets.cpp"
static void
+ImGui_InteractSliderProperty(project_state *State, memory *Memory, property_channel *Property)
+{
+ ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue,
+ Property->ScrubVal, &Property->MinVal, &Property->MaxVal, "%f");
+ /*
+ if (ImGui::IsItemActivated()) {
+ State->InteractCache[0] = Property->CurrentValue.f;
+ }
+ if (ImGui::IsItemActive()) {
+ State->UpdateFrame = true;
+ }
+ if (ImGui::IsItemDeactivatedAfterEdit()) {
+ if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
+ Property->CurrentValue.f = State->InteractCache[0];
+ } else {
+ History_Entry_Commit(Memory, action_entry_default, "Tranforms interact");
+ History_Action_Change(Memory, &Property->CurrentValue.f, &State->InteractCache[0],
+ &Property->CurrentValue.f, action_type_change_r32);
+ History_Entry_End(Memory);
+ }
+ State->UpdateFrame = true;
+ }
+ */
+}
+
+static void
+ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io)
+{
+ bool32 Display = 1;
+ block_layer *Layer = NULL;
+ if (State->MostRecentlySelectedLayer > -1) {
+ Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, State->MostRecentlySelectedLayer);
+ if (!Layer->Occupied)
+ Display = 0;
+ } else {
+ Display = 0;
+ }
+ if (Display) {
+ block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index);
+ char buf[256];
+ sprintf(buf, "Properties: %s###Properties", String->Char);
+ ImGui::Begin(buf);
+ if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
+ UI->FocusedWindow = focus_properties;
+ ImGui::Text("Transform");
+ for (int h = 0; h < AmountOf(Layer->Property); h++) {
+ property_channel *Property = &Layer->Property[h];
+ ImGui::PushID(Property);
+ ImGui::Button("K");
+ // if (ImGui::Button("K"))
+ // Keyframe_Insert(Property, Memory, File->CurrentFrame, Property->CurrentValue.f);
+ ImGui::SameLine();
+ ImGui_InteractSliderProperty(State, Memory, Property);
+ ImGui::PopID();
+ }
+ ImGui::End();
+ } else {
+ ImGui::Begin("Properties: empty###Properties");
+ if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
+ UI->FocusedWindow = focus_properties;
+ ImGui::End();
+ }
+}
+
+#if DEBUG
+static void
ImGui_DebugMemoryViewer(memory *Memory, project_state *State)
{
ImGui::Begin("Memory viewer");
@@ -53,23 +119,103 @@ ImGui_DebugMemoryViewer(memory *Memory, project_state *State)
}
static void
-ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io)
+ImGui_DebugUndoTree(memory *Memory, project_state *State)
+{
+ ImGui::Begin("undotree");
+ for (int i = 0; i < Memory->History.NumberOfEntries; i++) {
+ history_entry Entry = Memory->History.Entry[i];
+ bool32 CurrentPos = (i < Memory->History.EntryPlayhead);
+ ImGui::MenuItem(Entry.Name, NULL, CurrentPos);
+ }
+ ImGui::End();
+}
+#endif
+
+static void
+ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io,
+ sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray)
{
ImGui::Begin("Files");
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
+ if (!ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
+ Source_DeselectAll(File, Memory);
+ else if (ImGui::IsKeyPressed(ImGuiKey_Backspace)) {
+
+ /*
+ uint64 SortSize = (sizeof(uint16) * File->Comp_Count);
+ void *SortedArray = Memory_PushScratch(Memory, SortSize);
+ uint16 *SelectedSourceIndex = (uint16 *)SortedArray;
+ int SelectedSourceCount = 0;
+
+ int h = 0, c = 0, i = 0;
+ int SourceCount = File->Source_Count;
+ while (Block_Loop(Memory, F_Sources, SourceCount, &h, &c, &i)) {
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, i);
+ if (Source->IsSelected) {
+ SelectedSourceIndex[SelectedSourceCount] = i;
+ SelectedSourceCount++;
+ }
+ }
+
+ h = 0, c = 0, i = 0;
+ int LayerCount = File->Layer_Count;
+ while (Block_Loop(Memory, F_Layers, LayerCount, &h, &c, &i)) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
+ for (int b = 0; b < SelectedSourceCount; b++) {
+ if (SelectedSourceIndex[b] == Layer->Block_Source_Index) {
+ }
+ }
+ }
+
+ Memory_PopScratch(Memory, SortSize);
+ */
+
+ /*
+ bool32 CommitAction = 0;
+ while (Block_Loop(Memory, F_Sources, SourceCount, &h, &c, &i)) {
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, i);
+ if (Source->IsSelected) {
+ if (!CommitAction) {
+ History_Entry_Commit(Memory, "Delete source");
+ CommitAction = 1;
+ }
+ Source_Delete(File, Memory, i);
+ }
+ }
+ if (CommitAction)
+ History_Entry_End(Memory);
+ */
+ }
+
for (int c = 0; c < File->Comp_Count; c++) {
block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, c);
block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Comp->Name_String_Index);
ImGui::Text(String->Char);
}
- for (int c = 0; c < File->Source_Count; c++) {
- block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, c);
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Sources, File->Source_Count, &h, &c, &i)) {
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, i);
block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Source->Path_String_Index);
- ImGui::Text(String->Char);
+ ImGui::Selectable(String->Char, Source->IsSelected);
+ if (ImGui::IsItemClicked() || ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
+ if (!io.KeyShift && !Source->IsSelected) {
+ Source_DeselectAll(File, Memory);
+ }
+ Source->IsSelected = 1;
+ }
+ ImGui::OpenPopupOnItemClick("sourcecontext", ImGuiPopupFlags_MouseButtonRight);
+ }
+
+ if (ImGui::BeginPopup("sourcecontext")) {
+ if (ImGui::MenuItem("Create layer from source")) {
+ Source_UICreateButton(File, State, Memory, SortedCompArray, SortedLayerArray);
+ }
+ ImGui::EndPopup();
}
#if DEBUG
+
for (int i = 0; i < Debug.Temp.WatchedProperties; i++) {
if (Debug.Temp.DebugPropertyType[i] == d_float) {
ImGui::Text("%s: %f", Debug.Temp.String[i], Debug.Temp.Val[i].f);
@@ -84,7 +230,410 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io)
}
static void
-ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, GLuint textureID)
+ImGui_ColorPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io)
+{
+ ImGuiStyle& style = ImGui::GetStyle();
+
+ ImGui::Begin("Colors");
+
+ ImGuiColorEditFlags flags_primary = ImGuiColorEditFlags_AlphaPreview |
+ ImGuiColorEditFlags_Float;
+ ImGuiColorEditFlags flags_picker = ImGuiColorEditFlags_PickerHueBar |
+ ImGuiColorEditFlags_AlphaBar |
+ ImGuiColorEditFlags_NoSmallPreview |
+ ImGuiColorEditFlags_NoSidePreview |
+ ImGuiColorEditFlags_DisplayRGB |
+ ImGuiColorEditFlags_DisplayHSV |
+ ImGuiColorEditFlags_DisplayHex;
+
+ // Dim window if it's not active so there's not a big saturation square in
+ // the corner of my vision while I'm editing. Personal preference.
+ real32 AlphaMult = (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) ? 1.0f : 0.3f;
+ ImGui::PushStyleVar(ImGuiStyleVar_Alpha, style.Alpha * AlphaMult);
+
+ ImGui::ColorPicker4("##maincolorpicker", &UI->Color.r, flags_primary | flags_picker);
+
+ ImGui::PopStyleVar();
+
+ if (ImGui::ColorButton("##primarycolor", *(ImVec4*)&UI->Color.r, flags_primary, ImVec2(20, 20)))
+ {
+ v4 Temp = UI->Color;
+ UI->Color = UI->AltColor;
+ UI->AltColor = Temp;
+ }
+ if (ImGui::ColorButton("##secondarycolor", *(ImVec4*)&UI->AltColor.r, flags_primary, ImVec2(20, 20)))
+ {
+ v4 Temp = UI->Color;
+ UI->Color = UI->AltColor;
+ UI->AltColor = Temp;
+ }
+
+ if (State->Tool == tool_brush) {
+ real32 BrushSizeMin = 0;
+ real32 BrushSizeMax = 1024;
+ real32 BrushHardnessMin = 0.5;
+ real32 BrushHardnessMax = 100;
+ real32 BrushSpacingMin = 0.1;
+ real32 BrushSpacingMax = 100;
+ if (ImGui::DragScalar("Size", ImGuiDataType_Float, &State->Brush.Size, 1, &BrushSizeMin, &BrushSizeMax, "%.3f")) {
+ Brush_CalcBitmapAlphaFromSize(Memory, &State->Brush, 4);
+ State_BindBrushTexture(Memory, &State->Brush, 4);
+ }
+ if (ImGui::DragScalar("Hardness", ImGuiDataType_Float, &State->Brush.Hardness, 1, &BrushHardnessMin, &BrushHardnessMax, "%.3f", ImGuiSliderFlags_Logarithmic)) {
+ Brush_CalcBitmapAlphaFromSize(Memory, &State->Brush, 4);
+ State_BindBrushTexture(Memory, &State->Brush, 4);
+ }
+ if (ImGui::DragScalar("Spacing", ImGuiDataType_Float, &State->Brush.Spacing, 1, &BrushSpacingMin, &BrushSpacingMax, "%.3f", ImGuiSliderFlags_Logarithmic)) {
+ Brush_CalcBitmapAlphaFromSize(Memory, &State->Brush, 4);
+ State_BindBrushTexture(Memory, &State->Brush, 4);
+ }
+ ImGui::Button(BrushNames[State->Brush.Type]);
+ ImGui::OpenPopupOnItemClick("brush_picker", ImGuiPopupFlags_MouseButtonLeft);
+ if (ImGui::BeginPopup("brush_picker")) {
+ for (int16 b = 0; b < brush_amount; b++) {
+ if (ImGui::MenuItem(BrushNames[b], NULL, false, State->Brush.Type != b)) {
+ State->Brush.Type = (brush_type)b;
+ }
+ }
+ ImGui::EndPopup();
+ }
+ }
+
+ ImGui::End();
+}
+
+static void
+ImGui_Toolbar(project_state *State, ImDrawList *draw_list)
+{
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
+ // ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(50, 50, 50, 0));
+
+ real32 IconSize = ImGui::GetFontSize() * 4;
+ int ToolCount = (int)tool_count;
+ ImVec2 ButtonSize(IconSize, IconSize);
+ ImVec2 WindowSize(IconSize, IconSize * ToolCount);
+ ImGui::BeginChild("Toolbar", WindowSize, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar);
+ for (int i = 0; i < ToolCount; i++) {
+ ImGui::PushID(i);
+ // draw_list->AddImage((void *)(intptr_t)State->ToolIconTex[i], Min, Max);
+ if ((int)State->Tool == i) {
+ ImVec2 Min = ImGui::GetCursorScreenPos();
+ ImVec2 Max = Min + ButtonSize;
+ draw_list->AddRectFilled(Min, Max, IM_COL32(255, 255, 255, 128));
+ }
+ ImGui::Button(ToolName[i], ButtonSize);
+ if (ImGui::IsItemActivated()) {
+ State->Tool = (tool)i;
+ }
+ ImGui::PopID();
+ }
+ ImGui::EndChild();
+
+ // ImGui::PopStyleColor();
+ ImGui::PopStyleVar(2);
+}
+
+static void
+ImGui_RenderUIBrush(project_state *State, memory *Memory, ImVec2 ViewportMin, ImVec2 ViewportMax, ImVec2 CompZoom, ImGuiIO io, uint16 Width, uint16 Height)
+{
+
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ if (State->Tool == tool_brush) {
+
+ if (ImGui::IsKeyPressed(ImGuiKey_ModAlt, false)) {
+ State->Brush.UIPos = io.MousePos;
+ }
+
+ ImVec2 CompScale = CompZoom / ImVec2(Width, Height);
+ ImVec2 BrushSize = CompScale * State->Brush.Size;
+ ImVec2 MinBounds = State->Brush.UIPos - BrushSize/2;
+ ImVec2 MaxBounds = MinBounds + BrushSize;
+
+ if (io.KeyAlt) {
+ draw_list->PushClipRect(ViewportMin, ViewportMax, true);
+ draw_list->AddImage((void *)(intptr_t)State->Brush.GLTexture, MinBounds, MaxBounds, ImVec2(0, 0), ImVec2(1, 1), 1);
+ draw_list->PopClipRect();
+ ImGui::SetCursorScreenPos(State->Brush.UIPos);
+ char buf[256];
+ sprintf(buf, "Size: %.1f, Hardness: %.1f", State->Brush.Size, State->Brush.Hardness);
+ ImGui::Text(buf);
+ if (io.MouseDelta.x || io.MouseDelta.y) {
+ ImVec2 Delta = io.MouseDelta;
+ State->Brush.Size += Delta.x;
+ State->Brush.Hardness += Delta.y*State->Brush.Hardness/100;
+ if (State->Brush.Size < 0)
+ State->Brush.Size = 0;
+ if (State->Brush.Size > 1024)
+ State->Brush.Size = 1024;
+ if (State->Brush.Hardness < 0.5)
+ State->Brush.Hardness = 0.5;
+ if (State->Brush.Hardness > 100)
+ State->Brush.Hardness = 100;
+ Brush_CalcBitmapAlphaFromSize(Memory, &State->Brush, 4);
+ State_BindBrushTexture(Memory, &State->Brush, 4);
+ }
+ }
+ }
+}
+
+static void
+ImGui_TransformUI(project_data *File, project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list, ImGuiIO &io, interact_transform *Interact, ImVec2 ViewportMin, uint32 CompWidth, uint32 CompHeight)
+{
+ v2 InteractMin = Interact->Min + Interact->Position;
+ v2 InteractMax = Interact->Max + Interact->Position;
+
+ v2 BoxLength = InteractMax - InteractMin;
+ v2 Center = InteractMax - (BoxLength/2);
+
+ real32 Point0X = Center.x - InteractMin.x;
+ real32 Point0Y = Center.y - InteractMin.y;
+
+ real32 Rad = Interact->Radians;
+
+ v2 XAxis = (Point0X * Interact->Scale)*V2(cos(Rad), sin(Rad));
+ v2 YAxis = (Point0Y * -Interact->Scale)*V2(sin(Rad), -cos(Rad));
+
+ // Points are clockwise starting from the top left.
+ real32 X0 = -XAxis.x - YAxis.x + Center.x;
+ real32 Y0 = -XAxis.y - YAxis.y + Center.y;
+ real32 X1 = X0 + XAxis.x*2;
+ real32 Y1 = Y0 + XAxis.y*2;
+ real32 X2 = X1 + YAxis.x*2;
+ real32 Y2 = Y1 + YAxis.y*2;
+ real32 X3 = X2 - XAxis.x*2;
+ real32 Y3 = Y2 - XAxis.y*2;
+
+ // Midway points.
+ real32 Mid_X0 = X0 + XAxis.x;
+ real32 Mid_Y0 = Y0 + XAxis.y;
+ real32 Mid_X1 = X1 + YAxis.x;
+ real32 Mid_Y1 = Y1 + YAxis.y;
+ real32 Mid_X2 = X2 - XAxis.x;
+ real32 Mid_Y2 = Y2 - XAxis.y;
+ real32 Mid_X3 = X3 - YAxis.x;
+ real32 Mid_Y3 = Y3 - YAxis.y;
+
+ ImVec2 CompScale = UI->CompZoom / ImVec2(CompWidth, CompHeight);
+
+ ImVec2 P[4];
+ P[0] = ImVec2(X0, Y0)*CompScale + UI->CompPos;
+ P[1] = ImVec2(X1, Y1)*CompScale + UI->CompPos;
+ P[2] = ImVec2(X2, Y2)*CompScale + UI->CompPos;
+ P[3] = ImVec2(X3, Y3)*CompScale + UI->CompPos;
+
+ ImVec2 Mid_P[4];
+ Mid_P[0] = ImVec2(Mid_X0, Mid_Y0)*CompScale + UI->CompPos;
+ Mid_P[1] = ImVec2(Mid_X1, Mid_Y1)*CompScale + UI->CompPos;
+ Mid_P[2] = ImVec2(Mid_X2, Mid_Y2)*CompScale + UI->CompPos;
+ Mid_P[3] = ImVec2(Mid_X3, Mid_Y3)*CompScale + UI->CompPos;
+
+ ImU32 wcol = ImGui::GetColorU32(ImGuiCol_Text);
+ draw_list->AddLine(P[0], P[1], wcol, 2.0f);
+ draw_list->AddLine(P[1], P[2], wcol, 2.0f);
+ draw_list->AddLine(P[2], P[3], wcol, 2.0f);
+ draw_list->AddLine(P[3], P[0], wcol, 2.0f);
+
+ v2 XAxis2 = (BoxLength*CompScale.x)*V2(cos(Rad), sin(Rad));
+ v2 YAxis2 = (BoxLength*CompScale.y)*V2(sin(Rad), -cos(Rad));
+
+ v2 XAxisPerp = (1.0f / LengthSq(XAxis))*XAxis;
+ v2 YAxisPerp = (1.0f / LengthSq(YAxis))*YAxis;
+
+ // real32 LocalX = ((io.MousePos.x - UI->CompPos.x) - Center.x) ;
+ // real32 LocalY = ((io.MousePos.y - UI->CompPos.y) - Center.y) ;
+ layer_transforms BoxTransforms = { Center.x, Center.y, 0.5, 0.5, (real32)(Interact->Radians / (PI / 180)), Interact->Scale };
+ v2 LayerPoint = Transform_ScreenSpaceToLocal(BoxTransforms, CompWidth, CompHeight, BoxLength.x, BoxLength.y, *UI, ViewportMin, io.MousePos);
+
+ real32 U = LayerPoint.x / BoxLength.x;
+ real32 V = LayerPoint.y / BoxLength.y;
+
+ ImVec2 ScaleHandleSize(50, 50);
+
+ bool32 OtherActions = ImGui::IsKeyDown(ImGuiKey_Z);
+
+ // First do the halfway scale points, since they don't need UVs considered:
+ for (int i = 0; i < 4; i++) {
+ ImGui::SetCursorScreenPos(Mid_P[i] - ScaleHandleSize/2);
+ ImGui::PushID(i);
+
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::ColorConvertFloat4ToU32(ImVec4(0.6f, 0.0f, 0.3f, 1.0f)));
+ ImGui::Button("##ScaleMids", ScaleHandleSize);
+ ImGui::PopStyleColor();
+
+ if (ImGui::IsItemActivated() && !OtherActions) {
+ UI->InteractTransformMode = 1;
+ }
+
+ if (UI->InteractTransformMode == 1 && ImGui::IsItemActive())
+ {
+ uint32 side = i;
+ if (side == 0) {
+ Interact->Scale -= io.MouseDelta.y / BoxLength.y;
+ Interact->Position.y += io.MouseDelta.y / 2;
+ } else if (side == 1) {
+ Interact->Scale += io.MouseDelta.x / BoxLength.x;
+ Interact->Position.x += io.MouseDelta.x / 2;
+ } else if (side == 2) {
+ Interact->Scale += io.MouseDelta.y / BoxLength.y;
+ Interact->Position.y += io.MouseDelta.y / 2;
+ } else if (side == 3) {
+ Interact->Scale -= io.MouseDelta.x / BoxLength.x;
+ Interact->Position.x += io.MouseDelta.x / 2;
+ }
+ }
+ ImGui::PopID();
+ }
+
+ bool32 InBounds = false;
+ // Scale if cursor is on button within the UV, rotate if outside UV, and position if a non-button is dragged.
+ if (U >= 0.0f && U <= 1.0f && V >= 0.0f && V <= 1.0f)
+ {
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::ColorConvertFloat4ToU32(ImVec4(0.6f, 0.0f, 0.3f, 1.0f)));
+ InBounds = true;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ ImGui::SetCursorScreenPos(P[i] - ScaleHandleSize/2);
+ ImGui::PushID(i);
+ ImGui::Button("##ScaleRotateCorners", ScaleHandleSize);
+
+ if (ImGui::IsItemActivated() && !OtherActions) {
+ if (InBounds)
+ UI->InteractTransformMode = 1;
+ else
+ UI->InteractTransformMode = 2;
+ }
+
+ // Scale part
+ if (UI->InteractTransformMode == 1 && ImGui::IsItemActive())
+ {
+ // TODO(fox): Corner dragging scale only works in the X
+ // axis. Mostly feels right when dragged how you expect,
+ // but I'll fix it if someone complains.
+ uint32 side = i;
+ if (side == 0) {
+ Interact->Scale -= io.MouseDelta.x / BoxLength.x;
+ Interact->Position.x += io.MouseDelta.x / 2;
+ Interact->Position.y += io.MouseDelta.x*(BoxLength.y/BoxLength.x) / 2;
+ } else if (side == 1) {
+ Interact->Scale += io.MouseDelta.x / BoxLength.x;
+ Interact->Position.x += io.MouseDelta.x / 2;
+ Interact->Position.y -= io.MouseDelta.x*(BoxLength.y/BoxLength.x) / 2;
+ } else if (side == 2) {
+ Interact->Scale += io.MouseDelta.x / BoxLength.x;
+ Interact->Position.x += io.MouseDelta.x / 2;
+ Interact->Position.y += io.MouseDelta.x*(BoxLength.y/BoxLength.x) / 2;
+ } else if (side == 3) {
+ Interact->Scale -= io.MouseDelta.x / BoxLength.x;
+ Interact->Position.x += io.MouseDelta.x / 2;
+ Interact->Position.y -= io.MouseDelta.x*(BoxLength.y/BoxLength.x) / 2;
+ }
+ }
+
+ // Rotation part
+ if (UI->InteractTransformMode == 2 && ImGui::IsItemActive())
+ {
+ real32 LocalX = (io.MousePos.x - UI->CompPos.x)/CompScale.x - InteractMin.x - (BoxLength.x/2);
+ real32 LocalY = (io.MousePos.y - UI->CompPos.y)/CompScale.y - InteractMin.y - (BoxLength.y/2);
+
+ real32 Slope_Mouse = LocalY/LocalX;
+ real32 Slope_Corner = 0;
+ real32 Slope_Flipped = 0;
+ real32 Dot = 0;
+
+ // TODO(fox) learn basic geometry to do this properly
+
+ // We find the angle between the direction of whichever corner the
+ // mouse is grabbing (Slope_Corner) and the mouse's current
+ // position (Slope_Mouse) to get ExtraRadians. The calculation only
+ // works between -90 and 90, so I take the dot product of the
+ // opposite edge of the corner and add the extra degrees when it's negative.
+
+ v2 SlopeDot = V2(BoxLength.x, BoxLength.y);
+ // top left clockwise
+ uint32 side = i;
+ if (side == 0) {
+ Slope_Corner = BoxLength.y / BoxLength.x;
+ Slope_Flipped = -BoxLength.x / BoxLength.y;
+ Dot = LocalX * -SlopeDot.x + LocalY * -SlopeDot.y;
+ } else if (side == 1) {
+ Slope_Corner = -BoxLength.y / BoxLength.x;
+ Slope_Flipped = BoxLength.x / BoxLength.y;
+ Dot = LocalX * SlopeDot.x + LocalY * -SlopeDot.y;
+ } else if (side == 2) {
+ Slope_Corner = BoxLength.y / BoxLength.x;
+ Slope_Flipped = -BoxLength.x / BoxLength.y;
+ Dot = LocalX * SlopeDot.x + LocalY * SlopeDot.y;
+ } else if (side == 3) {
+ Slope_Corner = -BoxLength.y / BoxLength.x;
+ Slope_Flipped = BoxLength.x / BoxLength.y;
+ Dot = LocalX * -SlopeDot.x + LocalY * SlopeDot.y;
+ }
+
+ Interact->Radians = atan((Slope_Mouse - Slope_Corner) / (1 + Slope_Mouse * Slope_Corner));
+ real32 ExtraRadians2 = atan((Slope_Mouse - Slope_Flipped) / (1 + Slope_Mouse * Slope_Flipped));
+
+ if (Dot < 0) {
+ if (Interact->Radians < 0) {
+ Interact->Radians = (90 * (PI / 180)) + ExtraRadians2;
+ } else {
+ Interact->Radians = (-90 * (PI / 180)) + ExtraRadians2;
+ }
+ }
+ }
+
+ ImGui::PopID();
+ }
+
+ if (!UI->InteractTransformMode && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && InBounds && !OtherActions)
+ UI->InteractTransformMode = 3;
+
+ if (UI->InteractTransformMode == 3) {
+ Interact->Position.x += (real32)io.MouseDelta.x/CompScale.x;
+ Interact->Position.y += (real32)io.MouseDelta.y/CompScale.y;
+ }
+
+ if (UI->InteractTransformMode)
+ {
+ if (io.MouseDelta.x || io.MouseDelta.y)
+ State->UpdateFrame = true;
+ if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
+ UI->InteractTransformMode = 0;
+ }
+
+ if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
+ State->UpdateFrame = true;
+ }
+
+ // Second condition so you don't have to reach for Enter.
+ if (ImGui::IsKeyPressed(ImGuiKey_Enter) || (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && io.KeyCtrl)) {
+ int h = 0, c = 0, i = 0;
+ History_Entry_Commit(Memory, "Transform layers");
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
+ if (Layer->IsSelected) {
+ History_Action_Swap(Memory, F_File, sizeof(Layer->x.CurrentValue), &Layer->x.CurrentValue);
+ History_Action_Swap(Memory, F_File, sizeof(Layer->y.CurrentValue), &Layer->y.CurrentValue);
+ History_Action_Swap(Memory, F_File, sizeof(Layer->scale.CurrentValue), &Layer->scale.CurrentValue);
+ History_Action_Swap(Memory, F_File, sizeof(Layer->rotation.CurrentValue), &Layer->rotation.CurrentValue);
+ Transform_ApplyInteractive(*(interact_transform *)&State->Interact_Offset[0], &Layer->x.CurrentValue, &Layer->y.CurrentValue, &Layer->rotation.CurrentValue, &Layer->scale.CurrentValue);
+ }
+ }
+ History_Entry_End(Memory);
+ State->Interact_Active = interact_type_none;
+ State->UpdateFrame = true;
+ }
+
+ if (InBounds == true) {
+ ImGui::PopStyleColor();
+ }
+
+}
+
+static void
+ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, GLuint textureID,
+ sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray)
{
bool open = true;
ImGui::Begin("Viewport", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
@@ -119,6 +668,42 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
draw_list->AddImage((void *)(intptr_t)textureID, CompPosMin, CompPosMax);
draw_list->PopClipRect();
+ ImU32 wcol = ImGui::GetColorU32(ImGuiCol_Text);
+ // UI+interaction for layer
+ if (State->MostRecentlySelectedLayer > -1)
+ {
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i))
+ {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
+ if (Layer->IsSelected) {
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+
+ // Anchor point UI
+ v2 CenterPoint = V2(Source->Width*Layer->ax.CurrentValue, Source->Height*Layer->ay.CurrentValue);
+ ImVec2 ScreenAP = Layer_LocalToScreenSpace(State, Layer, UI, Source->Width, Source->Height, MainComp->Width, MainComp->Height, CenterPoint);
+ draw_list->AddNgon(ScreenAP, 20, wcol, 8, 10.0f);
+
+ // Bounding box UI
+ ImVec2 P1 = Layer_LocalToScreenSpace(State, Layer, UI, Source->Width, Source->Height, MainComp->Width, MainComp->Height, V2(0, 0));
+ ImVec2 P2 = Layer_LocalToScreenSpace(State, Layer, UI, Source->Width, Source->Height, MainComp->Width, MainComp->Height, V2(Source->Width, 0));
+ ImVec2 P3 = Layer_LocalToScreenSpace(State, Layer, UI, Source->Width, Source->Height, MainComp->Width, MainComp->Height, V2(0, Source->Height));
+ ImVec2 P4 = Layer_LocalToScreenSpace(State, Layer, UI, Source->Width, Source->Height, MainComp->Width, MainComp->Height, V2(Source->Width, Source->Height));
+ draw_list->AddLine(P1, P2, wcol, 2.0f);
+ draw_list->AddLine(P2, P4, wcol, 2.0f);
+ draw_list->AddLine(P1, P3, wcol, 2.0f);
+ draw_list->AddLine(P3, P4, wcol, 2.0f);
+
+ }
+ }
+
+ if (State->Interact_Active == interact_type_viewport_transform) {
+ ImGui_TransformUI(File, State, Memory, UI, draw_list, io, (interact_transform *)&State->Interact_Offset[0], ViewportMin, MainComp->Width, MainComp->Height);
+ }
+ }
+
+
+
// Interactions for dragging and zooming
ImGui::SetCursorScreenPos(ViewportMin);
@@ -133,29 +718,83 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
// Point to zoom in on if Z is held
UI->TempZoomRatio = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos);
+ if (State->Tool == tool_brush && File->Layer_Count != 2) {
+ State->Interact_Active = interact_type_newlayer_paint;
+ History_Entry_Commit(Memory,"Paint new layer");
+ uint16 SourceIndex = Source_Generate_Blank(File, State, Memory, MainComp->Width, MainComp->Height, MainComp->BytesPerPixel);
+ Assert(0);
+ // Layer_CreateFromSource(File, State, Memory, SourceIndex, MainComp->Frame_End);
+ History_Entry_End(Memory);
+ }
+
// Layer selection
- /*
- if (!ImGui::IsKeyDown(ImGuiKey_Z) || !State->Pen.IsActive) {
- for (int i = File.NumberOfLayers - 1; i >= 0; i--) {
- project_layer *Layer = File.Layer[i];
- if (!io.KeyShift) DeselectAllLayers(&File, State);
- v2 LayerUV = CompUVToLayerUV(Layer, &CompBuffer, UI->TempZoomRatio);
- if (TestUV(LayerUV) && !Layer->IsSelected)
- {
- SelectLayer(Layer, State, i);
- break;
- }
- }
+ if (!ImGui::IsKeyDown(ImGuiKey_Z) && State->Tool == tool_default && State->Interact_Active == interact_type_none) {
+ int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex);
+ if (!io.KeyShift && State->Interact_Active == interact_type_none)
+ Layer_DeselectAll(Memory, File->Layer_Count);
+ if (Selection != -1)
+ Layer_Select(Memory, State, Selection);
}
- */
}
+ /*
+ if (State->Interact_Active == interact_type_viewport_transform) {
+ interact_transform *Interact = (interact_transform *)&State->Interact_Offset[0];
+ ImVec2 DragDelta = io.MousePos - Interact->OGPos;
+ Interact->Position = V2(DragDelta.x, DragDelta.y);
+ if (io.MouseDelta.x || io.MouseDelta.y)
+ State->UpdateFrame = true;
+ }
+ */
+
if (IsActive && ImGui::IsMouseDragging(ImGuiMouseButton_Right, -1.0f))
{
UI->CompPos.x += io.MouseDelta.x;
UI->CompPos.y += io.MouseDelta.y;
}
+ bool32 OtherActions = ImGui::IsKeyDown(ImGuiKey_Z) || ImGui::IsMouseDown(ImGuiMouseButton_Right);
+ if (State->Tool == tool_brush) {
+ if (IsActive && !OtherActions) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 0);
+ layer_transforms T_Layer = Layer_GetTransforms(Layer);
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+ void *SourceBitmapAddress = Memory_Block_AddressAtIndex(Memory, F_PrincipalBitmaps, Source->Bitmap_Index);
+ ImVec2 MouseDelta = io.MouseDelta;
+ real32 Delta = MouseDelta.x + MouseDelta.y;
+ if (Delta != 0.0f) {
+ real32 DeltaDistance = sqrt(MouseDelta.x * MouseDelta.x + MouseDelta.y * MouseDelta.y);
+ real32 DeltaSlope = MouseDelta.y / MouseDelta.x;
+ for (real32 i = 0; i < DeltaDistance; i += State->Brush.Spacing) {
+ ImVec2 MousePos;
+ if (State->Brush.Type == brush_normal) {
+ MousePos = io.MousePos - (MouseDelta * (i / DeltaDistance));
+ } else if (State->Brush.Type == brush_wacky1) {
+ MousePos = io.MousePos + (io.MousePos * (i / MouseDelta));
+ } else if (State->Brush.Type == brush_wacky2) {
+ MousePos = io.MousePos - (MouseDelta / (i / DeltaDistance));
+ } else if (State->Brush.Type == brush_wacky3) {
+ MousePos = io.MousePos - (MouseDelta * (i / ImVec2(MouseDelta.y, MouseDelta.x)));
+ } else {
+ Assert(0);
+ }
+ v2 LayerPos = Transform_ScreenSpaceToLocal(T_Layer, MainComp->Width, MainComp->Height, Source->Width, Source->Height, *UI, ViewportMin, MousePos);
+ PaintTest(Memory, Source, &State->Brush, SourceBitmapAddress, LayerPos, 4, UI->Color);
+ }
+ } else if (IsActivated) {
+ ImVec2 MousePos = io.MousePos;
+ v2 LayerPos = Transform_ScreenSpaceToLocal(T_Layer, MainComp->Width, MainComp->Height, Source->Width, Source->Height, *UI, ViewportMin, MousePos);
+ PaintTest(Memory, Source, &State->Brush, SourceBitmapAddress, LayerPos, 4, UI->Color);
+ }
+ Memory_Cache_Invalidate(State, Memory, cache_entry_type_comp, Layer->Block_Composition_Index, 0);
+ State->UpdateFrame = true;
+ }
+
+ if (IsDeactivated) {
+ State->Interact_Active = interact_type_none;
+ }
+ }
+
if (IsActive && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1.0f) && ImGui::IsKeyDown(ImGuiKey_Z))
{
real32 Distance = io.MouseDelta.x + io.MouseDelta.y;
@@ -175,8 +814,12 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
State->MsgTime--;
}
- ImGui::End();
+ ImGui::SetCursorScreenPos(ViewportMin);
+ ImGui_Toolbar(State, draw_list);
+ ImGui_RenderUIBrush(State, Memory, ViewportMin, ViewportMax, UI->CompPos, io, MainComp->Width, MainComp->Height);
+
+ ImGui::End();
/*
for (int i = 0; i < AmountOf(Layer->Property); i++) {
@@ -192,10 +835,11 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
}
static void
-ImGui_TimelineHorizontalIncrementDraw(ui *UI, ImDrawList *draw_list, ImVec2 TimelineSizeWithBorder, ImVec2 TimelineAbsolutePos, block_composition MainComp,
+ImGui_TimelineHorizontalIncrementDraw(project_state *State, ui *UI, ImDrawList *draw_list, ImVec2 TimelineSizeWithBorder, ImVec2 TimelineAbsolutePos, block_composition MainComp,
ImVec2 TimelineZoomSize, ImVec2 TimelineMoveSize)
{
uint32 LineColor = IM_COL32(200, 200, 200, 40);
+ uint32 PlayheadColor = IM_COL32(000, 000, 200, 160);
Assert(TimelineZoomSize.x > 0.0f);
@@ -226,6 +870,10 @@ ImGui_TimelineHorizontalIncrementDraw(ui *UI, ImDrawList *draw_list, ImVec2 Time
RightmostEdge = true;
}
}
+
+ ImVec2 Min = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize.x + ((real32)State->Frame_Current / MainComp.Frame_Count)*TimelineZoomSize.x, TimelineAbsolutePos.y);
+ ImVec2 Max = ImVec2(Min.x + 2, TimelineAbsolutePos.y + TimelineSizeWithBorder.y);
+ draw_list->AddLine(Min, Max, PlayheadColor);
}
@@ -235,16 +883,17 @@ ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI
bool open = true;
ImGui::Begin("Graph info", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
- for (int a = 0; a < File->Layer_Count; a++)
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i))
{
- block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a);
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
if (!Layer->IsSelected)
continue;
block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index);
ImGui::Text(String->Char);
- ImGui::PushID(a);
+ ImGui::PushID(i);
for (int h = 0; h < AmountOf(Layer->Property); h++) {
property_channel *Property = &Layer->Property[h];
if (Property->Block_Bezier_Count) {
@@ -267,9 +916,10 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor
{
UI->Test.Split(draw_list, 2);
- for (int a = 0; a < File->Layer_Count; a++)
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i))
{
- block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a);
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
if (!Layer->IsSelected)
continue;
@@ -285,7 +935,7 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor
ImVec2 Layer_ScreenPos_Max = TimelineAbsolutePos + TimelineMoveSize + ((Layer_LocalPos_Ratio + Layer_LocalSize_Ratio) * TimelineZoomSize);
ImVec2 Layer_ScreenSize = Layer_ScreenPos_Max - Layer_ScreenPos_Min;
- ImGui::PushID(a);
+ ImGui::PushID(i);
ImU32 col = IM_COL32(255, 255, 255, 255);
@@ -304,6 +954,8 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor
State->Interact_Active == interact_type_keyframe_rotate ||
State->Interact_Active == interact_type_keyframe_scale))
{
+ Assert(0);
+ // Memory_Cache_Invalidate(State, Memory, cache_entry_type_comp, Lay
}
for (int h = 0; h < AmountOf(Layer->Property); h++) {
@@ -445,9 +1097,9 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
int32 Frame_Start = Layer->Frame_Start;
int32 Frame_End = Layer->Frame_End;
- real32 Vertical_Offset = Layer->Vertical_Offset;
- if (Layer->IsSelected)
- Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End, &Vertical_Offset);
+ real32 Vertical_Offset = SortEntry.SortedOffset;
+ // if (Layer->IsSelected)
+ // Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End, &Vertical_Offset);
ImVec2 Layer_LocalPos = ImVec2(Frame_Start, Vertical_Offset);
ImVec2 Layer_LocalSize = ImVec2(Frame_End - Frame_Start, Layer->Vertical_Height);
@@ -489,8 +1141,7 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
if (ImGui::IsItemActivated()) {
if (!Layer->IsSelected) {
if (!io.KeyShift) Layer_DeselectAll(Memory, File->Layer_Count);
- State->MostRecentlySelectedLayer = i;
- Layer->IsSelected = true;
+ Layer_Select(Memory, State, Index_Physical);
}
}
if (ImGui::IsItemActive()) {
@@ -506,15 +1157,19 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
}
if (ImGui::IsItemDeactivated()) {
if (State->Interact_Active == interact_type_layer_timeadjust) {
- for (int a = 0; a < File->Layer_Count; a++) {
- block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a);
- if (Layer->IsSelected) {
- Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Layer->Frame_Start, &Layer->Frame_End, &Layer->Vertical_Offset);
- }
+ Assert(0);
+ /*
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
+ // if (Layer->IsSelected) {
+ // Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Layer->Frame_Start, &Layer->Frame_End, &Layer->Vertical_Offset);
+ // }
}
State->Interact_Active = interact_type_none;
State->Interact_Offset[0] = 0;
State->Interact_Offset[1] = 0;
+ */
}
}
@@ -527,8 +1182,7 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
if (ImGui::IsItemActivated()) {
if (!Layer->IsSelected) {
if (!io.KeyShift) Layer_DeselectAll(Memory, File->Layer_Count);
- State->MostRecentlySelectedLayer = i;
- Layer->IsSelected = true;
+ Layer_Select(Memory, State, Index_Physical);
}
}
@@ -544,32 +1198,32 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
ImVec2 DragDelta = ImGui::GetMouseDragDelta();
DragDelta = DragDelta + (ImVec2(UI->Warp_X, UI->Warp_Y) * TimelineSize);
- State->Interact_Offset[0] = (DragDelta.x / TimelineSizeWithBorder.x * UI->TimelinePercentZoomed.x) * Comp->Frame_Count;
- State->Interact_Offset[1] = (DragDelta.y / TimelineSizeWithBorder.y * UI->TimelinePercentZoomed.y) * LayerIncrement;
+ ImVec2 Offset_Old = ImVec2(State->Interact_Offset[0], State->Interact_Offset[1]);
+ ImVec2 Offset_New = (DragDelta / TimelineSizeWithBorder * UI->TimelinePercentZoomed) * ImVec2(Comp->Frame_Count, -LayerIncrement);
- /*
- if (UI->DragDelta_Prev.x != 0) {
- ImVec2 Offset_Old = (UI->DragDelta_Prev / TimelineSizeWithBorder * UI->TimelinePercentZoomed) * ImVec2(MainComp->Frame_Count, LayerIncrement);
- if ((int32)State->Interact_Offset[1] != (int32)Offset_Old.y)
- State->UpdateFrame = true;
- }
+ // if (((int32)Offset_Old.x != (int32)Offset_New.x) || ((int32)Offset_Old.y != (int32)Offset_New.y))
+ State->UpdateFrame = true;
- UI->DragDelta_Prev = DragDelta;
- */
+ State->Interact_Offset[0] = Offset_New.x;
+ State->Interact_Offset[1] = Offset_New.y;
}
}
if (ImGui::IsItemDeactivated()) {
if (State->Interact_Active == interact_type_layer_move) {
- for (int a = 0; a < File->Layer_Count; a++) {
- block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a);
+ History_Entry_Commit(Memory, "Move layers");
+ for (int i = 0; i < SortedCompInfo.LayerCount; i++)
+ {
+ sorted_layer SortEntry = SortedLayerInfo[i];
+ uint32 Index_Physical = SortEntry.Block_Layer_Index;
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical);
if (Layer->IsSelected) {
- Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Layer->Frame_Start, &Layer->Frame_End, &Layer->Vertical_Offset);
+ History_Action_Swap(Memory, F_File, sizeof(Layer->Vertical_Offset), &Layer->Vertical_Offset);
+ Layer->Vertical_Offset = SortEntry.SortedOffset;
}
}
State->Interact_Active = interact_type_none;
- State->Interact_Offset[0] = 0;
- State->Interact_Offset[1] = 0;
+ History_Entry_End(Memory);
}
}
ImGui::PopID();
@@ -588,9 +1242,9 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
int32 Frame_Start = Layer->Frame_Start;
int32 Frame_End = Layer->Frame_End;
- real32 Vertical_Offset = Layer->Vertical_Offset;
- if (Layer->IsSelected)
- Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End, &Vertical_Offset);
+ real32 Vertical_Offset = SortEntry.SortedOffset;
+ // if (Layer->IsSelected)
+ // Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End, &Vertical_Offset);
ImVec2 Layer_LocalPos = ImVec2(Frame_Start, Vertical_Offset);
ImVec2 Layer_LocalSize = ImVec2(Frame_End - Frame_Start, Layer->Vertical_Height);
@@ -643,9 +1297,9 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
int32 Frame_Start = Layer->Frame_Start;
int32 Frame_End = Layer->Frame_End;
- real32 Vertical_Offset = Layer->Vertical_Offset;
- if (Layer->IsSelected)
- Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End, &Vertical_Offset);
+ real32 Vertical_Offset = SortEntry.SortedOffset;
+ // if (Layer->IsSelected)
+ // Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End, &Vertical_Offset);
ImVec2 Layer_LocalPos = ImVec2(Frame_Start, Vertical_Offset);
ImVec2 Layer_LocalSize = ImVec2(Frame_End - Frame_Start, Layer->Vertical_Height);
@@ -658,10 +1312,10 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
ImU32 LayerColor = 0;
ImU32 BorderColor = 0;
if (UI->TimelineMode == timeline_mode_graph) {
- LayerColor = ImColor(Layer->Col[0], Layer->Col[1], Layer->Col[2], 0.2f);
+ LayerColor = ImColor(UI->LayerColors[Layer->ColIndex]);
BorderColor = ImColor(0.3, 0.3, 0.3, 1.0f);
} else {
- LayerColor = ImColor(Layer->Col[0], Layer->Col[1], Layer->Col[2], 1.0f);
+ LayerColor = ImColor(UI->LayerColors[Layer->ColIndex]);
BorderColor = ImColor(0.2, 0.2, 0.2, 1.0f);
}
@@ -680,7 +1334,7 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
}
static void
-ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io)
+ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray)
{
if (UI->TimelineMode == timeline_mode_graph)
ImGui_GraphInfo(File, State, Memory, UI, io);
@@ -745,16 +1399,10 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
ImVec2 TimelineZoomSize = TimelineSizeWithBorder / UI->TimelinePercentZoomed;
ImVec2 TimelineMoveSize = TimelineSizeWithBorder * UI->TimelinePercentOffset / UI->TimelinePercentZoomed;
- ImGui_TimelineHorizontalIncrementDraw(UI, draw_list, TimelineSizeWithBorder, TimelineAbsolutePos, *MainComp, TimelineZoomSize, TimelineMoveSize);
+ ImGui_TimelineHorizontalIncrementDraw(State, UI, draw_list, TimelineSizeWithBorder, TimelineAbsolutePos, *MainComp, TimelineZoomSize, TimelineMoveSize);
ImVec2 Increment = ImVec2((real32)1 / MainComp->Frame_Count, (real32)1 / LayerIncrement);
- uint64 SortSize = (sizeof(sorted_comp_info) * File->Comp_Count) + (sizeof(sorted_layer) * File->Layer_Count);
- void *SortedArray = Memory_PushScratch(Memory, SortSize);
- Arbitrary_Zero((uint8 *)SortedArray, SortSize);
- sorted_comp_info *SortedCompArray = (sorted_comp_info *)SortedArray;
- sorted_layer *SortedLayerArray = (sorted_layer *)((uint8 *)SortedArray + (sizeof(sorted_comp_info) * File->Comp_Count));
- Layer_SortAll(Memory, SortedLayerArray, SortedCompArray, File->Layer_Count, File->Comp_Count);
ImGui_Timeline_DrawPrecomp(File, State, Memory, UI, io, draw_list, File->PrincipalCompIndex,
Increment, TimelineAbsolutePos, TimelineMoveSize, TimelineZoomSize,
@@ -772,8 +1420,6 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
// Memory_PopScratch(Memory, Keyframe_SortSize);
}
- Memory_PopScratch(Memory, SortSize);
-
ImVec2 MouseDelta = io.MouseDelta / TimelineSize;
real32 BarHandleSize = FontHeight;
@@ -912,6 +1558,23 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
bool32 LeftClick = ImGui::IsMouseDown(ImGuiMouseButton_Left);
bool32 RightClick = ImGui::IsMouseDown(ImGuiMouseButton_Right);
+ ImGui::OpenPopupOnItemClick("layercolor", ImGuiPopupFlags_MouseButtonRight);
+ if (ImGui::BeginPopup("layercolor")) {
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
+ for (int c = 0; c < AmountOf(UI->LayerColors); c++) {
+ ImGui::PushID(c);
+ ImGui::PushStyleColor(ImGuiCol_Button, UI->LayerColors[c]);
+ real32 Size = ImGui::GetFontSize() * 2;
+ ImVec2 ColSize(Size, Size);
+ ImGui::Button("##test", ColSize);
+ if ((c+1) % 4) { ImGui::SameLine(); }
+ ImGui::PopStyleColor();
+ ImGui::PopID();
+ }
+ ImGui::PopStyleVar();
+ ImGui::EndPopup();
+ }
+
if (IsHovered && io.MouseWheel) {
real32 Increment = 0.1;
bool32 Direction = (io.MouseWheel > 0) ? 1 : -1;
@@ -936,8 +1599,9 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI,
if (State->Interact_Active == interact_type_keyframe_move ||
State->Interact_Active == interact_type_keyframe_rotate ||
State->Interact_Active == interact_type_keyframe_scale) {
- for (int a = 0; a < File->Layer_Count; a++) {
- block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a);
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
if (!Layer->IsSelected)
continue;
for (int h = 0; h < AmountOf(Layer->Property); h++) {
@@ -998,9 +1662,31 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me
if (ImGui::IsKeyPressed(ImGuiKey_Q)) {
State->IsRunning = false;
}
- if (ImGui::IsKeyPressed(ImGuiKey_A)) {
+ if (ImGui::IsKeyPressed(ImGuiKey_W)) {
+ block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex);
+ State->Frame_Current = ((State->Frame_Current - 1) < 0) ? 0 : State->Frame_Current - 1;
State->UpdateFrame = true;
}
+ if (ImGui::IsKeyPressed(ImGuiKey_E)) {
+ block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex);
+ State->Frame_Current = ((State->Frame_Current + 1) >= MainComp->Frame_Count) ? 0 : State->Frame_Current + 1;
+ State->UpdateFrame = true;
+ }
+ if (ImGui::IsKeyPressed(ImGuiKey_X)) {
+ v4 Temp = UI->Color;
+ UI->Color = UI->AltColor;
+ UI->AltColor = Temp;
+ }
+
+ if (ImGui::IsKeyPressed(ImGuiKey_V)) {
+ State->Tool = tool_default;
+ }
+ if (ImGui::IsKeyPressed(ImGuiKey_B)) {
+ State->Tool = tool_brush;
+ }
+ if (ImGui::IsKeyPressed(ImGuiKey_T)) {
+ Interact_Transform_Begin(File, Memory, State, io.MousePos);
+ }
if (UI->TimelineMode == timeline_mode_graph) {
if (ImGui::IsKeyPressed(ImGuiKey_G)) {
State->Interact_Offset[2] = io.MousePos.x;
@@ -1031,22 +1717,174 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me
State->IsPlaying ^= 1;
}
if (ImGui::IsKeyPressed(ImGuiKey_T)) {
- for (int a = 0; a < File->Layer_Count; a++) {
- block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a);
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
if (Layer->IsSelected && Layer->IsPrecomp) {
Layer->Precomp_Toggled ^= 1;
}
}
}
+
+ if (ImGui::IsKeyPressed(ImGuiKey_Delete))
+ {
+ bool32 CommitAction = 0;
+ int h = 0, c = 0, i = 0;
+ int LayerCount = File->Layer_Count;
+ while (Block_Loop(Memory, F_Layers, LayerCount, &h, &c, &i)) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
+ if (Layer->IsSelected) {
+ if (!CommitAction) {
+ History_Entry_Commit(Memory, "Delete source");
+ CommitAction = 1;
+ }
+ Layer_Delete(File, Memory, i);
+ }
+ }
+ if (CommitAction) {
+ History_Entry_End(Memory);
+ State->UpdateFrame = true;
+ State->MostRecentlySelectedLayer = -1;
+ }
+ }
+
#if DEBUG
- if (ImGui::IsKeyPressed(ImGuiKey_W))
+ if (ImGui::IsKeyPressed(ImGuiKey_1))
{
Debug.ToggleWindow ^= 1;
}
#endif
+ bool32 mod_key = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
+ if (mod_key) {
+ /*
+ if (ImGui::IsKeyPressed(ImGuiKey_S)) {
+ if (io.KeyShift) {
+ State->ImGuiPopups = popup_saveas;
+ } else {
+ if (State->Context[0].Filename[0] == '\0') {
+ State->ImGuiPopups = popup_saveas;
+ } else {
+ if (File_SaveAs(State, Memory, 0, State->Context[0].Filename)) {
+ PostMsg(State, "File saved!");
+ } else {
+ PostMsg(State, "File save failed...");
+ }
+ }
+ }
+ }
+ if (ImGui::IsKeyPressed(ImGuiKey_N)) {
+ if (io.KeyShift)
+ State->ImGuiPopups = popup_newfile;
+ else
+ State->ImGuiPopups = popup_newlayer;
+ }
+ */
+ if (ImGui::IsKeyPressed(ImGuiKey_Z)) {
+ if (io.KeyShift) {
+ History_Redo(Memory);
+ State->UpdateFrame = true;
+ } else {
+ History_Undo(Memory);
+ State->UpdateFrame = true;
+ }
+ }
+ }
+
+}
+
+static void
+ImGui_Menu(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io)
+{
+ bool open = true;
+ ImGui::Begin("Menu", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar);
+ if (ImGui::BeginMenuBar())
+ {
+ if (ImGui::BeginMenu("File"))
+ {
+ if (ImGui::MenuItem("Save", "Ctrl+S"))
+ {
+ // if (File_SaveAs(State, Memory, 0, State->Context[0].Filename)) {
+ if (0) {
+ PostMsg(State, "File saved!");
+ } else {
+ PostMsg(State, "File save failed...");
+ }
+ }
+ /*
+ if (ImGui::MenuItem("New project file", "Ctrl+Shift+N"))
+ {
+ State->ImGuiPopups = popup_newfile;
+ }
+ if (ImGui::BeginMenu("Open file"))
+ {
+ ImGui::InputText("Filename", State->DummyName, 512);
+ if (ImGui::IsItemDeactivated() && ImGui::IsKeyPressed(ImGuiKey_Enter)) {
+ File_Open(State, Memory, State->DummyName);
+ State->Context[Index].UpdateFrame = true;
+ }
+ ImGui::EndMenu();
+ }
+ if (ImGui::MenuItem("Save as", "Ctrl+Shift+S"))
+ {
+ State->ImGuiPopups = popup_saveas;
+ }
+ */
+ ImGui::EndMenu();
+ }
+ if (ImGui::BeginMenu("Layer"))
+ {
+ if (ImGui::BeginMenu("Import source from file"))
+ {
+ ImGui::InputText("Path to image", State->DummyName2, 512);
+ if (ImGui::IsItemDeactivated() && ImGui::IsKeyPressed(ImGuiKey_Enter)) {
+ int SourceIndex = Source_Generate(File, State, Memory, (void *)State->DummyName2);
+ State->UpdateFrame = true;
+ }
+ ImGui::EndMenu();
+ }
+ /*
+ if (ImGui::MenuItem("New layer", "Ctrl+N"))
+ {
+ State->ImGuiPopups = popup_newlayer;
+ }
+ if (ImGui::BeginMenu("Layer from image path"))
+ {
+ ImGui::InputText("Path to image", State->DummyName2, 512);
+ if (ImGui::IsItemDeactivated() && ImGui::IsKeyPressed(ImGuiKey_Enter)) {
+ Layer_CreateFromFile(State, Memory, Index, State->DummyName2);
+ Layer_DeselectAll(State, File, &Context->UI);
+ layer_sorted Sorts = Layer_GetSortedList(State, File);
+ file_layer *Layer = (file_layer *)Sorts.Location[File->NumberOfLayers - 1];
+ Layer_Select(Layer, &Context->UI, File->NumberOfLayers - 1);
+ State->Context[Index].UpdateFrame = true;
+ }
+ ImGui::EndMenu();
+ }
+ if (ImGui::MenuItem("New adjustment layer", "Ctrl+Shift+Y"))
+ {
+ Layer_CreateAdjustment(State, Memory, Index);
+ }
+ if (ImGui::MenuItem("Duplicate layer", "Ctrl+Shift+Y"))
+ {
+ if (State->Context[Index].UI.MostRecentlySelectedLayer > -1)
+ Layer_Duplicate(State, Memory, Index, State->Context[Index].UI.MostRecentlySelectedLayer);
+ }
+ */
+ ImGui::EndMenu();
+ }
+ ImGui::EndMenuBar();
+ }
+
+ ImGui::End();
+}
+
+static void
+ImGui_Popups(project_state *State, ui *UI, memory *Memory, ImGuiIO io)
+{
}
+
#if 0
real32 MaxVal_Y = -10000;
real32 MinVal_Y = 10000;
@@ -1931,7 +2769,7 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *
static void
ImGui_Viewport(project_data File, project_state *State, ui *UI, memory *Memory, comp_buffer CompBuffer,
- ImGuiIO io, GLuint textureID)
+ ImGuiIO io, GLuint textureID, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray)
{
bool open = true;
ImGui::Begin("Viewport", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
@@ -2358,68 +3196,6 @@ ImGui_SlidingLayer(project_layer *Layer, real32 *DraggingThreshold, real32 Delta
}
static void
-ImGui_File(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io)
-{
- ImGui::Begin("Files");
- ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
-#if DEBUG
- if (State->DemoButton) {
- if (ImGui::Button("Generate demo scene")) {
- CreateDemoScene(File, State, Memory);
- State->UpdateKeyframes = true;
- State->UpdateFrame = true;
- State->DemoButton = false;
- }
- }
- if (State->GridButton) {
- ImGui::SameLine();
- if (ImGui::Button("Generate square grid")) {
- // CreateGrid(File, Memory);
- State->UpdateKeyframes = true;
- State->UpdateFrame = true;
- State->GridButton = false;
- }
- }
-#endif
- ImGui::Text("Sources:");
- for (int i = 0; i < File->NumberOfSources; i++) {
- bool32 Test = false;
- if (File->SourceSelected == i)
- Test = true;
- ImGui::Selectable(File->Source[i].Path, Test);
- if (ImGui::IsItemClicked())
- File->SourceSelected = i;
- if (ImGui::IsItemClicked(ImGuiMouseButton_Right))
- File->SourceSelected = i;
- ImGui::OpenPopupOnItemClick("sourcecontext", ImGuiPopupFlags_MouseButtonRight);
- }
- if (ImGui::BeginPopup("sourcecontext")) {
- if (ImGui::MenuItem("Create layer from source")) {
- Layer_CreateFromSource(File, State, Memory, &File->Source[File->SourceSelected]);
- }
- ImGui::EndPopup();
- }
- static char Input[1024];
- ImGui::InputTextWithHint("##sourceinput", "Input file path of source...", Input, STRING_SIZE);
- if (ImGui::IsItemDeactivated() && ImGui::IsKeyPressed(ImGuiKey_Enter)) {
- Source_Generate(File, State, Memory, Input);
- }
-#if DEBUG
- for (int i = 0; i < Debug.Temp.WatchedProperties; i++) {
- if (Debug.Temp.DebugPropertyType[i] == d_float) {
- ImGui::Text("%s: %f", Debug.Temp.String[i], Debug.Temp.Val[i].f);
- } else if (Debug.Temp.DebugPropertyType[i] == d_int) {
- ImGui::Text("%s: %i", Debug.Temp.String[i], Debug.Temp.Val[i].i);
- } else if (Debug.Temp.DebugPropertyType[i] == d_uint) {
- ImGui::Text("%s: %u", Debug.Temp.String[i], Debug.Temp.Val[i].u);
- }
- }
- Debug.Temp = {};
-#endif
- ImGui::End();
-}
-
-static void
ImGui_EffectsPanel(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io)
{
ImGui::Begin("Effects list", NULL);
diff --git a/prenderer.cpp b/prenderer.cpp
index b61290a..dcb4577 100644
--- a/prenderer.cpp
+++ b/prenderer.cpp
@@ -1,3 +1,152 @@
+static v2
+T_CompUVToLayerUV(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, v2 CompUV)
+{
+ real32 X = CompUV.x*FileWidth;
+ real32 Y = CompUV.y*FileHeight;
+
+ real32 Rad = (T.rotation* (PI / 180));
+ v2 XAxis = (SourceWidth * T.scale)*V2(cos(Rad), sin(Rad));
+ v2 YAxis = (SourceHeight * -T.scale)*V2(sin(Rad), -cos(Rad));
+
+ v2 Pos = {T.x, T.y};
+ v2 Origin = Pos - (XAxis * T.ax) - (YAxis * T.ay);
+
+ v2 XAxisPerp = (1.0f / LengthSq(XAxis))*XAxis;
+ v2 YAxisPerp = (1.0f / LengthSq(YAxis))*YAxis;
+
+ real32 StartVectorX = X - Origin.x;
+ real32 StartVectorY = Y - Origin.y;
+ real32 LayerU = (StartVectorX * XAxisPerp.x) + (StartVectorY * XAxisPerp.y);
+ real32 LayerV = (StartVectorX * YAxisPerp.x) + (StartVectorY * YAxisPerp.y);
+ return V2(LayerU, LayerV);
+}
+
+static v2
+T_CompPosToLayerPos(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, v2 CompUV)
+{
+ v2 UV = T_CompUVToLayerUV(T, FileWidth, FileHeight, SourceWidth, SourceHeight, CompUV/V2(FileWidth, FileHeight));
+ return UV*V2(SourceWidth, SourceHeight);
+}
+
+static v2
+Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight,
+ ui UI, ImVec2 ViewportMin, ImVec2 Point)
+{
+ v2 CompUV = ImGui_ScreenPointToCompUV(ViewportMin, UI.CompPos, UI.CompZoom, Point);
+ v2 LayerUV = T_CompUVToLayerUV(T, FileWidth, FileHeight, SourceWidth, SourceHeight, CompUV);
+ return V2(LayerUV.x * SourceWidth, LayerUV.y * SourceHeight);
+}
+
+// Transform given data based on state's Interact data.
+static void
+Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale)
+{
+ v2 BoxLength = Interact.Max - Interact.Min;
+ v2 Center = Interact.Max - (BoxLength/2);
+
+ real32 Point0X = Center.x - *OutputX;
+ real32 Point0Y = Center.y - *OutputY;
+
+ real32 Rad = Interact.Radians;
+ real32 Rotation = Interact.Radians / (PI / 180);
+
+ v2 XAxis = (Point0X * Interact.Scale)*V2(cos(Rad), sin(Rad));
+ v2 YAxis = (Point0Y * -Interact.Scale)*V2(sin(Rad), -cos(Rad));
+
+ real32 X0 = -XAxis.x - YAxis.x + Center.x;
+ real32 Y0 = -XAxis.y - YAxis.y + Center.y;
+
+ *OutputX = X0 + Interact.Position.x;
+ *OutputY = Y0 + Interact.Position.y;
+ *OutputRotation += Rotation;
+ *OutputScale += Interact.Scale - 1.0f;
+}
+
+static void
+Transform_IterateOuterBounds(block_layer *Layer, block_source *Source, real32 *MinX, real32 *MinY, real32 *MaxX, real32 *MaxY)
+{
+ real32 Rad = (Layer->rotation.CurrentValue * (PI / 180));
+ real32 s = Layer->scale.CurrentValue;
+
+ v2 XAxis = (Source->Width * s)*V2(cos(Rad), sin(Rad));
+ v2 YAxis = (Source->Height * -s)*V2(sin(Rad), -cos(Rad));
+
+ real32 AnchorX = Layer->ax.CurrentValue;
+ real32 AnchorY = Layer->ay.CurrentValue;
+
+ v2 Pos = {Layer->x.CurrentValue, Layer->y.CurrentValue};
+ v2 Origin = Pos - (XAxis * AnchorX) - (YAxis * AnchorY);
+
+ real32 XLengthSq = 1.0f / LengthSq(XAxis);
+ real32 YLengthSq = 1.0f / LengthSq(YAxis);
+
+ v2 Points[4] = {Origin, Origin + XAxis, Origin + YAxis, Origin + XAxis + YAxis};
+ for (int i = 0; i < 4; i++) {
+ if (Points[i].x < *MinX) { *MinX = Points[i].x; }
+ if (Points[i].y < *MinY) { *MinY = Points[i].y; }
+ if (Points[i].x > *MaxX) { *MaxX = Points[i].x; }
+ if (Points[i].y > *MaxY) { *MaxY = Points[i].y; }
+ }
+}
+
+// IMPORTANT(fox): The selection state and ordering of layers cannot change
+// until this action is exited/committed!
+static void
+Interact_Transform_Begin(project_data *File, memory *Memory, project_state *State, ImVec2 OGPos)
+{
+ real32 MinX = 100000;
+ real32 MinY = 100000;
+ real32 MaxX = -100000;
+ real32 MaxY = -100000;
+ bool32 Activate = false;
+ // Find the max dimensions of all the selected layers.
+ for (int i = 0; i < File->Layer_Count; i++) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
+ if (!Layer->IsSelected)
+ continue;
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+ Transform_IterateOuterBounds(Layer, Source, &MinX, &MinY, &MaxX, &MaxY);
+ Activate = true;
+ }
+ if (Activate) {
+ State->Interact_Active = interact_type_viewport_transform;
+ interact_transform *Interact = (interact_transform *)&State->Interact_Offset[0];
+ Interact->Min = V2(MinX, MinY);
+ Interact->Max = V2(MaxX, MaxY);
+ Interact->Position = V2(0);
+ Interact->Radians = 0;
+ Interact->Scale = 1.0f;
+ Interact->OGPos = OGPos;
+ }
+}
+
+static ImVec2
+Layer_LocalToScreenSpace(project_state *State, block_layer *Layer, ui *UI,
+ real32 SourceWidth, real32 SourceHeight, real32 CompWidth, real32 CompHeight, v2 Point)
+{
+ real32 Rotation = Layer->rotation.CurrentValue;
+ real32 s = Layer->scale.CurrentValue;
+ real32 X = Layer->x.CurrentValue;
+ real32 Y = Layer->y.CurrentValue;
+
+ if (State->Interact_Active == interact_type_viewport_transform && Layer->IsSelected) {
+ Transform_ApplyInteractive(*(interact_transform *)&State->Interact_Offset[0], &X, &Y, &Rotation, &s);
+ }
+
+ real32 Rad = (Rotation * (PI / 180));
+ real32 AX = Layer->ax.CurrentValue;
+ real32 AY = Layer->ay.CurrentValue;
+
+ v2 XAxis = (Point.x - AX*SourceWidth) * s * V2(cos(Rad), sin(Rad));
+ v2 YAxis = (Point.y - AY*SourceHeight) * -s * V2(sin(Rad), -cos(Rad));
+ v2 LocalPoint = XAxis + YAxis;
+ v2 CompUV = V2((X + LocalPoint.x) / CompWidth,
+ (Y + LocalPoint.y) / CompHeight);
+ v2 ScreenPoint = V2(UI->CompPos.x + CompUV.x * UI->CompZoom.x,
+ UI->CompPos.y + CompUV.y * UI->CompZoom.y);
+
+ return ImVec2(ScreenPoint.x, ScreenPoint.y);
+}
static void
Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegion);
@@ -31,29 +180,6 @@ Renderer_Check(bool32 *Test)
*Test = Threading_IsActive();
}
-// Helper for working with different bit depths.
-static render_byte_info
-Bitmap_ByteInfo(uint32 BytesPerPixel) {
- render_byte_info Byte = {};
- if (BytesPerPixel == 4) {
- Byte.MaskPixel = 0xFF;
- Byte.ByteOffset = 1;
- Byte.Normalized = 1 / 255.0f;
- Byte.Bits = 255;
- } else if (BytesPerPixel == 8) {
- Byte.MaskPixel = 0xFFFF;
- Byte.ByteOffset = 2;
- Byte.Normalized = 1 / 65535.0f;
- Byte.Bits = 65535;
- } else {
- Byte.MaskPixel = 0xFFFFFFFF;
- Byte.ByteOffset = 4;
- Byte.Normalized = 1 / 4294967295.0f;
- Byte.Bits = 4294967295;
- Assert(0);
- }
- return Byte;
-}
static transform_info
Transform_Calculate(project_state *State, memory *Memory, project_data *File, block_layer *Layer, block_composition *Comp)
@@ -78,6 +204,10 @@ Transform_Calculate(project_state *State, memory *Memory, project_data *File, bl
real32 s = Layer->scale.CurrentValue;
blend_mode BlendMode = Layer->BlendMode;
+ if (State->Interact_Active == interact_type_viewport_transform && Layer->IsSelected) {
+ Transform_ApplyInteractive(*(interact_transform *)&State->Interact_Offset[0], &X, &Y, &Rotation, &s);
+ }
+
/*
state_file_ui *UI = &State->Context[State->CurrentFileIndex].UI;
if (UI->IsInteracting == true && UI->InteractMode == interact_transforms && Layer->IsSelected && !Layer->IsAdjustment)