summaryrefslogtreecommitdiff
path: root/src/layer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/layer.cpp')
-rw-r--r--src/layer.cpp405
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;
+ }
+ }
+}