summaryrefslogtreecommitdiff
path: root/createcalls.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'createcalls.cpp')
-rw-r--r--createcalls.cpp389
1 files changed, 364 insertions, 25 deletions
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) {