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 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 408 insertions(+), 131 deletions(-) (limited to 'createcalls.cpp') 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) { -- cgit v1.2.3