summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFox Caminiti <fox@foxcam.net>2022-12-05 21:45:18 -0500
committerFox Caminiti <fox@foxcam.net>2022-12-05 21:45:18 -0500
commitcdb9e1f7240cb0716b7d99df5e1fd7c3fc3407a8 (patch)
treeb8d08b5dc18401afdb9d9e0f9e476a81e54eb108
parented27ab2e6bbe40120702dcc57e9b21434bfb4944 (diff)
v2.2, color space + brush improvements
-rw-r--r--bitmap_calls.cpp402
-rwxr-xr-xbuild.bat2
-rw-r--r--createcalls.cpp338
-rw-r--r--debug.h3
-rw-r--r--functions.h4
-rw-r--r--main.cpp190
-rw-r--r--main.h31
-rw-r--r--memory.cpp10
-rw-r--r--my_imgui_widgets.cpp194
-rwxr-xr-xpackage.sh2
-rw-r--r--prenderer.cpp79
-rw-r--r--threading.cpp2
-rw-r--r--undo.cpp2
13 files changed, 526 insertions, 733 deletions
diff --git a/bitmap_calls.cpp b/bitmap_calls.cpp
deleted file mode 100644
index 0e76039..0000000
--- a/bitmap_calls.cpp
+++ /dev/null
@@ -1,402 +0,0 @@
-// Bitmaps are curently stored two ways in this program, which I'm calling
-// "packed" and "unpacked." Both are 0xAAGGBBRR little endian. Unpacked bitmaps
-// use the typical method of storage, rows of X that you increment by
-// Width*BytesPerPixel to look up the Y coordinate. "Packed" bitmaps encode
-// pixels as 4x4 chunks. To illustrate this clearly with an 8x4 bitmap:
-
-// A1 A2 A3 A4 E1 E2 E3 E4
-// B1 B2 B3 B4 F1 F2 F3 F4
-// C1 C2 C3 C4 G1 G2 G3 G4
-// D1 D2 D3 D4 H1 H2 H3 H4
-
-// Unpacked would be stored in memory order as A1 A2 A3 A4 E1 E2 E3 E4...
-// while packed would be stored as A1 A2 A3 A4 B1 B2 B3 B4...
-
-// In cases where the bitmap is a non-divisible-by-four size, we simply treat
-// the bitmap as if it's the right size and add the extra pixels in the allocation.
-
-// This wasn't an optimization I necessarily _needed_ to make this early on--I
-// never even did any measuring to see if there was any speedup-- but I
-// couldn't resist it. I like doing the software rendering stuff.
-
-
-// TODO(fox): I could write an AVX version of this function, but it may not be
-// that much faster since we have to do a bit of uninterleaving.
-
-// 0 - store in 4x4 chunks
-// 1 - unpack to 1xwidth
-void Bitmap_ConvertPacking(void *Buffer, void *DestBuffer, uint16 Width, uint16 Height, uint16 BytesPerPixel, uint16 Which)
-{
- uint8 *Src = (uint8 *)Buffer;
- uint8 *Temp = (uint8 *)DestBuffer;
- uint32 RemainderPixels = Width % 4;
- uint16 WidthP, HeightP;
- Bitmap_CalcPackedDimensions(Width, Height, &WidthP, &HeightP);
- for (uint32 Y = 0; Y < Height; Y++) {
- uint32 X = 0;
- while (X < Width - RemainderPixels) {
- uint32 XLookup = (X >> 2)*16 + (X % 4);
- uint32 YLookup = (Y >> 2)*(WidthP*4) + (Y % 4)*4;
- uint32 PixelToSeek = XLookup + YLookup;
- if (Y == 48 && X == 0)
- uint8 war = 0;
- // if (YLookup == 2500 && XLookup == 1)
- uint8 *DPixel, *Pixel;
- if (Which == 0) {
- DPixel = Temp + PixelToSeek*BytesPerPixel;
- Pixel = Src + Y*Width*4 + X*BytesPerPixel;
- } else {
- Pixel = Src + PixelToSeek*BytesPerPixel;
- DPixel = Temp + Y*Width*4 + X*BytesPerPixel;
- }
-
-#if ARM
- if (InstructionMode == instruction_mode_neon) {
- uint32x2x2_t Row = vld2_u32((uint32 *)Pixel);
- vst2_u32((uint32 *)DPixel, Row);
- X += 4;
-#else
- if (InstructionMode == instruction_mode_sse || InstructionMode == instruction_mode_avx) {
- __m128i Row = _mm_loadu_si128((__m128i *)Pixel);
- _mm_storeu_si128((__m128i *)DPixel, Row);
- X+=4;
-#endif
- } else {
- *(uint32 *)DPixel = *(uint32 *)Pixel;
- X++;
- }
- }
- while (X < Width) {
- uint16 WidthP, HeightP;
- Bitmap_CalcPackedDimensions(Width, Height, &WidthP, &HeightP);
- uint32 XLookup = (X >> 2)*16 + (X % 4);
- uint32 YLookup = (Y >> 2)*(WidthP*4) + (Y % 4)*4;
- uint32 PixelToSeek = XLookup + YLookup;
- uint8 *DPixel, *Pixel;
- if (Which == 0) {
- DPixel = Temp + PixelToSeek*BytesPerPixel;
- Pixel = Src + Y*Width*4 + X*BytesPerPixel;
- } else {
- Pixel = Src + PixelToSeek*BytesPerPixel;
- DPixel = Temp + Y*Width*4 + X*BytesPerPixel;
- }
-
- *(uint32 *)DPixel = *(uint32 *)Pixel;
- X++;
- }
- }
-}
-
-// TODO(fox): Replace this in the future.
-#if 0
-static void *
-MoveImportToBitmap(memory *Memory, pixel_buffer *Raster, void *Input)
-{
- uint8 *Row = ((uint8 *)Input);
- // void *Output = AllocateMemory(Memory, Bitmap_CalcTotalBytes(Raster->Width, Raster->Height, Raster->BytesPerPixel), B_Layers);
- uint8 *Row2 = ((uint8 *)Output);
-
- uint64 bytes = 0;
- uint16 ByteOffset = Bitmap_CalculateByteOffset(BytesPerPixel);
- uint64 TotalBytes = Bitmap_CalculateTotalBytes(Width, Height, BytesPerPixel);
- uint64 RemainderBytes = TotalBytes % ByteOffset;
-
- while (bytes <= TotalBytes - RemainderBytes) {
- uint8 *Pixel = (uint8 *)Row + bytes;
- uint8 *Pixel2 = (uint8 *)Row2 + bytes;
- if (InstructionMode == instruction_mode_sse || InstructionMode == instruction_mode_avx) {
- __m128i OutputPixel = _mm_loadu_si128((__m128i *)Pixel);
- _mm_storeu_si128((__m128i *)Pixel2, OutputPixel);
- bytes += 4*Raster->BytesPerPixel;
- } else {
- *(uint32 *)Pixel2 = *(uint32 *)Pixel;
- bytes += Raster->BytesPerPixel;
- }
- }
- while (bytes <= TotalBytes) {
- uint8 *Pixel = (uint8 *)Row + bytes;
- uint8 *Pixel2 = (uint8 *)Row2 + bytes;
- *(uint32 *)Pixel2 = *(uint32 *)Pixel;
- bytes += Raster->BytesPerPixel;
- }
- return Output;
-}
-#endif
-
-static void
-Bitmap_Clear(void *Buffer, uint16 Width, uint16 Height, uint16 BytesPerPixel)
-{
- uint8 *Row = (uint8 *)Buffer;
-#if ARM
- uint32 Zero[4] = {0};
- uint32x2x4_t Zero8 = vld4_dup_u32(Zero);
-#else
- __m256i Zero8 = _mm256_setzero_si256();
- __m128i Zero = _mm_setzero_si128();
-#endif
- uint64 bytes = 0;
-
- uint16 ByteOffset = Bitmap_CalcByteOffset(BytesPerPixel);
- uint64 TotalBytes = Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel);
-
- while (bytes < TotalBytes) {
- uint8 *Pixel = Row + bytes;
-#if ARM
- if (InstructionMode == instruction_mode_neon) {
- vst4_u32((uint32 *)Pixel, Zero8);
-#else
- if (InstructionMode == instruction_mode_avx) {
- _mm256_storeu_si256((__m256i *)Pixel, Zero8);
- } else if (InstructionMode == instruction_mode_sse) {
- _mm_storeu_si128((__m128i *)Pixel, Zero);
-#endif
- } else {
- *(uint32 *)Pixel = 0x00000000;
- }
- bytes += ByteOffset;
- }
-}
-
-static void
-Bitmap_CalcPackedDimensions(uint16 Width, uint16 Height, uint16 *WidthP, uint16 *HeightP) {
- uint16 ExtraWidth = 4 - (Width % 4);
- if (ExtraWidth == 4)
- ExtraWidth = 0;
- uint16 ExtraHeight = 4 - (Height % 4);
- if (ExtraHeight == 4)
- ExtraHeight = 0;
- *WidthP = Width + ExtraWidth;
- *HeightP = Height + ExtraHeight;
-}
-
-static uint16
-Bitmap_CalcByteOffset(uint16 BytesPerPixel) {
- uint16 ByteOffset = BytesPerPixel;
-#if ARM
- if (InstructionMode == instruction_mode_neon)
- ByteOffset = 8*BytesPerPixel;
-#else
- if (InstructionMode == instruction_mode_avx)
- ByteOffset = 8*BytesPerPixel;
- if (InstructionMode == instruction_mode_sse)
- ByteOffset = 4*BytesPerPixel;
-#endif
- return ByteOffset;
-}
-
-static uint64
-Bitmap_CalcUnpackedBytes(uint16 Width, uint16 Height, uint16 BytesPerPixel) {
- uint64 TotalBytes = (uint64)Width*Height*BytesPerPixel;
- return TotalBytes;
-}
-
-static uint64
-Bitmap_CalcTotalBytes(uint16 Width, uint16 Height, uint16 BytesPerPixel) {
- uint16 WidthP, HeightP;
- Bitmap_CalcPackedDimensions(Width, Height, &WidthP, &HeightP);
- uint64 TotalBytes = (uint64)WidthP*HeightP*BytesPerPixel;
- return TotalBytes;
-}
-
-// TODO(fox): Maybe turn this into a generic memory copy; we don't need to care
-// about pixels for any particular reason here.
-static void
-Bitmap_CopyToPointer(void *Input, void *Output, uint16 BytesPerPixel, uint64 TotalBytes)
-{
- uint8 *Row = (uint8 *)Input;
- uint8 *Row2 = (uint8 *)Output;
-
- uint64 bytes = 0;
- uint16 ByteOffset = Bitmap_CalcByteOffset(BytesPerPixel);
- uint64 RemainderBytes = TotalBytes % ByteOffset;
-
- while (bytes <= TotalBytes - RemainderBytes) {
- uint8 *Pixel = (uint8 *)Row + bytes;
- uint8 *Pixel2 = (uint8 *)Row2 + bytes;
-#if ARM
- if (InstructionMode == instruction_mode_neon) {
- uint32x2x4_t OutputPixel = vld4_u32((uint32 *)Pixel);
- vst4_u32((uint32 *)Pixel2, OutputPixel);
-#else
- if (InstructionMode == instruction_mode_avx) {
- __m256i OutputPixel = _mm256_loadu_si256((__m256i *)Pixel);
- _mm256_storeu_si256((__m256i *)Pixel2, OutputPixel);
- } else if (InstructionMode == instruction_mode_sse) {
- __m128i OutputPixel = _mm_loadu_si128((__m128i *)Pixel);
- _mm_storeu_si128((__m128i *)Pixel2, OutputPixel);
-#endif
- } else {
- *(uint32 *)Pixel2 = *(uint32 *)Pixel;
- }
- bytes += ByteOffset;
- }
- while (bytes <= TotalBytes) {
- uint8 *Pixel = (uint8 *)Row + bytes;
- uint8 *Pixel2 = (uint8 *)Row2 + bytes;
- *(uint32 *)Pixel2 = *(uint32 *)Pixel;
- bytes += BytesPerPixel;
- }
-}
-
-static void
-Bitmap_StencilAlpha(void *Input, void *Output, uint16 BytesPerPixel, uint64 TotalBytes)
-{
- uint8 *Row = (uint8 *)Input;
- uint8 *Row2 = (uint8 *)Output;
-
- uint64 bytes = 0;
- uint16 ByteOffset = Bitmap_CalcByteOffset(BytesPerPixel);
- uint64 RemainderBytes = TotalBytes % ByteOffset;
-
-#if ARM
-#else
- __m256i AlphaBytes = _mm256_set1_epi32(0x00FFFFFF);
- __m256i Zeroi = _mm256_set1_epi32(0);
-#endif
-
- while (bytes <= TotalBytes - RemainderBytes) {
- uint8 *Pixel = (uint8 *)Row + bytes;
- uint8 *Pixel2 = (uint8 *)Row2 + bytes;
-#if ARM
- if (InstructionMode == instruction_mode_neon) {
- // TODO(fox): Optimize and write NEON!
- uint8 *DestAlpha = Pixel2 + (BytesPerPixel/4)*3;
- uint8 Alpha = *DestAlpha;
- uint32 *DestPixel = (uint32 *)Pixel2;
- uint32 *SrcPixel = (uint32 *)Pixel;
- *DestPixel = *SrcPixel;
- *DestAlpha = Alpha;
- bytes += BytesPerPixel;
-#else
- if (InstructionMode == instruction_mode_avx) {
- __m256i InputPixel = _mm256_loadu_si256((__m256i *)Pixel);
- __m256i OutputPixel = _mm256_loadu_si256((__m256i *)Pixel2);
- if (_mm256_movemask_epi8(OutputPixel)) {
- OutputPixel = _mm256_blendv_epi8(OutputPixel, InputPixel, AlphaBytes);
- _mm256_storeu_si256((__m256i *)Pixel2, OutputPixel);
- }
- bytes += ByteOffset;
- } else if (InstructionMode == instruction_mode_sse) {
- __m128i OutputPixel = _mm_loadu_si128((__m128i *)Pixel);
- _mm_storeu_si128((__m128i *)Pixel2, OutputPixel);
- bytes += ByteOffset;
-#endif
- } else {
- // TODO(fox): Optimize and write NEON!
- uint8 *DestAlpha = Pixel2 + (BytesPerPixel/4)*3;
- uint8 Alpha = *DestAlpha;
- uint32 *DestPixel = (uint32 *)Pixel2;
- uint32 *SrcPixel = (uint32 *)Pixel;
- *DestPixel = *SrcPixel;
- *DestAlpha = Alpha;
- bytes += BytesPerPixel;
- }
- }
- while (bytes <= TotalBytes) {
- uint8 *Pixel = (uint8 *)Row + bytes;
- uint8 *Pixel2 = (uint8 *)Row2 + bytes;
- // TODO(fox): Optimize and write NEON!
- uint8 *DestAlpha = Pixel2 + (BytesPerPixel/4)*3;
- uint8 Alpha = *DestAlpha;
- uint32 *DestPixel = (uint32 *)Pixel2;
- uint32 *SrcPixel = (uint32 *)Pixel;
- *DestPixel = *SrcPixel;
- *DestAlpha = Alpha;
- bytes += BytesPerPixel;
- }
-}
-
-// This would be an easy SIMD if only AVX had a scatter call...
-// NOTE(fox): Only works with unpacked bitmaps for now.
-static void
-Bitmap_CalcHistogram(void *Data, void *Input, uint16 BytesPerPixel, uint64 TotalBytes)
-{
- uint32 *Slot = (uint32 *)Data;
- uint8 *Row = (uint8 *)Input;
- uint64 bytes = 0;
- uint16 ByteOffset = Bitmap_CalcByteOffset(BytesPerPixel);
- uint64 RemainderBytes = TotalBytes % ByteOffset;
-
- for (int i = 0; i < 256*5; i++) {
- *(real32 *)((uint8 *)Slot + i*sizeof(real32)) = 0;
- }
-
- while (bytes <= TotalBytes) {
- uint8 *Pixel = (uint8 *)Row + bytes;
-
- uint8 A = (*(uint32 *)Pixel >> 24);
- uint8 R = (*(uint32 *)Pixel >> 16);
- uint8 G = (*(uint32 *)Pixel >> 8);
- uint8 B = (*(uint32 *)Pixel >> 0);
-
- uint8 Avg = (uint8)((real32)(R + G + B) / 3.0f);
-
- *(real32 *)((uint8 *)Slot + Avg*sizeof(real32)) += 1;
- *(real32 *)((uint8 *)Slot + (256 + R)*sizeof(real32)) += 1;
- *(real32 *)((uint8 *)Slot + (256*2 + G)*sizeof(real32)) += 1;
- *(real32 *)((uint8 *)Slot + (256*3 + B)*sizeof(real32)) += 1;
- *(real32 *)((uint8 *)Slot + (256*4 + A)*sizeof(real32)) += 1;
-
- bytes += BytesPerPixel;
- }
-}
-
-#if 0
-static void
-BitmapPackRGB(pixel_buffer *Buffer) {
- Assert(Buffer->Pitch);
- Convert4x4Chunk(Buffer, 0);
- CopyToBuffer(Buffer, 1);
- ClearBuffer(Buffer, Buffer->EffectBuffer);
-}
-
-static void
-DebugFillSolid(pixel_buffer *Raster, v4 Color)
-{
- uint32 ColS = ColToUint32(Color);
- __m256i Col8 = _mm256_set1_epi32(ColS);
- __m128i Col = _mm_set1_epi32(ColS);
- uint8 *Row = (uint8 *)Raster->OriginalBuffer;
-
- uint64 bytes = 0;
- uint16 ByteOffset = Raster->BytesPerPixel;
- if (InstructionMode == instruction_mode_avx)
- ByteOffset = 8*Raster->BytesPerPixel;
- else if (InstructionMode == instruction_mode_sse)
- ByteOffset = 4*Raster->BytesPerPixel;
-
- uint64 TotalBytes = Raster->FullHeight*Raster->FullWidth*Raster->BytesPerPixel;
-
- while (bytes < TotalBytes) {
- uint8 *Pixel = Row + bytes;
- if (InstructionMode == instruction_mode_avx) {
- _mm256_storeu_si256((__m256i *)Pixel, Col8);
- } else if (InstructionMode == instruction_mode_sse) {
- _mm_storeu_si128((__m128i *)Pixel, Col);
- } else {
- *(uint32 *)Pixel = ColS;
- }
- bytes += ByteOffset;
- }
-}
-
-static void
-DebugBitmap(pixel_buffer *Raster)
-{
- uint8 asda = 0x0;
- uint8 *Row = ((uint8 *)Raster->OriginalBuffer);
- real32 XInc = 255.0f / Raster->Width;
- real32 YInc = 255.0f / Raster->Height;
- for (uint8 Y = 0; Y < Raster->Height; Y++) {
- for (uint8 X = 0; X < Raster->Width; X++) {
- uint8 *Pixel = (uint8 *)Row + Raster->FullWidth*Y*4 + X*4;
- // *(uint32 *)Pixel = 0xffffffff;
- if (Y > 3) { asda = 0xff; }
- *(uint32 *)Pixel = ((0xff << 24) |
- (asda << 16) |
- (RoundReal32ToInt32((YInc * Y)) << 8) |
- (RoundReal32ToInt32((XInc * X))) );
- }
- }
-}
-#endif
diff --git a/build.bat b/build.bat
index e212882..7f644ee 100755
--- a/build.bat
+++ b/build.bat
@@ -7,7 +7,7 @@ set FFMPEG_DIR=C:\lib\ffmpeg-n5.0-latest-win64-lgpl-shared-5.0
REM /Zi /O2
set OPTIMIZATION=/O2
set DEBUG=0
-set IMGUI=0
+set IMGUI=1
set ARM=0
set PERF=0
set STABLE=0
diff --git a/createcalls.cpp b/createcalls.cpp
index 912917f..4be6b45 100644
--- a/createcalls.cpp
+++ b/createcalls.cpp
@@ -102,14 +102,15 @@ 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, 0);
+ History_Action_Block_Swap(Memory, F_Sources, Source);
Source->Occupied = 1;
Source->Width = Width;
Source->Height = Height;
- Source->BytesPerPixel= BytesPerPixel;
+ 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);
+ History_Action_Swap(Memory, F_File, sizeof(File->Source_Count), &File->Source_Count);
File->Source_Count++;
return Index;
}
@@ -204,15 +205,15 @@ Bezier_EvaluateValue(project_state *State, bezier_point *PointAddress, v2 *Pos,
}
}
-
+// TODO(fox): Test multiple keyframe blocks!
static void
Bezier_Add(memory *Memory, memory_table_list TableName, property_channel *Property, bezier_point PointData, uint16 *ArrayLocation)
{
if (!Property->Block_Bezier_Count) {
+ Assert(Property->Keyframe_Count < MAX_KEYFRAMES_PER_BLOCK);
Property->Block_Bezier_Index[0] = Memory_Block_AllocateNew(Memory, F_Bezier);
block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Property->Block_Bezier_Index[0], 0);
Bezier->Occupied = true;
- // NOTE(fox): Effects will change this!
History_Action_Swap(Memory, TableName, sizeof(Property->Block_Bezier_Count), &Property->Block_Bezier_Count);
Property->Block_Bezier_Count++;
}
@@ -320,6 +321,8 @@ Effect_Init(project_state *State, memory *Memory, uint32 EffectEntryIndex, int E
{
uint16 EffectAddressIndex = Memory_Block_AllocateNew(Memory, F_Effects);
block_effect *Effect = (block_effect *)Memory_Block_AddressAtIndex(Memory, F_Effects, EffectAddressIndex, 0);
+ History_Action_Block_Swap(Memory, F_Effects, Effect);
+ *Effect = {};
Effect->Occupied = true;
header_effect *EffectHeader = &State->Effect[EffectEntryIndex];
String_Copy(Effect->ID, EffectHeader->ID, 8);
@@ -328,6 +331,7 @@ Effect_Init(project_state *State, memory *Memory, uint32 EffectEntryIndex, int E
for (int e = 0; e < EffectHeader->Property_Count; e++) {
Effect->Block_Property_Index[e] = Memory_Block_AllocateNew(Memory, F_Properties);
property_channel *Property = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect->Block_Property_Index[e], 0);
+ History_Action_Block_Swap(Memory, F_Properties, Property);
Property->Occupied = true;
header_property PropertyHeader = State->Property[EffectHeader->PropertyStartIndex + e];
Property->Identifier = -1;
@@ -341,15 +345,21 @@ Effect_Init(project_state *State, memory *Memory, uint32 EffectEntryIndex, int E
static void
Effect_Add(project_data *File, project_state *State, memory *Memory, uint32 EffectEntryIndex)
{
+ History_Entry_Commit(Memory, "Add effect");
int h = 0, c = 0, i = 0;
+ int Selected = 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->Block_Effect_Index[Layer->Block_Effect_Count] = Effect_Init(State, Memory, EffectEntryIndex, Layer->Block_Effect_Count);
+ History_Action_Swap(Memory, F_File, sizeof(Layer->Block_Effect_Count), &Layer->Block_Effect_Count);
Layer->Block_Effect_Count++;
+ Selected++;
}
}
+ History_Entry_End(Memory);
+ Assert(Selected);
}
static void
@@ -793,13 +803,13 @@ Layer_TraverseForPoint(project_data *File, project_state *State, memory *Memory,
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, State->TempZoomRatio);
+ 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, State->TempZoomRatio);
+ PointUV = T_CompUVToLayerUV(T, OuterWidth, OuterHeight, InnerWidth, InnerHeight, PrincipalCompUV);
OuterWidth = InnerWidth;
OuterHeight = InnerHeight;
}
@@ -971,10 +981,6 @@ void Property_SortAll(memory *Memory, project_state *State, property_channel *Pr
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) {
@@ -1316,17 +1322,73 @@ void File_Sort_Pop(memory *Memory, uint64 Layer_SortSize, uint64 Property_SortSi
Memory_PopScratch(Memory, Layer_SortSize);
}
-
+// lots of cleanup...
static void
-Layer_Delete(project_data *File, memory *Memory, uint32 Index)
+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 void
+Project_Layer_Delete(project_data *File, project_state *State, memory *Memory)
+{
+ bool32 CommitAction = 0;
+ int h = 0, c = 0, i = 0;
+ int LayerCount = File->Layer_Count;
+ while (Block_Loop(Memory, F_Layers, LayerCount, &h, &c, &i)) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
+ if (Layer->IsSelected) {
+ if (!CommitAction) {
+ History_Entry_Commit(Memory, "Delete layer");
+ CommitAction = 1;
+ }
+ Layer_Delete(File, State, Memory, i);
+ }
+ }
+ if (CommitAction) {
+ History_Entry_End(Memory);
+ State->UpdateFrame = true;
+ State->MostRecentlySelectedLayer = -1;
+ }
+}
+
+static bool32
+Property_IsGraphSelected(memory *Memory, property_channel *Property, uint16 *ArrayLocation)
+{
+ for (int p = 0; p < Property->Keyframe_Count; p++) {
+ int k = ArrayLocation[p];
+ bezier_point *Point = Bezier_LookupAddress(Memory, Property, k);
+ if (Point->IsSelected)
+ return 1;
+ }
+ return 0;
+}
block_layer * Layer_Init(project_data *File, memory *Memory)
{
@@ -1342,6 +1404,7 @@ block_layer * Layer_Init(project_data *File, memory *Memory)
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);
@@ -1361,19 +1424,52 @@ 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)
+static int
+Layer_GetTopOffset(project_data *File, memory *Memory)
{
- 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;
+ 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
+Project_PaintLayer_New(project_data *File, project_state *State, memory *Memory)
+{
+ int TopOffset = Layer_GetTopOffset(File, Memory);
+ block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex);
+ Arbitrary_Zero((uint8 *)State->Brush.TransientBitmap, 2048*2048*4);
+ State->Interact_Active = interact_type_brush;
+ Layer_DeselectAll(File, State, Memory);
+ History_Entry_Commit(Memory, "Paint new layer");
+ uint16 i = Source_Generate_Blank(File, State, Memory, MainComp->Width, MainComp->Height, MainComp->BytesPerPixel);
+ block_layer *Layer = Layer_Init(File, Memory);
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+ State->Brush.LayerToPaint_Index = Memory_Block_LazyIndexAtAddress(Memory, F_Layers, (void *)Layer);
+ Layer->Block_Source_Index = i;
+ Layer->x.CurrentValue = MainComp->Width / 2;
+ Layer->y.CurrentValue = MainComp->Height / 2;
+ if (File->Layer_Count == 1) {
+ Layer->Vertical_Offset = 11 - 1;
} 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;
+ Layer->Vertical_Offset = TopOffset - 1;
}
+ Layer->Frame_Start = MainComp->Frame_Start;
+ Layer->Frame_End = MainComp->Frame_End;
+ Layer_Select(Memory, State, Memory_Block_LazyIndexAtAddress(Memory, F_Layers, Layer));
+ History_Entry_End(Memory);
+ State->UpdateFrame = true;
+}
+
+void Source_UICreateButton(project_data *File, project_state *State, memory *Memory)
+{
+ block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex);
+ int TopOffset = Layer_GetTopOffset(File, Memory);
bool32 CommitAction = 0;
int h = 0, c = 0, i = 0;
while (Block_Loop(Memory, F_Sources, File->Source_Count, &h, &c, &i)) {
@@ -1434,6 +1530,20 @@ void Precomp_UIDuplicate(project_data *File, project_state *State, memory *Memor
}
}
+void Precomp_UIDelete(project_data *File, project_state *State, memory *Memory, uint16 CompIndex,
+ sorted_comp_info SortedCompInfo, sorted_layer *SortedLayerInfo)
+{
+ block_layer *Layer = NULL;
+ for (int i = SortedCompInfo.LayerCount - 1; i >= 0; i--)
+ {
+ sorted_layer SortEntry = SortedLayerInfo[i];
+ uint32 Index_Physical = SortEntry.Block_Layer_Index;
+ Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical);
+ if (Layer->IsSelected) {
+ }
+ }
+}
+
void Precomp_UICreateButton(project_data *File, project_state *State, memory *Memory, uint16 CompIndex,
sorted_comp_info SortedCompInfo, sorted_layer *SortedLayerInfo)
{
@@ -1542,14 +1652,63 @@ Brush_CalcBitmapAlphaFromSize(memory *Memory, brush_state *Brush, uint32 BytesPe
real32 L = sqrt(LengthSq(Pos));
real32 Gradient = Ceil(L, MaxLength) / MaxLength;
Gradient = pow(Gradient, Brush->Hardness);
+ // Gradient = (Gradient >= 0.04045) ? pow((Gradient + 0.055) / (1 + 0.055), 2.4) : Gradient / 12.92;
+ // Gradient = (Gradient >= 0.0031308) ? (1.055) * pow(Gradient, (1.0/2.4)) - 0.055 : 12.92 * Gradient;
*R_DestAddress = (*R_DestAddress & ~Byte.MaskPixel) | Byte.Bits; // brush preview is red
*A_DestAddress = (*A_DestAddress & ~Byte.MaskPixel) | (uint32)((1.0f - Gradient)*Byte.Bits);
}
}
}
+// Imported bitmaps are stored in linear, and all ops are also done in linear.
+static void
+Bitmap_SRGBToLinear(void *Buffer, uint16 Width, uint16 Height, uint16 BytesPerPixel, bool32 ToLinear)
+{
+ uint8 *Row = (uint8 *)Buffer;
+ uint64 TotalBytes = Width * Height * BytesPerPixel;
+
+ render_byte_info LayerBits = Bitmap_ByteInfo(BytesPerPixel);
+
+ uint64 bytes = 0;
+ while (bytes < TotalBytes) {
+ uint8 *LayerPixel = Row + bytes;
+ 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 TexR = (real32)(*R_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized;
+ real32 TexG = (real32)(*G_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized;
+ real32 TexB = (real32)(*B_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized;
+ real32 TexA = (real32)(*A_DestAddress & LayerBits.MaskPixel) * LayerBits.Normalized;
+
+ if (ToLinear) {
+ TexR = (TexR >= 0.04045) ? pow((TexR + 0.055) / (1 + 0.055), 2.4) : TexR / 12.92;
+ TexG = (TexG >= 0.04045) ? pow((TexG + 0.055) / (1 + 0.055), 2.4) : TexG / 12.92;
+ TexB = (TexB >= 0.04045) ? pow((TexB + 0.055) / (1 + 0.055), 2.4) : TexB / 12.92;
+ TexA = (TexA >= 0.04045) ? pow((TexA + 0.055) / (1 + 0.055), 2.4) : TexA / 12.92;
+ } else {
+ TexR = (TexR >= 0.0031308) ? (1.055) * pow(TexR, (1.0/2.4)) - 0.055 : 12.92 * TexR;
+ TexG = (TexG >= 0.0031308) ? (1.055) * pow(TexG, (1.0/2.4)) - 0.055 : 12.92 * TexG;
+ TexB = (TexB >= 0.0031308) ? (1.055) * pow(TexB, (1.0/2.4)) - 0.055 : 12.92 * TexB;
+ TexA = (TexA >= 0.0031308) ? (1.055) * pow(TexA, (1.0/2.4)) - 0.055 : 12.92 * TexA;
+ }
+
+ uint32 R_Out = (uint32)(Normalize(TexR) * LayerBits.Bits);
+ uint32 G_Out = (uint32)(Normalize(TexG) * LayerBits.Bits);
+ uint32 B_Out = (uint32)(Normalize(TexB) * LayerBits.Bits);
+ uint32 A_Out = (uint32)(Normalize(TexA) * 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;
+ bytes += BytesPerPixel;
+ }
+}
+
static void
-Brush_Info(brush_info *B, brush_state *Brush, block_source *Source, v2 LayerPos, v4 Color)
+Brush_Info(brush_info *B, brush_state *Brush, block_source *Source, void *SourceBuffer, v2 LayerPos, v4 Color)
{
B->BrushLength = (uint32)Brush->Size;
if (B->BrushLength > 128) {
@@ -1573,9 +1732,12 @@ Brush_Info(brush_info *B, brush_state *Brush, block_source *Source, v2 LayerPos,
if (BrushPos.Max.y > Brush->CacheBounds.Max.y)
Brush->CacheBounds.Max.y = BrushPos.Max.y;
+ Assert(Source->Type == source_type_principal);
+
B->BytesPerPixel = 4;
B->SourceWidth = Source->Width;
B->SourceBytesPerPixel = Source->BytesPerPixel;
+ B->SourceBuffer = SourceBuffer;
Assert(Source->BytesPerPixel == 4);
@@ -1597,15 +1759,10 @@ Brush_Info(brush_info *B, brush_state *Brush, block_source *Source, v2 LayerPos,
B->BrushBuffer = Brush->PaintBuffer;
B->EraseMode = Brush->EraseMode;
- // 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;
- B->R_Brush = Color.r;
- B->G_Brush = Color.g;
- B->B_Brush = Color.b;
- B->A_Brush = Color.a;
+ B->R_Brush = (Color.r >= 0.04045) ? pow((Color.r + 0.055) / (1 + 0.055), 2.4) : Color.r / 12.92;
+ B->G_Brush = (Color.g >= 0.04045) ? pow((Color.g + 0.055) / (1 + 0.055), 2.4) : Color.g / 12.92;
+ B->B_Brush = (Color.b >= 0.04045) ? pow((Color.b + 0.055) / (1 + 0.055), 2.4) : Color.b / 12.92;
+ B->A_Brush = (Color.a >= 0.04045) ? pow((Color.a + 0.055) / (1 + 0.055), 2.4) : Color.a / 12.92;
B->BrushRow = (uint8 *)B->BrushBuffer;
}
@@ -1615,68 +1772,29 @@ void Bitmap_SwapData(uint8 *Address_0, uint8 *Address_1, uint64 Size, uint16 Byt
uint64 i = 0;
uint16 ByteOffset = Bitmap_ByteInfo(BytesPerPixel).ByteOffset;
uint64 RemainderBytes = Size % ByteOffset;
- Assert(BytesPerPixel == 8);
-
-#if ARM
- Assert(InstructionMode != instruction_mode_neon);
-#else
- if (BytesPerPixel == 4) {
- uint32 Temp = 0;
- while (i < Size) {
- uint32 *Pixel_0 = (uint32 *)(Address_0 + i);
- uint32 *Pixel_1 = (uint32 *)(Address_1 + i);
- if (*Pixel_0 != 0x00000000) {
- Temp = *Pixel_1;
- *Pixel_1 = *Pixel_0;
- *Pixel_0 = Temp;
- }
- i += sizeof(uint32);
+ Assert(BytesPerPixel == 4);
+
+ while (i < Size) {
+ uint32 *Pixel_0 = (uint32 *)(Address_0 + i);
+ uint32 *Pixel_1 = (uint32 *)(Address_1 + i);
+ if (*Pixel_0 != 0x00000000) {
+ uint32 Temp = *Pixel_1;
+ *Pixel_1 = *Pixel_0;
+ *Pixel_0 = Temp;
}
- } else if (BytesPerPixel == 8) {
- uint64 Temp = 0;
- __m256i Zero = _mm256_set1_epi64x(0);
- __m256i Max32 = _mm256_set1_epi32(0xFFFFFFFF);
- if (InstructionMode == instruction_mode_avx) {
- while (i < Size - RemainderBytes) {
- uint8 *Pixel_0_Address = (Address_0 + i);
- __m256i Pixel_0 = _mm256_loadu_si256((__m256i *)Pixel_0_Address);
- __m256i AlphaMask = _mm256_cmpeq_epi64(Pixel_0, Zero);
- if (_mm256_movemask_epi8(AlphaMask) != 0xFFFFFFFF) {
- uint8 *Pixel_1_Address = (Address_1 + i);
- __m256i Pixel_1 = _mm256_loadu_si256((__m256i *)Pixel_1_Address);
- AlphaMask = _mm256_andnot_si256(AlphaMask, Max32);
- _mm256_maskstore_epi64((long long *)Pixel_1_Address, AlphaMask, Pixel_0);
- _mm256_maskstore_epi64((long long *)Pixel_0_Address, AlphaMask, Pixel_1);
- }
- i += sizeof(uint64)*4;
- }
- }
- while (i < Size) {
- uint64 *Pixel_0 = (uint64 *)(Address_0 + i);
- uint64 *Pixel_1 = (uint64 *)(Address_1 + i);
- if (*Pixel_0 != 0x0000000000000000) {
- Temp = *Pixel_1;
- *Pixel_1 = *Pixel_0;
- *Pixel_0 = Temp;
- }
- i += sizeof(uint64);
- }
- } else {
- Assert(0);
+ i += sizeof(uint32);
}
-#endif
-
}
static void
-PaintTest(brush_info B, void *Buffer, rectangle RenderRegion)
+PaintTest(brush_info B, void *CacheBuffer, 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*B.LayerPitch + X*B.SourceBytesPerPixel;
- uint8 *LayerPixel = (uint8 *)Buffer + Offset;
+ uint8 *LayerPixel = (uint8 *)CacheBuffer + Offset;
uint32 *R_DestAddress = (uint32 *)(LayerPixel + B.LayerBits.ByteOffset * 0);
uint32 *G_DestAddress = (uint32 *)(LayerPixel + B.LayerBits.ByteOffset * 1);
@@ -1691,6 +1809,12 @@ PaintTest(brush_info B, void *Buffer, rectangle RenderRegion)
int32 TrueX = (X - B.LayerBounds.Min.x) - B.ExtraX;
int32 TrueY = (Y - B.LayerBounds.Min.y) - B.ExtraY;
+ uint8 *SourcePixel = (uint8 *)B.SourceBuffer + Offset;
+ Assert(B.SourceBytesPerPixel == 4);
+ bool32 IsEmpty = (*(uint32 *)SourcePixel == 0x00000000);
+ if (IsEmpty)
+ *(uint32 *)SourcePixel = 0x00010101;
+
// Assert(TrueX >= 0 && TrueX < BrushLength);
// Assert(TrueY >= 0 && TrueY < BrushLength);
@@ -1698,7 +1822,10 @@ PaintTest(brush_info B, void *Buffer, rectangle RenderRegion)
real32 Brush_BitmapAlpha = (real32)((*(uint32 *)(BrushPixel + B.BrushBits.ByteOffset*3)) & B.BrushBits.MaskPixel) * B.BrushBits.Normalized;
- real32 BrushAlpha = Brush_BitmapAlpha * B.A_Brush;
+ if (!Brush_BitmapAlpha)
+ continue;
+
+ real32 BrushAlpha = Brush_BitmapAlpha;
real32 LayerAlpha = A_Layer;
real32 A_Blend = 0;
@@ -1707,13 +1834,22 @@ PaintTest(brush_info B, void *Buffer, rectangle RenderRegion)
real32 B_Blend = 0;
if (!B.EraseMode) {
- A_Blend = LayerAlpha + BrushAlpha;
- // R_Blend = (R_Layer * (1.0f - BrushAlpha)) + (B.R_Brush * BrushAlpha);
- // G_Blend = (G_Layer * (1.0f - BrushAlpha)) + (B.G_Brush * BrushAlpha);
- // B_Blend = (B_Layer * (1.0f - BrushAlpha)) + (B.B_Brush * BrushAlpha);
- R_Blend = B.R_Brush;
- G_Blend = B.G_Brush;
- B_Blend = B.B_Brush;
+ if (IsEmpty) {
+ R_Blend = B.R_Brush;
+ G_Blend = B.G_Brush;
+ B_Blend = B.B_Brush;
+ A_Blend = LayerAlpha + BrushAlpha;
+ } else {
+ R_Blend = B.R_Brush;
+ G_Blend = B.G_Brush;
+ B_Blend = B.B_Brush;
+ A_Blend = LayerAlpha + ((1.0f - LayerAlpha) * BrushAlpha);
+ real32 Blend = BrushAlpha;
+ // R_Blend = (R_Layer * (1.0f - Blend)) + (B.R_Brush * Blend);
+ // G_Blend = (G_Layer * (1.0f - Blend)) + (B.G_Brush * Blend);
+ // B_Blend = (B_Layer * (1.0f - Blend)) + (B.B_Brush * Blend);
+ }
+ // A_Blend = BrushAlpha;
} else {
A_Blend = A_Layer * (1.0f - BrushAlpha);
R_Blend = R_Layer;
@@ -1815,13 +1951,17 @@ PaintTest_AVX2(brush_info B, void *Buffer, rectangle RenderRegion)
#endif
static void
-Brush_Render(project_state *State, ui *UI, layer_transforms T_Layer, block_composition *MainComp, block_source *Source, void *BitmapAddress, ImVec2 ViewportMin, v2 LayerPos)
+RenderQueue_AddBrush(project_state *State, v2 LayerPos)
{
- brush_info B;
- 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);
- }
+ State->Queue.Item[State->Queue.CurrentIdx].Pos = LayerPos;
+ State->Queue.Item[State->Queue.CurrentIdx].Type = 1;
+ State->Queue.CurrentIdx++;
+ State->Brush.PrevPos = LayerPos;
+}
+
+static void
+RenderQueue_AddBlit(project_state *State)
+{
+ State->Queue.Item[State->Queue.CurrentIdx].Type = 2;
+ State->Queue.CurrentIdx++;
}
diff --git a/debug.h b/debug.h
index a811b02..6321679 100644
--- a/debug.h
+++ b/debug.h
@@ -27,9 +27,10 @@ struct debug_temp
struct project_debug
{
debug_temp Temp;
- bool32 ToggleWindow = 0;
+ bool32 ToggleWindow = 1;
bool32 ReloadUI = true;
bool32 NoThreading = 0;
+ bool32 DisableAlpha = 0;
uint64 PixelCountTransparent;
uint64 PixelCountRendered;
uint64 PixelCountChecked;
diff --git a/functions.h b/functions.h
index ffba30c..de0aaf9 100644
--- a/functions.h
+++ b/functions.h
@@ -3,7 +3,9 @@ static void Arbitrary_Zero(uint8 *Address_Write, uint64 Size);
static void Arbitrary_SwapData(memory *Memory, uint8 *Address_0, uint8 *Address_1, uint64 Size);
static void Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 ShiftAmount, int32 Direction);
-static void Render_Main(void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion);
+static void
+Render_Main(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID,
+ void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion);
static void Effect_Curves_Init(block_effect *Effect, property_channel *Property);
diff --git a/main.cpp b/main.cpp
index a32598f..de14019 100644
--- a/main.cpp
+++ b/main.cpp
@@ -68,6 +68,8 @@ static uint64 BitmapBlockSize;
static instruction_mode InstructionMode = instruction_mode_scalar;
static uint32 RandomGlobalIncrement = 0;
+uint32 BitmapFill = 0x00000001;
+
#if STABLE
#include "lib/base64.c"
#include <curl/curl.h>
@@ -103,7 +105,7 @@ Main_RenderUI(ImGuiIO io, ImVec4 clear_color, SDL_Window *window)
}
static void
-Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, SDL_Window *window, GLuint textureID)
+Main_InputTest(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID)
{
ImGuiIO& io = ImGui::GetIO();
SDL_Event event = {};
@@ -138,47 +140,14 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI,
}
if (!io.WantCaptureKeyboard)
- ImGui_ProcessInputs(File, State, UI, Memory, io);
-
- sorted_file Sorted = File_Sort_Push(File, State, Memory);
-
- // These depend on sorting, so they can't be done in the ProcessInputs function:
- if (State->HotkeyInput) {
- switch (State->HotkeyInput) {
- case hotkey_none:
- {
- Assert(0);
- } break;
- case hotkey_transform:
- {
- Interact_Transform_Begin(File, Memory, State, io.MousePos, Sorted.CompArray, Sorted.LayerArray);
- } break;
- case hotkey_copy:
- {
- Clipboard_Store(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray);
- } break;
- case hotkey_paste:
- {
- Clipboard_Paste(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyArray);
- } break;
- case hotkey_togglechannels:
- {
- Project_ToggleAllChannels(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray);
- } break;
- default:
- {
- Assert(0);
- } break;
- }
- State->HotkeyInput = hotkey_none;
- }
-
+ ImGui_ProcessInputs(File, State, UI, Memory, io, Sorted);
ImGui::DockSpaceOverViewport();
#if DEBUG
if (Debug.ToggleWindow) {
ImGui::ShowDemoWindow();
+ ImGui_DebugRenderQueue(State);
ImGui_DebugMemoryViewer(Memory, State);
ImGui_DebugUndoTree(Memory, State);
}
@@ -199,8 +168,6 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI,
ImGui_Menu(File, State, UI, Memory, io);
ImGui_Popups(File, State, UI, Memory, io);
- File_Sort_Pop(Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize, Sorted.Source_SortSize);
-
#if DEBUG
Debug.Temp = {};
#endif
@@ -209,13 +176,15 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI,
}
static void
-Render_Main(void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion)
+Render_Main(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID,
+ void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion)
{
bool32 IsRendering = true;
Renderer_Start(Data, OutputBuffer, RenderType, RenderRegion);
while (IsRendering) {
-
- // Main_InputTest(File, State, &Memory, &UI);
+ Main_InputTest(File, State, Memory, Sorted, UI, window, textureID);
+ // ImGuiIO& io = ImGui::GetIO();
+ // Main_RenderUI(io, ImVec4(0.45f, 0.55f, 0.60f, 1.00f), window);
Renderer_Check(&IsRendering, RenderType);
}
}
@@ -274,7 +243,7 @@ Layer_UpdateAllKeyframes(project_data *File, project_state *State, memory *Memor
}
static void *
-Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io,
+Render_Comp(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, ImGuiIO io,
sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray,
sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray, uint32 CompIndex, int32 Frame_Current)
{
@@ -347,7 +316,7 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io
BytesPerPixel = Source->BytesPerPixel;
} else {
block_composition *Precomp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index);
- BitmapAddress = Render_Comp(File, State, Memory, io, SortedCompArray, SortedLayerArray,
+ BitmapAddress = Render_Comp(File, State, Memory, Sorted, UI, window, textureID, io, SortedCompArray, SortedLayerArray,
SortedPropertyInfo, SortedPropertyArray, Layer->Block_Source_Index, (int32)Layer->time.CurrentValue);
Width = Precomp->Width;
Height = Precomp->Height;
@@ -364,9 +333,9 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io
// TODO(fox): Do all these extra precomputes really make a difference in the renderer?
rectangle RenderRegion = { 0, 0, Width, Height };
direct_info Info = { (real32)Width, (real32)Height, (real32)BytesPerPixel, (real32)Width * BytesPerPixel,
- Bitmap_ByteInfo(BytesPerPixel), blend_normal,
- RenderRegion, State->Brush.TransientBitmap};
- Render_Main((void *)&Info, RenderAddress, render_type_notransform, State->Brush.CacheBounds);
+ Bitmap_ByteInfo(BytesPerPixel), UI->Color.a, blend_normal,
+ RenderRegion, State->Brush.TransientBitmap, 0, 0};
+ Render_Main(File, State, Memory, Sorted, UI, window, textureID, (void *)&Info, RenderAddress, render_type_notransform, State->Brush.CacheBounds);
} else if (Layer->Block_Effect_Count || Layer->Block_Mask_Count) {
Layer_UpdateMasksEffects(State, Layer, Memory, RenderAddress, Width, Height, BytesPerPixel);
}
@@ -377,7 +346,7 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io
T.SourceBuffer = RenderAddress;
rectangle RenderRegion = {0, 0, Comp->Width, Comp->Height};
- Render_Main((void *)&T, CompBuffer, render_type_main, RenderRegion);
+ Render_Main(File, State, Memory, Sorted, UI, window, textureID, (void *)&T, CompBuffer, render_type_main, RenderRegion);
Memory_PopScratch(Memory, ScratchSize);
}
}
@@ -387,17 +356,57 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io
}
static void
-Main_Renderer(project_data *File, project_state *State, memory *Memory, SDL_Window *window, GLuint textureID, ImGuiIO io)
+Render_Paint(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, ImGuiIO io, v2 LayerPos)
{
- block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex);
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, State->Brush.LayerToPaint_Index);
+ layer_transforms T_Layer = Layer_GetTransforms(Layer);
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+ void *SourceBitmapAddress = Memory_Block_AddressAtIndex(Memory, F_PrincipalBitmaps, Source->Bitmap_Index, 0);
+
+ brush_info B;
+ Brush_Info(&B, &State->Brush, Source, SourceBitmapAddress, LayerPos, UI->Color);
+ if (State->Brush.Size >= 128) {
+ Render_Main(File, State, Memory, Sorted, UI, window, textureID, (void *)&B, State->Brush.TransientBitmap, render_type_brush, B.LayerBounds);
+ } else {
+ PaintTest(B, State->Brush.TransientBitmap, B.LayerBounds);
+ }
+}
- sorted_file Sorted = File_Sort_Push(File, State, Memory);
+static void
+Render_Blit(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, ImGuiIO io, v2 LayerPos)
+{
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, State->Brush.LayerToPaint_Index);
+ layer_transforms T_Layer = Layer_GetTransforms(Layer);
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+ void *SourceBitmapAddress = Memory_Block_AddressAtIndex(Memory, F_PrincipalBitmaps, Source->Bitmap_Index, 0);
+ rectangle RenderRegion = { 0, 0, Source->Width, Source->Height };
+ direct_info Info = { (real32)Source->Width, (real32)Source->Height, (real32)Source->BytesPerPixel, (real32)Source->Width * Source->BytesPerPixel,
+ Bitmap_ByteInfo(Source->BytesPerPixel), UI->Color.a, blend_normal,
+ RenderRegion, State->Brush.TransientBitmap, 1, 0};
+ Render_Main(File, State, Memory, Sorted, UI, window, textureID, (void *)&Info, SourceBitmapAddress, render_type_notransform_swap, State->Brush.CacheBounds);
+ uint64 BitmapSize = Source->Width * Source->Height * Source->BytesPerPixel;
+ History_Entry_Commit(Memory, "Paintbrush stroke");
+ History_Action_BitmapPaint(Memory, BitmapSize, SourceBitmapAddress, State->Brush.TransientBitmap, Source->BytesPerPixel);
+ History_Entry_End(Memory);
+ State->Brush.LayerToPaint_Index = -1;
+ State->Brush.PrevPos = V2(-4000, -4000);
+ State->Brush.CacheBounds = { 99999, 99999, -99999, -99999 };
+ State->Interact_Active = interact_type_none;
+ State->Interact_Modifier = 0;
+ State->UpdateFrame = true;
+}
- void *MainCompBuffer = Render_Comp(File, State, Memory, io, Sorted.CompArray, Sorted.LayerArray,
- Sorted.PropertyInfo, Sorted.PropertyArray, File->PrincipalCompIndex, State->Frame_Current);
+static void
+Main_Renderer(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, ImGuiIO io)
+{
+ State->UpdateFrame = false;
+ State->UpdateKeyframes = false;
- File_Sort_Pop(Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize, Sorted.Source_SortSize);
+ block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex);
+ void *MainCompBuffer = Render_Comp(File, State, Memory, Sorted, UI, window, textureID, io, Sorted.CompArray, Sorted.LayerArray,
+ Sorted.PropertyInfo, Sorted.PropertyArray, File->PrincipalCompIndex, State->Frame_Current);
+ Bitmap_SRGBToLinear(MainCompBuffer, MainComp->Width, MainComp->Height, MainComp->BytesPerPixel, 0);
glBindTexture(GL_TEXTURE_2D, textureID);
int ByteFlag2 = (MainComp->BytesPerPixel == 4) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
@@ -408,9 +417,6 @@ Main_Renderer(project_data *File, project_state *State, memory *Memory, SDL_Wind
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, MainComp->Width, MainComp->Height, GL_RGBA, ByteFlag2, MainCompBuffer);
// TODO(fox): garbage collect AV state!
-
- State->UpdateFrame = false;
- State->UpdateKeyframes = false;
}
int main(int argc, char *argv[]) {
@@ -596,7 +602,7 @@ int main(int argc, char *argv[]) {
// loaded from disk or memory.
io.IniFilename = NULL;
ImGui::LoadIniSettingsFromMemory(ImGuiPrefs);
- // // ImGui::SaveIniSettingsToDisk("imgui.ini");
+ // ImGui::SaveIniSettingsToDisk("imgui.ini");
ImGui::StyleColorsDark();
@@ -625,7 +631,7 @@ int main(int argc, char *argv[]) {
#if DEBUG
#if 1
- sprintf(State->DummyName, "test2");
+ sprintf(State->DummyName, "test");
File_Open(File, State, &Memory, State->DummyName);
State->UpdateFrame = true;
State->MostRecentlySelectedLayer = 0;
@@ -634,16 +640,54 @@ int main(int argc, char *argv[]) {
while (State->IsRunning)
{
- // State->Interact_Active = interact_type_layer_move;
- // State->Interact_Offset[1] = -3.0f;
-
#if STABLE
if (State->CurlActive) {
Curl_Main(File, State, &Memory, &MainHandle, &ProgHandle);
}
#endif
- Main_InputTest(File, State, &Memory, &File->UI, window, textureID);
+ // NOTE(fox): These commands affect sorting, and should not be executed
+ // in any UI or the renderer.
+ if (State->HotkeyInput) {
+ switch (State->HotkeyInput) {
+ case hotkey_none:
+ {
+ Assert(0);
+ } break;
+ case hotkey_newpaintlayer:
+ {
+ Project_PaintLayer_New(File, State, &Memory);
+ } break;
+ case hotkey_newlayerfromsource:
+ {
+ Source_UICreateButton(File, State, &Memory);
+ State->UpdateKeyframes = true;
+ } break;
+ case hotkey_deletelayer:
+ {
+ Project_Layer_Delete(File, State, &Memory);
+ } break;
+ case hotkey_undo:
+ {
+ History_Undo(&Memory);
+ State->UpdateFrame = true;
+ } break;
+ case hotkey_redo:
+ {
+ History_Redo(&Memory);
+ State->UpdateFrame = true;
+ } break;
+ default:
+ {
+ Assert(0);
+ } break;
+ }
+ State->HotkeyInput = hotkey_none;
+ }
+
+ sorted_file Sorted = File_Sort_Push(File, State, &Memory);
+
+ Main_InputTest(File, State, &Memory, Sorted, &File->UI, window, textureID);
if (State->IsPlaying) {
block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(&Memory, F_Precomps, File->PrincipalCompIndex);
@@ -653,8 +697,28 @@ int main(int argc, char *argv[]) {
}
if (State->UpdateFrame) {
- Main_Renderer(File, State, &Memory, window, textureID, io);
+ State->Queue.CurrentIdx++;
}
+ for (int i = 0; i < State->Queue.CurrentIdx; i++) {
+ render_queue_item Item = State->Queue.Item[i];
+ State->Queue.Playhead = i;
+ if (Item.Type == 0) {
+ Main_Renderer(File, State, &Memory, Sorted, &File->UI, window, textureID, io);
+ } else if (Item.Type == 1) {
+ Assert(State->Interact_Active == interact_type_brush);
+ Render_Paint(File, State, &Memory, Sorted, &File->UI, window, textureID, io, Item.Pos);
+ } else if (Item.Type == 2) {
+ Assert(State->Interact_Active == interact_type_brush);
+ Render_Blit(File, State, &Memory, Sorted, &File->UI, window, textureID, io, Item.Pos);
+ } else {
+ Assert(0);
+ }
+ }
+ State->Queue.CurrentIdx = 0;
+ State->Queue.Playhead = 0;
+ Arbitrary_Zero((uint8 *)State->Queue.Item, sizeof(State->Queue.Item));
+
+ File_Sort_Pop(&Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize, Sorted.Source_SortSize);
Assert(Debug.ScratchState == 0);
diff --git a/main.h b/main.h
index 37701e4..2bda728 100644
--- a/main.h
+++ b/main.h
@@ -128,6 +128,19 @@ struct render_state
cache_entry Entry[2048];
};
+struct render_queue_item
+{
+ bool32 Type;
+ v2 Pos;
+};
+
+struct render_queue
+{
+ uint16 Playhead;
+ uint16 CurrentIdx;
+ render_queue_item Item[512];
+};
+
enum focused_window
{
focus_viewport,
@@ -139,7 +152,6 @@ struct sorted_property_info
{
uint32 MinYIndex;
uint32 MaxYIndex;
- bool32 IsGraphSelected;
};
struct sorted_comp_info
@@ -200,11 +212,12 @@ struct brush_state
{
ImVec2 UIPos; // Initial position when ctrl is held
real32 Size = 256; // Maxes at 1024 for now
- real32 Hardness = 1.0f; // From 1 to 100
+ real32 Hardness = 0.55f; // From 1 to 100
real32 Spacing = 1.0f;
bool32 EraseMode = 0;
brush_type Type = brush_normal;
GLuint GLTexture;
+ v2 PrevPos;
void *PaintBuffer;
void *TransientBitmap;
uint32 LayerToPaint_Index = -1;
@@ -254,10 +267,11 @@ struct interact_transform
enum hotkey_input
{
hotkey_none,
- hotkey_transform,
- hotkey_copy,
- hotkey_paste,
- hotkey_togglechannels
+ hotkey_newpaintlayer,
+ hotkey_newlayerfromsource,
+ hotkey_deletelayer,
+ hotkey_undo,
+ hotkey_redo,
};
enum property_display_type
@@ -330,6 +344,7 @@ struct project_state
bool32 DebugDisableCache = 1;
render_state Render;
+ render_queue Queue;
int32 Frame_Current;
tool Tool = tool_default;
@@ -630,11 +645,14 @@ struct direct_info {
real32 BufferPitch;
render_byte_info BufferBits;
+ real32 Opacity;
+
blend_mode BlendMode;
rectangle ClipRect;
void *SourceBuffer;
bool32 SwapActive;
+ bool32 OnlyBlendAlpha;
};
struct brush_info {
@@ -649,6 +667,7 @@ struct brush_info {
int BytesPerPixel;
int SourceWidth;
int SourceBytesPerPixel;
+ void *SourceBuffer;
void *BrushBuffer;
real32 R_Brush;
real32 G_Brush;
diff --git a/memory.cpp b/memory.cpp
index 30574e9..901fbab 100644
--- a/memory.cpp
+++ b/memory.cpp
@@ -124,6 +124,7 @@ Memory_Block_PrincipalBitmap_AllocateNew(project_data *File, project_state *Stat
uint32 Blocks_Max = Memory->Slot[B_CachedBitmaps].Size / BitmapBlockSize;
Assert(Blocks_Max > (LastBlock + BlockSize));
+
return LastBlock + BlockSize;
}
@@ -260,6 +261,15 @@ void Memory_Copy(uint8 *Address_Write, uint8 *Address_Read, uint64 Size)
}
}
+void Memory_Fill(uint8 *Address_Write, uint8 *Address_Read, uint64 WriteSize, uint64 ReadSize)
+{
+ uint64 i = 0;
+ while (i < WriteSize) {
+ *(Address_Write + i) = *(Address_Read + (i % ReadSize));
+ i++;
+ }
+}
+
void Arbitrary_Zero(uint8 *Address_Write, uint64 Size)
{
uint64 i = 0;
diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp
index 36bc79e..f267f67 100644
--- a/my_imgui_widgets.cpp
+++ b/my_imgui_widgets.cpp
@@ -578,9 +578,22 @@ ImGui_DebugMemoryViewer(memory *Memory, project_state *State)
}
static void
+ImGui_DebugRenderQueue(project_state *State)
+{
+ ImGui::Begin("debug_queue");
+ for (int i = 0; i < State->Queue.CurrentIdx; i++) {
+ v2 Pos = State->Queue.Item[i].Pos;
+ char size[20];
+ sprintf(size, "Type %i: %.2f, %.2f", State->Queue.Item[i].Type, Pos.x, Pos.y);
+ ImGui::MenuItem(size, NULL, (i == State->Queue.Playhead));
+ }
+ ImGui::End();
+}
+
+static void
ImGui_DebugUndoTree(memory *Memory, project_state *State)
{
- ImGui::Begin("undotree");
+ ImGui::Begin("debug_undotree");
for (int i = 0; i < Memory->History.NumberOfEntries; i++) {
history_entry Entry = Memory->History.Entry[i];
bool32 CurrentPos = (i < Memory->History.EntryPlayhead);
@@ -666,8 +679,7 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io,
if (ImGui::BeginPopup("sourcecontext")) {
if (ImGui::MenuItem("Create layer from source")) {
- Source_UICreateButton(File, State, Memory, SortedCompArray, SortedLayerArray);
- State->UpdateKeyframes = true;
+ State->HotkeyInput = hotkey_newlayerfromsource;
}
ImGui::EndPopup();
}
@@ -761,8 +773,7 @@ ImGui_SD_Thumbnail(project_data *File, project_state *State, ui *UI, memory *Mem
}
if (ImGui::BeginPopup("temptosource")) {
if (ImGui::MenuItem("Create layer from source")) {
- Source_UICreateButton(File, State, Memory, SortedCompArray, SortedLayerArray);
- State->UpdateKeyframes = true;
+ State->HotkeyInput = hotkey_newlayerfromsource;
}
ImGui::EndPopup();
}
@@ -990,6 +1001,12 @@ ImGui_RenderUIBrush(project_state *State, memory *Memory, ImVec2 ViewportMin, Im
ImVec2 MinBounds = State->Brush.UIPos - BrushSize/2;
ImVec2 MaxBounds = MinBounds + BrushSize;
+ // if (io.KeyCtrl) {
+ // ImGui::SetCursorScreenPos(State->Brush.UIPos);
+ // char buf[256];
+ // sprintf(buf, "RGBA: %.1f, %.1f, %.1f, %.1f", State->Brush.Size, State->Brush.Hardness);
+ // }
+
if (io.KeyAlt) {
draw_list->PushClipRect(ViewportMin, ViewportMax, true);
draw_list->AddImage((void *)(intptr_t)State->Brush.GLTexture, MinBounds, MaxBounds, ImVec2(0, 0), ImVec2(1, 1), 1);
@@ -1354,42 +1371,16 @@ ImGui_LayerViewportUI(project_state *State, memory *Memory, ui *UI, ImDrawList *
UI->CompPos.y + CompUV.y * UI->CompZoom.y);
}
- draw_list->AddNgon(ScreenPoint[0], 20, wcol, 8, 10.0f);
+ if (State->Tool != tool_brush) {
+ ImU32 wcol2 = IM_COL32(10, 10, 10, 255);
+ draw_list->AddNgon(ScreenPoint[0], 10, wcol2, 8, 9.0f);
+ draw_list->AddNgon(ScreenPoint[0], 10, wcol, 8, 5.0f);
+ }
draw_list->AddLine(ScreenPoint[1], ScreenPoint[2], wcol, 2.0f);
draw_list->AddLine(ScreenPoint[2], ScreenPoint[4], wcol, 2.0f);
draw_list->AddLine(ScreenPoint[1], ScreenPoint[3], wcol, 2.0f);
draw_list->AddLine(ScreenPoint[3], ScreenPoint[4], wcol, 2.0f);
}
- /*
- if (Layer->IsSelected) {
- uint32 Width = 0, Height = 0;
- if (!Layer->IsPrecomp) {
- block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
- Width = Source->Width;
- Height = Source->Height;
- } else {
- block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index);
- Width = Comp->Width;
- Height = Comp->Height;
- }
- // Anchor point UI
- v2 CenterPoint = V2(Width*Layer->ax.CurrentValue, Height*Layer->ay.CurrentValue);
- ImVec2 ScreenAP = Layer_LocalToScreenSpace(State, Memory, Layer, UI, File->PrincipalCompIndex, CenterPoint);
- draw_list->AddNgon(ScreenAP, 20, wcol, 8, 10.0f);
-
- // Bounding box UI
- ImVec2 P1 = Layer_LocalToScreenSpace(State, Memory, Layer, UI, File->PrincipalCompIndex, V2(0, 0));
- ImVec2 P2 = Layer_LocalToScreenSpace(State, Memory, Layer, UI, File->PrincipalCompIndex, V2(Width, 0));
- ImVec2 P3 = Layer_LocalToScreenSpace(State, Memory, Layer, UI, File->PrincipalCompIndex, V2(0, Height));
- ImVec2 P4 = Layer_LocalToScreenSpace(State, Memory, Layer, UI, File->PrincipalCompIndex, V2(Width, Height));
- draw_list->AddLine(P1, P2, wcol, 2.0f);
- draw_list->AddLine(P2, P4, wcol, 2.0f);
- draw_list->AddLine(P1, P3, wcol, 2.0f);
- draw_list->AddLine(P3, P4, wcol, 2.0f);
-
- }
- */
-
}
}
@@ -1480,6 +1471,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
if (!Layer->IsPrecomp) {
block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
if (Layer->IsSelected && Source->Type == source_type_principal) {
+ Assert(Source->BytesPerPixel == 4);
Arbitrary_Zero((uint8 *)State->Brush.TransientBitmap, 2048*2048*4);
State->Interact_Active = interact_type_brush;
State->Brush.LayerToPaint_Index = i;
@@ -1489,31 +1481,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
}
}
if (State->Brush.LayerToPaint_Index == -1) {
- Arbitrary_Zero((uint8 *)State->Brush.TransientBitmap, 2048*2048*4);
- State->Interact_Active = interact_type_brush;
- Layer_DeselectAll(File, State, Memory);
- History_Entry_Commit(Memory,"Paint new layer");
- uint16 i = Source_Generate_Blank(File, State, Memory, MainComp->Width, MainComp->Height, MainComp->BytesPerPixel);
- block_layer *Layer = Layer_Init(File, Memory);
- block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
- State->Brush.LayerToPaint_Index = Memory_Block_LazyIndexAtAddress(Memory, F_Layers, (void *)Layer);
- Layer->Block_Source_Index = i;
- Layer->x.CurrentValue = MainComp->Width / 2;
- Layer->y.CurrentValue = MainComp->Height / 2;
- int TopOffset = (File->Layer_Count == 1) ? 11 : 0;
- sorted_comp_info SortedCompInfo = SortedCompArray[File->PrincipalCompIndex];
- if (SortedCompInfo.LayerCount)
- {
- 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;
- }
- Layer->Vertical_Offset = TopOffset - 1;
- Layer->Frame_Start = MainComp->Frame_Start;
- Layer->Frame_End = MainComp->Frame_End;
- Layer->IsSelected = true;
- History_Entry_End(Memory);
- State->UpdateFrame = true;
+ State->HotkeyInput = hotkey_newpaintlayer;
}
}
@@ -1553,44 +1521,23 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
ImVec2 MouseDelta = io.MouseDelta;
real32 Delta = MouseDelta.x + MouseDelta.y;
- if (Delta != 0.0f) {
- real32 DeltaDistance = sqrt(MouseDelta.x * MouseDelta.x + MouseDelta.y * MouseDelta.y);
- real32 DeltaSlope = MouseDelta.y / MouseDelta.x;
- for (real32 i = 0; i < DeltaDistance; i += State->Brush.Spacing) {
- ImVec2 MousePos = ImGui_Brush_CalcMousePos(State, io, MouseDelta, i, DeltaDistance, DeltaSlope);
- v2 PrincipalCompUV = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos);
- v2 LayerPos = Layer_TraverseForPoint(File, State, Memory, PrincipalCompUV, SortedCompArray, SortedLayerArray);
- Brush_Render(State, UI, T_Layer, MainComp, Source, State->Brush.TransientBitmap, ViewportMin, LayerPos);
+ v2 PrincipalCompUV = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos);
+ v2 LayerPos = Layer_TraverseForPoint(File, State, Memory, PrincipalCompUV, SortedCompArray, SortedLayerArray);
+ if (IsActivated) {
+ RenderQueue_AddBrush(State, LayerPos);
+ } else if (Delta != 0.0f) {
+ v2 PrevPos = State->Brush.PrevPos;
+ v2 Delta = PrevPos - LayerPos;
+ real32 Dist = sqrt(LengthSq(Delta));
+ if (Dist > State->Brush.Spacing) {
+ RenderQueue_AddBrush(State, LayerPos);
}
- } else if (IsActivated) {
- ImVec2 MousePos = io.MousePos;
- v2 PrincipalCompUV = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos);
- v2 LayerPos = Layer_TraverseForPoint(File, State, Memory, PrincipalCompUV, SortedCompArray, SortedLayerArray);
- Brush_Render(State, UI, T_Layer, MainComp, Source, State->Brush.TransientBitmap, ViewportMin, LayerPos);
}
State->UpdateFrame = true;
}
if (IsDeactivated) {
- block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, State->Brush.LayerToPaint_Index);
- block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
- void *SourceBitmapAddress = Memory_Block_AddressAtIndex(Memory, F_PrincipalBitmaps, Source->Bitmap_Index, 0);
- rectangle RenderRegion = { 0, 0, Source->Width, Source->Height };
- direct_info Info = { (real32)Source->Width, (real32)Source->Height, (real32)Source->BytesPerPixel, (real32)Source->Width * Source->BytesPerPixel,
- Bitmap_ByteInfo(Source->BytesPerPixel), blend_normal,
- RenderRegion, State->Brush.TransientBitmap, 1};
- Render_Main((void *)&Info, SourceBitmapAddress, render_type_notransform_swap, State->Brush.CacheBounds);
-
- uint64 BitmapSize = Source->Width * Source->Height * Source->BytesPerPixel;
-
- // History_Entry_Commit(Memory, "Paintbrush stroke");
- // History_Action_BitmapPaint(Memory, BitmapSize, SourceBitmapAddress, State->Brush.TransientBitmap, Source->BytesPerPixel);
- // History_Entry_End(Memory);
-
- State->Brush.LayerToPaint_Index = -1;
- State->Interact_Active = interact_type_none;
- State->Interact_Modifier = 0;
- State->UpdateFrame = true;
+ RenderQueue_AddBlit(State);
}
}
@@ -1751,7 +1698,7 @@ ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI
sorted_property_info *InfoLocation = Property_GetSortedInfo(SortedPropertyInfo, i, h);
uint16 *ArrayLocation = Property_GetSortedArray(SortedPropertyArray, i, h);
ImGui::PushID(Property);
- if (ImGui::Selectable(DefaultChannel[h], InfoLocation->IsGraphSelected)) {
+ if (ImGui::Selectable(DefaultChannel[h], Property_IsGraphSelected(Memory, Property, ArrayLocation))) {
Property_DeselectAll(File, State, Memory, SortedCompArray, SortedLayerArray, SortedPropertyInfo, SortedPropertyArray);
for (int p = 0; p < Property->Keyframe_Count; p++) {
int k = ArrayLocation[p];
@@ -1933,7 +1880,8 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor
real32 GraphMoveHeight = TimelineMoveSize.y + (TimelineZoomSize.y * GraphPos);
real32 GraphZoomHeight = TimelineZoomSize.y * GraphScale;
- uint32 GraphCol = InfoLocation->IsGraphSelected ? IM_COL32(255, 180, 150, 255) : IM_COL32(255, 255, 255, 70);
+ bool32 IsGraphSelected = Property_IsGraphSelected(Memory, Property, ArrayLocation);
+ uint32 GraphCol = IsGraphSelected ? IM_COL32(255, 180, 150, 255) : IM_COL32(255, 255, 255, 70);
bezier_point *PointAddress[2] = {};
ImVec2 Keyframe_ScreenPos[6] = {};
@@ -1995,7 +1943,7 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor
if (b == 0) {
draw_list->AddCircleFilled(Keyframe_ScreenPos[NewIdx + b], 4, PointCol);
- if (InfoLocation->IsGraphSelected) {
+ if (IsGraphSelected) {
char buf[8];
sprintf(buf, "%.2f", Keyframe_LocalPos[0].y);
draw_list->AddText(Keyframe_ScreenPos[NewIdx + b], 0xFFFFFFFF, buf);
@@ -2220,6 +2168,10 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem
if (ImGui::MenuItem("Duplicate layer")) {
Precomp_UIDuplicate(File, State, Memory, CompIndex, SortedCompInfo, SortedLayerInfo);
}
+ if (ImGui::MenuItem("Delete layer")) {
+ Precomp_UICreateButton(File, State, Memory, CompIndex, SortedCompInfo, SortedLayerInfo);
+ State->UpdateKeyframes = true;
+ }
if (ImGui::BeginMenu("Layer color"))
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
@@ -2869,7 +2821,7 @@ ImGui_Popups(project_data *File, project_state *State, ui *UI, memory *Memory, I
}
static void
-ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io)
+ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, sorted_file Sorted)
{
if (ImGui::IsKeyPressed(ImGuiKey_Q)) {
State->IsRunning = false;
@@ -2891,7 +2843,7 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me
}
}
if (ImGui::IsKeyPressed(ImGuiKey_U)) {
- State->HotkeyInput = hotkey_togglechannels;
+ Project_ToggleAllChannels(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray);
}
if (ImGui::IsKeyPressed(ImGuiKey_X)) {
if (State->TimelineMode == timeline_mode_graph && State->Interact_Active == interact_type_keyframe_move) {
@@ -2976,7 +2928,8 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me
}
} else if (State->FocusedWindow == focus_viewport) {
if (ImGui::IsKeyPressed(ImGuiKey_T)) {
- State->HotkeyInput = hotkey_transform;
+ Interact_Transform_Begin(File, Memory, State, io.MousePos, Sorted.CompArray, Sorted.LayerArray);
+ State->Tool = tool_default;
}
}
}
@@ -3011,24 +2964,7 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me
if (ImGui::IsKeyPressed(ImGuiKey_Delete))
{
- bool32 CommitAction = 0;
- int h = 0, c = 0, i = 0;
- int LayerCount = File->Layer_Count;
- while (Block_Loop(Memory, F_Layers, LayerCount, &h, &c, &i)) {
- block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
- if (Layer->IsSelected) {
- if (!CommitAction) {
- History_Entry_Commit(Memory, "Delete source");
- CommitAction = 1;
- }
- Layer_Delete(File, Memory, i);
- }
- }
- if (CommitAction) {
- History_Entry_End(Memory);
- State->UpdateFrame = true;
- State->MostRecentlySelectedLayer = -1;
- }
+ State->HotkeyInput = hotkey_deletelayer;
}
if (io.KeyShift && ImGui::IsKeyPressed(ImGuiKey_Slash))
@@ -3039,7 +2975,19 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me
#if DEBUG
if (ImGui::IsKeyPressed(ImGuiKey_3))
{
- State->ImGuiPopups = popup_keybinds;
+ // State->ImGuiPopups = popup_keybinds;
+ Debug.DisableAlpha = 0;
+ State->UpdateFrame = true;
+ }
+ if (ImGui::IsKeyPressed(ImGuiKey_4))
+ {
+ Debug.DisableAlpha = 1;
+ State->UpdateFrame = true;
+ }
+ if (ImGui::IsKeyPressed(ImGuiKey_5))
+ {
+ Debug.DisableAlpha = 2;
+ State->UpdateFrame = true;
}
if (ImGui::IsKeyPressed(ImGuiKey_F))
{
@@ -3072,18 +3020,16 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me
}
}
if (ImGui::IsKeyPressed(ImGuiKey_C)) {
- State->HotkeyInput = hotkey_copy;
+ Clipboard_Store(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray);
}
if (ImGui::IsKeyPressed(ImGuiKey_V)) {
- State->HotkeyInput = hotkey_paste;
+ Clipboard_Paste(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyArray);
}
if (ImGui::IsKeyPressed(ImGuiKey_Z)) {
if (io.KeyShift) {
- History_Redo(Memory);
- State->UpdateFrame = true;
+ State->HotkeyInput = hotkey_redo;
} else {
- History_Undo(Memory);
- State->UpdateFrame = true;
+ State->HotkeyInput = hotkey_undo;
}
}
}
diff --git a/package.sh b/package.sh
index f1861b4..758c1b1 100755
--- a/package.sh
+++ b/package.sh
@@ -21,4 +21,4 @@ zip -r zip/real2d_arm_linux.zip real2d_arm_linux
rsync -avz zip/* root@foxcam.net:/var/www/foxcam/bin/
rm -r zip
-rm -r real2d_windows
+rm -r real*
diff --git a/prenderer.cpp b/prenderer.cpp
index cf5990e..0940d16 100644
--- a/prenderer.cpp
+++ b/prenderer.cpp
@@ -530,15 +530,6 @@ Transform_Calculate(project_state *State, memory *Memory, project_data *File, bl
}\
} break;\
}\
-\
- R_Blend = (R_Dest * (1.0f - LayerAlpha)) + (R_Blend * LayerAlpha);\
- G_Blend = (G_Dest * (1.0f - LayerAlpha)) + (G_Blend * LayerAlpha);\
- B_Blend = (B_Dest * (1.0f - LayerAlpha)) + (B_Blend * LayerAlpha);\
-\
- if (T.BlendMode == blend_normal)\
- A_Blend = A_Dest + LayerAlpha;\
- else\
- A_Blend = A_Dest;\
static void
Fallback_RenderDirect(direct_info T, void *OutputBuffer, rectangle RenderRegion)
@@ -571,7 +562,10 @@ Fallback_RenderDirect(direct_info T, void *OutputBuffer, rectangle RenderRegion)
real32 B_Col = (real32)(*B_SrcAddress & T.BufferBits.MaskPixel) * T.BufferBits.Normalized;
real32 A_Col = (real32)(*A_SrcAddress & T.BufferBits.MaskPixel) * T.BufferBits.Normalized;
- real32 LayerAlpha = A_Col * 1; // brush opacity
+ if (A_Col == 0)
+ continue;
+
+ real32 LayerAlpha = A_Col * T.Opacity;
uint8 *DestPixel =((uint8 *)OutputBuffer + ((uint16)Y * (uint16)T.BufferPitch) + ((uint16)X * (uint16)T.BufferBytesPerPixel));
@@ -589,14 +583,27 @@ Fallback_RenderDirect(direct_info T, void *OutputBuffer, rectangle RenderRegion)
real32 G_Dest = (real32)(G_DestInt) * T.BufferBits.Normalized;
real32 B_Dest = (real32)(B_DestInt) * T.BufferBits.Normalized;
real32 A_Dest = (real32)(A_DestInt) * T.BufferBits.Normalized;
+ real32 Test = (A_Dest > 0.01) ? 1 : 0;
real32 R_Blend = R_Col;
real32 G_Blend = G_Col;
real32 B_Blend = B_Col;
real32 A_Blend = A_Col;
+ // A_Blend = (A_Blend >= 0.04045) ? pow((A_Blend + 0.055) / (1 + 0.055), 2.4) : A_Blend / 12.92;
if (LayerAlpha != 1.0f || T.BlendMode != blend_normal) {
+
Fallback_Blend();
+
+ if (A_Dest == 0) {
+ A_Blend = LayerAlpha;
+ } else {
+ A_Blend = A_Dest + ((1.0f - A_Dest) * LayerAlpha);
+ real32 Alpha = pow(LayerAlpha, A_Dest);
+ R_Blend = (R_Dest * (1.0f - Alpha)) + (R_Blend * Alpha);
+ G_Blend = (G_Dest * (1.0f - Alpha)) + (G_Blend * Alpha);
+ B_Blend = (B_Dest * (1.0f - Alpha)) + (B_Blend * Alpha);
+ }
}
uint32 R_Out = (uint32)(Normalize(R_Blend) * T.BufferBits.Bits);
@@ -712,29 +719,7 @@ Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegio
real32 TexGD = (real32)(*(uint32 *)(TexPTR3 + T.LayerBits.ByteOffset * 1) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
real32 TexBD = (real32)(*(uint32 *)(TexPTR3 + T.LayerBits.ByteOffset * 2) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
real32 TexAD = (real32)(*(uint32 *)(TexPTR3 + T.LayerBits.ByteOffset * 3) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
-#if 0
- for (int i = 0; i < 50; i++) {
- real32 TexRA = (real32)(*(uint32 *)(TexPTR0 + T.LayerBits.ByteOffset * 0) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexGA = (real32)(*(uint32 *)(TexPTR0 + T.LayerBits.ByteOffset * 1) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexBA = (real32)(*(uint32 *)(TexPTR0 + T.LayerBits.ByteOffset * 2) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexAA = (real32)(*(uint32 *)(TexPTR0 + T.LayerBits.ByteOffset * 3) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
-
- real32 TexRB = (real32)(*(uint32 *)(TexPTR1 + T.LayerBits.ByteOffset * 0) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexGB = (real32)(*(uint32 *)(TexPTR1 + T.LayerBits.ByteOffset * 1) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexBB = (real32)(*(uint32 *)(TexPTR1 + T.LayerBits.ByteOffset * 2) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexAB = (real32)(*(uint32 *)(TexPTR1 + T.LayerBits.ByteOffset * 3) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
-
- real32 TexRC = (real32)(*(uint32 *)(TexPTR2 + T.LayerBits.ByteOffset * 0) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexGC = (real32)(*(uint32 *)(TexPTR2 + T.LayerBits.ByteOffset * 1) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexBC = (real32)(*(uint32 *)(TexPTR2 + T.LayerBits.ByteOffset * 2) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexAC = (real32)(*(uint32 *)(TexPTR2 + T.LayerBits.ByteOffset * 3) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
-
- real32 TexRD = (real32)(*(uint32 *)(TexPTR3 + T.LayerBits.ByteOffset * 0) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexGD = (real32)(*(uint32 *)(TexPTR3 + T.LayerBits.ByteOffset * 1) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexBD = (real32)(*(uint32 *)(TexPTR3 + T.LayerBits.ByteOffset * 2) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- real32 TexAD = (real32)(*(uint32 *)(TexPTR3 + T.LayerBits.ByteOffset * 3) & T.LayerBits.MaskPixel) * T.LayerBits.Normalized;
- }
-#endif
+
#endif
real32 R_Col = (TexBothInv * TexRA) + (TexBothYInv * TexRB)
@@ -748,6 +733,13 @@ Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegio
real32 LayerAlpha = A_Col * T.LayerOpacity;
+#if DEBUG
+ if (Debug.DisableAlpha == 1) {
+ A_Col = 1;
+ LayerAlpha = 1;
+ }
+#endif
+
real32 R_Blend = R_Col;
real32 G_Blend = G_Col;
real32 B_Blend = B_Col;
@@ -769,6 +761,27 @@ Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegio
real32 A_Dest = (real32)(*A_DestAddress & T.BufferBits.MaskPixel) * T.BufferBits.Normalized;
Fallback_Blend();
+
+ R_Blend = (R_Dest * (1.0f - LayerAlpha)) + (R_Blend * LayerAlpha);
+ G_Blend = (G_Dest * (1.0f - LayerAlpha)) + (G_Blend * LayerAlpha);
+ B_Blend = (B_Dest * (1.0f - LayerAlpha)) + (B_Blend * LayerAlpha);
+
+ if (T.BlendMode == blend_normal)
+ A_Blend = A_Dest + LayerAlpha;
+ // A_Blend = A_Dest + ((1.0f - A_Dest) * LayerAlpha);
+ else
+ A_Blend = A_Dest;
+#if DEBUG
+ if (Debug.DisableAlpha == 1) {
+ G_Blend = R_Blend;
+ B_Blend = R_Blend;
+ } else
+ if (Debug.DisableAlpha == 2) {
+ R_Blend = LayerAlpha;
+ G_Blend = LayerAlpha;
+ B_Blend = LayerAlpha;
+ }
+#endif
}
uint8 R_Out = (uint8)(Normalize(R_Blend) * T.BufferBits.Bits);
diff --git a/threading.cpp b/threading.cpp
index f1d7284..5a42ea7 100644
--- a/threading.cpp
+++ b/threading.cpp
@@ -62,7 +62,7 @@ Threading_BitmapOp(void *Data, void *OutputBuffer, render_type RenderType, recta
rectangle RenderRegion = { TileWidth*x, TileHeight*y,
TileWidth + TileWidth*x, TileHeight + TileHeight*y };
- if (RenderType == render_type_brush) {
+ if (RenderType != render_type_main) {
RenderRegion.Min.x += InitialRenderRegion.Min.x;
RenderRegion.Min.y += InitialRenderRegion.Min.y;
RenderRegion.Max.x += InitialRenderRegion.Min.x;
diff --git a/undo.cpp b/undo.cpp
index 16349d2..bfedc8c 100644
--- a/undo.cpp
+++ b/undo.cpp
@@ -14,7 +14,7 @@ static uint64
History_GetActionSize(history_entry_list *History, int i, uint16 ActionCount_EndOfPlayhead)
{
history_action *Action = &History->Action[i];
- if (Action->Type == action_type_swap)
+ if (Action->Type == action_type_swap || Action->Type == action_type_swap_bitmap)
return Action->Size;
return 0;
}