From 0a6e95f855afad36481baa9ed72b39ba6e297df6 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Sat, 5 Nov 2022 11:07:29 -0400 Subject: many changes --- createcalls.cpp | 389 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 364 insertions(+), 25 deletions(-) (limited to 'createcalls.cpp') diff --git a/createcalls.cpp b/createcalls.cpp index 5c569fb..c018eaa 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -6,12 +6,45 @@ PostMsg(project_state *State, char *msg) } static uint16 +Source_Generate_Blank(project_data *File, project_state *State, memory *Memory, uint16 Width, uint16 Height, uint16 BytesPerPixel) +{ + Assert(File->Source_Count < MAX_SOURCES); + uint16 Index = Memory_Block_AllocateNew(Memory, F_Sources); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Index); + Source->Occupied = 1; + Source->Width = Width; + Source->Height = Height; + Source->BytesPerPixel= BytesPerPixel; + Source->Type = source_type_principal; + Source->Bitmap_Index = Memory_Block_PrincipalBitmap_AllocateNew(File, State, Memory); + Source->Path_String_Index = String_AddToFile(Memory, "test"); + // History_Action_Swap(Memory, F_File, sizeof(File->Source_Count), &File->Source_Count); + File->Source_Count++; + return Index; +} + +static bool32 Source_IsFileSupported(char *Path, bool32 *IsVideo) { + return stbi_info(Path, NULL, NULL, NULL); + // AV_IsFileSupported(Path, IsVideo) +} + +static void +Source_Delete(project_data *File, memory *Memory, uint32 Index) +{ + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Index); + History_Action_Block_Swap(Memory, F_Sources, Source); + Source->Occupied = 0; + History_Action_Swap(Memory, F_File, sizeof(File->Source_Count), &File->Source_Count); + File->Source_Count--; +} + +static int16 Source_Generate(project_data *File, project_state *State, memory *Memory, void *TempString) { Assert(File->Source_Count < MAX_SOURCES); bool32 IsVideo = 0; - if (AV_IsFileSupported((char *)TempString, &IsVideo)) { + if (Source_IsFileSupported((char *)TempString, &IsVideo)) { uint16 Index = Memory_Block_AllocateNew(Memory, F_Sources); block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Index); History_Entry_Commit(Memory, "Add source"); @@ -19,10 +52,8 @@ Source_Generate(project_data *File, project_state *State, memory *Memory, void * Source->Occupied = 1; Source->Path_String_Index = String_AddToFile(Memory, (char *)TempString); - if (IsVideo) - Source->Type = source_type_video; - else - Source->Type = source_type_image; + Assert(!IsVideo); + Source->Type = source_type_file; History_Action_Swap(Memory, F_File, sizeof(File->Source_Count), &File->Source_Count); File->Source_Count++; @@ -109,6 +140,7 @@ Keyframe_Interact_Evaluate(memory *Memory, project_state *State, uint8 IsSelecte } } +/* static void Layer_Interact_Evaluate(memory *Memory, project_state *State, uint16 Layer_Index_Physical, sorted_comp_info SortedCompInfo, sorted_layer *SortedLayerInfo, int32 *Frame_Start, int32 *Frame_End, real32 *Vertical_Offset) @@ -146,8 +178,26 @@ Layer_Interact_Evaluate(memory *Memory, project_state *State, uint16 Layer_Index *Frame_End += (int32)(State->Interact_Offset[0] * Side[1]); if (*Frame_End <= *Frame_Start) *Frame_End = *Frame_Start + 1; + } else if (State->Interact_Active == interact_type_viewport_transform) { + int i = SortedCompInfo.LayerCount - 1; + while (i >= 0) { + sorted_layer SortEntry = SortedLayerInfo[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + i--; + } } } +*/ + +static void +Layer_Select(memory *Memory, project_state *State, int32 i) +{ + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); + Layer->IsSelected = true; + State->MostRecentlySelectedLayer = i; + // State->RecentSelectionType = selection_layer; +} // TODO(fox): Precomps! void Layer_DeselectAll(memory *Memory, uint32 LayerCount) { @@ -158,6 +208,15 @@ void Layer_DeselectAll(memory *Memory, uint32 LayerCount) { } } +void Source_DeselectAll(project_data *File, memory *Memory) +{ + int h = 0, c = 0, i = 0; + while (Block_Loop(Memory, F_Sources, File->Source_Count, &h, &c, &i)) { + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, i); + Source->IsSelected = 0; + } +} + static sorted_layer * Layer_GetSortedArray(sorted_layer *LayerArrayStart, sorted_comp_info *SortedCompStart, uint32 TargetComp) { @@ -169,6 +228,35 @@ Layer_GetSortedArray(sorted_layer *LayerArrayStart, sorted_comp_info *SortedComp return LayerArrayStart + LayerOffset; } +int32 Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, uint16 PrincipalIndex) +{ + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, PrincipalIndex); + sorted_comp_info SortedCompInfo = SortedCompArray[PrincipalIndex]; + sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, PrincipalIndex); + int32 LayerIndex = -1; + // for (int i = 0; i < SortedCompInfo.LayerCount; i++) { + for (int i = SortedCompInfo.LayerCount - 1; i >= 0; i--) { + sorted_layer SortEntry = SortedLayerInfo[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); + layer_transforms T = Layer_GetTransforms(Layer); + v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, UI->TempZoomRatio); + if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && !Layer->IsSelected) + { + LayerIndex = Index_Physical; + break; + } + // if (Layer->IsPrecomp) { + // Layer_RecursiveDeselect(Memory, SortedCompArray, SortedLayerArray, TargetIndex, Layer->Block_Source_Index); + // } + // if (Layer->Block_Composition_Index != TargetIndex) { + // Layer->IsSelected = false; + // } + } + return LayerIndex; +} + void Layer_RecursiveDeselect(memory *Memory, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, uint16 TargetIndex, uint16 PrincipalIndex) { block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, PrincipalIndex); @@ -187,16 +275,35 @@ void Layer_RecursiveDeselect(memory *Memory, sorted_comp_info *SortedCompArray, } } -void Layer_SortAll(memory *Memory, sorted_layer *LayerArrayStart, sorted_comp_info *CompStart, uint32 LayerCount, uint32 CompCount) +void Layer_Sort_CheckPrev(memory *Memory, int i, int Direction, sorted_layer *SortedLayerInfo, sorted_comp_info SortedCompInfo, int *EntriesPassed, sorted_layer *LayerEntry) { - for (uint32 i = 0; i < LayerCount; i++) { + int PrevOffsetIndex = i + Direction + (*EntriesPassed * Direction); + bool32 OutOfBounds = (Direction > 0) ? (PrevOffsetIndex > (SortedCompInfo.LayerCount - 1)) : (PrevOffsetIndex < 0); + if (!OutOfBounds) { + sorted_layer *PrevLayerEntry = &SortedLayerInfo[PrevOffsetIndex]; + // block_layer *PrevLayer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, PrevLayerEntry->Block_Layer_Index); + // real32 PrevOffset = PrevLayer->Vertical_Offset; + real32 PrevOffset = PrevLayerEntry->SortedOffset; + if (PrevOffset == (LayerEntry->SortedOffset - Direction)) { + LayerEntry->SortedOffset -= Direction; + (*EntriesPassed)++; + Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerInfo, SortedCompInfo, EntriesPassed, LayerEntry); + } + } +} + + +void Layer_SortAll(project_data *File, project_state *State, memory *Memory, sorted_layer *LayerArrayStart, sorted_comp_info *CompStart, uint32 LayerCount, uint32 CompCount) +{ + int h = 0, c = 0, i = 0; + while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) { block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); Assert(Layer->Block_Composition_Index < CompCount); CompStart[Layer->Block_Composition_Index].LayerCount++; } - for (uint32 i = 0; i < LayerCount; i++) { - // SortedLayerArray->Block_Layer_Index = 0; + h = 0, c = 0, i = 0; + while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) { block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); sorted_comp_info *SortedCompInfo = &CompStart[Layer->Block_Composition_Index]; sorted_layer *SortedLayerInfo = Layer_GetSortedArray(LayerArrayStart, CompStart, Layer->Block_Composition_Index); @@ -218,19 +325,63 @@ void Layer_SortAll(memory *Memory, sorted_layer *LayerArrayStart, sorted_comp_in } sorted_layer *LayerEntry = SortedLayerInfo + SortedIndex_Playhead; LayerEntry->Block_Layer_Index = i; + LayerEntry->SortedOffset = Layer->Vertical_Offset; SortedCompInfo->CurrentSortIndex++; } - // Assert(CompStart[0].LayerCount == 3); - // Assert(CompStart[1].LayerCount == 2); - // Assert(LayerArrayStart[0].Block_Layer_Index == 0); - // Assert(LayerArrayStart[1].Block_Layer_Index == 2); - // Assert(LayerArrayStart[2].Block_Layer_Index == 4); - // Assert(LayerArrayStart[4].Block_Layer_Index == 1); - // Assert(LayerArrayStart[5].Block_Layer_Index == 3); + if (State->Interact_Active == interact_type_layer_move) { + int32 Offset = (int32)State->Interact_Offset[1]; + bool32 Direction = (Offset > 0) ? 1 : -1; + for (uint32 c = 0; c < CompCount; c++) { + sorted_comp_info *SortedCompInfo = &CompStart[c]; + if (!SortedCompInfo->LayerCount) + continue; + sorted_layer *SortedLayerInfo = Layer_GetSortedArray(LayerArrayStart, CompStart, c); + int i = (Direction > 0) ? SortedCompInfo->LayerCount - 1 : 0; + bool32 Case = 1; + while (Case) { + int32 EntriesPassed = 0; + sorted_layer *LayerEntry = &SortedLayerInfo[i]; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, LayerEntry->Block_Layer_Index); + Assert(LayerEntry->SortedOffset == Layer->Vertical_Offset); + if (Layer->IsSelected) { + int32 SpacesToMove = Offset * Direction; + while (SpacesToMove) { + Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerInfo, *SortedCompInfo, &EntriesPassed, LayerEntry); + LayerEntry->SortedOffset -= Direction; + SpacesToMove--; + } + } + int b = 0; + while (b < EntriesPassed) { + sorted_layer *FrontEntry = &SortedLayerInfo[i+(b*Direction)]; + sorted_layer *BackEntry = &SortedLayerInfo[i+((b+1)*Direction)]; + sorted_layer Swap = *FrontEntry; + *FrontEntry = *BackEntry; + *BackEntry = Swap; + b++; + } + i -= Direction; + Case = (Direction > 0) ? (i >= 0) : (i < SortedCompInfo->LayerCount); + } + } + } +} + +static void +Layer_Delete(project_data *File, memory *Memory, uint32 Index) +{ + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index); + History_Action_Block_Swap(Memory, F_Layers, Layer); + Layer->Occupied = 0; + History_Action_Swap(Memory, F_File, sizeof(File->Layer_Count), &File->Layer_Count); + File->Layer_Count--; } block_layer * Layer_Init(project_data *File, memory *Memory) { + if (File->Layer_Count + 1 > MAX_LAYERS) { + Assert(0); + } block_layer *Layer = (block_layer *)Memory_Block_AllocateAddress(Memory, F_Layers); History_Action_Block_Swap(Memory, F_Layers, Layer); @@ -259,22 +410,210 @@ block_layer * Layer_Init(project_data *File, memory *Memory) return Layer; } +void Source_UICreateButton(project_data *File, project_state *State, memory *Memory, + sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray) +{ + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); + sorted_comp_info *SortedCompInfo = &SortedCompArray[File->PrincipalCompIndex]; + int32 TopOffset; + if (!File->Layer_Count) { + TopOffset = 11; + } else { + sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, File->PrincipalCompIndex); + block_layer *TopLayer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, SortedLayerInfo[SortedCompInfo->LayerCount - 1].Block_Layer_Index); + TopOffset = TopLayer->Vertical_Offset; + } + bool32 CommitAction = 0; + int h = 0, c = 0, i = 0; + while (Block_Loop(Memory, F_Sources, File->Source_Count, &h, &c, &i)) { + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, i); + if (Source->IsSelected) { + if (!CommitAction) { + History_Entry_Commit(Memory, "Create layer from source"); + CommitAction = 1; + } + block_layer *Layer = Layer_Init(File, Memory); + Layer->Block_Source_Index = i; + Layer->x.CurrentValue = Source->Width / 2; + Layer->y.CurrentValue = Source->Height / 2; + Layer->Vertical_Offset = TopOffset-1; + Layer->Frame_End = Comp->Frame_End; + TopOffset--; + } + State->UpdateFrame = true; + } + if (CommitAction) + History_Entry_End(Memory); + Source_DeselectAll(File, Memory); +} + + +// Helper for working with different bit depths. +static render_byte_info +Bitmap_ByteInfo(uint32 BytesPerPixel) { + render_byte_info Byte = {}; + if (BytesPerPixel == 4) { + Byte.MaskPixel = 0xFF; + Byte.ByteOffset = 1; + Byte.Normalized = 1 / 255.0f; + Byte.Bits = 255; + } else if (BytesPerPixel == 8) { + Byte.MaskPixel = 0xFFFF; + Byte.ByteOffset = 2; + Byte.Normalized = 1 / 65535.0f; + Byte.Bits = 65535; + } else { + Byte.MaskPixel = 0xFFFFFFFF; + Byte.ByteOffset = 4; + Byte.Normalized = 1 / 4294967295.0f; + Byte.Bits = 4294967295; + Assert(0); + } + return Byte; +} + +// TODO(fox): Make separate full-size bitmap that gets scaled on the GPU instead of this static void -Layer_CreateFromSource(project_data *File, project_state *State, memory *Memory, uint16 SourceIndex, int32 Frame_End) +State_BindBrushTexture(memory *Memory, brush_state *Brush, uint32 BytesPerPixel) { - if (File->Layer_Count + 1 > MAX_LAYERS) { - Assert(0); + GL_GenAndBindTexture(&Brush->GLTexture, Brush->Size, Brush->Size, BytesPerPixel, Brush->PaintBuffer); +} + +static void +Brush_CalcBitmapAlphaFromSize(memory *Memory, brush_state *Brush, uint32 BytesPerPixel) +{ + real32 BrushLength = Brush->Size; + real32 BrushCenter = BrushLength / 2; + real32 MaxLength = BrushCenter; + void *BrushAddress = Brush->PaintBuffer; + + render_byte_info Byte = Bitmap_ByteInfo(BytesPerPixel); + + for (int Y = 0; Y < (int)BrushLength; Y++) { + for (int X = 0; X < (int)BrushLength; X++) { + uint8 *PixelAddress = (uint8 *)BrushAddress + (Y * BytesPerPixel*(int)BrushLength) + (X * BytesPerPixel); + uint32 *R_DestAddress = (uint32 *)(PixelAddress + Byte.ByteOffset*0); + // uint32 *G_DestAddress = (uint32 *)(PixelAddress + Byte.ByteOffset*1); + // uint32 *B_DestAddress = (uint32 *)(PixelAddress + Byte.ByteOffset*2); + uint32 *A_DestAddress = (uint32 *)(PixelAddress + Byte.ByteOffset*3); + v2 Pos = V2(BrushCenter - X, BrushCenter - Y); + real32 L = sqrt(LengthSq(Pos)); + real32 Gradient = Ceil(L, MaxLength) / MaxLength; + Gradient = pow(Gradient, Brush->Hardness); + *R_DestAddress = (*R_DestAddress & ~Byte.MaskPixel) | Byte.Bits; // brush preview is red + *A_DestAddress = (*A_DestAddress & ~Byte.MaskPixel) | (uint32)((1.0f - Gradient)*Byte.Bits); + } } - History_Entry_Commit(Memory,"Add layer from source"); - block_layer *Layer = Layer_Init(File, Memory); - Layer->Block_Source_Index = SourceIndex; - Layer->Frame_End = Frame_End; - History_Entry_End(Memory); +} - State->UpdateFrame = true; +// TODO(fox): We could merge this exactly with the standard rendering code. +static void +PaintTest(memory *Memory, block_source *Source, brush_state *Brush, void *Address, v2 LayerPos, uint32 BytesPerPixel, v4 Color) +{ + uint32 BrushLength = (uint32)Brush->Size; + + rectangle RenderRegion = { 0, 0, Source->Width, Source->Height }; + rectangle BrushPos = { (int32)(LayerPos.x - (BrushLength / 2)), + (int32)(LayerPos.y - (BrushLength / 2)), + (int32)(LayerPos.x + (BrushLength / 2)), + (int32)(LayerPos.y + (BrushLength / 2)) }; + rectangle LayerBounds = ClipRectangle(BrushPos, RenderRegion); + + if (BrushPos.Min.x < Brush->CacheBounds.Min.x) + Brush->CacheBounds.Min.x = BrushPos.Min.x; + if (BrushPos.Min.y < Brush->CacheBounds.Min.y) + Brush->CacheBounds.Min.y = BrushPos.Min.y; + if (BrushPos.Max.x > Brush->CacheBounds.Max.x) + Brush->CacheBounds.Max.x = BrushPos.Max.x; + if (BrushPos.Max.y > Brush->CacheBounds.Max.y) + Brush->CacheBounds.Max.y = BrushPos.Max.y; + + uint32 LayerPitch = Source->Width*Source->BytesPerPixel; + uint32 BrushPitch = (int)BrushLength * BytesPerPixel; + + render_byte_info LayerBits = Bitmap_ByteInfo(Source->BytesPerPixel); + render_byte_info BrushBits = Bitmap_ByteInfo(BytesPerPixel); + + int32 ExtraX = 0; + int32 ExtraY = 0; + if (BrushPos.Min.x < 0) { + ExtraX = BrushPos.Min.x; + } + if (BrushPos.Min.y < 0) { + ExtraY = BrushPos.Min.y; + } + + void *BrushBuffer = Brush->PaintBuffer; + + // ImGui's color picker works in sRGB, so we need to convert to linear. + // real32 R_Brush = (Color.r >= 0.04045) ? pow((Color.r + 0.055) / (1 + 0.055), 2.4) : Color.r / 12.92; + // real32 G_Brush = (Color.g >= 0.04045) ? pow((Color.g + 0.055) / (1 + 0.055), 2.4) : Color.g / 12.92; + // real32 B_Brush = (Color.b >= 0.04045) ? pow((Color.b + 0.055) / (1 + 0.055), 2.4) : Color.b / 12.92; + // real32 A_Brush = (Color.a >= 0.04045) ? pow((Color.a + 0.055) / (1 + 0.055), 2.4) : Color.a / 12.92; + real32 R_Brush = Color.r; + real32 G_Brush = Color.g; + real32 B_Brush = Color.b; + real32 A_Brush = Color.a; + + uint8 *BrushRow = (uint8 *)BrushBuffer; + for (int32 Y = LayerBounds.Min.y; Y < LayerBounds.Max.y; Y++) { + for (int32 X = LayerBounds.Min.x; X < LayerBounds.Max.x; X++) { + + uint32 Offset = Y*LayerPitch + X*Source->BytesPerPixel; + uint8 *LayerPixel = (uint8 *)Address + Offset; + + uint32 *R_DestAddress = (uint32 *)(LayerPixel + LayerBits.ByteOffset * 0); + uint32 *G_DestAddress = (uint32 *)(LayerPixel + LayerBits.ByteOffset * 1); + uint32 *B_DestAddress = (uint32 *)(LayerPixel + LayerBits.ByteOffset * 2); + uint32 *A_DestAddress = (uint32 *)(LayerPixel + LayerBits.ByteOffset * 3); + + real32 R_Layer = (real32)(*R_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized; + real32 G_Layer = (real32)(*G_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized; + real32 B_Layer = (real32)(*B_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized; + real32 A_Layer = (real32)(*A_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized; + + int32 TrueX = (X - LayerBounds.Min.x) - ExtraX; + int32 TrueY = (Y - LayerBounds.Min.y) - ExtraY; + + // Assert(TrueX >= 0 && TrueX < BrushLength); + // Assert(TrueY >= 0 && TrueY < BrushLength); + + uint8 *BrushPixel = (uint8 *)BrushBuffer + (TrueY * BrushPitch) + (TrueX * BytesPerPixel); + + real32 Brush_BitmapAlpha = (real32)((*(uint32 *)(BrushPixel + BrushBits.ByteOffset*3)) & BrushBits.MaskPixel) * BrushBits.Normalized; + + real32 BrushAlpha = Brush_BitmapAlpha * A_Brush; + real32 LayerAlpha = A_Layer; + + real32 A_Blend = LayerAlpha + BrushAlpha; + + real32 R_Blend = (R_Layer * (1.0f - BrushAlpha)) + (R_Brush * BrushAlpha); + real32 G_Blend = (G_Layer * (1.0f - BrushAlpha)) + (G_Brush * BrushAlpha); + real32 B_Blend = (B_Layer * (1.0f - BrushAlpha)) + (B_Brush * BrushAlpha); + + /* + R_Blend = (R_Brush * (1.0f - LayerAlpha)) + (R_Blend * LayerAlpha); + G_Blend = (G_Brush * (1.0f - LayerAlpha)) + (G_Blend * LayerAlpha); + B_Blend = (B_Brush * (1.0f - LayerAlpha)) + (B_Blend * LayerAlpha); + */ + + Assert(R_Blend <= 1.0f); + + uint32 R_Out = (uint32)(Normalize(R_Blend) * LayerBits.Bits); + uint32 G_Out = (uint32)(Normalize(G_Blend) * LayerBits.Bits); + uint32 B_Out = (uint32)(Normalize(B_Blend) * LayerBits.Bits); + uint32 A_Out = (uint32)(Normalize(A_Blend) * LayerBits.Bits); + + *R_DestAddress = (*R_DestAddress & ~LayerBits.MaskPixel) | R_Out; + *G_DestAddress = (*G_DestAddress & ~LayerBits.MaskPixel) | G_Out; + *B_DestAddress = (*B_DestAddress & ~LayerBits.MaskPixel) | B_Out; + *A_DestAddress = (*A_DestAddress & ~LayerBits.MaskPixel) | A_Out; + } + } } + #if 0 static void IncrementFrame(project_data *File, int16 Amount) { -- cgit v1.2.3