From cdb9e1f7240cb0716b7d99df5e1fd7c3fc3407a8 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Mon, 5 Dec 2022 21:45:18 -0500 Subject: v2.2, color space + brush improvements --- bitmap_calls.cpp | 402 --------------------------------------------------- build.bat | 2 +- createcalls.cpp | 338 ++++++++++++++++++++++++++++++------------- debug.h | 3 +- functions.h | 4 +- main.cpp | 190 ++++++++++++++++-------- main.h | 31 +++- memory.cpp | 10 ++ my_imgui_widgets.cpp | 194 +++++++++---------------- package.sh | 2 +- prenderer.cpp | 79 +++++----- threading.cpp | 2 +- undo.cpp | 2 +- 13 files changed, 526 insertions(+), 733 deletions(-) delete mode 100644 bitmap_calls.cpp 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 @@ -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 @@ -577,10 +577,23 @@ ImGui_DebugMemoryViewer(memory *Memory, project_state *State) ImGui::End(); } +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; } -- cgit v1.2.3