From bb4d634962cdf97affd041a81b12c3d2c8d46bf7 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Thu, 17 Nov 2022 23:56:43 -0500 Subject: clipboard, simd, sd experiments --- createcalls.cpp | 539 ++++++++++++++++++++++++++++---------- functions.h | 6 +- imgui_helper_widgets.cpp | 18 ++ lib/base64.c | 189 ++++++++++++++ lib/base64.h | 17 ++ main.cpp | 235 +++++++++++------ main.h | 75 +++++- memory.cpp | 42 ++- my_imgui_widgets.cpp | 596 +++++++++++++++++++++++++----------------- prenderer.cpp | 665 +++++++++++++++++------------------------------ stable_diffusion.cpp | 28 ++ stable_diffusion.h | 25 ++ strings.cpp | 2 +- threading.cpp | 66 ++--- 14 files changed, 1568 insertions(+), 935 deletions(-) create mode 100644 lib/base64.c create mode 100644 lib/base64.h create mode 100644 stable_diffusion.cpp create mode 100644 stable_diffusion.h diff --git a/createcalls.cpp b/createcalls.cpp index 01f1caa..85faa3c 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -10,7 +10,7 @@ Source_Generate_Blank(project_data *File, project_state *State, memory *Memory, { 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); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Index, 0); Source->Occupied = 1; Source->Width = Width; Source->Height = Height; @@ -46,7 +46,7 @@ Source_Generate(project_data *File, project_state *State, memory *Memory, void * bool32 IsVideo = 0; 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); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Index, 0); History_Entry_Commit(Memory, "Add source"); History_Action_Block_Swap(Memory, F_Sources, Source); @@ -74,27 +74,24 @@ Bezier_LookupAddress(memory *Memory, property_channel *Property, uint16 Index) return &Bezier->Point[Index]; } -/* -if (State->Interact_Active == interact_type_keyframe_rotate) { - ImVec2 Keyframe_LocalPos_Ratio = (V2(Keyframe_LocalPos_[0]) - ImVec2(0, GraphInfo.MinVal)) * ImVec2(Increment.x, Y_Increment); - ImVec2 Keyframe_ScreenPos = Layer_ScreenPos_Min + ((ImVec2(1, -1) * Keyframe_LocalPos_Ratio + ImVec2(0, 0.5)) * TimelineZoomSize) + ImVec2(0, Layer_ScreenSize.y/2); - real32 Slope_Old = (Keyframe_ScreenPos.y - State->Interact_Offset[3]) / (Keyframe_ScreenPos.x - State->Interact_Offset[2]); - real32 Slope_New = (Keyframe_ScreenPos.y - io.MousePos.y) / (Keyframe_ScreenPos.x - io.MousePos.x); - State->Interact_Offset[0] = atan((Slope_Old - Slope_New) / (1 + Slope_Old * Slope_New)); - DebugWatchVar("Rotation: ", &State->Interact_Offset[0], d_float); -} -*/ -// Keyframe_Interact_Evaluate(Memory, State, Point->IsSelected, Point->Pos, Keyframe_LocalPos_); - - +// NOTE(fox): It's not required for the Y to be set correctly in i.e. sorting. static void -Bezier_EvaluateValue(project_state *State, bezier_point *PointAddress, v2 *Pos) +Bezier_EvaluateValue(project_state *State, bezier_point *PointAddress, v2 *Pos, real32 GraphZoomHeight = 1, real32 Y_Increment = 1) { Pos[0] = PointAddress->Pos[0]; Pos[1] = PointAddress->Pos[1]; Pos[2] = PointAddress->Pos[2]; - if (State->Interact_Active == interact_type_keyframe_move && PointAddress->IsSelected) { - Pos[0].x += (int32)State->Interact_Offset[0]; + if (PointAddress->IsSelected) { + if (State->Interact_Active == interact_type_keyframe_move) { + Pos[PointAddress->IsSelected - 1].x += (int32)State->Interact_Offset[0]; + Pos[PointAddress->IsSelected - 1].y -= (State->Interact_Offset[1] / GraphZoomHeight / Y_Increment); + } else if (State->Interact_Active == interact_type_keyframe_scale) { + Pos[1].x += State->Interact_Offset[0]; + Pos[2].x -= State->Interact_Offset[0]; + } else if (State->Interact_Active == interact_type_keyframe_rotate) { + // how do I do this?? + Assert(0); + } } } @@ -125,36 +122,17 @@ Bezier_Add(memory *Memory, property_channel *Property, bezier_point PointData) static property_channel -Property_InitFloat(char *Name, real32 Val, real32 ScrubVal, real32 MinVal = PROPERTY_REAL_MIN, real32 MaxVal = PROPERTY_REAL_MAX) { property_channel Property = {}; +Property_InitFloat(char *Name, real32 Val, real32 ScrubVal, real32 MinVal = PROPERTY_REAL_MIN, real32 MaxVal = PROPERTY_REAL_MAX, bool32 AlwaysInteger = 0) { + property_channel Property = {}; Property.Name = Name; Property.CurrentValue = Val; Property.MinVal = MinVal; Property.MaxVal = MaxVal; + Property.AlwaysInteger = AlwaysInteger; Property.ScrubVal = ScrubVal; return Property; } -static void -Keyframe_Interact_Evaluate(memory *Memory, project_state *State, uint8 IsSelected, v2 Pos_Initial[3], v2 Pos_New[3]) -{ - /* - Assert(Pos_New[0].y == Pos_Initial[0].y); - if (State->Interact_Active == interact_type_keyframe_move) { - Pos_New[0].x = Pos_New[0].x + Offset.x; - Pos_New[0].y = Pos_New[0].y + Offset.y; - } else if (State->Interact_Active == interact_type_keyframe_scale) { - Pos_New[1].x += (IsSelected - 1 == 0 || IsSelected - 1 == 1) ? Offset.x : 0; - Pos_New[2].x -= (IsSelected - 1 == 0 || IsSelected - 1 == 2) ? Offset.x : 0; - } else if (State->Interact_Active == interact_type_keyframe_rotate) { - real32 Rad = State->Interact_Offset[0]; - v2 XAxis = V2(8, 8) * V2(cos(Rad), sin(Rad)); - v2 YAxis = V2(sin(Rad), -cos(Rad)); - Pos_New[2].x += XAxis.x + XAxis.y; - Pos_New[2].y += YAxis.x + YAxis.y; - } - */ -} - static block_composition * Precomp_Init(project_data *File, memory *Memory) { @@ -212,13 +190,13 @@ Layer_Select(memory *Memory, project_state *State, int32 i) // State->RecentSelectionType = selection_layer; } -// TODO(fox): Precomps! -void Layer_DeselectAll(memory *Memory, uint32 LayerCount) { - for (uint32 i = 0; i < LayerCount; i++) { +void Layer_DeselectAll(project_data *File, project_state *State, memory *Memory) { + int h = 0, c = 0, i = 0; + while (Block_Loop(Memory, F_Sources, File->Layer_Count, &h, &c, &i)) { block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); - if (Layer->IsSelected) - Layer->IsSelected = false; + Layer->IsSelected = false; } + State->MostRecentlySelectedLayer = -1; } void Source_DeselectAll(project_data *File, memory *Memory) @@ -230,6 +208,81 @@ void Source_DeselectAll(project_data *File, memory *Memory) } } +void Clipboard_Paste(project_data *File, project_state *State, memory *Memory, sorted_layer *SortedLayerArray) +{ + clipboard_contents *Contents = (clipboard_contents *)State->ClipboardBuffer; + uint64 ClipboardPos = sizeof(clipboard_contents); + ClipboardPos = sizeof(clipboard_contents); + int h = 0, c = 0, i = 0; + block_layer *Layer; + clipboard_channel *Channel; + int b = 0; + while (b < Contents->ChannelCount) { + Channel = &Contents->Channel[b]; + while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) + { + Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); + if (Layer->IsSelected) + break; + } + // NOTE(fox): This loop assumes all layers and the clipboard have + // channels laid out in the same way! + for (int h = 0; h < AmountOf(Layer->Property); h++) { + property_channel *Property = &Layer->Property[h]; + if (Property->Name == Channel->Name) { + for (int p = 0; p < Channel->KeyframeCount; p++) { + bezier_point PointData = *(bezier_point *)((uint8 *)State->ClipboardBuffer + ClipboardPos); + Bezier_Add(Memory, Property, PointData); + ClipboardPos += sizeof(bezier_point); + } + b++; + Channel = &Contents->Channel[b]; + } + } + } +} + + +void Clipboard_Store(project_data *File, project_state *State, memory *Memory, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray) +{ + // TODO(fox): Multi-precomp support! + int LocalOffset = 0; + clipboard_contents *Contents = (clipboard_contents *)State->ClipboardBuffer; + *Contents = {}; + uint64 ClipboardPos = sizeof(clipboard_contents); + // for (int i = SortedCompInfo.LayerCount - 1; i >= 0; i--) + Assert(0); + for (int i = 10; 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); + for (int h = 0; h < AmountOf(Layer->Property); h++) { + property_channel *Property = &Layer->Property[h]; + if (Property->IsToggled || Layer->IsSelected) { + sorted_property_info *InfoLocation = SortedPropertyInfo + (i * 7) + h; + uint16 *ArrayLocation = SortedPropertyArray + (i * 7 * MAX_KEYFRAMES_PER_BLOCK) + (h * MAX_KEYFRAMES_PER_BLOCK); + clipboard_channel *Channel = &Contents->Channel[Contents->ChannelCount]; + for (int p = 0; p < Property->Keyframe_Count; p++) { + bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[p]); + if (PointAddress->IsSelected) { + Arbitrary_WriteInto((uint8 *)PointAddress, (uint8 *)State->ClipboardBuffer + ClipboardPos, sizeof(bezier_point)); + ClipboardPos += sizeof(bezier_point); + Channel->KeyframeCount++; + } + } + if (Channel->KeyframeCount) { + if (!LocalOffset) + LocalOffset = i; + Contents->ChannelCount++; + Channel->LayerOffset = LocalOffset - i; + Channel->Name = Property->Name; + } + } + } + } +} + static sorted_layer * Layer_GetSortedArray(sorted_layer *LayerArrayStart, sorted_comp_info *SortedCompStart, uint32 TargetComp) { @@ -288,41 +341,67 @@ void Layer_RecursiveDeselect(memory *Memory, sorted_comp_info *SortedCompArray, } } -void Property_MinMax(memory *Memory, project_state *State, property_channel *Property, uint16 *ArrayLocation, v2 *Min, v2 *Max) +void Property_MinMax_X(memory *Memory, project_state *State, property_channel *Property, + uint16 *ArrayLocation, real32 *Min, real32 *Max) { v2 FirstPointPos[3]; bezier_point *FirstPointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[0]); Bezier_EvaluateValue(State, FirstPointAddress, FirstPointPos); - Min->x = FirstPointPos[0].x; + *Min = FirstPointPos[0].x; v2 LastPointPos[3]; bezier_point *LastPointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[Property->Keyframe_Count - 1]); Bezier_EvaluateValue(State, LastPointAddress, LastPointPos); - Max->x = LastPointPos[0].x; - int32 Offset = (State->Interact_Active == interact_type_keyframe_move) ? (int32)State->Interact_Offset[0] : 0; - real32 MinY = FLT_MAX; - real32 MaxY = FLT_MIN; - for (int p = 0; p < Property->Keyframe_Count; p++) { - bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[p]); - MinY = (MinY < PointAddress->Pos[0].y) ? MinY : PointAddress->Pos[0].y; - MaxY = (MaxY > PointAddress->Pos[0].y) ? MaxY : PointAddress->Pos[0].y; + *Max = LastPointPos[0].x; +} +void Property_MinMax_Y(memory *Memory, project_state *State, property_channel *Property, + sorted_property_info *PropertyInfo, real32 *Min, real32 *Max, bool32 Evaluate = 1) +{ + if (Evaluate) { + v2 MinYPointPos[3]; + bezier_point *MinYPointAddress = Bezier_LookupAddress(Memory, Property, PropertyInfo->MinYIndex); + Bezier_EvaluateValue(State, MinYPointAddress, MinYPointPos); + *Min = MinYPointPos[0].y; + v2 MaxYPointPos[3]; + bezier_point *MaxYPointAddress = Bezier_LookupAddress(Memory, Property, PropertyInfo->MaxYIndex); + Bezier_EvaluateValue(State, MaxYPointAddress, MaxYPointPos); + *Max = MaxYPointPos[0].y; + } else { + bezier_point *MinYPointAddress = Bezier_LookupAddress(Memory, Property, PropertyInfo->MinYIndex); + *Min = MinYPointAddress->Pos[0].y; + bezier_point *MaxYPointAddress = Bezier_LookupAddress(Memory, Property, PropertyInfo->MaxYIndex); + *Max = MaxYPointAddress->Pos[0].y; } - Min->y = MinY; - Max->y = MaxY; } // The sorting algorithm is straightforward: read every point, evaluate it if // it's currently being interacted with by the user, record index in a sorted // list, and repeat, shiftig the list as necessary. -void Property_SortAll(memory *Memory, project_state *State, property_channel *Property, uint16 *PropertyArrayStart) +void Property_SortAll(memory *Memory, project_state *State, property_channel *Property, sorted_property_info *PropertyInfo, uint16 *PropertyArrayStart) { int h = 0, c = 0, i = 0; uint32 CurrentSortIndex = 0; + real32 MinY = FLT_MAX; + real32 MaxY = FLT_MIN; int32 Offset = (State->Interact_Active == interact_type_keyframe_move) ? (int32)State->Interact_Offset[0] : 0; while (Block_Loop(Memory, Property, Property->Keyframe_Count, &h, &c, &i)) { v2 PointPos[3]; bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, i); + + if (PointAddress->IsSelected) + PropertyInfo->IsGraphSelected = true; + Bezier_EvaluateValue(State, PointAddress, PointPos); + + if (MinY > PointAddress->Pos[0].y) { + MinY = PointAddress->Pos[0].y; + PropertyInfo->MinYIndex = i; + } + if (MaxY < PointAddress->Pos[0].y) { + MaxY = PointAddress->Pos[0].y; + PropertyInfo->MaxYIndex = i; + } + uint32 SortedIndex_Playhead = 0; while (SortedIndex_Playhead < CurrentSortIndex) { uint16 TestPointEntry = PropertyArrayStart[SortedIndex_Playhead]; @@ -347,7 +426,26 @@ void Property_SortAll(memory *Memory, project_state *State, property_channel *Pr } } -void Layer_Sort_CheckPrev(memory *Memory, int i, int Direction, sorted_layer *SortedLayerInfo, sorted_comp_info SortedCompInfo, int *EntriesPassed, sorted_layer *LayerEntry) +void Property_DeselectAll(project_data *File, memory *Memory, uint16 *SortedPropertyArray) +{ + 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++) { + property_channel *Property = &Layer->Property[h]; + uint16 *ArrayLocation = SortedPropertyArray + (i * 7 * MAX_KEYFRAMES_PER_BLOCK) + (h * MAX_KEYFRAMES_PER_BLOCK); + for (int p = 0; p < Property->Keyframe_Count; p++) { + int k = ArrayLocation[p]; + bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, k); + PointAddress->IsSelected = 0; + } + } + } +} + +void Layer_Sort_CheckPrev(memory *Memory, int i, int Direction, sorted_layer *SortedLayerInfo, sorted_comp_info SortedCompInfo, int *EntriesPassed, sorted_layer *LayerEntry, bool32 AltMethod) { int PrevOffsetIndex = i + Direction + (*EntriesPassed * Direction); bool32 OutOfBounds = (Direction > 0) ? (PrevOffsetIndex > (SortedCompInfo.LayerCount - 1)) : (PrevOffsetIndex < 0); @@ -355,18 +453,46 @@ void Layer_Sort_CheckPrev(memory *Memory, int i, int Direction, sorted_layer *So sorted_layer *PrevLayerEntry = &SortedLayerInfo[PrevOffsetIndex]; real32 PrevOffset = PrevLayerEntry->SortedOffset; if (PrevOffset == (LayerEntry->SortedOffset - Direction)) { - LayerEntry->SortedOffset -= Direction; (*EntriesPassed)++; - Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerInfo, SortedCompInfo, EntriesPassed, LayerEntry); + if (!AltMethod) { + PrevLayerEntry->SortedOffset += Direction; + } else { + LayerEntry->SortedOffset -= Direction; + Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerInfo, SortedCompInfo, EntriesPassed, LayerEntry, AltMethod); + } } } } +void Layer_Evaluate_Display(block_layer *Layer, sorted_layer *LayerArrayStart, sorted_comp_info *CompStart, sorted_layer *SortedLayerInfo, int i, real32 *Offset) +{ + int ExtraPad = 1; + for (int h = 0; h < AmountOf(Layer->Property); h++) { + property_channel *Property = &Layer->Property[h]; + if (Property->IsToggled) { + *Offset += 1 + ExtraPad; + ExtraPad = 0; + } + } + /* + if (Layer->Precomp_Toggled) { + Assert(Layer->IsPrecomp); + sorted_comp_info *Layer_SortedCompInfo = &CompStart[Layer->Block_Source_Index]; + sorted_layer *Layer_SortedLayerInfo = Layer_GetSortedArray(LayerArrayStart, CompStart, Layer->Block_Source_Index); + sorted_layer *TopLayerEntry = &Layer_SortedLayerInfo[0]; + sorted_layer *BottomLayerEntry = &Layer_SortedLayerInfo[Layer_SortedCompInfo->LayerCount - 1]; + *Offset += TopLayerEntry->SortedOffset - BottomLayerEntry->SortedOffset + 2; + } + */ +} + // The first loop is for counting how many layers are in each precomp, the // second is for sorting the layers by offset, and the third is for applying // interactivity if the user is moving any layers. -void Layer_SortAll(project_data *File, project_state *State, memory *Memory, sorted_layer *LayerArrayStart, sorted_comp_info *CompStart, uint16 *SortedPropertyArray, uint32 LayerCount, uint32 CompCount) +void Layer_SortAll(project_data *File, project_state *State, memory *Memory, sorted_layer *LayerArrayStart, + sorted_comp_info *CompStart, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray, + uint32 LayerCount, uint32 CompCount) { int h = 0, c = 0, i = 0; while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) { @@ -376,19 +502,19 @@ void Layer_SortAll(project_data *File, project_state *State, memory *Memory, sor for (int h = 0; h < AmountOf(Layer->Property); h++) { property_channel *Property = &Layer->Property[h]; if (Property->Block_Bezier_Count) { + sorted_property_info *InfoLocation = SortedPropertyInfo + (i * 7) + h; uint16 *ArrayLocation = SortedPropertyArray + (i * 7 * MAX_KEYFRAMES_PER_BLOCK) + (h * MAX_KEYFRAMES_PER_BLOCK); - Property_SortAll(Memory, State, Property, ArrayLocation); + Property_SortAll(Memory, State, Property, InfoLocation, ArrayLocation); } } } h = 0, c = 0, i = 0; - uint32 CurrentSortIndex = 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); uint32 SortedIndex_Playhead = 0; - while (SortedIndex_Playhead < CurrentSortIndex) { + while (SortedIndex_Playhead < SortedCompInfo->CurrentSortIndex) { sorted_layer LayerEntry = SortedLayerInfo[SortedIndex_Playhead]; block_layer *TestLayer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, LayerEntry.Block_Layer_Index); if (-Layer->Vertical_Offset < -TestLayer->Vertical_Offset) { @@ -397,16 +523,16 @@ void Layer_SortAll(project_data *File, project_state *State, memory *Memory, sor SortedIndex_Playhead++; } } - if (SortedIndex_Playhead != CurrentSortIndex) { + if (SortedIndex_Playhead != SortedCompInfo->CurrentSortIndex) { uint8 *Address_Start = (uint8 *)(SortedLayerInfo + SortedIndex_Playhead); - uint8 *Address_End = (uint8 *)(SortedLayerInfo + CurrentSortIndex) - 1; - Assert(CurrentSortIndex != SortedCompInfo->LayerCount); + uint8 *Address_End = (uint8 *)(SortedLayerInfo + SortedCompInfo->CurrentSortIndex) - 1; + Assert(SortedCompInfo->CurrentSortIndex != SortedCompInfo->LayerCount); Arbitrary_ShiftData(Address_Start, Address_End, sizeof(sorted_layer), 1); } sorted_layer *LayerEntry = SortedLayerInfo + SortedIndex_Playhead; LayerEntry->Block_Layer_Index = i; LayerEntry->SortedOffset = Layer->Vertical_Offset; - CurrentSortIndex++; + SortedCompInfo->CurrentSortIndex++; } if (State->Interact_Active == interact_type_layer_move) { int32 Offset = (int32)State->Interact_Offset[1]; @@ -426,7 +552,7 @@ void Layer_SortAll(project_data *File, project_state *State, memory *Memory, sor if (Layer->IsSelected) { int32 SpacesToMove = Offset * Direction; while (SpacesToMove) { - Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerInfo, *SortedCompInfo, &EntriesPassed, LayerEntry); + Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerInfo, *SortedCompInfo, &EntriesPassed, LayerEntry, 0); LayerEntry->SortedOffset -= Direction; SpacesToMove--; } @@ -465,7 +591,7 @@ sorted_file File_Sort_Push(project_data *File, project_state *State, memory *Mem Sorted.PropertyInfo = (sorted_property_info *)Property_SortedArray; Sorted.PropertyArray = (uint16 *)((uint8 *)Property_SortedArray + PropertyInfoSize); - Layer_SortAll(File, State, Memory, Sorted.LayerArray, Sorted.CompArray, Sorted.PropertyArray, File->Layer_Count, File->Comp_Count); + Layer_SortAll(File, State, Memory, Sorted.LayerArray, Sorted.CompArray, Sorted.PropertyInfo, Sorted.PropertyArray, File->Layer_Count, File->Comp_Count); return Sorted; } @@ -486,6 +612,7 @@ Layer_Delete(project_data *File, memory *Memory, uint32 Index) File->Layer_Count--; } + block_layer * Layer_Init(project_data *File, memory *Memory) { if (File->Layer_Count + 1 > MAX_LAYERS) { @@ -498,7 +625,7 @@ block_layer * Layer_Init(project_data *File, memory *Memory) Layer->Occupied = 1; Layer->Block_String_Index = Memory_Block_AllocateNew(Memory, F_Strings); - block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index); + block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index, 0); sprintf(String->Char, "Layer %i", File->Layer_Count + 1); // CSbros... String->Occupied = 1; @@ -509,7 +636,7 @@ block_layer * Layer_Init(project_data *File, memory *Memory) Layer->scale = Property_InitFloat("Scale", 1.0f, 0.005f); Layer->rotation = Property_InitFloat("Rotation", 0.0f, 1.0f); Layer->opacity = Property_InitFloat("Opacity", 1.0f, 0.005f, 0.0f, 1.0f); - Layer->time = Property_InitFloat("Frame Number", 0.0f, 1.0f, 0, 100000); + Layer->time = Property_InitFloat("Frame Number", 0.0f, 1.0f, 0, 100000, 1); Layer->IsVisible = 1; @@ -546,6 +673,7 @@ void Source_UICreateButton(project_data *File, project_state *State, memory *Mem Layer->x.CurrentValue = Source->Width / 2; Layer->y.CurrentValue = Source->Height / 2; Layer->Vertical_Offset = TopOffset-1; + Layer->Frame_Start = Comp->Frame_Start; Layer->Frame_End = Comp->Frame_End; TopOffset--; } @@ -556,6 +684,56 @@ void Source_UICreateButton(project_data *File, project_state *State, memory *Mem Source_DeselectAll(File, Memory); } +void Precomp_UICreateButton(project_data *File, project_state *State, memory *Memory, uint16 CompIndex, + sorted_comp_info SortedCompInfo, sorted_layer *SortedLayerInfo) +{ + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); + History_Entry_Commit(Memory, "Pre-compose layer"); + block_composition *NewComp = Precomp_Init(File, Memory); + NewComp->Width = Comp->Width; + NewComp->Height = Comp->Height; + NewComp->FPS = Comp->FPS; + NewComp->BytesPerPixel = Comp->BytesPerPixel; + NewComp->Frame_Count = Comp->Frame_Count; + NewComp->Frame_Start = Comp->Frame_Start; + NewComp->Frame_End = Comp->Frame_End; + int32 TopOffset = 0; + 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); + if (Layer->IsSelected) { + TopOffset = Layer->Vertical_Offset; + break; + } + } + 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); + if (Layer->IsSelected) { + History_Action_Swap(Memory, F_File, sizeof(Layer->Block_Composition_Index), &Layer->Block_Composition_Index); + Layer->Block_Composition_Index = File->Comp_Count - 1; + } + } + block_layer *PrecompLayer = Layer_Init(File, Memory); + bezier_point Point0 = { 1, {0, 0, 1, 0, 1, 0}, interpolation_type_linear, 0, {0, 0, 0}, 0 }; + bezier_point Point1 = { 1, {(real32)NewComp->Frame_End, (real32)NewComp->Frame_End, 1, 0, 1, 0}, interpolation_type_linear, 0, {0, 0, 0}, 0 }; + Bezier_Add(Memory, &PrecompLayer->time, Point0); + Bezier_Add(Memory, &PrecompLayer->time, Point1); + PrecompLayer->IsPrecomp = true; + PrecompLayer->Block_Source_Index = File->Comp_Count - 1; + PrecompLayer->Block_Composition_Index = CompIndex; + PrecompLayer->Vertical_Offset = TopOffset; + PrecompLayer->Frame_End = NewComp->Frame_End; + PrecompLayer->ColIndex = 3; + PrecompLayer->x.CurrentValue = Comp->Width/2; + PrecompLayer->y.CurrentValue = Comp->Height/2; + History_Entry_End(Memory); + State->UpdateFrame = true; +} // Helper for working with different bit depths. @@ -592,16 +770,19 @@ State_BindBrushTexture(memory *Memory, brush_state *Brush, uint32 BytesPerPixel) static void Brush_CalcBitmapAlphaFromSize(memory *Memory, brush_state *Brush, uint32 BytesPerPixel) { - real32 BrushLength = Brush->Size; - real32 BrushCenter = BrushLength / 2; + int32 BrushLength = Brush->Size; + if (BrushLength > 128) { + BrushLength = BrushLength + (16 - (BrushLength % 16)); + } + real32 BrushCenter = (real32)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); + for (int Y = 0; Y < BrushLength; Y++) { + for (int X = 0; X < BrushLength; X++) { + uint8 *PixelAddress = (uint8 *)BrushAddress + (Y * BytesPerPixel*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); @@ -616,18 +797,21 @@ Brush_CalcBitmapAlphaFromSize(memory *Memory, brush_state *Brush, uint32 BytesPe } } -// 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) +Brush_Info(brush_info *B, brush_state *Brush, block_source *Source, v2 LayerPos, v4 Color) { - uint32 BrushLength = (uint32)Brush->Size; + B->BrushLength = (uint32)Brush->Size; + if (B->BrushLength > 128) { + B->BrushLength = B->BrushLength + (16 - (B->BrushLength % 16)); + } 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); + rectangle BrushPos = { (int32)(LayerPos.x - (B->BrushLength / 2)), + (int32)(LayerPos.y - (B->BrushLength / 2)), + (int32)(LayerPos.x + (B->BrushLength / 2)), + (int32)(LayerPos.y + (B->BrushLength / 2)) }; + + B->LayerBounds = ClipRectangle(BrushPos, RenderRegion); if (BrushPos.Min.x < Brush->CacheBounds.Min.x) Brush->CacheBounds.Min.x = BrushPos.Min.x; @@ -638,68 +822,79 @@ PaintTest(memory *Memory, block_source *Source, brush_state *Brush, void *Addres 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; + B->BytesPerPixel = 4; + B->SourceWidth = Source->Width; + B->SourceBytesPerPixel = Source->BytesPerPixel; + + Assert(Source->BytesPerPixel == 4); - render_byte_info LayerBits = Bitmap_ByteInfo(Source->BytesPerPixel); - render_byte_info BrushBits = Bitmap_ByteInfo(BytesPerPixel); + B->LayerPitch = Source->Width*Source->BytesPerPixel; + B->BrushPitch = (int)B->BrushLength * B->BytesPerPixel; - int32 ExtraX = 0; - int32 ExtraY = 0; + B->LayerBits = Bitmap_ByteInfo(Source->BytesPerPixel); + B->BrushBits = Bitmap_ByteInfo(B->BytesPerPixel); + + B->ExtraX = 0; + B->ExtraY = 0; if (BrushPos.Min.x < 0) { - ExtraX = BrushPos.Min.x; + B->ExtraX = BrushPos.Min.x; } if (BrushPos.Min.y < 0) { - ExtraY = BrushPos.Min.y; + B->ExtraY = BrushPos.Min.y; } - void *BrushBuffer = Brush->PaintBuffer; + B->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; + B->R_Brush = Color.r; + B->G_Brush = Color.g; + B->B_Brush = Color.b; + B->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++) { + B->BrushRow = (uint8 *)B->BrushBuffer; +} + +static void +PaintTest(brush_info B, void *Buffer, rectangle RenderRegion) +{ + for (int32 Y = RenderRegion.Min.y; Y < RenderRegion.Max.y; Y++) { + for (int32 X = RenderRegion.Min.x; X < RenderRegion.Max.x; X++) { - uint32 Offset = Y*LayerPitch + X*Source->BytesPerPixel; - uint8 *LayerPixel = (uint8 *)Address + Offset; + uint32 Offset = Y*B.LayerPitch + X*B.SourceBytesPerPixel; + uint8 *LayerPixel = (uint8 *)Buffer + 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); + uint32 *R_DestAddress = (uint32 *)(LayerPixel + B.LayerBits.ByteOffset * 0); + uint32 *G_DestAddress = (uint32 *)(LayerPixel + B.LayerBits.ByteOffset * 1); + uint32 *B_DestAddress = (uint32 *)(LayerPixel + B.LayerBits.ByteOffset * 2); + uint32 *A_DestAddress = (uint32 *)(LayerPixel + B.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; + real32 R_Layer = (real32)(*R_DestAddress & B.LayerBits.MaskPixel) * B.LayerBits.Normalized; + real32 G_Layer = (real32)(*G_DestAddress & B.LayerBits.MaskPixel) * B.LayerBits.Normalized; + real32 B_Layer = (real32)(*B_DestAddress & B.LayerBits.MaskPixel) * B.LayerBits.Normalized; + real32 A_Layer = (real32)(*A_DestAddress & B.LayerBits.MaskPixel) * B.LayerBits.Normalized; - int32 TrueX = (X - LayerBounds.Min.x) - ExtraX; - int32 TrueY = (Y - LayerBounds.Min.y) - ExtraY; + int32 TrueX = (X - B.LayerBounds.Min.x) - B.ExtraX; + int32 TrueY = (Y - B.LayerBounds.Min.y) - B.ExtraY; // Assert(TrueX >= 0 && TrueX < BrushLength); // Assert(TrueY >= 0 && TrueY < BrushLength); - uint8 *BrushPixel = (uint8 *)BrushBuffer + (TrueY * BrushPitch) + (TrueX * BytesPerPixel); + uint8 *BrushPixel = (uint8 *)B.BrushRow + (TrueY * B.BrushPitch) + (TrueX * B.BytesPerPixel); - real32 Brush_BitmapAlpha = (real32)((*(uint32 *)(BrushPixel + BrushBits.ByteOffset*3)) & BrushBits.MaskPixel) * BrushBits.Normalized; + real32 Brush_BitmapAlpha = (real32)((*(uint32 *)(BrushPixel + B.BrushBits.ByteOffset*3)) & B.BrushBits.MaskPixel) * B.BrushBits.Normalized; - real32 BrushAlpha = Brush_BitmapAlpha * A_Brush; + real32 BrushAlpha = Brush_BitmapAlpha * B.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); + real32 R_Blend = (R_Layer * (1.0f - BrushAlpha)) + (B.R_Brush * BrushAlpha); + real32 G_Blend = (G_Layer * (1.0f - BrushAlpha)) + (B.G_Brush * BrushAlpha); + real32 B_Blend = (B_Layer * (1.0f - BrushAlpha)) + (B.B_Brush * BrushAlpha); /* R_Blend = (R_Brush * (1.0f - LayerAlpha)) + (R_Blend * LayerAlpha); @@ -709,19 +904,102 @@ PaintTest(memory *Memory, block_source *Source, brush_state *Brush, void *Addres 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); + uint32 R_Out = (uint32)(Normalize(R_Blend) * B.LayerBits.Bits); + uint32 G_Out = (uint32)(Normalize(G_Blend) * B.LayerBits.Bits); + uint32 B_Out = (uint32)(Normalize(B_Blend) * B.LayerBits.Bits); + uint32 A_Out = (uint32)(Normalize(A_Blend) * B.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; + *R_DestAddress = (*R_DestAddress & ~B.LayerBits.MaskPixel) | R_Out; + *G_DestAddress = (*G_DestAddress & ~B.LayerBits.MaskPixel) | G_Out; + *B_DestAddress = (*B_DestAddress & ~B.LayerBits.MaskPixel) | B_Out; + *A_DestAddress = (*A_DestAddress & ~B.LayerBits.MaskPixel) | A_Out; } } } +static void +PaintTest_AVX2(brush_info B, void *Buffer, rectangle RenderRegion) +{ + __m256 One = _mm256_set1_ps(1); + __m256 Zero = _mm256_set1_ps(0); + __m256 Eight = _mm256_set1_ps(8); + __m256i FF = _mm256_set1_epi32(0xFF); + __m256 R_Brush =_mm256_set1_ps(B.R_Brush); + __m256 G_Brush =_mm256_set1_ps(B.G_Brush); + __m256 B_Brush =_mm256_set1_ps(B.B_Brush); + __m256 A_Brush =_mm256_set1_ps(B.A_Brush); + __m256 Norm255 = _mm256_set1_ps(1/255.0f); + __m256 Real255 = _mm256_set1_ps(255.0f); + __m256 LayerBoundsMaxX = _mm256_set1_ps(B.SourceWidth); + + for (int32 Y = RenderRegion.Min.y; Y < RenderRegion.Max.y; Y++) { + __m256 PixelX = _mm256_setr_ps((real32)RenderRegion.Min.x, + (real32)RenderRegion.Min.x+1, + (real32)RenderRegion.Min.x+2, + (real32)RenderRegion.Min.x+3, + (real32)RenderRegion.Min.x+4, + (real32)RenderRegion.Min.x+5, + (real32)RenderRegion.Min.x+6, + (real32)RenderRegion.Min.x+7); + for (int32 X = RenderRegion.Min.x; X < RenderRegion.Max.x; X += 8) { + + __m256i TileBarrier = _mm256_cvtps_epi32(_mm256_cmp_ps(PixelX, LayerBoundsMaxX, 1)); + + uint32 Offset = Y*B.LayerPitch + X*B.SourceBytesPerPixel; + uint8 *LayerPixelAddress = (uint8 *)Buffer + Offset; + + __m256i LayerPixels = _mm256_loadu_si256((const __m256i *)LayerPixelAddress); + + __m256 R_Layer = _mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_and_si256( LayerPixels, FF)), Norm255); + __m256 G_Layer = _mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srli_epi32(LayerPixels, 8), FF)), Norm255); + __m256 B_Layer = _mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srli_epi32(LayerPixels, 16), FF)), Norm255); + __m256 A_Layer = _mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srli_epi32(LayerPixels, 24), FF)), Norm255); + + int32 TrueX = (X - B.LayerBounds.Min.x) - B.ExtraX; + int32 TrueY = (Y - B.LayerBounds.Min.y) - B.ExtraY; + uint8 *BrushPixelAddress = (uint8 *)B.BrushRow + (TrueY * B.BrushPitch) + (TrueX * B.BytesPerPixel); + __m256i BrushPixels = _mm256_loadu_si256((const __m256i *)BrushPixelAddress); + + __m256 Brush_BitmapAlpha = _mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srli_epi32(BrushPixels, 24), FF)), Norm255); + + __m256 A_BrushMultiplied = _mm256_mul_ps(Brush_BitmapAlpha, A_Brush); + + __m256 A_Blend = _mm256_add_ps(A_Layer, A_BrushMultiplied); + + __m256 R_Blend = _mm256_add_ps(_mm256_mul_ps(R_Layer, _mm256_sub_ps(One, A_BrushMultiplied)), _mm256_mul_ps(R_Brush, A_BrushMultiplied)); + __m256 G_Blend = _mm256_add_ps(_mm256_mul_ps(G_Layer, _mm256_sub_ps(One, A_BrushMultiplied)), _mm256_mul_ps(G_Brush, A_BrushMultiplied)); + __m256 B_Blend = _mm256_add_ps(_mm256_mul_ps(B_Layer, _mm256_sub_ps(One, A_BrushMultiplied)), _mm256_mul_ps(B_Brush, A_BrushMultiplied)); + + __m256i R_Out = _mm256_cvtps_epi32(_mm256_mul_ps(_mm256_max_ps(_mm256_min_ps(One, R_Blend), Zero), Real255)); + __m256i G_Out = _mm256_cvtps_epi32(_mm256_mul_ps(_mm256_max_ps(_mm256_min_ps(One, G_Blend), Zero), Real255)); + __m256i B_Out = _mm256_cvtps_epi32(_mm256_mul_ps(_mm256_max_ps(_mm256_min_ps(One, B_Blend), Zero), Real255)); + __m256i A_Out = _mm256_cvtps_epi32(_mm256_mul_ps(_mm256_max_ps(_mm256_min_ps(One, A_Blend), Zero), Real255)); + + __m256i OutputPixel = _mm256_or_si256( + _mm256_or_si256(R_Out, _mm256_slli_epi32(G_Out, 8)), + _mm256_or_si256(_mm256_slli_epi32(B_Out, 16), _mm256_slli_epi32(A_Out, 24))); + + // _mm256_storeu_si256((__m256i *)LayerPixelAddress, OutputPixel); + _mm256_maskstore_epi32((int *)LayerPixelAddress, TileBarrier, OutputPixel); + PixelX = _mm256_add_ps(PixelX, Eight); + } + } +} + +static void +Brush_Render(project_state *State, ui *UI, layer_transforms T_Layer, block_composition *MainComp, block_source *Source, void *BitmapAddress, ImVec2 ViewportMin, ImVec2 MousePos) +{ + brush_info B; + v2 LayerPos = Transform_ScreenSpaceToLocal(T_Layer, MainComp->Width, MainComp->Height, Source->Width, Source->Height, UI->CompPos, UI->CompZoom, ViewportMin, MousePos); + Brush_Info(&B, &State->Brush, Source, LayerPos, UI->Color); + if (State->Brush.Size >= 128) { + Render_Main((void *)&B, BitmapAddress, render_type_brush, B.LayerBounds); + } else { + PaintTest(B, BitmapAddress, B.LayerBounds); + } +} + + #if 0 static void @@ -913,14 +1191,13 @@ Layer_LocalToScreenSpace(project_layer *Layer, ui *UI, comp_buffer CompBuffer, v } static v2 -Layer_ScreenSpaceToLocal(project_layer *Layer, ui *UI, comp_buffer CompBuffer, ImVec2 ViewportMin, ImVec2 Point) +Layer_ScreenSpaceToLocal(project_layer *Layer, ImVec2 CompPos, ImVec2 CompZoom, comp_buffer CompBuffer, ImVec2 ViewportMin, ImVec2 Point) { source *Source = Layer->Source; - v2 CompUV = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, Point); + v2 CompUV = ImGui_ScreenPointToCompUV(ViewportMin, CompPos, CompZoom, Point); v2 LayerUV = CompUVToLayerUV(Layer, &CompBuffer, CompUV); return V2(LayerUV.x * Source->Info.Width, LayerUV.y * Source->Info.Height); } - static void LoadTestFootage(project_data *File, project_state *State, memory *Memory) { diff --git a/functions.h b/functions.h index a6b608e..a1f5d2a 100644 --- a/functions.h +++ b/functions.h @@ -5,17 +5,19 @@ 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 void Render_Main(void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion); + 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, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray); -static v2 Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, ui UI, ImVec2 ViewportMin, ImVec2 Point); +static v2 Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, ImVec2 CompPos, ImVec2 CompZoom, ImVec2 ViewportMin, ImVec2 Point); static ImVec2 Layer_LocalToScreenSpace(project_state *State, memory *Memory, block_layer *Layer, ui *UI, uint32 PrincipalCompIndex, v2 Point); static v2 TransformPoint(layer_transforms T, real32 Width, real32 Height, v2 Point); static bezier_point * Bezier_LookupAddress(memory *Memory, property_channel *Property, uint16 Index); -static void Bezier_EvaluateValue(project_state *State, bezier_point *PointAddress, v2 *Pos); +static void Bezier_EvaluateValue(project_state *State, bezier_point *PointAddress, v2 *Pos, real32 Y_Increment); static void Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale); diff --git a/imgui_helper_widgets.cpp b/imgui_helper_widgets.cpp index 105dad2..17a9193 100644 --- a/imgui_helper_widgets.cpp +++ b/imgui_helper_widgets.cpp @@ -66,3 +66,21 @@ ImGui_WarpMouseFinish(ui *UI, ImVec2 MousePos) Assert(0); } } + +static ImVec2 +ImGui_Brush_CalcMousePos(project_state *State, ImGuiIO &io, ImVec2 MouseDelta, int32 i, real32 DeltaDistance, real32 DeltaSlope) +{ + 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); + } + return MousePos; +} diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 0000000..1e7e192 --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,189 @@ +/* +The compilation of software known as FreeBSD is distributed under the +following terms: + +Copyright (c) 1992-2014 The FreeBSD Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ + +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "base64.h" + +static const unsigned char base64_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** + * base64_encode - Base64 encode + * @src: Data to be encoded + * @len: Length of the data to be encoded + * @out_len: Pointer to output length variable, or %NULL if not used + * Returns: Allocated buffer of out_len bytes of encoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. Returned buffer is + * nul terminated to make it easier to use as a C string. The nul terminator is + * not included in out_len. + */ + +size_t base64_encode_size(size_t len) +{ + size_t olen; + olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ + olen += olen / 72; /* line feeds */ + olen++; /* nul termination */ + Assert(olen >= len); + return olen; +} + +void base64_encode(const unsigned char *src, size_t len, + unsigned char *out, size_t *out_len) +{ + unsigned char *pos; + const unsigned char *end, *in; + int line_len; + + Assert(out != NULL) + + end = src + len; + in = src; + pos = out; + line_len = 0; + while (end - in >= 3) { + *pos++ = base64_table[in[0] >> 2]; + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = base64_table[in[2] & 0x3f]; + in += 3; + line_len += 4; + if (line_len >= 72) { + *pos++ = '\n'; + line_len = 0; + } + } + + if (end - in) { + *pos++ = base64_table[in[0] >> 2]; + if (end - in == 1) { + *pos++ = base64_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } else { + *pos++ = base64_table[((in[0] & 0x03) << 4) | + (in[1] >> 4)]; + *pos++ = base64_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + line_len += 4; + } + + if (line_len) + *pos++ = '\n'; + + *pos = '\0'; + if (out_len) + *out_len = pos - out; +} + + +/** + * base64_decode - Base64 decode + * @src: Data to be decoded + * @len: Length of the data to be decoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of decoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. + */ +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char dtable[256], *out, *pos, block[4], tmp; + size_t i, count, olen; + int pad = 0; + + // paranoid + // os_memset(dtable, 0x80, 256); + for (i = 0; i < 256; i++) { + dtable[i] = 0x80; + } + + for (i = 0; i < sizeof(base64_table) - 1; i++) + dtable[base64_table[i]] = (unsigned char) i; + dtable[(int)'='] = 0; + + count = 0; + for (i = 0; i < len; i++) { + if (dtable[src[i]] != 0x80) + count++; + } + + if (count == 0 || count % 4) + return NULL; + + olen = count / 4 * 3; + // pos = out = os_malloc(olen); + pos = out = NULL; + Assert(0); + if (out == NULL) + return NULL; + + count = 0; + for (i = 0; i < len; i++) { + tmp = dtable[src[i]]; + if (tmp == 0x80) + continue; + + if (src[i] == '=') + pad++; + block[count] = tmp; + count++; + if (count == 4) { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + if (pad) { + if (pad == 1) + pos--; + else if (pad == 2) + pos -= 2; + else { + /* Invalid padding */ + return NULL; + } + break; + } + } + } + + *out_len = pos - out; + return out; +} + diff --git a/lib/base64.h b/lib/base64.h new file mode 100644 index 0000000..aa21fd0 --- /dev/null +++ b/lib/base64.h @@ -0,0 +1,17 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef BASE64_H +#define BASE64_H + +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len); +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len); + +#endif /* BASE64_H */ diff --git a/main.cpp b/main.cpp index 31572b4..85dd002 100644 --- a/main.cpp +++ b/main.cpp @@ -33,11 +33,13 @@ #define STBI_FAILURE_USERMSG #include "lib/stb_image.h" + #include "defines.h" #include "my_math.h" #include "structs.h" #include "memory.h" +#include "stable_diffusion.h" #include "main.h" #include "debug.h" @@ -57,7 +59,7 @@ static uint64 BitmapBlockSize; static instruction_mode InstructionMode = instruction_mode_scalar; static uint32 RandomGlobalIncrement = 0; -// render_entry Entries[256]; +#include "lib/base64.c" #include "memory.cpp" #include "undo.cpp" @@ -67,6 +69,7 @@ static uint32 RandomGlobalIncrement = 0; #endif #include "createcalls.cpp" // #include "ffmpeg_backend.cpp" +#include "stable_diffusion.cpp" #include "my_imgui_widgets.cpp" #include "prenderer.cpp" #include "gl_calls.cpp" @@ -136,6 +139,16 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, Interact_Transform_Begin(File, Memory, State, io.MousePos, Sorted.CompArray, Sorted.LayerArray); } + bool32 mod_key = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl; + if (mod_key) { + if (ImGui::IsKeyPressed(ImGuiKey_C)) { + Clipboard_Store(File, State, Memory, Sorted.PropertyInfo, Sorted.PropertyArray); + } + if (ImGui::IsKeyPressed(ImGuiKey_V)) { + Clipboard_Paste(File, State, Memory, Sorted.LayerArray); + } + } + ImGui::DockSpaceOverViewport(); if (Debug.ToggleWindow) { @@ -146,58 +159,90 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, if (State->Initializing == 3) { Source_UICreateButton(File, State, Memory, Sorted.CompArray, Sorted.LayerArray); - block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 0); + /* + block_layer *Layera = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 2); + Layera->x.IsToggled = true; + Layera->y.IsToggled = true; + block_layer *Layerb = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 1); + Layerb->x.IsToggled = true; + Layerb->y.IsToggled = true; + block_layer *Layerc = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 0); + Layerc->x.IsToggled = true; + Layerc->y.IsToggled = true; + */ + /* + Layer_Select(Memory, State, 0); + Layer_Select(Memory, State, 1); + Layer_Select(Memory, State, 2); + } + if (State->Initializing == 2) { + block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); + Precomp_UICreateButton(File, State, Memory, MainComp, *Sorted.CompArray, Sorted.LayerArray); + Layer_DeselectAll(Memory, State, File->Layer_Count); + */ + // block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 0); + Layer_Select(Memory, State, 0); + /* History_Entry_Commit(Memory, "Add keyframe"); property_channel *Property = &Layer->x; { - bezier_point Point = { 1, {0, 800, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; + bezier_point Point = { 1, {1, 0, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; Bezier_Add(Memory, Property, Point); } { - bezier_point Point = { 1, {20, 300, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; + bezier_point Point = { 1, {10, 300, -3, 0, 3, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; Bezier_Add(Memory, Property, Point); } { - bezier_point Point = { 1, {10, 200, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; + bezier_point Point = { 1, {20, 300, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; Bezier_Add(Memory, Property, Point); } + Property = &Layer->y; { - bezier_point Point = { 1, {15, 200, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; + bezier_point Point = { 1, {10, 50, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; Bezier_Add(Memory, Property, Point); } - History_Entry_End(Memory); - - /* - History_Entry_Commit(Memory, "Add keyframe"); - Property = &Layer->y; { - bezier_point Point = { 1, {0, 400, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; + bezier_point Point = { 1, {0, -800, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; Bezier_Add(Memory, Property, Point); } { bezier_point Point = { 1, {20, 400, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; Bezier_Add(Memory, Property, Point); } + Property = &Layer->rotation; + { + bezier_point Point = { 1, {0, 0, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; + Bezier_Add(Memory, Property, Point); + } + { + bezier_point Point = { 1, {20, -360, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; + Bezier_Add(Memory, Property, Point); + } + { + bezier_point Point = { 1, {40, 360, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; + Bezier_Add(Memory, Property, Point); + } Property = &Layer->opacity; { bezier_point Point = { 1, {0, 1, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; Bezier_Add(Memory, Property, Point); } { - bezier_point Point = { 1, {20, 0, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; + bezier_point Point = { 1, {35, 0, -5, 0, 5, 0}, interpolation_type_bezier, 0, {0, 0, 0}, 0 }; Bezier_Add(Memory, Property, Point); } - */ - History_Entry_End(Memory); + */ } ImGui_Viewport(File, State, UI, Memory, io, textureID, Sorted.CompArray, Sorted.LayerArray); - ImGui_Timeline(File, State, Memory, UI, io, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyArray); + ImGui_Timeline(File, State, Memory, UI, io, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray); ImGui_File(File, State, Memory, io, Sorted.CompArray, Sorted.LayerArray); ImGui_PropertiesPanel(File, State, UI, Memory, io); ImGui_ColorPanel(File, State, UI, Memory, io); + ImGui_StableDiffusion(File, State, UI, Memory, io); ImGui_Menu(File, State, UI, Memory, io); File_Sort_Pop(Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize); @@ -209,11 +254,26 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, ImGui::EndFrame(); } +static void +Render_Main(void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion) +{ + bool32 IsRendering = true; + Renderer_Start(Data, OutputBuffer, RenderType, RenderRegion); + while (IsRendering) { + // SDL_Delay(1); + // Main_InputTest(File, State, &Memory, &UI); + Renderer_Check(&IsRendering, RenderType); + // TODO(fox): Make interruptable if the render time gets too long. + } +} + static void * -Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, uint16 *SortedPropertyArray, uint32 CompIndex) +Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io, + sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, + sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray, uint32 CompIndex, int32 Frame_Current) { block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); - cache_entry *Entry_Main = Memory_Cache_Search(State, Memory, cache_entry_type_comp, CompIndex, State->Frame_Current); + cache_entry *Entry_Main = Memory_Cache_Search(State, Memory, cache_entry_type_comp, CompIndex, 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); @@ -230,16 +290,69 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io 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->Frame_Start <= State->Frame_Current && - Layer->Frame_End > State->Frame_Current && Layer->IsVisible) + if (Layer->Frame_Start <= Frame_Current && + Layer->Frame_End > Frame_Current && Layer->IsVisible) { + int32 Offset = (State->Interact_Active == interact_type_keyframe_move) ? (int32)State->Interact_Offset[0] : 0; + for (int h = 0; h < AmountOf(Layer->Property); h++) { + property_channel *Property = &Layer->Property[h]; + sorted_property_info *InfoLocation = SortedPropertyInfo + (Index_Physical * 7) + h; + uint16 *ArrayLocation = SortedPropertyArray + (Index_Physical * 7 * MAX_KEYFRAMES_PER_BLOCK) + (h * MAX_KEYFRAMES_PER_BLOCK); + if (Property->Block_Bezier_Count) { + real32 MinY, MaxY; + Property_MinMax_Y(Memory, State, Property, InfoLocation, &MinY, &MaxY); + real32 Y_Increment = 1 / (MaxY - MinY); + v2 FirstPointPos[3]; + bezier_point *FirstPointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[0]); + Bezier_EvaluateValue(State, FirstPointAddress, FirstPointPos); + v2 LastPointPos[3]; + bezier_point *LastPointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[Property->Keyframe_Count - 1]); + Bezier_EvaluateValue(State, LastPointAddress, LastPointPos); + if (FirstPointPos[0].x >= Frame_Current) { + Property->CurrentValue = FirstPointPos[0].y; + } else if (LastPointPos[0].x <= Frame_Current) { + Property->CurrentValue = LastPointPos[0].y; + } else { + int KeyframeIndex = 0; + for (;;) { + v2 PointPos[3]; + bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[KeyframeIndex + 1]); + Bezier_EvaluateValue(State, PointAddress, PointPos, 1, Y_Increment); + if (PointPos[0].x >= Frame_Current) + break; + KeyframeIndex++; + } + v2 PointPos[3]; + bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[KeyframeIndex]); + Bezier_EvaluateValue(State, PointAddress, PointPos, 1, Y_Increment); + v2 NextPointPos[3]; + bezier_point *NextPointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[KeyframeIndex + 1]); + Bezier_EvaluateValue(State, NextPointAddress, NextPointPos, 1, Y_Increment); + if (PointAddress->Type == interpolation_type_hold) { + Property->CurrentValue = PointPos[0].y; + } else if (PointAddress->Type == interpolation_type_linear && NextPointAddress->Type == interpolation_type_linear) { + real32 Ratio = (Frame_Current - PointPos[0].x) / (NextPointPos[0].x - PointPos[0].x); + Property->CurrentValue = PointPos[0].y + ((NextPointPos[0].y - PointPos[0].y) * Ratio); + } else { + Property->CurrentValue = Bezier_SolveYForX(PointPos[0], PointPos[0] + PointPos[2], NextPointPos[0] + NextPointPos[1], NextPointPos[0], Frame_Current); + } + } + } + } + layer_bitmap_state *BitmapState = &State->Render.Bitmap[Index_Physical]; void *BitmapAddress = NULL; if (!Layer->IsPrecomp) { block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); if (Source->Type == source_type_principal) { - BitmapAddress = Memory_Block_AddressAtIndex(Memory, F_PrincipalBitmaps, Source->Bitmap_Index); + if (State->Interact_Active == interact_type_brush && State->Brush.LayerToPaint_Index == Index_Physical) { + // Assert(0); + // Render_Main((void *)T, , RenderRegion); + BitmapAddress = Memory_Block_AddressAtIndex(Memory, F_PrincipalBitmaps, Source->Bitmap_Index); + } else { + 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) { @@ -266,13 +379,8 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io } else { block_composition *Precomp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index); - 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, SortedPropertyArray, Layer->Block_Source_Index); - Entry->CycleTime = GetTime() - Src_TimeStart; - // } - BitmapAddress = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex); + BitmapAddress = Render_Comp(File, State, Memory, io, SortedCompArray, SortedLayerArray, + SortedPropertyInfo, SortedPropertyArray, Layer->Block_Source_Index, (int32)Layer->time.CurrentValue); } Assert(BitmapAddress); @@ -281,38 +389,6 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io // for (int a = 0; a < Layer->Block_Effect_Count; a++) { // } - int32 Offset = (State->Interact_Active == interact_type_keyframe_move) ? (int32)State->Interact_Offset[0] : 0; - for (int h = 0; h < AmountOf(Layer->Property); h++) { - property_channel *Property = &Layer->Property[h]; - uint16 *ArrayLocation = SortedPropertyArray + (i * 7 * MAX_KEYFRAMES_PER_BLOCK) + (h * MAX_KEYFRAMES_PER_BLOCK); - if (Property->Block_Bezier_Count) { - v2 Min, Max; - Property_MinMax(Memory, State, Property, ArrayLocation, &Min, &Max); - if (Min.x >= State->Frame_Current) { - Property->CurrentValue = Min.y; - } else if (Max.x <= State->Frame_Current) { - Property->CurrentValue = Max.y; - } else { - int KeyframeIndex = 0; - for (;;) { - v2 PointPos[3]; - bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[KeyframeIndex + 1]); - Bezier_EvaluateValue(State, PointAddress, PointPos); - if (PointPos[0].x >= State->Frame_Current) - break; - KeyframeIndex++; - } - v2 PointPos[3]; - bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[KeyframeIndex]); - Bezier_EvaluateValue(State, PointAddress, PointPos); - v2 NextPointPos[3]; - bezier_point *NextPointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[KeyframeIndex + 1]); - Bezier_EvaluateValue(State, NextPointAddress, NextPointPos); - Property->CurrentValue = Bezier_SolveYForX(PointPos[0], PointPos[0] + PointPos[2], NextPointPos[0] + NextPointPos[1], NextPointPos[0], State->Frame_Current); - } - } - } - /* for (int h = 0; h < AmountOf(Layer->Property); h++) { property_channel *Property = &Layer->Property[h]; @@ -326,13 +402,7 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io T.SourceBuffer = BitmapAddress; rectangle RenderRegion = {0, 0, Comp->Width, Comp->Height}; - bool32 IsRendering = true; - Renderer_Start((void *)&T, CompBuffer, RenderRegion); - while (IsRendering) { - SDL_Delay(1); - Renderer_Check(&IsRendering); - // TODO(fox): Make interruptable if the render time gets too long. - } + Render_Main((void *)&T, CompBuffer, render_type_main, RenderRegion); } } Entry_Main->CycleTime = GetTime() - Comp_TimeStart; @@ -349,7 +419,8 @@ Main_Renderer(project_data *File, project_state *State, memory *Memory, SDL_Wind sorted_file Sorted = File_Sort_Push(File, State, Memory); - void *MainCompBuffer = Render_Comp(File, State, Memory, io, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyArray, File->PrincipalCompIndex); + void *MainCompBuffer = Render_Comp(File, State, Memory, io, Sorted.CompArray, Sorted.LayerArray, + Sorted.PropertyInfo, Sorted.PropertyArray, File->PrincipalCompIndex, State->Frame_Current); File_Sort_Pop(Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize); @@ -402,7 +473,7 @@ int main(int argc, char *argv[]) { 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"); + Memory_InitTable(&GlobalMemory, &Memory, (uint64)50 * 1024 * 1024, B_CachedBitmaps, "Cached bitmap buffer"); #if ARM @@ -416,16 +487,26 @@ int main(int argc, char *argv[]) { } #endif - - project_state *State = (project_state *)Memory.Slot[P_MiscCache].Address; - *State = {}; + project_state State_ = {}; + project_state *State = &State_; project_data *File = (project_data *)Memory_Block_AllocateAddress(&Memory, F_File); *File = {}; File->Occupied = 1; - State->Brush.PaintBuffer = Memory.Slot[B_ScratchSpace].Address; + // NOTE(fox): Right now I'm just gonna throw all dynamic allocs that can't + // be simplified to the push/pop model here; will worry about how to best + // use RAM later. + + State->Brush.PaintBuffer = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); uint64 ScratchPaintSize = 2048*2048*4; Memory.ScratchPos += ScratchPaintSize; + State->Brush.TransientBitmap = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); + ScratchPaintSize = 2048*2048*4; + Memory.ScratchPos += ScratchPaintSize; + + State->ClipboardBuffer = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); + State->ClipboardSize = 1024*1024; + Memory.ScratchPos += State->ClipboardSize; ui UI = {}; UI.Test = ImDrawListSplitter(); @@ -438,8 +519,8 @@ int main(int argc, char *argv[]) { block_composition *MainComp = (block_composition *)Memory_Block_AllocateAddress(&Memory, F_Precomps); - MainComp->Width = 1024; - MainComp->Height = 512; + MainComp->Width = 1280; + MainComp->Height = 720; MainComp->FPS = 24; MainComp->BytesPerPixel = 4; MainComp->Frame_Count = 48; @@ -763,8 +844,8 @@ int main(int argc, char *argv[]) { GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); - 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_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); diff --git a/main.h b/main.h index 26b3666..e0a9374 100644 --- a/main.h +++ b/main.h @@ -90,6 +90,28 @@ struct block_bezier { bezier_point Point[MAX_KEYFRAMES_PER_BLOCK]; }; +enum selection_type +{ + selection_none, + selection_layer, + selection_effect, + selection_keyframe, + selection_maskpoint, + selection_source +}; + +struct clipboard_channel { + void *Name; + uint16 LayerOffset; + uint16 KeyframeCount; +}; + +struct clipboard_contents { + selection_type Type; + clipboard_channel Channel[16]; + uint16 ChannelCount; +}; + struct layer_bitmap_state { // Image and video bool32 ToUpdate = 1; @@ -120,11 +142,13 @@ struct sorted_property_info { uint32 MinYIndex; uint32 MaxYIndex; + bool32 IsGraphSelected; }; struct sorted_comp_info { uint32 LayerCount; + uint32 CurrentSortIndex; // Used intermediately in the sorting algorithm }; struct sorted_layer @@ -227,12 +251,14 @@ char *BrushNames[brush_amount] = { struct brush_state { ImVec2 UIPos; // Initial position when ctrl is held - real32 Size = 15; // Maxes at 1024 for now + real32 Size = 512; // 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; + void *TransientBitmap; + uint32 LayerToPaint_Index = -1; rectangle CacheBounds; }; @@ -245,7 +271,7 @@ enum interact_type interact_type_keyframe_move, interact_type_keyframe_scale, interact_type_keyframe_rotate, - interact_type_newlayer_paint + interact_type_brush }; char *ToolName[] { @@ -288,12 +314,17 @@ struct project_state pen_state Pen = {}; brush_state Brush; + sd_state SD; + char DummyName2[512]; bool32 IsRunning = 1; bool32 IsPlaying; bool32 FirstFrame = 1; + void *ClipboardBuffer; + uint64 ClipboardSize; + int16 MostRecentlySelectedLayer = -1; // selection_type RecentSelectionType = selection_none; @@ -376,6 +407,7 @@ struct property_header real32 DefaultVal; real32 MinVal; real32 MaxVal; + bool32 AlwaysInteger; }; struct property_channel { @@ -388,6 +420,7 @@ struct property_channel { real32 CurrentValue; real32 MaxVal; real32 MinVal; + bool32 AlwaysInteger; real32 ScrubVal; // increment when dragging on sliders, etc. bool32 IsToggled; @@ -476,9 +509,36 @@ struct transform_info { void *SourceBuffer; }; +struct brush_info { + uint32 BrushLength; + rectangle LayerBounds; + uint32 LayerPitch; + uint32 BrushPitch; + int32 ExtraX; + int32 ExtraY; + render_byte_info LayerBits; + render_byte_info BrushBits; + int BytesPerPixel; + int SourceWidth; + int SourceBytesPerPixel; + void *BrushBuffer; + real32 R_Brush; + real32 G_Brush; + real32 B_Brush; + real32 A_Brush; + uint8 *BrushRow; +}; + +enum render_type { + render_type_main, + render_type_direct, + render_type_brush +}; + struct render_entry { void *RenderData; void *OutputBuffer; + render_type RenderType; rectangle RenderRegion; }; @@ -538,17 +598,6 @@ struct main_sdl SDL_Renderer *Renderer; }; -// used to determine what to copy/paste, delete, etc -enum selection_type -{ - selection_none, - selection_layer, - selection_effect, - selection_keyframe, - selection_maskpoint, - selection_source -}; - char *ToolName[] { "Move", "Pen" diff --git a/memory.cpp b/memory.cpp index 53388bf..4593d49 100644 --- a/memory.cpp +++ b/memory.cpp @@ -26,16 +26,18 @@ Memory_Block_AllocateNew(memory *Memory, memory_table_list TableName) } static void * -Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 Index) +Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 Index, bool32 AssertExists = 1) { memory_table *Table = &Memory->Slot[TableName]; Assert(Table->Block_ElementSize != 0); uint8 *Address = (uint8 *)Table->Address + (Table->Block_ElementSize * Index); + if (AssertExists) + Assert(*Address != 0); return (void *)Address; } static uint16 -Memory_Block_IndexAtAddress(memory *Memory, memory_table_list TableName, void *Address) +Memory_Block_LazyIndexAtAddress(memory *Memory, memory_table_list TableName, void *Address) { memory_table *Table = &Memory->Slot[TableName]; return ((uint8 *)Address - (uint8 *)Table->Address) / Table->Block_ElementSize; @@ -45,7 +47,7 @@ static void * Memory_Block_AllocateAddress(memory *Memory, memory_table_list TableName) { uint16 FileIndex = Memory_Block_AllocateNew(Memory, TableName); - return Memory_Block_AddressAtIndex(Memory, TableName, FileIndex); + return Memory_Block_AddressAtIndex(Memory, TableName, FileIndex, 0); } // IMPORTANT(fox): All block data has to start with a uint8 Occupied variable! @@ -60,7 +62,7 @@ Block_Loop(memory *Memory, memory_table_list TableName, uint32 TotalCount, int * *HasIncremented = 0; (*Index)++; } - uint8 *Occupied = (uint8 *)Memory_Block_AddressAtIndex(Memory, TableName, *Index); + uint8 *Occupied = (uint8 *)Memory_Block_AddressAtIndex(Memory, TableName, *Index, 0); if (*Occupied) { *HasIncremented = 1; (*CurrentCount)++; @@ -179,23 +181,6 @@ 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_type Type, uint32 TypeInfo, uint32 TypeInfo_Sub) { @@ -203,10 +188,17 @@ Memory_Cache_Search(project_state *State, memory *Memory, cache_entry_type Type, int c = 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]; + if (Type == cache_entry_type_comp) { + if (EntryArray[c].Type == Type && + EntryArray[c].TypeInfo == TypeInfo) { + return &EntryArray[c]; + } + } else { + if (EntryArray[c].Type == Type && + EntryArray[c].TypeInfo == TypeInfo && + EntryArray[c].TypeInfo_Sub == TypeInfo_Sub) { + return &EntryArray[c]; + } } c++; count--; diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index 04cedb0..bfe114b 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -52,9 +52,12 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * 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); + if (ImGui::Button("K")) { + History_Entry_Commit(Memory, "Add keyframe"); + bezier_point Point = { 1, {(real32)State->Frame_Current, Property->CurrentValue, -1, 0, 1, 0}, interpolation_type_linear, 0, {0, 0, 0}, 0 }; + Bezier_Add(Memory, Property, Point); + History_Entry_End(Memory); + } ImGui::SameLine(); ImGui_InteractSliderProperty(State, Memory, Property); ImGui::PopID(); @@ -83,15 +86,19 @@ ImGui_DebugMemoryViewer(memory *Memory, project_state *State) cache_entry *EntryArray = State->Render.Entry; char *Type[4] = { "unassigned", "comp", "source", "layer" }; - int c = 0; uint32 Blocks_Total = Memory->Slot[B_CachedBitmaps].Size / BitmapBlockSize; uint32 PerRow = sqrt(Blocks_Total); real32 BlockSize = ViewportScale.x / PerRow; - while (EntryArray[c+1].CycleTime != 0) { + for (int c = 0; c < Memory->EntryCount; c++) { ImGui::PushID(c); cache_entry Entry = EntryArray[c]; - cache_entry NextEntry = EntryArray[c+1]; - uint32 BlockSpan = NextEntry.Block_StartIndex - Entry.Block_StartIndex; + uint32 BlockSpan; + if (c+1 != Memory->EntryCount) { + cache_entry NextEntry = EntryArray[c+1]; + BlockSpan = NextEntry.Block_StartIndex - Entry.Block_StartIndex; + } else { + BlockSpan = 1; + } ImVec2 ButtonPos = ViewportMin + ImVec2((Entry.Block_StartIndex % PerRow) * BlockSize, BlockSize * (Entry.Block_StartIndex / PerRow)); ImVec2 ButtonSize = ImVec2(BlockSpan * BlockSize, BlockSize); ImGui::SetCursorScreenPos(ButtonPos); @@ -111,7 +118,6 @@ ImGui_DebugMemoryViewer(memory *Memory, project_state *State) ImGui::Text("Type - %s, Start - %i, Info - %i, %i", Type[EntryArray[c].Type], EntryArray[c].Block_StartIndex, EntryArray[c].TypeInfo, EntryArray[c].TypeInfo_Sub); ImGui::EndTooltip(); } - c++; ImGui::PopID(); } // ImGui::PopStyleVar(2); @@ -230,6 +236,54 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io, ImGui::End(); } +static void +ImGui_StableDiffusion(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io) +{ + ImGui::Begin("SD prompt input"); + sd_state *SD = &State->SD; + int Size = ImGui::GetFontSize(); + ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(200, 80, 0, 255)); + if (ImGui::Button("Generate!", ImVec2(Size*8, Size*2))) { + /* + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 0); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); + cache_entry *Entry = Memory_Cache_Search(State, Memory, cache_entry_type_source, Layer->Block_Source_Index, 0); + Assert(Entry->IsCached); + void *BitmapAddress = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex); + uint64 Size = Source->Width * Source->Height * Source->BytesPerPixel; + uint64 EncodedLength = 0; + uint64 EncodedAllocSize = base64_encode_size(Size); + void *EncodedOutput = Memory_PushScratch(Memory, EncodedSize); + uint64 EncodedTrueSize; + base64_encode((uint8 *)BitmapAddress, Size, (uint8 *)EncodedOutput, &EncodedTrueSize); + Memory_PopScratch(Memory, EncodedSize); + */ + SD_Txt2Txt(SD); + } + ImGui::InputText("Address", SD->ServerAddress, SD_LEN_ADDRESS); + if (State->Initializing && (SD->ServerAddress[0] == '\0')) { + sprintf(SD->Prompt, "%s", "1girl, looking at viewer, smile, hakurei reimu, cowboy shot"); + sprintf(SD->NegPrompt, "%s", "nsfw, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark"); + sprintf(SD->ServerAddress, "%s", "http://127.0.0.1:7860"); + } + ImGui::PopStyleColor(); + ImGui::InputTextMultiline("Prompt", SD->Prompt, SD_LEN_PROMPT); + ImGui::InputTextMultiline("Negative prompt", SD->NegPrompt, SD_LEN_PROMPT); + ImGui::SliderInt("Steps", &SD->Steps, 0, 150); + ImGui::SliderInt("Width", &SD->Width, 64, 2048, "%i px"); + if (ImGui::IsItemDeactivatedAfterEdit()) { + SD->Width = SD->Width + (64 - (SD->Width % 64)); + } + ImGui::SliderInt("Height", &SD->Height, 64, 2048, "%i px"); + if (ImGui::IsItemDeactivatedAfterEdit()) { + SD->Height = SD->Height + (64 - (SD->Height % 64)); + } + ImGui::SliderFloat("CFG scale", &SD->CFG, 1, 30, "%.2f"); + ImGui::SliderFloat("Denoising strength", &SD->DenoisingStrength, 0, 1, "%.2f"); + ImGui::InputInt("Seed", &SD->Seed); + ImGui::End(); +} + static void ImGui_ColorPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io) { @@ -444,7 +498,7 @@ ImGui_TransformUI(project_data *File, project_state *State, memory *Memory, ui * // 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); + v2 LayerPoint = Transform_ScreenSpaceToLocal(BoxTransforms, CompWidth, CompHeight, BoxLength.x, BoxLength.y, UI->CompPos, UI->CompZoom, ViewportMin, io.MousePos); real32 U = LayerPoint.x / BoxLength.x; real32 V = LayerPoint.y / BoxLength.y; @@ -744,7 +798,6 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, UI->FocusedWindow = focus_viewport; block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); - block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 0); ImVec2 ViewportMin = ImGui::GetCursorScreenPos(); @@ -763,7 +816,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImDrawList* draw_list = ImGui::GetWindowDrawList(); draw_list->AddRectFilled(ViewportMin, ViewportMax, IM_COL32(50, 50, 50, 255)); draw_list->AddRect(ViewportMin, ViewportMax, IM_COL32(255, 255, 255, 255)); - draw_list->AddRect(CompPosMin, CompPosMax, IM_COL32(255, 255, 255, 55)); + // draw_list->AddRect(CompPosMin, CompPosMax, IM_COL32(255, 255, 255, 55)); // Actual composition texture draw_list->PushClipRect(ViewportMin, ViewportMax, true); @@ -787,29 +840,67 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImGui::InvisibleButton("canvas", ViewportScale, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); bool32 IsHovered = ImGui::IsItemHovered(); +#if 0 bool32 IsActive = ImGui::IsItemActive(); bool32 IsActivated = ImGui::IsItemActivated(); +#else + bool32 IsActive = ImGui::IsKeyDown(ImGuiKey_3); + bool32 IsActivated = ImGui::IsKeyPressed(ImGuiKey_3); +#endif bool32 IsDeactivated = ImGui::IsItemDeactivated(); - if (IsHovered && IsActivated && ImGui::IsMouseDown(ImGuiMouseButton_Left)) + if (IsHovered && IsActivated && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) { // 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); + if (State->Tool == tool_brush) { + sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, File->PrincipalCompIndex); + sorted_comp_info SortedCompInfo = SortedCompArray[File->PrincipalCompIndex]; + 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); + if (Layer->IsSelected && Source->Type == source_type_principal) { + State->Interact_Active = interact_type_brush; + State->Brush.LayerToPaint_Index = Layer->Block_Source_Index; + } + } + if (State->Brush.LayerToPaint_Index == -1) { + State->Interact_Active = interact_type_brush; + Layer_DeselectAll(File, State, Memory); + Arbitrary_Zero((uint8 *)State->Brush.TransientBitmap, 2048*2048*4); + History_Entry_Commit(Memory,"Paint new layer"); + uint16 i = Source_Generate_Blank(File, State, Memory, MainComp->Width, MainComp->Height, MainComp->BytesPerPixel); + block_layer *Layer = Layer_Init(File, Memory); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); + State->Brush.LayerToPaint_Index = Memory_Block_LazyIndexAtAddress(Memory, F_Layers, (void *)Layer); + Layer->Block_Source_Index = i; + Layer->x.CurrentValue = MainComp->Width / 2; + Layer->y.CurrentValue = MainComp->Height / 2; + int TopOffset = 0; + sorted_comp_info SortedCompInfo = SortedCompArray[File->PrincipalCompIndex]; + if (SortedCompInfo.LayerCount) + { + 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; + } + Layer->Vertical_Offset = TopOffset - 1; + Layer->Frame_Start = MainComp->Frame_Start; + Layer->Frame_End = MainComp->Frame_End; + Layer->IsSelected = true; + History_Entry_End(Memory); + State->UpdateFrame = true; + } } // Layer selection 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); + Layer_DeselectAll(File, State, Memory); if (Selection != -1) Layer_Select(Memory, State, Selection); } @@ -832,9 +923,10 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, } bool32 OtherActions = ImGui::IsKeyDown(ImGuiKey_Z) || ImGui::IsMouseDown(ImGuiMouseButton_Right); - if (State->Tool == tool_brush) { + if (State->Tool == tool_brush && State->Interact_Active == interact_type_brush) { + Assert(State->Brush.LayerToPaint_Index != -1); if (IsActive && !OtherActions) { - block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 0); + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, State->Brush.LayerToPaint_Index); 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); @@ -844,31 +936,19 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, 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); + ImVec2 MousePos = ImGui_Brush_CalcMousePos(State, io, MouseDelta, i, DeltaDistance, DeltaSlope); + Brush_Render(State, UI, T_Layer, MainComp, Source, SourceBitmapAddress, ViewportMin, MousePos); } } 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); + Brush_Render(State, UI, T_Layer, MainComp, Source, SourceBitmapAddress, ViewportMin, MousePos); } - Memory_Cache_Invalidate(State, Memory, cache_entry_type_comp, Layer->Block_Composition_Index, 0); + // Memory_Cache_Invalidate(State, Memory, cache_entry_type_comp, Layer->Block_Composition_Index, 0); State->UpdateFrame = true; } if (IsDeactivated) { + State->Brush.LayerToPaint_Index = -1; State->Interact_Active = interact_type_none; } } @@ -956,7 +1036,7 @@ ImGui_TimelineHorizontalIncrementDraw(project_state *State, ui *UI, ImDrawList * static void -ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io) +ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray) { bool open = true; ImGui::Begin("Graph info", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); @@ -975,8 +1055,14 @@ ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI for (int h = 0; h < AmountOf(Layer->Property); h++) { property_channel *Property = &Layer->Property[h]; if (Property->Block_Bezier_Count) { + sorted_property_info *InfoLocation = SortedPropertyInfo + (i * 7) + h; + uint16 *ArrayLocation = SortedPropertyArray + (i * 7 * MAX_KEYFRAMES_PER_BLOCK) + (h * MAX_KEYFRAMES_PER_BLOCK); ImGui::PushID(Property); - ImGui::Text(Property->Name); + if (ImGui::Selectable(Property->Name, InfoLocation->IsGraphSelected)) { + Property_DeselectAll(File, Memory, SortedPropertyArray); + bezier_point *FirstPointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[0]); + FirstPointAddress->IsSelected = true; + } ImGui::PopID(); } } @@ -987,16 +1073,78 @@ ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI ImGui::End(); } +static void +ImGui_Timeline_DrawKeySheet(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, ImDrawList *draw_list, property_channel *Property, uint16 *ArrayLocation, + ImVec2 Increment, ImVec2 TimelineAbsolutePos, ImVec2 TimelineMoveSize, ImVec2 TimelineZoomSize, + ImVec2 TimelineSize, ImVec2 TimelineSizeWithBorder, real32 LayerIncrement) +{ + ImGui::PushID(Property); + for (int p = 0; p < Property->Keyframe_Count; p++) { + int k = ArrayLocation[p]; + bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, k); + + v2 PointPos[3]; + Bezier_EvaluateValue(State, PointAddress, PointPos); + + real32 LocalPos_Ratio_X = PointPos[0].x * Increment.x; + real32 Keyframe_ScreenPos_X = TimelineAbsolutePos.x + TimelineMoveSize.x + LocalPos_Ratio_X * TimelineZoomSize.x; + + ImVec2 Keyframe_ScreenPos(Keyframe_ScreenPos_X, TimelineAbsolutePos.y); + + if (UI->BoxSelect) { + real32 Y_Top = (io.MouseClickedPos[0].y < io.MousePos.y) ? io.MouseClickedPos[0].y : io.MousePos.y; + real32 Y_Bottom = (io.MouseClickedPos[0].y > io.MousePos.y) ? io.MouseClickedPos[0].y : io.MousePos.y; + real32 X_Left = (io.MouseClickedPos[0].x < io.MousePos.x) ? io.MouseClickedPos[0].x : io.MousePos.x; + real32 X_Right = (io.MouseClickedPos[0].x > io.MousePos.x) ? io.MouseClickedPos[0].x : io.MousePos.x; + + if (Keyframe_ScreenPos.y >= Y_Top && Keyframe_ScreenPos.y <= Y_Bottom && + Keyframe_ScreenPos.x >= X_Left && Keyframe_ScreenPos.x <= X_Right) + { + if (!PointAddress->IsSelected) { + PointAddress->IsSelected = 1; + } + } else if (!io.KeyShift) { + PointAddress->IsSelected = 0; + } + } + + ImVec2 ButtonSize(16, 16); + + ImGui::PushID(p); + + ImU32 PointCol = (PointAddress->IsSelected) ? ImColor(0.8f, 0.5f, 0.0f, 1.0f) : ImColor(0.1f, 0.1f, 0.1f, 1.0f); + ImU32 LineCol = (PointAddress->IsSelected) ? ImColor(0.8f, 0.5f, 0.5f, 1.0f) : ImColor(0.4f, 0.4f, 0.4f, 1.0f); + ImGui::SetCursorScreenPos(Keyframe_ScreenPos - (ButtonSize * 0.5)); + ImGui::InvisibleButton("##keyframemover", ButtonSize, ImGuiMouseButton_Left); + bool32 IsHovered = ImGui::IsItemHovered(); + bool32 IsItemActive = ImGui::IsItemActive(); + bool32 IsItemActivated = ImGui::IsItemActivated(); + bool32 IsItemDeactivated = ImGui::IsItemDeactivated(); + bool32 LeftClick = ImGui::IsMouseDown(ImGuiMouseButton_Left); + bool32 RightClick = ImGui::IsMouseDown(ImGuiMouseButton_Right); + + if (IsHovered) + PointCol = ImColor(1.0f, 0.8f, 0.8f, 1.0f); + + if (IsItemActivated) { + PointAddress->IsSelected = 1; + } + + draw_list->AddCircleFilled(Keyframe_ScreenPos, 4, PointCol); + + ImGui::PopID(); + } + ImGui::PopID(); +} + static void ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, ImDrawList *draw_list, ImVec2 Increment, ImVec2 TimelineAbsolutePos, ImVec2 TimelineMoveSize, ImVec2 TimelineZoomSize, - ImVec2 TimelineSize, ImVec2 TimelineSizeWithBorder, real32 LayerIncrement, uint16 *SortedPropertyArray) + ImVec2 TimelineSize, ImVec2 TimelineSizeWithBorder, real32 LayerIncrement, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray) { + // I'm using the draw splitter here to be able to draw the dots on top of the graph lines. UI->Test.Split(draw_list, 2); - TimelineMoveSize.y = TimelineMoveSize.y + (TimelineZoomSize.y * (0.25 / 4)); - TimelineZoomSize.y = TimelineZoomSize.y * 0.6; - int h = 0, c = 0, i = 0; while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) { @@ -1006,44 +1154,63 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor int32 Frame_Start = Layer->Frame_Start; - ImVec2 Layer_ScreenPos_Min = TimelineAbsolutePos + TimelineMoveSize; // (* TimelineZoomSize); - ImGui::PushID(i); - ImU32 col = IM_COL32(255, 255, 255, 255); - - if (State->Interact_Active == interact_type_keyframe_move) { - ImVec2 DragDelta = io.MousePos - ImVec2(State->Interact_Offset[2], State->Interact_Offset[3]); - // NOTE(fox): I'm setting the X (time) to the transformed value and - // the Y (value) to the raw drag delta, because the Y units can be - // normalized while the X units are always universal across all the - // graphs (and it has to be passed into the sorter). - State->Interact_Offset[0] = (DragDelta.x / TimelineZoomSize.x) / Increment.x; - State->Interact_Offset[1] = DragDelta.y; - DebugWatchVar("DeltaX: ", &DragDelta.x, d_float); - DebugWatchVar("Deltay: ", &DragDelta.y, d_float); - } else if (State->Interact_Active == interact_type_keyframe_scale) { - ImVec2 DragDelta = io.MousePos - ImVec2(State->Interact_Offset[2], State->Interact_Offset[3]); - State->Interact_Offset[0] = (DragDelta.x / TimelineSizeWithBorder.x * UI->TimelinePercentZoomed.x) / Increment.x; - // TODO(fox): Pass min/max to sort to calculate this better! - } - - if ((io.MouseDelta.x || io.MouseDelta.y) && - (State->Interact_Active == interact_type_keyframe_move || + if ((State->Interact_Active == interact_type_keyframe_move || State->Interact_Active == interact_type_keyframe_rotate || State->Interact_Active == interact_type_keyframe_scale)) { - // Memory_Cache_Invalidate(State, Memory, cache_entry_type_comp, Lay + ImGui_WarpMouse(UI, io.MousePos, TimelineAbsolutePos, TimelineAbsolutePos + TimelineSizeWithBorder); + ImVec2 DragDelta = io.MousePos - ImVec2(State->Interact_Offset[2], State->Interact_Offset[3]); + DragDelta = DragDelta + (ImVec2(UI->Warp_X, UI->Warp_Y) * TimelineSize); + if (io.MouseDelta.x || io.MouseDelta.y) { + State->UpdateFrame = true; + } + if (State->Interact_Active == interact_type_keyframe_move) { + // The Y increment varies between graphs, so we have to do it in the Bezier_EvaluateValue call. + State->Interact_Offset[0] = (DragDelta.x / TimelineZoomSize.x) / Increment.x; + State->Interact_Offset[1] = DragDelta.y; + } else if (State->Interact_Active == interact_type_keyframe_scale) { + State->Interact_Offset[0] = (DragDelta.x / TimelineSizeWithBorder.x * UI->TimelinePercentZoomed.x) / Increment.x; + } else if (State->Interact_Active == interact_type_keyframe_rotate) { + State->Interact_Offset[0] = (DragDelta.x / TimelineZoomSize.x); + /* + real32 Slope_Old = (Keyframe_ScreenPos.y - State->Interact_Offset[3]) / (Keyframe_ScreenPos.x - State->Interact_Offset[2]); + real32 Slope_New = (Keyframe_ScreenPos.y - io.MousePos.y) / (Keyframe_ScreenPos.x - io.MousePos.x); + State->Interact_Offset[0] = atan((Slope_Old - Slope_New) / (1 + Slope_Old * Slope_New)); + */ + } } for (int h = 0; h < AmountOf(Layer->Property); h++) { property_channel *Property = &Layer->Property[h]; + sorted_property_info *InfoLocation = SortedPropertyInfo + (i * 7) + h; uint16 *ArrayLocation = SortedPropertyArray + (i * 7 * MAX_KEYFRAMES_PER_BLOCK) + (h * MAX_KEYFRAMES_PER_BLOCK); ImGui::PushID(Property); if (Property->Block_Bezier_Count) { - v2 Min, Max; - Property_MinMax(Memory, State, Property, ArrayLocation, &Min, &Max); - real32 Y_Increment = 1 / (Max.y - Min.y); + real32 MinY, MaxY; + Property_MinMax_Y(Memory, State, Property, InfoLocation, &MinY, &MaxY, 0); + real32 Y_Increment = 1 / (MaxY - MinY); + + real32 GraphScale = 0; + real32 GraphPos = 0; + if ((1 / Y_Increment) < 5) { + GraphScale = 0.2; + GraphPos = 0.3; + } else if ((1 / Y_Increment) > 700) { + GraphScale = 0.6; + GraphPos = 0.06; + } else { + GraphScale = 0.4; + GraphPos = 0.2; + } + + + real32 GraphMoveHeight = TimelineMoveSize.y + (TimelineZoomSize.y * GraphPos); + real32 GraphZoomHeight = TimelineZoomSize.y * GraphScale; + + uint32 GraphCol = InfoLocation->IsGraphSelected ? IM_COL32(255, 180, 150, 255) : IM_COL32(255, 255, 255, 70); + bezier_point *PointAddress[2] = {}; ImVec2 Keyframe_ScreenPos[6] = {}; for (int p = 0; p < Property->Keyframe_Count; p++) { @@ -1054,14 +1221,14 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor PointAddress[Idx] = Bezier_LookupAddress(Memory, Property, k); v2 PointPos[3]; - Bezier_EvaluateValue(State, PointAddress[Idx], PointPos); + Bezier_EvaluateValue(State, PointAddress[Idx], PointPos, GraphZoomHeight, Y_Increment); ImVec2 Keyframe_LocalPos[3] = { V2(PointPos[0]), V2(PointPos[0] + PointPos[1]), V2(PointPos[0] + PointPos[2]) }; ImVec2 Keyframe_LocalPos_Ratio[3]; for (int b = 0; b < 3; b++) { - Keyframe_LocalPos_Ratio[b] = (Keyframe_LocalPos[b] - ImVec2(0, Min.y)) * ImVec2(Increment.x, Y_Increment); - Keyframe_ScreenPos[NewIdx + b] = TimelineAbsolutePos + TimelineMoveSize + ((ImVec2(1, 1) * Keyframe_LocalPos_Ratio[b]) * TimelineZoomSize); + Keyframe_LocalPos_Ratio[b] = (Keyframe_LocalPos[b] - ImVec2(0, MinY)) * ImVec2(Increment.x, Y_Increment); + Keyframe_ScreenPos[NewIdx + b] = TimelineAbsolutePos + ImVec2(TimelineMoveSize.x, GraphMoveHeight) + ((ImVec2(1, -1) * Keyframe_LocalPos_Ratio[b] + ImVec2(0, 1)) * ImVec2(TimelineZoomSize.x, GraphZoomHeight)); } if (UI->BoxSelect) { @@ -1110,10 +1277,16 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor if (b != 0 && PointAddress[Idx]->IsSelected) draw_list->AddLine(Keyframe_ScreenPos[NewIdx], Keyframe_ScreenPos[NewIdx + b], LineCol, 2.0f); - if (b == 0) + if (b == 0) { draw_list->AddCircleFilled(Keyframe_ScreenPos[NewIdx + b], 4, PointCol); - else + if (InfoLocation->IsGraphSelected) { + char buf[8]; + sprintf(buf, "%.2f", Keyframe_LocalPos[0].y); + draw_list->AddText(Keyframe_ScreenPos[NewIdx + b], 0xFFFFFFFF, buf); + } + } else { draw_list->AddCircle(Keyframe_ScreenPos[NewIdx + b], 6, PointCol, 0, 2); + } ImGui::PopID(); } @@ -1124,9 +1297,9 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor if (p != 0) { if (PointAddress[0]->Type == interpolation_type_bezier && PointAddress[1]->Type == interpolation_type_bezier) { draw_list->AddBezierCubic(Keyframe_ScreenPos[OldIdx], Keyframe_ScreenPos[OldIdx + 2], - Keyframe_ScreenPos[NewIdx + 1], Keyframe_ScreenPos[NewIdx], col, 1.0f, 0); + Keyframe_ScreenPos[NewIdx + 1], Keyframe_ScreenPos[NewIdx], GraphCol, 1.0f, 0); } else { - draw_list->AddLine(Keyframe_ScreenPos[0], Keyframe_ScreenPos[3], col, 1.0f); + draw_list->AddLine(Keyframe_ScreenPos[0], Keyframe_ScreenPos[3], GraphCol, 1.0f); } } } @@ -1144,7 +1317,7 @@ static void ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, ImDrawList *draw_list, uint16 CompIndex, ImVec2 Increment, ImVec2 TimelineAbsolutePos, ImVec2 TimelineMoveSize, ImVec2 TimelineZoomSize, ImVec2 TimelineSize, ImVec2 TimelineSizeWithBorder, real32 LayerIncrement, - sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray) + sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray) { block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); sorted_comp_info SortedCompInfo = SortedCompArray[CompIndex]; @@ -1152,29 +1325,60 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem ImGui::PushID(CompIndex); - if (UI->TimelineMode == timeline_mode_default) { + // Layers are drawn from top to bottom, so we can account for opened precomps/keyframes + // without needing another loop. + real32 DisplayOffset = 0; + 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); + + int32 Frame_Start = Layer->Frame_Start; + int32 Frame_End = Layer->Frame_End; + real32 Vertical_Offset = SortEntry.SortedOffset + DisplayOffset; + + Layer_Evaluate_Display(Layer, SortedLayerArray, SortedCompArray, SortedLayerInfo, i, &DisplayOffset); - 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); - - int32 Frame_Start = Layer->Frame_Start; - int32 Frame_End = Layer->Frame_End; - real32 Vertical_Offset = SortEntry.SortedOffset; - if (Layer->IsSelected) - Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End); - ImVec2 Layer_LocalPos = ImVec2(Frame_Start, Vertical_Offset); - ImVec2 Layer_LocalSize = ImVec2(Frame_End - Frame_Start, Layer->Vertical_Height); - - ImVec2 Layer_LocalPos_Ratio = (Layer_LocalPos * Increment); - ImVec2 Layer_LocalSize_Ratio = Layer_LocalSize * Increment; - ImVec2 Layer_ScreenPos_Min = TimelineAbsolutePos + TimelineMoveSize + (Layer_LocalPos_Ratio * TimelineZoomSize); - ImVec2 Layer_ScreenPos_Max = TimelineAbsolutePos + TimelineMoveSize + ((Layer_LocalPos_Ratio + Layer_LocalSize_Ratio) * TimelineZoomSize); - ImVec2 Layer_ScreenSize = Layer_ScreenPos_Max - Layer_ScreenPos_Min; - - ImGui::PushID(i); + if (Layer->IsSelected) + Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End); + + ImVec2 Layer_LocalPos = ImVec2(Frame_Start, Vertical_Offset); + ImVec2 Layer_LocalSize = ImVec2(Frame_End - Frame_Start, Layer->Vertical_Height); + + ImVec2 Layer_LocalPos_Ratio = (Layer_LocalPos * Increment); + ImVec2 Layer_LocalSize_Ratio = Layer_LocalSize * Increment; + ImVec2 Layer_ScreenPos_Min = TimelineAbsolutePos + TimelineMoveSize + (Layer_LocalPos_Ratio * TimelineZoomSize); + ImVec2 Layer_ScreenPos_Max = TimelineAbsolutePos + TimelineMoveSize + ((Layer_LocalPos_Ratio + Layer_LocalSize_Ratio) * TimelineZoomSize); + ImVec2 Layer_ScreenSize = Layer_ScreenPos_Max - Layer_ScreenPos_Min; + + // UI + + ImU32 LayerColor = 0; + ImU32 BorderColor = 0; + LayerColor = ImColor(UI->LayerColors[Layer->ColIndex]); + BorderColor = ImColor(0.2, 0.2, 0.2, 1.0f); + + draw_list->AddRectFilled(Layer_ScreenPos_Min, Layer_ScreenPos_Max, LayerColor); + draw_list->AddRect(Layer_ScreenPos_Min, Layer_ScreenPos_Max, BorderColor, 2); + block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index); + char buf[21]; + sprintf(buf, "%.2f, %.2f", Layer->Vertical_Offset, SortEntry.SortedOffset); + // draw_list->AddText(Layer_ScreenPos_Min, 0xFFFFFFFF, buf); + if (UI->TimelinePercentZoomed.y <= 1.0f) + draw_list->AddText(Layer_ScreenPos_Min, 0xFFFFFFFF, String->Char); + + if (Layer->IsSelected) { + draw_list->AddRectFilled(Layer_ScreenPos_Min, Layer_ScreenPos_Max, ImColor(0.25f, 0.25f, 0.25f, 0.5f), 2); + draw_list->AddRect(Layer_ScreenPos_Min, Layer_ScreenPos_Max, ImColor(1.0f, 1.0f, 1.0f, 0.5f), 2); + } + + // + + // Main interaction + + ImGui::PushID(i); + if (UI->TimelineMode == timeline_mode_default) { if (UI->BoxSelect && UI->TimelineMode == timeline_mode_default) { bool32 Test = 0; @@ -1190,7 +1394,7 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem if (Test) { if (!Layer->IsSelected) { - Layer->IsSelected = true; + Layer_Select(Memory, State, Index_Physical); } } else if (!io.KeyShift) { Layer->IsSelected = false; @@ -1210,7 +1414,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); + if (!io.KeyShift) Layer_DeselectAll(File, State, Memory); Layer_Select(Memory, State, Index_Physical); } } @@ -1254,7 +1458,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); + if (!io.KeyShift) Layer_DeselectAll(File, State, Memory); Layer_Select(Memory, State, Index_Physical); } } @@ -1262,47 +1466,7 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem ImGui::OpenPopupOnItemClick("layerpopup", ImGuiPopupFlags_MouseButtonRight); if (ImGui::BeginPopup("layerpopup")) { if (ImGui::MenuItem("Pre-compose layer")) { - History_Entry_Commit(Memory, "Pre-compose layer"); - block_composition *NewComp = Precomp_Init(File, Memory); - NewComp->Width = Comp->Width; - NewComp->Height = Comp->Height; - NewComp->FPS = Comp->FPS; - NewComp->BytesPerPixel = Comp->BytesPerPixel; - NewComp->Frame_Count = Comp->Frame_Count; - NewComp->Frame_Start = Comp->Frame_Start; - NewComp->Frame_End = Comp->Frame_End; - int32 TopOffset = 0; - 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); - if (Layer->IsSelected) { - TopOffset = Layer->Vertical_Offset; - break; - } - } - 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); - if (Layer->IsSelected) { - History_Action_Swap(Memory, F_File, sizeof(Layer->Block_Composition_Index), &Layer->Block_Composition_Index); - Layer->Block_Composition_Index = 1; - } - } - block_layer *PrecompLayer = Layer_Init(File, Memory); - PrecompLayer->IsPrecomp = true; - PrecompLayer->Block_Source_Index = 1; - PrecompLayer->Block_Composition_Index = 0; - PrecompLayer->Vertical_Offset = TopOffset; - PrecompLayer->Frame_End = NewComp->Frame_End; - PrecompLayer->ColIndex = 3; - PrecompLayer->x.CurrentValue = Comp->Width/2; - PrecompLayer->y.CurrentValue = Comp->Height/2; - History_Entry_End(Memory); - State->UpdateFrame = true; + Precomp_UICreateButton(File, State, Memory, CompIndex, SortedCompInfo, SortedLayerInfo); } if (ImGui::BeginMenu("Layer color")) { @@ -1354,12 +1518,12 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem 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); + // NOTE(fox): Some data on the tree could be saved here. + History_Action_Swap(Memory, F_File, sizeof(Layer->Vertical_Offset), &Layer->Vertical_Offset); + Layer->Vertical_Offset = SortEntry.SortedOffset; if (Layer->IsSelected) { - // NOTE(fox): Some data on the tree could be saved here. - History_Action_Swap(Memory, F_File, sizeof(Layer->Vertical_Offset), &Layer->Vertical_Offset); History_Action_Swap(Memory, F_File, sizeof(Layer->Frame_Start), &Layer->Frame_Start); History_Action_Swap(Memory, F_File, sizeof(Layer->Frame_End), &Layer->Frame_End); - Layer->Vertical_Offset = SortEntry.SortedOffset; Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Layer->Frame_Start, &Layer->Frame_End); } } @@ -1367,33 +1531,26 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem History_Entry_End(Memory); } } - ImGui::PopID(); - } - - } - - // Check if any layers are precomps; we want to test hit detection for them _after_ the layers in front. - for (int i = 0; i < SortedCompInfo.LayerCount; i++) - { - ImGui::PushID(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); + // Keyframe view + uint32 Channel = 0; + for (int h = 0; h < AmountOf(Layer->Property); h++) { + property_channel *Property = &Layer->Property[h]; + if (Property->IsToggled) { + // sorted_property_info *InfoLocation = SortedPropertyInfo + (i * 7) + h; + ImVec2 GraphPos(TimelineAbsolutePos.x, Layer_ScreenPos_Min.y + (Layer_ScreenSize.y * 2) + (Layer_ScreenSize.y * Channel)); + uint16 *ArrayLocation = SortedPropertyArray + (i * 7 * MAX_KEYFRAMES_PER_BLOCK) + (h * MAX_KEYFRAMES_PER_BLOCK); + ImGui_Timeline_DrawKeySheet(File, State, Memory, UI, io, draw_list, Property, ArrayLocation, + Increment, GraphPos, TimelineMoveSize, TimelineZoomSize, + TimelineSize, TimelineSizeWithBorder, LayerIncrement); + Channel++; + } + } + } - int32 Frame_Start = Layer->Frame_Start; - int32 Frame_End = Layer->Frame_End; - real32 Vertical_Offset = SortEntry.SortedOffset; - if (Layer->IsSelected) - Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End); - ImVec2 Layer_LocalPos = ImVec2(Frame_Start, Vertical_Offset); - ImVec2 Layer_LocalSize = ImVec2(Frame_End - Frame_Start, Layer->Vertical_Height); + // - ImVec2 Layer_LocalPos_Ratio = (Layer_LocalPos * Increment); - ImVec2 Layer_LocalSize_Ratio = Layer_LocalSize * Increment; - ImVec2 Layer_ScreenPos_Min = TimelineAbsolutePos + TimelineMoveSize + (Layer_LocalPos_Ratio * TimelineZoomSize); - ImVec2 Layer_ScreenPos_Max = TimelineAbsolutePos + TimelineMoveSize + ((Layer_LocalPos_Ratio + Layer_LocalSize_Ratio) * TimelineZoomSize); - ImVec2 Layer_ScreenSize = Layer_ScreenPos_Max - Layer_ScreenPos_Min; + // Precomp recursion if (Layer->IsPrecomp && Layer->Precomp_Toggled) { @@ -1404,7 +1561,9 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem block_layer *Layer_Bottom = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Precomp_SortedLayerInfo[0].Block_Layer_Index); real32 SmallestY = Layer_Top->Vertical_Offset; real32 LargestY = Layer_Bottom->Vertical_Offset; - real32 PrecompHeight = LargestY - SmallestY + 1; + // Layer_Evaluate_Display(Layer_Top, SortedLayerArray, SortedCompArray, Precomp_SortedLayerInfo, Precomp_SortedCompInfo.LayerCount - 1, &SmallestY); + // Layer_Evaluate_Display(Layer_Bottom, SortedLayerArray, SortedCompArray, Precomp_SortedLayerInfo, 0, &LargestY); + real32 PrecompHeight = LargestY - SmallestY + 2; ImVec2 MinClipPos = ImVec2(Layer_ScreenPos_Min.x, Layer_ScreenPos_Max.y); ImVec2 MaxClipPos = ImVec2(Layer_ScreenPos_Max.x, MinClipPos.y + (PrecompHeight * Increment.y * TimelineZoomSize.y)); @@ -1412,79 +1571,33 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem ImVec2 Layer_LocalPos_Screen = Layer_LocalPos_Ratio * TimelineZoomSize; - ImVec2 NestedTimelineAbsolutePos = TimelineAbsolutePos + Layer_LocalPos_Screen - ImVec2(0, SmallestY * Increment.y * TimelineZoomSize.y) + ImVec2(0, Layer_ScreenSize.y); + ImVec2 NestedTimelineAbsolutePos = TimelineAbsolutePos + Layer_LocalPos_Screen - ImVec2(0, SmallestY * Increment.y * TimelineZoomSize.y) + ImVec2(0, Layer_ScreenSize.y * 1.5); ImGui::PushClipRect(MinClipPos, MaxClipPos, true); draw_list->PushClipRect(MinClipPos, MaxClipPos, true); ImGui_Timeline_DrawPrecomp(File, State, Memory, UI, io, draw_list, Layer->Block_Source_Index, Increment, NestedTimelineAbsolutePos, TimelineMoveSize, TimelineZoomSize, TimelineSize, TimelineSizeWithBorder, LayerIncrement, - SortedCompArray, SortedLayerArray); + SortedCompArray, SortedLayerArray, SortedPropertyInfo, SortedPropertyArray); draw_list->PopClipRect(); ImGui::PopClipRect(); } - ImGui::PopID(); - } - - // TODO(fox): Draw calls are executed in reverse order, so we need another iteration to draw layers on top of precomps. - // The ImDrawListSplitter API can probably do this without another iteration. - - 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); - - int32 Frame_Start = Layer->Frame_Start; - int32 Frame_End = Layer->Frame_End; - real32 Vertical_Offset = SortEntry.SortedOffset; - if (Layer->IsSelected) - Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End); - ImVec2 Layer_LocalPos = ImVec2(Frame_Start, Vertical_Offset); - ImVec2 Layer_LocalSize = ImVec2(Frame_End - Frame_Start, Layer->Vertical_Height); - - ImVec2 Layer_LocalPos_Ratio = (Layer_LocalPos * Increment); - ImVec2 Layer_LocalSize_Ratio = Layer_LocalSize * Increment; - ImVec2 Layer_ScreenPos_Min = TimelineAbsolutePos + TimelineMoveSize + (Layer_LocalPos_Ratio * TimelineZoomSize); - ImVec2 Layer_ScreenPos_Max = TimelineAbsolutePos + TimelineMoveSize + ((Layer_LocalPos_Ratio + Layer_LocalSize_Ratio) * TimelineZoomSize); - ImVec2 Layer_ScreenSize = Layer_ScreenPos_Max - Layer_ScreenPos_Min; - - ImU32 LayerColor = 0; - ImU32 BorderColor = 0; - LayerColor = ImColor(UI->LayerColors[Layer->ColIndex]); - BorderColor = ImColor(0.2, 0.2, 0.2, 1.0f); - /* - if (UI->TimelineMode == timeline_mode_graph) { - LayerColor = ImColor(UI->LayerColors[Layer->ColIndex]); - BorderColor = ImColor(0.3, 0.3, 0.3, 1.0f); - } else { - LayerColor = ImColor(UI->LayerColors[Layer->ColIndex]); - BorderColor = ImColor(0.2, 0.2, 0.2, 1.0f); - } - */ - draw_list->AddRectFilled(Layer_ScreenPos_Min, Layer_ScreenPos_Max, LayerColor); - draw_list->AddRect(Layer_ScreenPos_Min, Layer_ScreenPos_Max, BorderColor, 2); - // block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index); - char buf[21]; - sprintf(buf, "%.2f, %.2f", Layer->Vertical_Offset, SortEntry.SortedOffset); - draw_list->AddText(Layer_ScreenPos_Min, 0xFFFFFFFF, buf); + // - if (Layer->IsSelected) { - draw_list->AddRectFilled(Layer_ScreenPos_Min, Layer_ScreenPos_Max, ImColor(0.25f, 0.25f, 0.25f, 0.5f), 2); - draw_list->AddRect(Layer_ScreenPos_Min, Layer_ScreenPos_Max, ImColor(1.0f, 1.0f, 1.0f, 0.5f), 2); - } + ImGui::PopID(); } ImGui::PopID(); } static void -ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, uint16 *SortedPropertyArray) +ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, + sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray) { if (UI->TimelineMode == timeline_mode_graph) - ImGui_GraphInfo(File, State, Memory, UI, io); + ImGui_GraphInfo(File, State, Memory, UI, io, SortedPropertyInfo, SortedPropertyArray); ImVec2 FramePadding = ImGui::GetStyle().FramePadding; ImVec2 ItemSpacing = ImGui::GetStyle().ItemSpacing; @@ -1556,14 +1669,12 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, DebugWatchVar("TimelineY: ", &TimelineMoveSize.y, d_float); - ImGui_TimelineHorizontalIncrementDraw(State, UI, draw_list, TimelineSizeWithBorder, TimelineAbsolutePos, *MainComp, TimelineZoomSize, TimelineMoveSize); - ImVec2 Increment = ImVec2((real32)1 / MainComp->Frame_Count, (real32)1 / LayerIncrement); ImGui_Timeline_DrawPrecomp(File, State, Memory, UI, io, draw_list, File->PrincipalCompIndex, Increment, TimelineAbsolutePos, TimelineMoveSize, TimelineZoomSize, TimelineSize, TimelineSizeWithBorder, LayerIncrement, - SortedCompArray, SortedLayerArray); + SortedCompArray, SortedLayerArray, SortedPropertyInfo, SortedPropertyArray); if (UI->TimelineMode == timeline_mode_graph) { @@ -1582,12 +1693,15 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, DebugWatchVar("movesize: ", &GraphMoveSize.y, d_float); draw_list->AddRectFilled(WindowMinAbs, WindowMaxAbs, - IM_COL32(50, 50, 50, 150)); + IM_COL32(50, 50, 50, 230)); ImGui_Timeline_DrawGraph(File, State, Memory, UI, io, draw_list, Increment, TimelineAbsolutePos, GraphMoveSize, GraphZoomSize, - TimelineSize, TimelineSizeWithBorder, LayerIncrement, SortedPropertyArray); + TimelineSize, TimelineSizeWithBorder, LayerIncrement, SortedPropertyInfo, SortedPropertyArray); } + ImGui_TimelineHorizontalIncrementDraw(State, UI, draw_list, TimelineSizeWithBorder, TimelineAbsolutePos, *MainComp, TimelineZoomSize, TimelineMoveSize); + + ImVec2 MouseDelta = io.MouseDelta / TimelineSize; real32 BarHandleSize = FontHeight; @@ -1747,10 +1861,15 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, if (LeftClick) { if (IsItemActivated) { - if (!io.KeyShift && UI->TimelineMode == timeline_mode_default) Layer_DeselectAll(Memory, File->Layer_Count); + if (!io.KeyShift && UI->TimelineMode == timeline_mode_default) Layer_DeselectAll(File, State, Memory); if (State->Interact_Active == interact_type_keyframe_move || State->Interact_Active == interact_type_keyframe_rotate || State->Interact_Active == interact_type_keyframe_scale) { + // bool32 CommitAction = 0; + // if (!CommitAction) { + // History_Entry_Commit(Memory, "Delete source"); + // CommitAction = 1; + History_Entry_Commit(Memory, "Add keyframe"); 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); @@ -1765,11 +1884,15 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, if (PointAddress->IsSelected) { v2 NewPos[3]; Bezier_EvaluateValue(State, PointAddress, NewPos); - PointAddress->Pos[0].x = NewPos[0].x; + History_Action_Swap(Memory, F_Bezier, sizeof(PointAddress->Pos), &PointAddress->Pos); + PointAddress->Pos[0] = NewPos[0]; + PointAddress->Pos[1] = NewPos[1]; + PointAddress->Pos[2] = NewPos[2]; } } } } + History_Entry_End(Memory); State->Interact_Offset[0] = 0; State->Interact_Offset[1] = 0; State->Interact_Offset[2] = 0; @@ -1844,9 +1967,9 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me State->Interact_Offset[3] = io.MousePos.y; State->Interact_Active = interact_type_keyframe_move; } else if (ImGui::IsKeyPressed(ImGuiKey_R)) { - State->Interact_Offset[2] = io.MousePos.x; - State->Interact_Offset[3] = io.MousePos.y; - State->Interact_Active = interact_type_keyframe_rotate; + // State->Interact_Offset[2] = io.MousePos.x; + // State->Interact_Offset[3] = io.MousePos.y; + // State->Interact_Active = interact_type_keyframe_rotate; } else if (ImGui::IsKeyPressed(ImGuiKey_S)) { State->Interact_Offset[2] = io.MousePos.x; State->Interact_Offset[3] = io.MousePos.y; @@ -1862,6 +1985,7 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me State->Interact_Offset[2] = 0; State->Interact_Offset[3] = 0; State->Interact_Active = interact_type_none; + State->UpdateFrame = true; } } if (ImGui::IsKeyPressed(ImGuiKey_Space)) { diff --git a/prenderer.cpp b/prenderer.cpp index 58e1b22..aa44a5a 100644 --- a/prenderer.cpp +++ b/prenderer.cpp @@ -30,9 +30,9 @@ T_CompPosToLayerPos(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uin static v2 Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, - ui UI, ImVec2 ViewportMin, ImVec2 Point) + ImVec2 CompPos, ImVec2 CompZoom, ImVec2 ViewportMin, ImVec2 Point) { - v2 CompUV = ImGui_ScreenPointToCompUV(ViewportMin, UI.CompPos, UI.CompZoom, Point); + v2 CompUV = ImGui_ScreenPointToCompUV(ViewportMin, CompPos, CompZoom, Point); v2 LayerUV = T_CompUVToLayerUV(T, FileWidth, FileHeight, SourceWidth, SourceHeight, CompUV); return V2(LayerUV.x * SourceWidth, LayerUV.y * SourceHeight); } @@ -260,7 +260,26 @@ Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegio static void RenderLayers(render_entry Entry) { - Fallback_RenderLayer(*(transform_info *)Entry.RenderData, Entry.OutputBuffer, Entry.RenderRegion); + switch (Entry.RenderType) + { + case render_type_main: + { + Fallback_RenderLayer(*(transform_info *)Entry.RenderData, Entry.OutputBuffer, Entry.RenderRegion); + } break; + case render_type_direct: + { + Assert(0); + // Fallback_RenderDirect(*(direct_info *)Entry.RenderData, Entry.OutputBuffer, Entry.RenderRegion); + } break; + case render_type_brush: + { + PaintTest_AVX2(*(brush_info *)Entry.RenderData, Entry.OutputBuffer, Entry.RenderRegion); + } break; + default: + { + Assert(0); + } + } #if 0 #if ARM Fallback_RenderLayer(RenderData->TransformInfo[i], RenderInfo->CompBuffer, RenderRegion); @@ -274,17 +293,17 @@ RenderLayers(render_entry Entry) { } static void -Renderer_Start(void *Data, void *OutputBuffer, rectangle RenderRegion) +Renderer_Start(void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion) { // CPU - Threading_BitmapOp(Data, OutputBuffer, RenderRegion); + Threading_BitmapOp(Data, OutputBuffer, RenderType, RenderRegion); } static void -Renderer_Check(bool32 *Test) +Renderer_Check(bool32 *Test, render_type RenderType) { // CPU - *Test = Threading_IsActive(); + *Test = Threading_IsActive(RenderType); } @@ -351,7 +370,6 @@ Transform_Calculate(project_state *State, memory *Memory, project_data *File, bl if (Points[i].x > MaxX) { MaxX = Points[i].x; } if (Points[i].y > MaxY) { MaxY = Points[i].y; } } - TransformInfo.XAxisPX = XLengthSq*XAxis.x; TransformInfo.XAxisPY = XLengthSq*XAxis.y; TransformInfo.YAxisPX = YLengthSq*YAxis.x; @@ -373,15 +391,137 @@ Transform_Calculate(project_state *State, memory *Memory, project_data *File, bl TransformInfo.OriginY = Origin.y; TransformInfo.BufferPitch = Comp->Width*Comp->BytesPerPixel; TransformInfo.LayerPitch = Width*BytesPerPixel; - TransformInfo.ClipRect = {MinX - (MinX & 3), MinY, MaxX + 1, MaxY + 1}; + TransformInfo.ClipRect = {MinX, MinY, MaxX, MaxY}; TransformInfo.IsAdjustment = Layer->IsAdjustment; return TransformInfo; } +// NOTE(fox): is this too ridiculous? i don't trust inline +#define Fallback_Blend() \ + switch (T.BlendMode)\ + {\ + case blend_normal:\ + {\ + } break;\ + case blend_multiply:\ + {\ + R_Blend = R_Dest * R_Col;\ + G_Blend = G_Dest * G_Col;\ + B_Blend = B_Dest * B_Col;\ + } break;\ + case blend_colorburn:\ + {\ + /* NOTE(fox): Padding to prevent actual crashing from zero division */ \ + R_Blend = 1.0f - ((1.0f - R_Dest) / (R_Col + 0.001f));\ + G_Blend = 1.0f - ((1.0f - G_Dest) / (G_Col + 0.001f));\ + B_Blend = 1.0f - ((1.0f - B_Dest) / (B_Col + 0.001f));\ + } break;\ + case blend_linearburn:\ + {\ + R_Blend = (R_Dest + R_Col) - 1.0f;\ + G_Blend = (G_Dest + G_Col) - 1.0f;\ + B_Blend = (B_Dest + B_Col) - 1.0f;\ + } break;\ + case blend_add:\ + {\ + R_Blend = R_Dest + R_Col;\ + G_Blend = G_Dest + G_Col;\ + B_Blend = B_Dest + B_Col;\ + } break;\ + case blend_screen:\ + {\ + R_Blend = 1.0f - ((1.0f - R_Dest) * (1.0f - R_Col));\ + G_Blend = 1.0f - ((1.0f - G_Dest) * (1.0f - G_Col));\ + B_Blend = 1.0f - ((1.0f - B_Dest) * (1.0f - B_Col));\ + } break;\ + case blend_overlay:\ + {\ + if (R_Dest < 0.5) {\ + R_Blend = 2.0f * R_Dest * R_Col;\ + } else {\ + R_Blend = 1.0f - (2.0f * (1.0f - R_Dest) * (1.0f - R_Col));\ + }\ + if (G_Dest < 0.5) {\ + G_Blend = 2.0f * G_Dest * G_Col;\ + } else {\ + G_Blend = 1.0f - (2.0f * (1.0f - G_Dest) * (1.0f - G_Col));\ + }\ + if (B_Dest < 0.5) {\ + B_Blend = 2.0f * B_Dest * B_Col;\ + } else {\ + B_Blend = 1.0f - (2.0f * (1.0f - B_Dest) * (1.0f - B_Col));\ + }\ + } break;\ + case blend_softlight:\ + {\ + /* using Pegtop's equation */ \ + R_Blend = ((1.0f - R_Col * 2) * R_Dest * R_Dest) + (R_Col * 2 * R_Dest);\ + G_Blend = ((1.0f - G_Col * 2) * G_Dest * G_Dest) + (G_Col * 2 * G_Dest);\ + B_Blend = ((1.0f - B_Col * 2) * B_Dest * B_Dest) + (B_Col * 2 * B_Dest);\ + } break;\ + case blend_hardlight:\ + {\ + if (R_Dest > 0.5) {\ + R_Blend = 2.0f * R_Dest * R_Col;\ + } else {\ + R_Blend = 1.0f - (2.0f * (1.0f - R_Dest) * (1.0f - R_Col));\ + }\ + if (G_Dest > 0.5) {\ + G_Blend = 2.0f * G_Dest * G_Col;\ + } else {\ + G_Blend = 1.0f - (2.0f * (1.0f - G_Dest) * (1.0f - G_Col));\ + }\ + if (B_Dest > 0.5) {\ + B_Blend = 2.0f * B_Dest * B_Col;\ + } else {\ + B_Blend = 1.0f - (2.0f * (1.0f - B_Dest) * (1.0f - B_Col));\ + }\ + } break;\ + case blend_subtract:\ + {\ + R_Blend = R_Dest - R_Col;\ + G_Blend = G_Dest - G_Col;\ + B_Blend = B_Dest - B_Col;\ + } break;\ + case blend_divide:\ + {\ + R_Blend = R_Dest / (R_Col + 0.001f);\ + G_Blend = G_Dest / (G_Col + 0.001f);\ + B_Blend = B_Dest / (B_Col + 0.001f);\ + } break;\ + case blend_difference:\ + {\ + if (R_Col - R_Dest > 0) {\ + R_Blend = R_Col - R_Dest;\ + } else {\ + R_Blend = R_Dest - R_Col;\ + }\ + if (G_Col - G_Dest > 0) {\ + G_Blend = G_Col - G_Dest;\ + } else {\ + G_Blend = G_Dest - G_Col;\ + }\ + if (B_Col - B_Dest > 0) {\ + B_Blend = B_Col - B_Dest;\ + } else {\ + B_Blend = B_Dest - B_Col;\ + }\ + } break;\ + }\ +\ + R_Blend = (R_Dest * (1.0f - LayerAlpha)) + (R_Blend * LayerAlpha);\ + G_Blend = (G_Dest * (1.0f - LayerAlpha)) + (G_Blend * LayerAlpha);\ + B_Blend = (B_Dest * (1.0f - LayerAlpha)) + (B_Blend * LayerAlpha);\ +\ + if (T.BlendMode == blend_normal)\ + A_Blend = A_Dest + LayerAlpha;\ + else\ + A_Blend = A_Dest;\ + static void -Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegion) +Fallback_RenderDirect(transform_info T, void *OutputBuffer, rectangle RenderRegion) { rectangle LayerBounds = ClipRectangle( T.ClipRect, RenderRegion); @@ -390,15 +530,84 @@ Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegio for (int16 Y = LayerBounds.Min.y; Y < LayerBounds.Max.y; Y++) { - real32 StartVectorY = (real32)Y - T.OriginY; - for (int16 X = LayerBounds.Min.x; X < LayerBounds.Max.x; X++) { + uint16 LX = X; + uint16 LY = Y; + uint16 LXPlus = Ceil(X+1, (uint32)T.LayerWidth - 1); + uint16 LYPlus = Ceil(Y+1, (uint32)T.LayerHeight - 1); + + uint8 *TexPTR0 = ((uint8 *)T.SourceBuffer + ((uint16)T.LayerPitch * LY) + (LX * (uint16)T.LayerBytesPerPixel)); + uint32 PixelA = *(uint32 *)TexPTR0; + + real32 TexRA = (real32)(*(uint32 *)(TexPTR0 + T.LayerBits.ByteOffset * 0) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized; + real32 TexGA = (real32)(*(uint32 *)(TexPTR0 + T.LayerBits.ByteOffset * 1) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized; + real32 TexBA = (real32)(*(uint32 *)(TexPTR0 + T.LayerBits.ByteOffset * 2) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized; + real32 TexAA = (real32)(*(uint32 *)(TexPTR0 + T.LayerBits.ByteOffset * 3) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized; + + real32 LayerAlpha = TexAA * 1; // brush opacity + + real32 R_Col = TexRA; + real32 G_Col = TexGA; + real32 B_Col = TexBA; + real32 A_Col = TexAA; + + real32 R_Blend = TexRA; + real32 G_Blend = TexGA; + real32 B_Blend = TexBA; + real32 A_Blend = TexAA; + + uint8 *DestPixel =((uint8 *)OutputBuffer + ((uint16)Y * (uint16)T.BufferPitch) + ((uint16)X * (uint16)T.BufferBytesPerPixel)); + + uint32 *R_DestAddress = (uint32 *)(DestPixel + T.BufferBits.ByteOffset * 0); + uint32 *G_DestAddress = (uint32 *)(DestPixel + T.BufferBits.ByteOffset * 1); + uint32 *B_DestAddress = (uint32 *)(DestPixel + T.BufferBits.ByteOffset * 2); + uint32 *A_DestAddress = (uint32 *)(DestPixel + T.BufferBits.ByteOffset * 3); + + if (LayerAlpha != 1.0f || T.BlendMode != blend_normal) { + + real32 R_Dest = (real32)(*R_DestAddress & T.BufferBits.MaskPixel) * T.BufferBits.Normalized; + real32 G_Dest = (real32)(*G_DestAddress & T.BufferBits.MaskPixel) * T.BufferBits.Normalized; + real32 B_Dest = (real32)(*B_DestAddress & T.BufferBits.MaskPixel) * T.BufferBits.Normalized; + real32 A_Dest = (real32)(*A_DestAddress & T.BufferBits.MaskPixel) * T.BufferBits.Normalized; + + Fallback_Blend(); + } + + uint32 R_Out = (uint32)(Normalize(R_Blend) * T.BufferBits.Bits); + uint32 G_Out = (uint32)(Normalize(G_Blend) * T.BufferBits.Bits); + uint32 B_Out = (uint32)(Normalize(B_Blend) * T.BufferBits.Bits); + uint32 A_Out = (uint32)(Normalize(A_Blend) * T.BufferBits.Bits); + + *R_DestAddress = (*R_DestAddress & ~T.BufferBits.MaskPixel) | R_Out; + *G_DestAddress = (*G_DestAddress & ~T.BufferBits.MaskPixel) | G_Out; + *B_DestAddress = (*B_DestAddress & ~T.BufferBits.MaskPixel) | B_Out; + *A_DestAddress = (*A_DestAddress & ~T.BufferBits.MaskPixel) | A_Out; + } + } +} +static void +Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegion) +{ + rectangle LayerBounds = ClipRectangle( T.ClipRect, RenderRegion); + + Assert(LayerBounds.Max.x <= T.BufferWidth); + Assert(LayerBounds.Max.y <= T.BufferHeight); + + for (int Y = LayerBounds.Min.y; Y < LayerBounds.Max.y; Y++) + { + real32 StartVectorY = (real32)Y - T.OriginY; + + for (int X = LayerBounds.Min.x; X < LayerBounds.Max.x; X++) + { real32 StartVectorX = X - T.OriginX; real32 U = (StartVectorX * T.XAxisPX) + (StartVectorY * T.XAxisPY); real32 V = (StartVectorX * T.YAxisPX) + (StartVectorY * T.YAxisPY); + if (X == T.BufferWidth) + int why = 0; + if (U < 1.0f && U >= 0.0f && V < 1.0f && V >= 0.0f) { real32 TexXFull = U * T.LayerWidth; @@ -418,15 +627,15 @@ Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegio uint32 XLookup, YLookup, PixelToSeek; - uint16 LX = TexXInt; - uint16 LY = TexYInt; - uint16 LXPlus = Ceil(TexXInt+1, (uint32)T.LayerWidth - 1); - uint16 LYPlus = Ceil(TexYInt+1, (uint32)T.LayerHeight - 1); + uint32 LX = TexXInt; + uint32 LY = TexYInt; + uint32 LXPlus = Ceil(TexXInt+1, (uint32)T.LayerWidth - 1); + uint32 LYPlus = Ceil(TexYInt+1, (uint32)T.LayerHeight - 1); - uint8 *TexPTR0 = ((uint8 *)T.SourceBuffer + ((uint16)T.LayerPitch * LY) + (LX * (uint16)T.LayerBytesPerPixel)); - uint8 *TexPTR1 = ((uint8 *)T.SourceBuffer + ((uint16)T.LayerPitch * LY) + (LXPlus * (uint16)T.LayerBytesPerPixel)); - uint8 *TexPTR2 = ((uint8 *)T.SourceBuffer + ((uint16)T.LayerPitch * LYPlus) + (LX * (uint16)T.LayerBytesPerPixel)); - uint8 *TexPTR3 = ((uint8 *)T.SourceBuffer + ((uint16)T.LayerPitch * LYPlus) + (LXPlus * (uint16)T.LayerBytesPerPixel)); + uint8 *TexPTR0 = ((uint8 *)T.SourceBuffer + ((uint32)T.LayerPitch * LY) + (LX * (uint32)T.LayerBytesPerPixel)); + uint8 *TexPTR1 = ((uint8 *)T.SourceBuffer + ((uint32)T.LayerPitch * LY) + (LXPlus * (uint32)T.LayerBytesPerPixel)); + uint8 *TexPTR2 = ((uint8 *)T.SourceBuffer + ((uint32)T.LayerPitch * LYPlus) + (LX * (uint32)T.LayerBytesPerPixel)); + uint8 *TexPTR3 = ((uint8 *)T.SourceBuffer + ((uint32)T.LayerPitch * LYPlus) + (LXPlus * (uint32)T.LayerBytesPerPixel)); uint32 PixelA = *(uint32 *)TexPTR0; uint32 PixelB = *(uint32 *)TexPTR1; @@ -515,12 +724,13 @@ Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegio real32 B_Blend = B_Col; real32 A_Blend = A_Col; - uint8 *DestPixel =((uint8 *)OutputBuffer + ((uint16)Y * (uint16)T.BufferPitch) + ((uint16)X * (uint16)T.BufferBytesPerPixel)); + uint8 *DestPixel =((uint8 *)OutputBuffer + ((uint32)Y * (uint32)T.BufferPitch) + ((uint32)X * (uint32)T.BufferBytesPerPixel)); + Assert(X != (T.BufferWidth)); - uint32 *R_DestAddress = (uint32 *)(DestPixel + T.BufferBits.ByteOffset * 0); - uint32 *G_DestAddress = (uint32 *)(DestPixel + T.BufferBits.ByteOffset * 1); - uint32 *B_DestAddress = (uint32 *)(DestPixel + T.BufferBits.ByteOffset * 2); - uint32 *A_DestAddress = (uint32 *)(DestPixel + T.BufferBits.ByteOffset * 3); + uint8 *R_DestAddress = (DestPixel + T.BufferBits.ByteOffset * 0); + uint8 *G_DestAddress = (DestPixel + T.BufferBits.ByteOffset * 1); + uint8 *B_DestAddress = (DestPixel + T.BufferBits.ByteOffset * 2); + uint8 *A_DestAddress = (DestPixel + T.BufferBits.ByteOffset * 3); if (LayerAlpha != 1.0f || T.BlendMode != blend_normal) { @@ -529,136 +739,18 @@ Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegio real32 B_Dest = (real32)(*B_DestAddress & T.BufferBits.MaskPixel) * T.BufferBits.Normalized; real32 A_Dest = (real32)(*A_DestAddress & T.BufferBits.MaskPixel) * T.BufferBits.Normalized; - switch (T.BlendMode) - { - case blend_normal: - { - } break; - case blend_multiply: - { - R_Blend = R_Dest * R_Col; - G_Blend = G_Dest * G_Col; - B_Blend = B_Dest * B_Col; - } break; - case blend_colorburn: - { - // NOTE(fox): Padding to prevent actual crashing from zero division - R_Blend = 1.0f - ((1.0f - R_Dest) / (R_Col + 0.001f)); - G_Blend = 1.0f - ((1.0f - G_Dest) / (G_Col + 0.001f)); - B_Blend = 1.0f - ((1.0f - B_Dest) / (B_Col + 0.001f)); - } break; - case blend_linearburn: - { - R_Blend = (R_Dest + R_Col) - 1.0f; - G_Blend = (G_Dest + G_Col) - 1.0f; - B_Blend = (B_Dest + B_Col) - 1.0f; - } break; - case blend_add: - { - R_Blend = R_Dest + R_Col; - G_Blend = G_Dest + G_Col; - B_Blend = B_Dest + B_Col; - } break; - case blend_screen: - { - R_Blend = 1.0f - ((1.0f - R_Dest) * (1.0f - R_Col)); - G_Blend = 1.0f - ((1.0f - G_Dest) * (1.0f - G_Col)); - B_Blend = 1.0f - ((1.0f - B_Dest) * (1.0f - B_Col)); - } break; - case blend_overlay: - { - if (R_Dest < 0.5) { - R_Blend = 2.0f * R_Dest * R_Col; - } else { - R_Blend = 1.0f - (2.0f * (1.0f - R_Dest) * (1.0f - R_Col)); - } - if (G_Dest < 0.5) { - G_Blend = 2.0f * G_Dest * G_Col; - } else { - G_Blend = 1.0f - (2.0f * (1.0f - G_Dest) * (1.0f - G_Col)); - } - if (B_Dest < 0.5) { - B_Blend = 2.0f * B_Dest * B_Col; - } else { - B_Blend = 1.0f - (2.0f * (1.0f - B_Dest) * (1.0f - B_Col)); - } - } break; - case blend_softlight: - { - // using Pegtop's equation - R_Blend = ((1.0f - R_Col * 2) * R_Dest * R_Dest) + (R_Col * 2 * R_Dest); - G_Blend = ((1.0f - G_Col * 2) * G_Dest * G_Dest) + (G_Col * 2 * G_Dest); - B_Blend = ((1.0f - B_Col * 2) * B_Dest * B_Dest) + (B_Col * 2 * B_Dest); - } break; - case blend_hardlight: - { - if (R_Dest > 0.5) { - R_Blend = 2.0f * R_Dest * R_Col; - } else { - R_Blend = 1.0f - (2.0f * (1.0f - R_Dest) * (1.0f - R_Col)); - } - if (G_Dest > 0.5) { - G_Blend = 2.0f * G_Dest * G_Col; - } else { - G_Blend = 1.0f - (2.0f * (1.0f - G_Dest) * (1.0f - G_Col)); - } - if (B_Dest > 0.5) { - B_Blend = 2.0f * B_Dest * B_Col; - } else { - B_Blend = 1.0f - (2.0f * (1.0f - B_Dest) * (1.0f - B_Col)); - } - } break; - case blend_subtract: - { - R_Blend = R_Dest - R_Col; - G_Blend = G_Dest - G_Col; - B_Blend = B_Dest - B_Col; - } break; - case blend_divide: - { - R_Blend = R_Dest / (R_Col + 0.001f); - G_Blend = G_Dest / (G_Col + 0.001f); - B_Blend = B_Dest / (B_Col + 0.001f); - } break; - case blend_difference: - { - if (R_Col - R_Dest > 0) { - R_Blend = R_Col - R_Dest; - } else { - R_Blend = R_Dest - R_Col; - } - if (G_Col - G_Dest > 0) { - G_Blend = G_Col - G_Dest; - } else { - G_Blend = G_Dest - G_Col; - } - if (B_Col - B_Dest > 0) { - B_Blend = B_Col - B_Dest; - } else { - B_Blend = B_Dest - B_Col; - } - } break; - } - - R_Blend = (R_Dest * (1.0f - LayerAlpha)) + (R_Blend * LayerAlpha); - G_Blend = (G_Dest * (1.0f - LayerAlpha)) + (G_Blend * LayerAlpha); - B_Blend = (B_Dest * (1.0f - LayerAlpha)) + (B_Blend * LayerAlpha); - - if (T.BlendMode == blend_normal) - A_Blend = A_Dest + LayerAlpha; - else - A_Blend = A_Dest; + Fallback_Blend(); } - uint32 R_Out = (uint32)(Normalize(R_Blend) * T.BufferBits.Bits); - uint32 G_Out = (uint32)(Normalize(G_Blend) * T.BufferBits.Bits); - uint32 B_Out = (uint32)(Normalize(B_Blend) * T.BufferBits.Bits); - uint32 A_Out = (uint32)(Normalize(A_Blend) * T.BufferBits.Bits); + uint8 R_Out = (uint8)(Normalize(R_Blend) * T.BufferBits.Bits); + uint8 G_Out = (uint8)(Normalize(G_Blend) * T.BufferBits.Bits); + uint8 B_Out = (uint8)(Normalize(B_Blend) * T.BufferBits.Bits); + uint8 A_Out = (uint8)(Normalize(A_Blend) * T.BufferBits.Bits); - *R_DestAddress = (*R_DestAddress & ~T.BufferBits.MaskPixel) | R_Out; - *G_DestAddress = (*G_DestAddress & ~T.BufferBits.MaskPixel) | G_Out; - *B_DestAddress = (*B_DestAddress & ~T.BufferBits.MaskPixel) | B_Out; - *A_DestAddress = (*A_DestAddress & ~T.BufferBits.MaskPixel) | A_Out; + *R_DestAddress = R_Out; + *G_DestAddress = G_Out; + *B_DestAddress = B_Out; + *A_DestAddress = A_Out; // *R_DestAddress = 255; // *G_DestAddress = 255; // *B_DestAddress = 255; @@ -1781,274 +1873,5 @@ SSE2_RenderLayer(transform_info T, comp_buffer *Buffer, rectangle RenderRegion) } } - -#endif - -static void -Fallback_RenderLayer(transform_info T, comp_buffer *Buffer, rectangle RenderRegion) -{ - rectangle LayerBounds = ClipRectangle( T.ClipRect, RenderRegion); - - Assert(LayerBounds.Max.x <= Buffer->Width); - Assert(LayerBounds.Max.y <= Buffer->Height); - - uint16 WidthP, HeightP; - Bitmap_CalcPackedDimensions(Buffer->Width, Buffer->Height, &WidthP, &HeightP); - - real32 Normalized255 = 1 / 255.0f; - - for (int16 Y = LayerBounds.Min.y; Y < LayerBounds.Max.y; Y++) - { - real32 StartVectorY = (real32)Y - T.OriginY; - - for (int16 X = LayerBounds.Min.x; X < LayerBounds.Max.x; X++) - { - - real32 StartVectorX = X - T.OriginX; - real32 U = (StartVectorX * T.XAxisPX) + (StartVectorY * T.XAxisPY); - real32 V = (StartVectorX * T.YAxisPX) + (StartVectorY * T.YAxisPY); - - if (U < 1.0f && U >= 0.0f && V < 1.0f && V >= 0.0f) { - - real32 TexXFull = U * T.LayerWidth; - uint32 TexXInt = (uint32)TexXFull; - real32 TexX = TexXFull - TexXInt; - - real32 TexYFull = V * T.LayerHeight; - uint32 TexYInt = (uint32)TexYFull; - real32 TexY = TexYFull - TexYInt; - - real32 TexXInv = 1 - TexX; - real32 TexYInv = 1 - TexY; - real32 TexBothXInv = TexXInv * TexY; - real32 TexBothYInv = TexX * TexYInv; - real32 TexBoth = TexY * TexX; - real32 TexBothInv = TexXInv * TexYInv; - - uint32 XLookup, YLookup, PixelToSeek; - - uint16 LX = TexXInt; - uint16 LY = TexYInt; - uint16 LXPlus = Ceil(TexXInt+1, (uint32)T.LayerWidth - 1); - uint16 LYPlus = Ceil(TexYInt+1, (uint32)T.LayerHeight - 1); - -#if PACKEDRGB - // TODO(fox): Be careful with the BytesPerPixel here! It's the - // buffer's, not the layer's (currently everything is 4 bytes - // per pixel). - XLookup = (LX >> 2)*16 + (LX % 4); - YLookup = (LY >> 2)*(T.FullLayerWidth*4) + (LY % 4)*4; - PixelToSeek = XLookup + YLookup; - uint32 PixelA = *(uint32 *)((uint8 *)T.SourceBuffer + PixelToSeek*Buffer->BytesPerPixel); - - XLookup = (LXPlus >> 2)*16 + (LXPlus % 4); - YLookup = (LY >> 2)*(T.FullLayerWidth*4) + (LY % 4)*4; - PixelToSeek = XLookup + YLookup; - uint32 PixelB = *(uint32 *)((uint8 *)T.SourceBuffer + PixelToSeek*Buffer->BytesPerPixel); - - XLookup = (LX >> 2)*16 + (LX % 4); - YLookup = (LYPlus >> 2)*(T.FullLayerWidth*4) + (LYPlus % 4)*4; - PixelToSeek = XLookup + YLookup; - uint32 PixelC = *(uint32 *)((uint8 *)T.SourceBuffer + PixelToSeek*Buffer->BytesPerPixel); - - XLookup = (LXPlus >> 2)*16 + (LXPlus % 4); - YLookup = (LYPlus >> 2)*(T.FullLayerWidth*4) + (LYPlus % 4)*4; - PixelToSeek = XLookup + YLookup; - uint32 PixelD = *(uint32 *)((uint8 *)T.SourceBuffer + PixelToSeek*Buffer->BytesPerPixel); - - XLookup = (X >> 2)*16 + (X % 4); - YLookup = (Y >> 2)*(WidthP*4) + (Y % 4)*4; - PixelToSeek = XLookup + YLookup; - uint32 *Pixel = (uint32 *)((uint8 *)Buffer->PackedBuffer + PixelToSeek*Buffer->BytesPerPixel); - -#else - uint8 *TexPTR0 = ((uint8 *)T.SourceBuffer + (uint16)T.LayerPitch*LY + LX*Buffer->BytesPerPixel); - uint8 *TexPTR1 = ((uint8 *)T.SourceBuffer + (uint16)T.LayerPitch*LY + LXPlus*Buffer->BytesPerPixel); - uint8 *TexPTR2 = ((uint8 *)T.SourceBuffer + (uint16)T.LayerPitch*LYPlus + LX*Buffer->BytesPerPixel); - uint8 *TexPTR3 = ((uint8 *)T.SourceBuffer + (uint16)T.LayerPitch*LYPlus + LXPlus*Buffer->BytesPerPixel); - - uint32 PixelA = *(uint32 *)TexPTR0; - uint32 PixelB = *(uint32 *)TexPTR1; - uint32 PixelC = *(uint32 *)TexPTR2; - uint32 PixelD = *(uint32 *)TexPTR3; - - uint32 *Pixel = (uint32 *)((uint8 *)Buffer->UnpackedBuffer + Y*T.BufferPitch + X*Buffer->BytesPerPixel); #endif - real32 TexRA = (real32)(PixelA & 0xFF) * Normalized255; - real32 TexRB = (real32)(PixelB & 0xFF) * Normalized255; - real32 TexRC = (real32)(PixelC & 0xFF) * Normalized255; - real32 TexRD = (real32)(PixelD & 0xFF) * Normalized255; - - real32 TexGA = (real32)((PixelA >> 8) & 0xFF) * Normalized255; - real32 TexGB = (real32)((PixelB >> 8) & 0xFF) * Normalized255; - real32 TexGC = (real32)((PixelC >> 8) & 0xFF) * Normalized255; - real32 TexGD = (real32)((PixelD >> 8) & 0xFF) * Normalized255; - - real32 TexBA = (real32)((PixelA >> 16) & 0xFF) * Normalized255; - real32 TexBB = (real32)((PixelB >> 16) & 0xFF) * Normalized255; - real32 TexBC = (real32)((PixelC >> 16) & 0xFF) * Normalized255; - real32 TexBD = (real32)((PixelD >> 16) & 0xFF) * Normalized255; - - real32 TexAA = (real32)((PixelA >> 24) & 0xFF) * Normalized255; - real32 TexAB = (real32)((PixelB >> 24) & 0xFF) * Normalized255; - real32 TexAC = (real32)((PixelC >> 24) & 0xFF) * Normalized255; - real32 TexAD = (real32)((PixelD >> 24) & 0xFF) * Normalized255; - - real32 R_Col = (TexBothInv * TexRA) + (TexBothYInv * TexRB) - + (TexBothXInv * TexRC) + (TexBoth * TexRD); - real32 G_Col = (TexBothInv * TexGA) + (TexBothYInv * TexGB) - + (TexBothXInv * TexGC) + (TexBoth * TexGD); - real32 B_Col = (TexBothInv * TexBA) + (TexBothYInv * TexBB) - + (TexBothXInv * TexBC) + (TexBoth * TexBD); - real32 A_Col = (TexBothInv * TexAA) + (TexBothYInv * TexAB) - + (TexBothXInv * TexAC) + (TexBoth * TexAD); - - real32 LayerAlpha = A_Col * T.LayerOpacity; - - real32 R_Blend = R_Col; - real32 G_Blend = G_Col; - real32 B_Blend = B_Col; - real32 A_Blend = A_Col; - - if (LayerAlpha != 1.0f || T.BlendMode != blend_normal) { - - real32 R_Dest = (real32)((*Pixel >> 0) & 0xFF) * Normalized255; - real32 G_Dest = (real32)((*Pixel >> 8) & 0xFF) * Normalized255; - real32 B_Dest = (real32)((*Pixel >> 16) & 0xFF) * Normalized255; - real32 A_Dest = (real32)((*Pixel >> 24) & 0xFF) * Normalized255; - - switch (T.BlendMode) - { - case blend_normal: - { - } break; - case blend_multiply: - { - R_Blend = R_Dest * R_Col; - G_Blend = G_Dest * G_Col; - B_Blend = B_Dest * B_Col; - } break; - case blend_colorburn: - { - // NOTE(fox): Padding to prevent actual crashing from zero division - R_Blend = 1.0f - ((1.0f - R_Dest) / (R_Col + 0.001f)); - G_Blend = 1.0f - ((1.0f - G_Dest) / (G_Col + 0.001f)); - B_Blend = 1.0f - ((1.0f - B_Dest) / (B_Col + 0.001f)); - } break; - case blend_linearburn: - { - R_Blend = (R_Dest + R_Col) - 1.0f; - G_Blend = (G_Dest + G_Col) - 1.0f; - B_Blend = (B_Dest + B_Col) - 1.0f; - } break; - case blend_add: - { - R_Blend = R_Dest + R_Col; - G_Blend = G_Dest + G_Col; - B_Blend = B_Dest + B_Col; - } break; - case blend_screen: - { - R_Blend = 1.0f - ((1.0f - R_Dest) * (1.0f - R_Col)); - G_Blend = 1.0f - ((1.0f - G_Dest) * (1.0f - G_Col)); - B_Blend = 1.0f - ((1.0f - B_Dest) * (1.0f - B_Col)); - } break; - case blend_overlay: - { - if (R_Dest < 0.5) { - R_Blend = 2.0f * R_Dest * R_Col; - } else { - R_Blend = 1.0f - (2.0f * (1.0f - R_Dest) * (1.0f - R_Col)); - } - if (G_Dest < 0.5) { - G_Blend = 2.0f * G_Dest * G_Col; - } else { - G_Blend = 1.0f - (2.0f * (1.0f - G_Dest) * (1.0f - G_Col)); - } - if (B_Dest < 0.5) { - B_Blend = 2.0f * B_Dest * B_Col; - } else { - B_Blend = 1.0f - (2.0f * (1.0f - B_Dest) * (1.0f - B_Col)); - } - } break; - case blend_softlight: - { - // using Pegtop's equation - R_Blend = ((1.0f - R_Col * 2) * R_Dest * R_Dest) + (R_Col * 2 * R_Dest); - G_Blend = ((1.0f - G_Col * 2) * G_Dest * G_Dest) + (G_Col * 2 * G_Dest); - B_Blend = ((1.0f - B_Col * 2) * B_Dest * B_Dest) + (B_Col * 2 * B_Dest); - } break; - case blend_hardlight: - { - if (R_Dest > 0.5) { - R_Blend = 2.0f * R_Dest * R_Col; - } else { - R_Blend = 1.0f - (2.0f * (1.0f - R_Dest) * (1.0f - R_Col)); - } - if (G_Dest > 0.5) { - G_Blend = 2.0f * G_Dest * G_Col; - } else { - G_Blend = 1.0f - (2.0f * (1.0f - G_Dest) * (1.0f - G_Col)); - } - if (B_Dest > 0.5) { - B_Blend = 2.0f * B_Dest * B_Col; - } else { - B_Blend = 1.0f - (2.0f * (1.0f - B_Dest) * (1.0f - B_Col)); - } - } break; - case blend_subtract: - { - R_Blend = R_Dest - R_Col; - G_Blend = G_Dest - G_Col; - B_Blend = B_Dest - B_Col; - } break; - case blend_divide: - { - R_Blend = R_Dest / (R_Col + 0.001f); - G_Blend = G_Dest / (G_Col + 0.001f); - B_Blend = B_Dest / (B_Col + 0.001f); - } break; - case blend_difference: - { - if (R_Col - R_Dest > 0) { - R_Blend = R_Col - R_Dest; - } else { - R_Blend = R_Dest - R_Col; - } - if (G_Col - G_Dest > 0) { - G_Blend = G_Col - G_Dest; - } else { - G_Blend = G_Dest - G_Col; - } - if (B_Col - B_Dest > 0) { - B_Blend = B_Col - B_Dest; - } else { - B_Blend = B_Dest - B_Col; - } - } break; - } - - R_Blend = (R_Dest * (1.0f - LayerAlpha)) + (R_Blend * LayerAlpha); - G_Blend = (G_Dest * (1.0f - LayerAlpha)) + (G_Blend * LayerAlpha); - B_Blend = (B_Dest * (1.0f - LayerAlpha)) + (B_Blend * LayerAlpha); - - if (T.BlendMode == blend_normal) - A_Blend = A_Dest + LayerAlpha; - else - A_Blend = A_Dest; - } - - uint8 R_Out = (uint8)(Normalize(R_Blend) * 255.0f); - uint8 G_Out = (uint8)(Normalize(G_Blend) * 255.0f); - uint8 B_Out = (uint8)(Normalize(B_Blend) * 255.0f); - uint8 A_Out = (uint8)(Normalize(A_Blend) * 255.0f); - - *Pixel = ((A_Out << 24) | - (B_Out << 16) | - (G_Out << 8) | - (R_Out << 0)); - } - } - } -} #endif diff --git a/stable_diffusion.cpp b/stable_diffusion.cpp new file mode 100644 index 0000000..0c42f03 --- /dev/null +++ b/stable_diffusion.cpp @@ -0,0 +1,28 @@ + +static void +SD_Txt2Txt(sd_state *SD) +{ + char JSONPayload[1024]; + char CurlCommand[1024]; + char *Test[] = { "prompt", "negative_prompt", "steps", "width", "height", "cfg_scale" }; + void *Test2[6] = { (void *)SD->Prompt, (void *)SD->NegPrompt, + (void *)&SD->Steps, (void *)&SD->Width, + (void *)&SD->Height, (void *)&SD->CFG }; + int Type[6] = { 0, 0, 1, 1, 1, 2}; + sprintf(JSONPayload, "%s{\n", JSONPayload); + for (int i = 0; i < 6; i++) { + if (Type[i] == 0) { + sprintf(JSONPayload, "%s\"%s\": \"%s\",\n", JSONPayload, Test[i], (char *)Test2[i]); + } else if (Type[i] == 1) { + sprintf(JSONPayload, "%s\"%s\": %i,\n", JSONPayload, Test[i], *(int *)Test2[i]); + } else if (Type[i] == 2) { + sprintf(JSONPayload, "%s\"%s\": %.2f,\n", JSONPayload, Test[i], *(real32 *)Test2[i]); + } else { + Assert(0); + } + } + sprintf(JSONPayload, "%s}\n", JSONPayload); + sprintf(CurlCommand, "curl -X POST -H 'Content-Type: application/json' -i '%s/sdapi/v1/txt2img' --data '%s'", + SD->ServerAddress, JSONPayload); + printf("%s\n", CurlCommand); +}; diff --git a/stable_diffusion.h b/stable_diffusion.h new file mode 100644 index 0000000..6e7dd54 --- /dev/null +++ b/stable_diffusion.h @@ -0,0 +1,25 @@ + + +// curl -X POST -H 'Content-Type: application/json' -i 'http://127.0.0.1:7860/sdapi/v1/txt2img' --data '{ +// "prompt": "cute dinosaur sticker with polka dots", +// "steps": 50, +// "sampler_index": "DDIM" +// }' + +#define SD_LEN_PROMPT 256 +#define SD_LEN_ADDRESS 128 + +struct sd_state +{ + char Prompt[256]; + char NegPrompt[256]; + char ServerAddress[128]; + int32 Steps = 25; + int32 Width = 512; + int32 Height = 512; + int32 SamplerIndex = 0; + real32 CFG = 7; + real32 DenoisingStrength = 0.7; + int32 Seed = -1; +}; + diff --git a/strings.cpp b/strings.cpp index ab410b2..0842576 100644 --- a/strings.cpp +++ b/strings.cpp @@ -27,7 +27,7 @@ static uint16 String_AddToFile(memory *Memory, char *Char) { uint16 FileIndex = Memory_Block_AllocateNew(Memory, F_Strings); - block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, FileIndex); + block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, FileIndex, 0); History_Action_Block_Swap(Memory, F_Strings, String); String->Occupied = 1; uint16 i = 0; diff --git a/threading.cpp b/threading.cpp index 84e5463..f1d7284 100644 --- a/threading.cpp +++ b/threading.cpp @@ -34,50 +34,58 @@ TestThread(void *ptr) } static bool32 -Threading_IsActive() +Threading_IsActive(render_type RenderType) { + int32 Threads = 16; + if (RenderType == render_type_brush) + Threads = 4; uint32 C = SDL_AtomicGet(&CompletedEntries); - Assert(C < 17); - return (C == 16) ? false : true; + Assert(C < Threads + 1); + return (C == Threads) ? false : true; } static void -Threading_BitmapOp(void *Data, void *OutputBuffer, rectangle InitialRenderRegion) +Threading_BitmapOp(void *Data, void *OutputBuffer, render_type RenderType, rectangle InitialRenderRegion) { - uint16 TileWidth = (InitialRenderRegion.Max.x - InitialRenderRegion.Min.x) / 4; - uint16 TileHeight = (InitialRenderRegion.Max.y - InitialRenderRegion.Min.y) / 4; + int i = (RenderType != render_type_brush) ? 4 : 2; + uint16 TileWidth = (InitialRenderRegion.Max.x - InitialRenderRegion.Min.x) / i; + uint16 TileHeight = (InitialRenderRegion.Max.y - InitialRenderRegion.Min.y) / i; SDL_AtomicSet(&QueuedEntries, 0); SDL_AtomicSet(&CurrentEntry, 0); SDL_AtomicSet(&CompletedEntries, 0); - for (int y = 0; y < 4; y++) { - for (int x = 0; x < 4; x++) { - // if (x == y) { - rectangle RenderRegion = { TileWidth*x, TileHeight*y, TileWidth + TileWidth*x, TileHeight + TileHeight*y }; + for (int y = 0; y < i; y++) { + for (int x = 0; x < i; x++) { + // if ((x == 0 && y == 0)|| RenderType != render_type_brush) { - RenderRegion.Min.x -= RenderRegion.Min.x % 8; - RenderRegion.Min.y -= RenderRegion.Min.y % 8; - RenderRegion.Max.x -= RenderRegion.Max.x % 8; - RenderRegion.Max.y -= RenderRegion.Max.y % 8; + rectangle RenderRegion = { TileWidth*x, TileHeight*y, + TileWidth + TileWidth*x, TileHeight + TileHeight*y }; - if (RenderRegion.Max.x > InitialRenderRegion.Max.x) - RenderRegion.Max.x = InitialRenderRegion.Max.x; - if (RenderRegion.Max.y > InitialRenderRegion.Max.y) - RenderRegion.Max.y = InitialRenderRegion.Max.y; + if (RenderType == render_type_brush) { + RenderRegion.Min.x += InitialRenderRegion.Min.x; + RenderRegion.Min.y += InitialRenderRegion.Min.y; + RenderRegion.Max.x += InitialRenderRegion.Min.x; + RenderRegion.Max.y += InitialRenderRegion.Min.y; + } - if (x == 3) - RenderRegion.Max.x = InitialRenderRegion.Max.x; - if (y == 3) - RenderRegion.Max.y = InitialRenderRegion.Max.y; + if (RenderRegion.Max.x > InitialRenderRegion.Max.x) + RenderRegion.Max.x = InitialRenderRegion.Max.x; + if (RenderRegion.Max.y > InitialRenderRegion.Max.y) + RenderRegion.Max.y = InitialRenderRegion.Max.y; - render_entry Entry = { Data, OutputBuffer, RenderRegion }; + if (x == i-1) + RenderRegion.Max.x = InitialRenderRegion.Max.x; + if (y == i-1) + RenderRegion.Max.y = InitialRenderRegion.Max.y; - uint32 Q = SDL_AtomicGet(&QueuedEntries); - *(Entries + Q) = Entry; - SDL_AtomicAdd(&QueuedEntries, 1); - SDL_SemPost(Semaphore); - } - // } + render_entry Entry = { Data, OutputBuffer, RenderType, RenderRegion }; + + uint32 Q = SDL_AtomicGet(&QueuedEntries); + *(Entries + Q) = Entry; + SDL_AtomicAdd(&QueuedEntries, 1); + SDL_SemPost(Semaphore); + // } + } } } -- cgit v1.2.3