diff options
Diffstat (limited to 'src/layer.cpp')
-rw-r--r-- | src/layer.cpp | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/src/layer.cpp b/src/layer.cpp new file mode 100644 index 0000000..f1ce0f4 --- /dev/null +++ b/src/layer.cpp @@ -0,0 +1,405 @@ + +static property_channel +Property_InitFloat(real32 Val, real32 ScrubVal, real32 MinVal = PROPERTY_REAL_MIN, real32 MaxVal = PROPERTY_REAL_MAX, bool32 AlwaysInteger = 0); + +static block_layer * +Layer_Init(project_data *File, memory *Memory) +{ + if (File->Layer_Count + 1 > MAX_LAYERS) { + Assert(0); + } + block_layer *Layer = (block_layer *)Memory_Block_AllocateAddress(Memory, F_Layers); + History_Action_Block_Swap(Memory, F_Layers, Layer); + + *Layer = {}; + 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, 0); + sprintf(String->Char, "Layer %i", File->Layer_Count + 1); // CSbros... + History_Action_Swap(Memory, F_File, sizeof(String->Occupied), &String->Occupied); + String->Occupied = 1; + + Layer->x = Property_InitFloat(0.0f, 1.0f); + Layer->y = Property_InitFloat(0.0f, 1.0f); + Layer->ax = Property_InitFloat(0.5f, 0.005f); + Layer->ay = Property_InitFloat(0.5f, 0.005f); + Layer->scale = Property_InitFloat(1.0f, 0.005f); + Layer->rotation = Property_InitFloat(0.0f, 1.0f); + Layer->opacity = Property_InitFloat(1.0f, 0.005f, 0.0f, 1.0f); + Layer->time = Property_InitFloat(0.0f, 1.0f, 0, 100000, 1); + + Layer->IsVisible = 1; + + History_Action_Swap(Memory, F_File, sizeof(File->Layer_Count), &File->Layer_Count); + File->Layer_Count++; + + return Layer; +} + +// lots of cleanup... +static void +Layer_Delete(project_data *File, project_state *State, memory *Memory, uint32 Index) +{ + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index); + History_Action_Block_Swap(Memory, F_Layers, Layer); + Layer->Occupied = 0; + + block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index, 0); + History_Action_Block_Swap(Memory, F_Strings, String); + String->Occupied = 0; + + for (int i = 0; i < Layer->Block_Effect_Count; i++) { + block_effect *Effect = (block_effect *)Memory_Block_AddressAtIndex(Memory, F_Effects, Layer->Block_Effect_Index[i]); + header_effect *EffectHeader = Effect_EntryFromID(State, Effect->ID); + for (int h = 0; h < EffectHeader->Property_Count; h++) { + header_property ChannelHeader = State->Property[EffectHeader->PropertyStartIndex + h]; + property_channel *Property = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect->Block_Property_Index[h]); + if (Property->Block_Bezier_Count) { + block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Property->Block_Bezier_Index[i], 0); + History_Action_Block_Swap(Memory, F_Bezier, Bezier); + Bezier->Occupied = 0; + } + History_Action_Block_Swap(Memory, F_Properties, Property); + Property->Occupied = 0; + } + History_Action_Block_Swap(Memory, F_Effects, Effect); + Effect->Occupied = 0; + } + History_Action_Swap(Memory, F_File, sizeof(File->Layer_Count), &File->Layer_Count); + File->Layer_Count--; +} + +static layer_transforms +Layer_GetTransforms(block_layer *Layer) { + return { Layer->x.CurrentValue, Layer->y.CurrentValue, Layer->ax.CurrentValue, Layer->ay.CurrentValue, Layer->rotation.CurrentValue, Layer->scale.CurrentValue }; +} + +static int +Layer_GetTopOffset(project_data *File, memory *Memory) +{ + if (File->Layer_Count == 0) + return 11; + int TopOffset = 9999; + 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->Block_Composition_Index == File->PrincipalCompIndex) { + TopOffset = (Layer->Vertical_Offset < TopOffset) ? Layer->Vertical_Offset : TopOffset; + } + } + return TopOffset; +} + + +static void +Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memory, void *EffectBitmapAddress, + int Width, int Height, int BytesPerPixel) +{ + uint64 Size = Width*Height*BytesPerPixel; + + // We need two of these: one with multisampling enabled and a + // non-multisampled one that we can blit to. + gl_effect_layer TestL = {}; + gl_effect_layer TestM = {}; + + GL_UpdateTexture(&TestL, EffectBitmapAddress, Width, Height, BytesPerPixel, 0); + GL_UpdateTexture(&TestM, EffectBitmapAddress, Width, Height, BytesPerPixel, 1); + + for (int i = 0; i < Layer->Block_Effect_Count; i++) + { + block_effect Effect = *(block_effect *)Memory_Block_AddressAtIndex(Memory, F_Effects, Layer->Block_Effect_Index[i]); + header_effect *EffectEntry = Effect_EntryFromID(State, Effect.ID); + + if (Effect.IsToggled) { + uint64 Size = (sizeof(real32) * MAX_PROPERTIES_PER_EFFECT) + (sizeof(real32) * 10); + real32 *Data; + if (EffectEntry->DisplayType == effect_display_type_curves) { + Data = (real32 *)Memory_PushScratch(Memory, Size); + uint16 SortedPointIndex[MAX_PROPERTIES_PER_EFFECT]; + v2 *SortedPointValues = (v2 *)(Data + 5); + for (int c = 0; c < 5; c++) { + *(Data + c) = Effect.ExtraData[c]; + uint32 Shift = MAX_PROPERTIES_PER_EFFECT / 5 * c; + uint16 *SortedPointIndexPlayhead = SortedPointIndex + Shift; + v2 *SortedPointValuesPlayhead = SortedPointValues + Shift; + Effect_Curves_Sort(Memory, &Effect, SortedPointIndexPlayhead, c); + for (int a = 0; a < Effect.ExtraData[c]; a++) { + *SortedPointValuesPlayhead = Effect_V2(Memory, &Effect, SortedPointIndexPlayhead[a]); + SortedPointValuesPlayhead++; + } + } + } else { + Data = (real32 *)Memory_PushScratch(Memory, Size); + for (int c = 0; c < EffectEntry->Property_Count; c++) { + property_channel *Property = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect.Block_Property_Index[c]); + Data[c] = Property->CurrentValue; + } + } + EffectEntry->func(Data, Width, Height, BytesPerPixel, EffectBitmapAddress, EffectEntry->GLShaderIndex); + Memory_PopScratch(Memory, Size); + } + } + /* + if (Layer->NumberOfMasks) { + for (int i = 0; i < Layer->NumberOfMasks; i++) { + file_mask_header *MaskHeader = (file_mask_header *)((uint8 *)Layer + sizeof(file_layer) + MaskOffset); + if (MaskHeader->IsClosed && MaskHeader->IsToggled) { + mask_point *Point = (mask_point *)((uint8 *)MaskHeader + sizeof(file_mask_header)); + Mask_TriangulateAndRasterize(TestM, TestL, Memory, MaskHeader, Point, Source->Width, Source->Height, Source->BytesPerPixel, EffectBitmapAddress); + } + } + Bitmap_StencilAlpha(SourceBitmapAddress, EffectBitmapAddress, Source->BytesPerPixel, Size); + } + + Layer->OutputBitmapLocation = EffectBitmapAddress; + */ + + GL_DeleteHWBuffer(&TestL); + GL_DeleteHWBuffer(&TestM); +} + +static void +Layer_ToggleChannel(project_data *File, memory *Memory, int32 a) +{ + int h = 0, c = 0, i = 0; + while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) + { + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); + if (Layer->IsSelected) + Layer->Property[a].IsToggled ^= 1; + } +} + +static void +Layer_Select(memory *Memory, project_state *State, int32 i) +{ + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); + Layer->IsSelected = true; + State->MostRecentlySelectedLayer = i; + State->RecentSelectionType = selection_type_layer; +} + +static void +Layer_Select_RecurseUp(memory *Memory, project_state *State, int32 i, int16 RecursionIdx[MAX_PRECOMP_RECURSIONS], uint32 Recursions) +{ + for (int a = 1; a <= Recursions; a++) { + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, RecursionIdx[a]); + Layer->IsSelected = 2; + } +} + +static void +Layer_DeselectAll(project_data *File, project_state *State, memory *Memory) { + 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); + Layer->IsSelected = false; + } + State->MostRecentlySelectedLayer = -1; +} + +// h: index of the total amount of properties and effects +// c: index of the amount of properties in a given effect +// p: prior property's keyframe count, so we can increment the sorted keyframe array properly +static bool32 +Layer_LoopChannels(project_state *State, memory *Memory, sorted_property_array **SortedProperty, uint16 **SortedKeyframe, block_layer *Layer, + property_channel **Property, block_effect **EffectOut, int *h, int *c, int *p) +{ + uint32 Amount = AmountOf(Layer->Property) + Layer->Block_Effect_Count; + // Assert(Layer->Block_Effect_Count < 2); + while (*h < Amount) { + if (*h < AmountOf(Layer->Property) && *c == 0) { + *Property = &Layer->Property[*h]; + if (*h != 0) { + *SortedProperty += 1; + *SortedKeyframe += *p; + } + *h += 1; + *p = (**Property).Keyframe_Count; + return 1; + } else { + uint16 EffectIdx = Layer->Block_Effect_Index[*h - AmountOf(Layer->Property)]; + block_effect *Effect = (block_effect *)Memory_Block_AddressAtIndex(Memory, F_Effects, EffectIdx); + if (EffectOut) + *EffectOut = Effect; + header_effect *EffectHeader = Effect_EntryFromID(State, Effect->ID); + while (*c < EffectHeader->Property_Count) { + // header_property ChannelHeader = State->Property[EffectHeader->PropertyStartIndex + c]; + *Property = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect->Block_Property_Index[*c]); + *SortedProperty += 1; + *SortedKeyframe += *p; + *p = (**Property).Keyframe_Count; + *c += 1; + return 1; + } + *h += 1; + *c = 0; + } + } + Assert(*h != (Amount - 1)); + return 0; +} + +static void +Layer_ToggleAllChannels(project_state *State, memory *Memory, block_layer *Layer, + sorted_comp_array *SortedCompStart, sorted_layer_array *SortedLayerStart, + sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray) +{ + bool32 ToggleMode = 1; + { + sorted_property_array *InfoLocation = SortedPropertyStart + SortedLayerStart->SortedPropertyStart; + uint16 *ArrayLocation = SortedKeyframeArray + SortedLayerStart->SortedKeyframeStart; + int h = 0, c = 0, p = 0; + property_channel *Property = NULL; + block_effect *Effect = NULL; + while (Layer_LoopChannels(State, Memory, &InfoLocation, &ArrayLocation, Layer, &Property, &Effect, &h, &c, &p)) + { + if (Property->IsToggled) { + ToggleMode = 0; + break; + } + } + } + sorted_property_array *InfoLocation = SortedPropertyStart + SortedLayerStart->SortedPropertyStart; + uint16 *ArrayLocation = SortedKeyframeArray + SortedLayerStart->SortedKeyframeStart; + int h = 0, c = 0, p = 0; + property_channel *Property = NULL; + block_effect *Effect = NULL; + while (Layer_LoopChannels(State, Memory, &InfoLocation, &ArrayLocation, Layer, &Property, &Effect, &h, &c, &p)) + { + if (Property->Keyframe_Count) { + Property->IsToggled = ToggleMode; + } + } +} + +static void +Layer_Select_Traverse(uint16 PrincipalCompIndex, memory *Memory, project_state *State, int32 IndexToFind, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, + int16 RecursionIdx[MAX_PRECOMP_RECURSIONS], int32 *Recursions) +{ + uint16 CompIndex = 0; + if (RecursionIdx[*Recursions] == -1) { + CompIndex = PrincipalCompIndex; + } else { + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, RecursionIdx[*Recursions]); + CompIndex = Layer->Block_Source_Index; + } + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, CompIndex); + sorted_comp_array SortedCompStart = SortedCompArray[CompIndex]; + uint32 RecursionsCurrent = *Recursions; + for (int i = SortedCompStart.LayerCount - 1; i >= 0; i--) + { + sorted_layer_array SortEntry = SortedLayerStart[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + if (Layer->IsPrecomp && Layer->IsSelected == 2) { + *Recursions = RecursionsCurrent + 1; + RecursionIdx[*Recursions] = Index_Physical; + Layer_Select_Traverse(PrincipalCompIndex, Memory, State, IndexToFind, SortedCompArray, SortedLayerArray, RecursionIdx, Recursions); + } else if (Index_Physical == IndexToFind) { + return; + } + } +} + +static v2 +Layer_TraverseForPoint(project_data *File, project_state *State, memory *Memory, v2 PrincipalCompUV, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray) +{ + int16 RecursionIdx[MAX_PRECOMP_RECURSIONS] = {}; + RecursionIdx[0] = -1; + int32 Recursions = 0; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, File->PrincipalCompIndex); + sorted_comp_array SortedCompStart = SortedCompArray[File->PrincipalCompIndex]; + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); + Layer_Select_Traverse(File->PrincipalCompIndex, Memory, State, State->Brush.LayerToPaint_Index, SortedCompArray, SortedLayerArray, RecursionIdx, &Recursions); + v2 PointUV = {0, 0}; + int OuterWidth = Comp->Width, OuterHeight = Comp->Height; + int InnerWidth = 0, InnerHeight = 0; + if (Recursions == 0) { + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, State->Brush.LayerToPaint_Index); + layer_transforms T = Layer_GetTransforms(Layer); + Layer_GetDimensions(Memory, Layer, &InnerWidth, &InnerHeight); + PointUV = T_CompUVToLayerUV(T, OuterWidth, OuterHeight, InnerWidth, InnerHeight, PrincipalCompUV); + } else { + for (int i = 1; i <= Recursions; i++) { + block_layer *InnerLayer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, RecursionIdx[i]); + layer_transforms T = Layer_GetTransforms(InnerLayer); + Layer_GetDimensions(Memory, InnerLayer, &InnerWidth, &InnerHeight); + PointUV = T_CompUVToLayerUV(T, OuterWidth, OuterHeight, InnerWidth, InnerHeight, PrincipalCompUV); + OuterWidth = InnerWidth; + OuterHeight = InnerHeight; + } + } + return PointUV * V2(InnerWidth, InnerHeight); +} + +static int32 +Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 PrincipalIndex) +{ + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, PrincipalIndex); + sorted_comp_array SortedCompStart = SortedCompArray[PrincipalIndex]; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, PrincipalIndex); + int SelectionCount = 0; + int SelectedLayerIndex = 0; + for (int i = SortedCompStart.LayerCount - 1; i >= 0; i--) { + sorted_layer_array SortEntry = SortedLayerStart[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); + layer_transforms T = Layer_GetTransforms(Layer); + v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, State->TempZoomRatio); + if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && Layer->IsSelected) + { + SelectionCount++; + SelectedLayerIndex = i; + } + } + int32 LayerIndex = -1; + for (int i = SortedCompStart.LayerCount - 1; i >= 0; i--) { + sorted_layer_array SortEntry = SortedLayerStart[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); + layer_transforms T = Layer_GetTransforms(Layer); + v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, State->TempZoomRatio); + if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && !Layer->IsSelected) + { + if (SelectionCount == 1) { + if (i < SelectedLayerIndex) { + LayerIndex = Index_Physical; + break; + } + } else { + LayerIndex = Index_Physical; + break; + } + } + // if (Layer->IsPrecomp) { + // Layer_RecursiveDeselect(Memory, SortedCompArray, SortedLayerArray, TargetIndex, Layer->Block_Source_Index); + // } + // if (Layer->Block_Composition_Index != TargetIndex) { + // Layer->IsSelected = false; + // } + } + return LayerIndex; +} + +static void +Layer_RecursiveDeselect(memory *Memory, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 TargetIndex, uint16 PrincipalIndex) +{ + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, PrincipalIndex); + sorted_comp_array SortedCompStart = SortedCompArray[PrincipalIndex]; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, PrincipalIndex); + for (int i = 0; i < SortedCompStart.LayerCount; i++) { + sorted_layer_array SortEntry = SortedLayerStart[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + if (Layer->IsPrecomp) { + Layer_RecursiveDeselect(Memory, SortedCompArray, SortedLayerArray, TargetIndex, Layer->Block_Source_Index); + } + if (Layer->Block_Composition_Index != TargetIndex) { + Layer->IsSelected = false; + } + } +} |