diff options
author | Fox Caminiti <fox@foxcam.net> | 2022-08-01 20:03:12 -0400 |
---|---|---|
committer | Fox Caminiti <fox@foxcam.net> | 2022-08-01 20:04:43 -0400 |
commit | b26f27d9e3fd44ec5775accdc3666a339684be4c (patch) | |
tree | e5c7b8b48f5597904190529f90d71a8526ca9800 | |
parent | 7d3dcee5b370c05065eb409ad5c21d0bc64790b1 (diff) |
large changes to bitmap structure
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | bitmap_calls.cpp | 107 | ||||
-rwxr-xr-x | build.sh | 33 | ||||
-rw-r--r-- | caching.cpp | 14 | ||||
-rw-r--r-- | createcalls.cpp | 466 | ||||
-rw-r--r-- | debug.h | 8 | ||||
-rw-r--r-- | defines.h | 40 | ||||
-rw-r--r-- | effects.cpp | 45 | ||||
-rw-r--r-- | ffmpeg_backend.cpp (renamed from video.cpp) | 179 | ||||
-rw-r--r-- | ffmpeg_backend.h | 22 | ||||
-rw-r--r-- | functions.h | 18 | ||||
-rw-r--r-- | keyframes.cpp | 40 | ||||
-rw-r--r-- | layer.cpp | 30 | ||||
-rw-r--r-- | main.cpp | 158 | ||||
-rw-r--r-- | main.h | 134 | ||||
-rw-r--r-- | memory.cpp | 4 | ||||
-rw-r--r-- | my_imgui_internal_widgets.cpp | 294 | ||||
-rw-r--r-- | my_imgui_internal_widgets.h | 11 | ||||
-rw-r--r-- | my_imgui_widgets.cpp | 160 | ||||
-rw-r--r-- | paint.cpp | 4 | ||||
-rw-r--r-- | prenderer.cpp | 118 | ||||
-rw-r--r-- | strings.cpp | 9 | ||||
-rw-r--r-- | threading.cpp | 8 | ||||
-rw-r--r-- | ui.cpp | 2 |
24 files changed, 1177 insertions, 728 deletions
@@ -1 +1,2 @@ bin/* +compile_commands.json diff --git a/bitmap_calls.cpp b/bitmap_calls.cpp index 132aec5..09d1cb1 100644 --- a/bitmap_calls.cpp +++ b/bitmap_calls.cpp @@ -6,28 +6,29 @@ // 0 - store in 4x4 chunks // 1 - unpack to 1xwidth -internal void -Convert4x4Chunk(pixel_buffer *Buffer, uint8 Which) +void Bitmap_ConvertPacking(void *Buffer, void *DestBuffer, uint16 Width, uint16 Height, uint16 BytesPerPixel, uint16 Which) { - uint8 *Src = (uint8 *)Buffer->OriginalBuffer; - uint8 *Temp = (uint8 *)Buffer->EffectBuffer; - uint32 RemainderPixels = Buffer->Width % 4; - for (uint32 Y = 0; Y < Buffer->Height; Y++) { + uint8 *Src = (uint8 *)Buffer; + uint8 *Temp = (uint8 *)DestBuffer; + uint32 RemainderPixels = Width % 4; + for (uint32 Y = 0; Y < Height; Y++) { uint32 X = 0; - while (X < Buffer->Width - RemainderPixels) { + while (X < Width - RemainderPixels) { + uint16 WidthP, HeightP; + Bitmap_CalcPackedDimensions(Width, Height, &WidthP, &HeightP); uint32 XLookup = (X >> 2)*16 + (X % 4); - uint32 YLookup = (Y >> 2)*(Buffer->FullWidth*4) + (Y % 4)*4; + uint32 YLookup = (Y >> 2)*(WidthP*4) + (Y % 4)*4; uint32 PixelToSeek = XLookup + YLookup; uint8 *DPixel, *Pixel; if (Which == 0) { - DPixel = Temp + PixelToSeek*Buffer->BytesPerPixel; - Pixel = Src + Y*Buffer->Width*4 + X*Buffer->BytesPerPixel; + DPixel = Temp + PixelToSeek*BytesPerPixel; + Pixel = Src + Y*Width*4 + X*BytesPerPixel; } else { - Pixel = Src + PixelToSeek*Buffer->BytesPerPixel; - DPixel = Temp + Y*Buffer->Width*4 + X*Buffer->BytesPerPixel; + Pixel = Src + PixelToSeek*BytesPerPixel; + DPixel = Temp + Y*Width*4 + X*BytesPerPixel; } - if (InstructionMode == sse_enabled || InstructionMode == avx_enabled) { + if (InstructionMode == instruction_mode_sse || InstructionMode == instruction_mode_avx) { __m128i Row = _mm_loadu_si128((__m128i *)Pixel); _mm_storeu_si128((__m128i *)DPixel, Row); X+=4; @@ -36,17 +37,19 @@ Convert4x4Chunk(pixel_buffer *Buffer, uint8 Which) X++; } } - while (X < Buffer->Width) { + while (X < Width) { + uint16 WidthP, HeightP; + Bitmap_CalcPackedDimensions(Width, Height, &WidthP, &HeightP); uint32 XLookup = (X >> 2)*16 + (X % 4); - uint32 YLookup = (Y >> 2)*(Buffer->FullWidth*4) + (Y % 4)*4; + uint32 YLookup = (Y >> 2)*(WidthP*4) + (Y % 4)*4; uint32 PixelToSeek = XLookup + YLookup; uint8 *DPixel, *Pixel; if (Which == 0) { - DPixel = Temp + PixelToSeek*Buffer->BytesPerPixel; - Pixel = Src + Y*Buffer->Width*4 + X*Buffer->BytesPerPixel; + DPixel = Temp + PixelToSeek*BytesPerPixel; + Pixel = Src + Y*Width*4 + X*BytesPerPixel; } else { - Pixel = Src + PixelToSeek*Buffer->BytesPerPixel; - DPixel = Temp + Y*Buffer->Width*4 + X*Buffer->BytesPerPixel; + Pixel = Src + PixelToSeek*BytesPerPixel; + DPixel = Temp + Y*Width*4 + X*BytesPerPixel; } *(uint32 *)DPixel = *(uint32 *)Pixel; @@ -56,27 +59,23 @@ Convert4x4Chunk(pixel_buffer *Buffer, uint8 Which) } // TODO(fox): Replace this in the future. -internal void * +#if 0 +static void * MoveImportToBitmap(memory *Memory, pixel_buffer *Raster, void *Input) { uint8 *Row = ((uint8 *)Input); - void *Output = AllocateMemory(Memory, Raster->FullWidth * Raster->FullHeight * Raster->BytesPerPixel, B_Scratch); + // void *Output = AllocateMemory(Memory, Bitmap_CalcTotalBytes(Raster->Width, Raster->Height, Raster->BytesPerPixel), B_Layers); uint8 *Row2 = ((uint8 *)Output); uint64 bytes = 0; - uint16 ByteOffset = Raster->BytesPerPixel; - if (InstructionMode == avx_enabled) - ByteOffset = 8*Raster->BytesPerPixel; - else if (InstructionMode == avx_enabled) - ByteOffset = 4*Raster->BytesPerPixel; - - uint64 TotalBytes = Raster->Height*Raster->Width*Raster->BytesPerPixel; + 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 == sse_enabled || InstructionMode == avx_enabled) { + 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; @@ -93,28 +92,24 @@ MoveImportToBitmap(memory *Memory, pixel_buffer *Raster, void *Input) } return Output; } +#endif -internal void -ClearBuffer(pixel_buffer *Raster, void *Buffer) +static void +Bitmap_Clear(void *Buffer, uint16 Width, uint16 Height, uint16 BytesPerPixel) { uint8 *Row = (uint8 *)Buffer; __m256i Zero8 = _mm256_setzero_si256(); __m128i Zero = _mm_setzero_si128(); - uint64 bytes = 0; - uint16 ByteOffset = Raster->BytesPerPixel; - if (InstructionMode == avx_enabled) - ByteOffset = 8*Raster->BytesPerPixel; - else if (InstructionMode == avx_enabled) - ByteOffset = 4*Raster->BytesPerPixel; - uint64 TotalBytes = Raster->FullHeight*Raster->FullWidth*Raster->BytesPerPixel; + uint16 ByteOffset = Bitmap_CalcByteOffset(BytesPerPixel); + uint64 TotalBytes = Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel); while (bytes < TotalBytes) { uint8 *Pixel = Row + bytes; - if (InstructionMode == avx_enabled) { + if (InstructionMode == instruction_mode_avx) { _mm256_storeu_si256((__m256i *)Pixel, Zero8); - } else if (InstructionMode == sse_enabled) { + } else if (InstructionMode == instruction_mode_sse) { _mm_storeu_si128((__m128i *)Pixel, Zero); } else { *(uint32 *)Pixel = 0x00000000; @@ -122,10 +117,10 @@ ClearBuffer(pixel_buffer *Raster, void *Buffer) bytes += ByteOffset; } } - +#if 0 // 0 - original -> effect // 1 - effect -> original -internal void +static void CopyToBuffer(pixel_buffer *Raster, uint16 Which) { uint8 *Row, *Row2; @@ -138,19 +133,14 @@ CopyToBuffer(pixel_buffer *Raster, uint16 Which) } uint64 bytes = 0; - uint16 ByteOffset = Raster->BytesPerPixel; - if (InstructionMode == avx_enabled) - ByteOffset = 8*Raster->BytesPerPixel; - else if (InstructionMode == avx_enabled) - ByteOffset = 4*Raster->BytesPerPixel; - - uint64 TotalBytes = Raster->FullHeight*Raster->FullWidth*Raster->BytesPerPixel; + 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 == sse_enabled || InstructionMode == avx_enabled) { + 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; @@ -167,7 +157,7 @@ CopyToBuffer(pixel_buffer *Raster, uint16 Which) } } -internal void +static void BitmapPackRGB(pixel_buffer *Buffer) { Assert(Buffer->Pitch); Convert4x4Chunk(Buffer, 0); @@ -175,7 +165,7 @@ BitmapPackRGB(pixel_buffer *Buffer) { ClearBuffer(Buffer, Buffer->EffectBuffer); } -internal void +static void OutputToViewport(pixel_buffer *CompBuffer, project_state *State, GLuint textureID) { Convert4x4Chunk(CompBuffer, 1); EndRenderState(State); @@ -184,7 +174,7 @@ OutputToViewport(pixel_buffer *CompBuffer, project_state *State, GLuint textureI CompBuffer->EffectBuffer); } -internal void +static void DebugFillSolid(pixel_buffer *Raster, v4 Color) { uint32 ColS = ColToUint32(Color); @@ -194,18 +184,18 @@ DebugFillSolid(pixel_buffer *Raster, v4 Color) uint64 bytes = 0; uint16 ByteOffset = Raster->BytesPerPixel; - if (InstructionMode == avx_enabled) + if (InstructionMode == instruction_mode_avx) ByteOffset = 8*Raster->BytesPerPixel; - else if (InstructionMode == avx_enabled) + 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 == avx_enabled) { + if (InstructionMode == instruction_mode_avx) { _mm256_storeu_si256((__m256i *)Pixel, Col8); - } else if (InstructionMode == sse_enabled) { + } else if (InstructionMode == instruction_mode_sse) { _mm_storeu_si128((__m128i *)Pixel, Col); } else { *(uint32 *)Pixel = ColS; @@ -214,7 +204,7 @@ DebugFillSolid(pixel_buffer *Raster, v4 Color) } } -internal void +static void DebugBitmap(pixel_buffer *Raster) { uint8 asda = 0x0; @@ -233,3 +223,4 @@ DebugBitmap(pixel_buffer *Raster) } } } +#endif @@ -26,12 +26,17 @@ FFMPEG_LIBS=" libavutil " +# IMGUI_FILES=" +# imgui/imgui +# imgui/imgui_demo +# imgui/imgui_draw +# imgui/imgui_tables +# imgui/imgui_widgets +# my_imgui_internal_widgets +# " + IMGUI_FILES=" - imgui - imgui_demo - imgui_draw - imgui_tables - imgui_widgets + my_imgui_internal_widgets " IMGUI_FILES_IMPL=" @@ -51,12 +56,12 @@ fi imgui() { for i in $IMGUI_FILES do - clang $IMGUI_FLAGS -o bin/$i.o imgui/$i.cpp - done - for i in $IMGUI_FILES_IMPL - do - clang $IMGUI_FLAGS -o bin/$i.o imgui/backends/$i.cpp + clang $IMGUI_FLAGS -o bin/$i.o $i.cpp done +# for i in $IMGUI_FILES_IMPL +# do +# clang $IMGUI_FLAGS -o bin/$i.o imgui/backends/$i.cpp +# done } if [[ "$OSTYPE" =~ ^darwin ]]; then @@ -65,7 +70,9 @@ else SDL_ARGS="`sdl2-config --cflags` -lGL -ldl `sdl2-config --libs`" fi -# imgui +imgui + + # -lm $(pkg-config --cflags --libs $FFMPEG_LIBS) -MJresult.json if [[ "$WINDOWS" == 1 ]]; then clang++ -g $WARNING_FLAGS -target x86_64-pc-windows-gnu -march=x86-64-v3 -I .. -Iimgui -Iimgui/backends \ @@ -74,9 +81,9 @@ clang++ -g $WARNING_FLAGS -target x86_64-pc-windows-gnu -march=x86-64-v3 -I .. - -lmingw32 -lopengl32 -lSDL2main -lSDL2 -llibavcodec -llibswscale -llibavformat -llibavutil \ -o bin/real2d else -clang main.cpp $WARNING_FLAGS -g -O0 -march=native -o bin/real2d bin/*.o \ +clang main.cpp $WARNING_FLAGS -g -march=native -o bin/real2d bin/*.o \ -std=c++11 -lstdc++ -Iimgui -Iimgui/backends \ $SDL_ARGS \ -I . \ - -lm $(pkg-config --cflags --libs $FFMPEG_LIBS) + -lm -I /usr/local/include ~/.local/src/ffmpeg/bin/*.so fi diff --git a/caching.cpp b/caching.cpp index d84377a..c35189e 100644 --- a/caching.cpp +++ b/caching.cpp @@ -1,5 +1,6 @@ -internal void +#if 0 +static void CacheFrame(cache *Cache, pixel_buffer *CompBuffer) { @@ -33,7 +34,7 @@ CacheFrame(cache *Cache, pixel_buffer *CompBuffer) } } -internal void +static void FetchCache(cache *Cache, pixel_buffer *CompBuffer) { @@ -67,7 +68,7 @@ FetchCache(cache *Cache, pixel_buffer *CompBuffer) } } -internal void +static void InteractToComp(pixel_buffer *CompBuffer, cache_pool *Cache) { int MinX = 0; @@ -114,15 +115,14 @@ InteractToComp(pixel_buffer *CompBuffer, cache_pool *Cache) } } -internal void +static void UncacheFrames(int16 Min, int16 Max, cache_pool *Cache) { for (int16 i = Min; i < Max; i++) Cache->Frame[i].Cached = false; }; -#if 0 -internal void +static void CacheKeyframeAtIndex(uint16 i, struct property_channel *Property, cache_pool *Cache) { Assert(Property->NumberOfKeyframes > 0); @@ -140,7 +140,7 @@ CacheKeyframeAtIndex(uint16 i, struct property_channel *Property, cache_pool *Ca } } -internal void +static void SortAndCacheKeyframeAtFrame(uint16 f, struct property_channel *Property, cache_pool *Cache) { Assert(Property->NumberOfKeyframes > 0); diff --git a/createcalls.cpp b/createcalls.cpp index 7088694..42ab9b1 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -1,4 +1,4 @@ -internal void +static void IncrementFrame(project_data *File, int16 Amount) { if ((File->CurrentFrame <= 0 && Amount < File->StartFrame) || (File->CurrentFrame >= File->EndFrame)) { File->CurrentFrame = 0; @@ -7,46 +7,70 @@ IncrementFrame(project_data *File, int16 Amount) { } } -internal void -CalculateFull(pixel_buffer *Buffer) { - uint16 ExtraWidth = 4 - (Buffer->Width % 4); +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 - (Buffer->Height % 4); + uint16 ExtraHeight = 4 - (Height % 4); if (ExtraHeight == 4) ExtraHeight = 0; - Buffer->FullWidth = Buffer->Width + ExtraWidth; - Buffer->FullHeight = Buffer->Height + ExtraHeight; + *WidthP = Width + ExtraWidth; + *HeightP = Height + ExtraHeight; } -internal pixel_buffer -CreateBuffer(int Width, int Height, memory *Memory) -{ - pixel_buffer Buffer = {}; - Buffer.BytesPerPixel = 4; - Buffer.Width = Width; - Buffer.Height = Height; - CalculateFull(&Buffer); - Buffer.Pitch = Buffer.FullWidth*Buffer.BytesPerPixel; - Buffer.OriginalBuffer = AllocateMemory(Memory, Buffer.FullWidth * Buffer.FullHeight * Buffer.BytesPerPixel, B_Scratch); - Buffer.EffectBuffer = AllocateMemory(Memory, Buffer.FullWidth * Buffer.FullHeight * Buffer.BytesPerPixel, B_Scratch); - Buffer.ToUpdate = true; - return Buffer; +static uint16 +Bitmap_CalcByteOffset(uint16 BytesPerPixel) { + uint16 ByteOffset = BytesPerPixel; + if (InstructionMode == instruction_mode_avx) + ByteOffset = 8*BytesPerPixel; + if (InstructionMode == instruction_mode_sse) + ByteOffset = 4*BytesPerPixel; + return ByteOffset; } -internal void -AddSource(project_data *File, memory *Memory, char *Path) +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; +} + +static bool32 +Source_Generate(project_data *File, memory *Memory, char *Path) { - int16 a = File->NumberOfSources++; - Assert(a < MAX_SOURCES); - if (Path == NULL) { - File->Source[a] = (char *)AllocateMemory(Memory, STRING_SIZE, F_Strings); - } else { - File->Source[a] = Path; + Assert(File->NumberOfSources < MAX_SOURCES); + source *Source = &File->Source[File->NumberOfSources]; + + bool32 Found = 0; + + int w, h; + if (stbi_info(Path, &w, &h, NULL)) { + Source->Info.Width = w; + Source->Info.Height = h; + Source->SourceType = source_type_image; + Found = true; + } + + if (!Found && AV_IsFileSupported(Path)) { + Source->SourceType = source_type_video; + AV_CodecInfo_Init(Path, Source, Memory); + Found = true; + } + + if (Found) { + Source->Info.BytesPerPixel = 4; + Source->Path = Path; + File->NumberOfSources++; + return 1; } + + return 0; } -internal pixel_buffer + /* +static pixel_buffer LoadImage(memory *Memory, char *filename) { pixel_buffer Buffer = {}; @@ -69,110 +93,9 @@ LoadImage(memory *Memory, char *filename) return Buffer; } -internal pixel_buffer -CreateSolidBitmap(memory *Memory, uint16 Height, uint16 Width, v4 Color) { - pixel_buffer Buffer = {}; - Buffer.BytesPerPixel = 4; - Buffer.Height = Height; - Buffer.Width = Width; - CalculateFull(&Buffer); - Buffer.Pitch = Buffer.FullWidth*Buffer.BytesPerPixel; - Buffer.OriginalBuffer = AllocateMemory(Memory, Buffer.FullHeight * Buffer.FullWidth * Buffer.BytesPerPixel, B_Scratch); - Buffer.EffectBuffer = AllocateMemory(Memory, Buffer.FullHeight * Buffer.FullWidth * Buffer.BytesPerPixel, B_Scratch); - DebugFillSolid(&Buffer, Color); - BitmapPackRGB(&Buffer); - Buffer.ToUpdate = true; - return Buffer; -} - -internal pixel_buffer -CreateDebugBitmap(memory *Memory, uint16 Height, uint16 Width) { - pixel_buffer Buffer = {}; - Buffer.BytesPerPixel = 4; - Buffer.Height = Height; - Buffer.Width = Width; - CalculateFull(&Buffer); - Buffer.Pitch = Buffer.FullWidth*Buffer.BytesPerPixel; - Buffer.OriginalBuffer = AllocateMemory(Memory, Buffer.FullHeight * Buffer.FullWidth * Buffer.BytesPerPixel, B_Scratch); - Buffer.EffectBuffer = AllocateMemory(Memory, Buffer.FullHeight * Buffer.FullWidth * Buffer.BytesPerPixel, B_Scratch); - DebugBitmap(&Buffer); - BitmapPackRGB(&Buffer); - Buffer.ToUpdate = true; - return Buffer; -} - - -internal void -DrawHistogram(project_layer *Layer, pixel_buffer *UIBuffer, void *Scratch, memory *Memory, sdl_input Input, project_state *State, - rectangle Box) -{ - uint16 Padding = 20; //UI->LayerPadding / 5; - uint16 Margin = 100; - - uint16 *Levels = (uint16 *)Scratch; - - uint16 *Mean = (Levels + 256*7); - - uint32 Color = 0; - uint32 AltColor = ColToUint32(V4(0.1,0.1,0.1,1.0)); - - // this is a bad idea - real32 *Zoom = (real32 *)(Levels + 256*6); - if (*Zoom < 0.0f) - *Zoom = 0.0f; - uint16 *SelectedChannel = (uint16 *)(Levels + 256*6 + 3); - - if (*SelectedChannel == 0) { - Color = ColToUint32(V4(0.6,0.6,0.6,1.0)); - } else if (*SelectedChannel == 1) { - Levels += 256; - Color = ColToUint32(V4(0.6,0.0,0.0,1.0)); - } else if (*SelectedChannel == 2) { - Levels += 256*2; - Color = ColToUint32(V4(0.0,0.6,0.0,1.0)); - } else if (*SelectedChannel == 3) { - Levels += 256*3; - Color = ColToUint32(V4(0.0,0.0,0.6,1.0)); - } else if (*SelectedChannel == 4) { - Levels += 256*4; - Color = ColToUint32(V4(0.9,0.9,0.9,1.0)); - } - - - /* - if (TestRectangle(Box, Input.Mouse) && - Input.MouseButton[0].IsDown) - { - State->ArbitrarySlide = 1; - State->Sliding.RandomPointer = Zoom; - } */ - uint8 *Row = ((uint8 *)UIBuffer->OriginalBuffer + - UIBuffer->BytesPerPixel + - UIBuffer->Pitch); - for (int Y = 0; - Y > Box.Min.y; - Y--) - { - uint32 *Pixel = (uint32 *)Row + Box.Min.x; - for(int X = Box.Min.x; - X < Box.Max.x; - ++X) - { - real32 Span = (Box.Max.x - Box.Min.x) / 256.0f; - int16 XLocal = (X - Box.Min.x) / Span; - int16 YLocal = -(Y - Box.Max.y); - if (*(Levels + XLocal) > (YLocal * RoundReal32ToInt32(*Zoom)) && XLocal < 256) - *Pixel++ = Color; - else - *Pixel++ = AltColor; - } - Row -= UIBuffer->Pitch; - } -} - -internal property_channel +static property_channel InitFloatProperty(char *Name, real32 Val, real32 ScrubVal, real32 MinVal = PROPERTY_REAL_MIN, real32 MaxVal = PROPERTY_REAL_MAX) { property_channel Property = {}; Property.Name = Name; @@ -185,66 +108,55 @@ InitFloatProperty(char *Name, real32 Val, real32 ScrubVal, real32 MinVal = PROPE return Property; } -internal bool32 -IsSupportedFile(source_type *Type, char *filename) { - bool32 Result = 0; - if (stbi_info(filename, NULL, NULL, NULL)) { - *Type = source_image; - Result = 1; - } else if (TestAV(filename)) { - *Type = source_video; - Result = 1; - } - return Result; -} -internal void -CreateRenderInfo(project_layer *Layer, memory *Memory, project_data File, source_type Type, char *filename) +static void +CreateKeyframeBlock(property_channel *Property, memory *Memory) { - if (Type == source_image) { - Layer->RenderInfo = AllocateMemory(Memory, sizeof(image_source), P_SourceData); - image_source *Source = (image_source *)Layer->RenderInfo; - Source->Raster = LoadImage(Memory, filename); - Layer->SourceType = source_image; - - Layer->x.CurrentValue.f = 1280/2; - Layer->y.CurrentValue.f = 720/2; - Layer->StartFrame = 0; - Layer->EndFrame = File.EndFrame; - } - else if (Type == source_video) { - Layer->RenderInfo = AllocateMemory(Memory, sizeof(video_source), P_SourceData); - video_source *Source = (video_source *)Layer->RenderInfo; - InitAV(filename, &Source->AV); - - Layer->SourceType = source_video; - Source->VideoCurrentFrame = -1; + int16 a = Property->NumberOfKeyframeBlocks++; + Assert(a < MAX_KEYFRAME_BLOCKS); - int32 Width = Source->AV.VideoCodecContext->width; - int32 Height = Source->AV.VideoCodecContext->height; - Source->Raster = CreateBuffer(Width, Height, Memory); + Property->KeyframeBlock[a] = (keyframe_block *)AllocateMemory(Memory, sizeof(keyframe_block), F_Keyframes); +} - Layer->x.CurrentValue.f = 1280/2; - Layer->y.CurrentValue.f = 720/2; - Layer->StartFrame = 0; - Layer->EndFrame = File.EndFrame; - } else { - Assert(0); - } +static void +PostMsg(project_state *State, char *msg) +{ + State->MsgTime = 120; + State->Msg = msg; } +/* +static project_layer * +CreateSolidLayer(project_data *File, memory *Memory, uint16 Width, uint16 Height, v4 Col) +{ + project_layer *Layer = CreateLayer(File, Memory); + Layer->RenderInfo = AllocateMemory(Memory, sizeof(source_image), P_SourceData); + source_image *Source = (source_image *)Layer->RenderInfo; + Source->Raster = CreateSolidBitmap(Memory, Width, Height, Col); + Layer->SourceType = source_type_image; + return Layer; +} -internal void -CreateKeyframeBlock(property_channel *Property, memory *Memory) +static project_layer * +CreateDebugLayer(project_data *File, memory *Memory, uint16 Width, uint16 Height, int i) { - int16 a = Property->NumberOfKeyframeBlocks++; - Assert(a < MAX_KEYFRAME_BLOCKS); + project_layer *Layer = CreateLayer(File, Memory); + Layer->RenderInfo = AllocateMemory(Memory, sizeof(source_image), P_SourceData); + source_image *Source = (source_image *)Layer->RenderInfo; + Source->Raster = CreateDebugBitmap(Memory, Width, Height); + Layer->SourceType = source_type_image; + return Layer; +} +*/ - Property->KeyframeBlock[a] = (keyframe_block *)AllocateMemory(Memory, sizeof(keyframe_block), F_Keyframes); +void * Layer_AllocateBitmap(memory *Memory, uint16 Width, uint16 Height, uint16 BytesPerPixel) +{ + uint64 TotalBytes = Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel); + void *Address = AllocateMemory(Memory, TotalBytes, B_LayerBitmaps); + return Address; } -internal project_layer * -CreateLayer(project_data *File, memory *Memory) +project_layer * Layer_Init(project_data *File, memory *Memory) { int16 a = File->NumberOfLayers++; Assert(a < MAX_LAYERS); @@ -266,54 +178,28 @@ CreateLayer(project_data *File, memory *Memory) return File->Layer[a]; } -internal void -PostMsg(project_state *State, char *msg) -{ - State->MsgTime = 120; - State->Msg = msg; -} - -internal void -CreateLayerFromSource(project_data *File, project_state *State, memory *Memory, char *filename) -{ - source_type Type = source_none; - if (IsSupportedFile(&Type, filename)) { - project_layer *Layer = CreateLayer(File, Memory); - CreateRenderInfo(Layer, Memory, *File, Type, filename); - State->UpdateFrame = true; - State->DemoButton = true; - } else { - PostMsg(State, "File open fail..."); - } -} - - -internal project_layer * -CreateSolidLayer(project_data *File, memory *Memory, uint16 Width, uint16 Height, v4 Col) -{ - project_layer *Layer = CreateLayer(File, Memory); - Layer->RenderInfo = AllocateMemory(Memory, sizeof(image_source), P_SourceData); - image_source *Source = (image_source *)Layer->RenderInfo; - Source->Raster = CreateSolidBitmap(Memory, Width, Height, Col); - Layer->SourceType = source_image; - return Layer; +static void +Layer_UpdateBitmap(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, int32 CurrentFrame) { + AV_LoadVideoFrame(Source, BitmapInfo, Memory, CurrentFrame); + // UpdateEffects(Layer, Memory); } -internal project_layer * -CreateDebugLayer(project_data *File, memory *Memory, uint16 Width, uint16 Height, int i) -{ - project_layer *Layer = CreateLayer(File, Memory); - Layer->RenderInfo = AllocateMemory(Memory, sizeof(image_source), P_SourceData); - image_source *Source = (image_source *)Layer->RenderInfo; - Source->Raster = CreateDebugBitmap(Memory, Width, Height); - Layer->SourceType = source_image; - return Layer; -} - -internal void +static void LoadTestFootage(project_data *File, project_state *State, memory *Memory) { - CreateLayerFromSource(File, State, Memory, "../asset/24.mp4"); + if (!Source_Generate(File, Memory, "../asset/24.mp4")) + PostMsg(State, "File open fail..."); + source *Source = &File->Source[0]; + project_layer *Layer = Layer_Init(File, Memory); + Layer->Source = Source; + AV_PacketInfo_Init(&Layer->BitmapInfo, Memory); + uint16 Height = Source->Info.Height; + uint16 Width = Source->Info.Width; + uint16 BytesPerPixel = Source->Info.BytesPerPixel; + Layer_AllocateBitmap(Memory, Width, Height, BytesPerPixel); + + SelectLayer(File->Layer[0], State, 0); + // AddEffect(File->Layer[0], Memory, 2); // project_layer *Layer1 = CreateDebugLayer(&File, &Memory, 9, 14); // project_layer *Layer1 = CreateSolidLayer(&File, &Memory, 9, 13, V4(1.0, 1.0, 1.0, 1.0)); // Layer1->x.CurrentValue.f = 7; @@ -322,9 +208,10 @@ LoadTestFootage(project_data *File, project_state *State, memory *Memory) // Layer1->EndFrame = File.EndFrame; } -internal void +static void CreateDemoScene(project_data *File, memory *Memory) { +#if 0 project_layer *Layer1 = CreateSolidLayer(File, Memory, 720, 1280, V4(0.0, 0.0, 0.0, 1.0)); Layer1->x.CurrentValue.f = 1280/2; Layer1->y.CurrentValue.f = 720/2; @@ -350,9 +237,11 @@ CreateDemoScene(project_data *File, memory *Memory) ManualKeyframeInsertF(&Layer3->x, Memory, 60, Layer3->x.CurrentValue.f+(1280/3)); Layer3->x.IsToggled = true; Layer3->y.IsToggled = true; +#endif } -internal void +#if 0 +static void CreateGrid(project_data *File, memory *Memory) { uint16 Amount = 8; real32 XInc = File->Width / Amount; @@ -370,3 +259,128 @@ CreateGrid(project_data *File, memory *Memory) { } } } +#endif +#if 0 +static void +DrawHistogram(project_layer *Layer, pixel_buffer *UIBuffer, void *Scratch, memory *Memory, sdl_input Input, project_state *State, + rectangle Box) +{ + uint16 Padding = 20; //UI->LayerPadding / 5; + uint16 Margin = 100; + + uint16 *Levels = (uint16 *)Scratch; + + uint16 *Mean = (Levels + 256*7); + + uint32 Color = 0; + uint32 AltColor = ColToUint32(V4(0.1,0.1,0.1,1.0)); + + // this is a bad idea + real32 *Zoom = (real32 *)(Levels + 256*6); + if (*Zoom < 0.0f) + *Zoom = 0.0f; + uint16 *SelectedChannel = (uint16 *)(Levels + 256*6 + 3); + + if (*SelectedChannel == 0) { + Color = ColToUint32(V4(0.6,0.6,0.6,1.0)); + } else if (*SelectedChannel == 1) { + Levels += 256; + Color = ColToUint32(V4(0.6,0.0,0.0,1.0)); + } else if (*SelectedChannel == 2) { + Levels += 256*2; + Color = ColToUint32(V4(0.0,0.6,0.0,1.0)); + } else if (*SelectedChannel == 3) { + Levels += 256*3; + Color = ColToUint32(V4(0.0,0.0,0.6,1.0)); + } else if (*SelectedChannel == 4) { + Levels += 256*4; + Color = ColToUint32(V4(0.9,0.9,0.9,1.0)); + } + + + /* + if (TestRectangle(Box, Input.Mouse) && + Input.MouseButton[0].IsDown) + { + State->ArbitrarySlide = 1; + State->Sliding.RandomPointer = Zoom; + } + */ + + uint8 *Row = ((uint8 *)UIBuffer->OriginalBuffer + + UIBuffer->BytesPerPixel + + UIBuffer->Pitch); + for (int Y = 0; + Y > Box.Min.y; + Y--) + { + uint32 *Pixel = (uint32 *)Row + Box.Min.x; + for(int X = Box.Min.x; + X < Box.Max.x; + ++X) + { + real32 Span = (Box.Max.x - Box.Min.x) / 256.0f; + int16 XLocal = (X - Box.Min.x) / Span; + int16 YLocal = -(Y - Box.Max.y); + if (*(Levels + XLocal) > (YLocal * RoundReal32ToInt32(*Zoom)) && XLocal < 256) + *Pixel++ = Color; + else + *Pixel++ = AltColor; + } + Row -= UIBuffer->Pitch; + } +} + +static pixel_buffer +CreateSolidBitmap(memory *Memory, uint16 Height, uint16 Width, v4 Color) { + pixel_buffer Buffer = {}; + Buffer.BytesPerPixel = 4; + Buffer.Height = Height; + Buffer.Width = Width; + CalculateFull(&Buffer); + Buffer.Pitch = Buffer.FullWidth*Buffer.BytesPerPixel; + Buffer.OriginalBuffer = AllocateMemory(Memory, Buffer.FullHeight * Buffer.FullWidth * Buffer.BytesPerPixel, B_Scratch); + Buffer.EffectBuffer = AllocateMemory(Memory, Buffer.FullHeight * Buffer.FullWidth * Buffer.BytesPerPixel, B_Scratch); + DebugFillSolid(&Buffer, Color); + BitmapPackRGB(&Buffer); + Buffer.ToUpdate = true; + return Buffer; +} + +static pixel_buffer +CreateDebugBitmap(memory *Memory, uint16 Height, uint16 Width) { + pixel_buffer Buffer = {}; + Buffer.BytesPerPixel = 4; + Buffer.Height = Height; + Buffer.Width = Width; + CalculateFull(&Buffer); + Buffer.Pitch = Buffer.FullWidth*Buffer.BytesPerPixel; + Buffer.OriginalBuffer = AllocateMemory(Memory, Buffer.FullHeight * Buffer.FullWidth * Buffer.BytesPerPixel, B_Scratch); + Buffer.EffectBuffer = AllocateMemory(Memory, Buffer.FullHeight * Buffer.FullWidth * Buffer.BytesPerPixel, B_Scratch); + DebugBitmap(&Buffer); + BitmapPackRGB(&Buffer); + Buffer.ToUpdate = true; + return Buffer; +} + +/* +{ + Layer->RenderInfo = AllocateMemory(Memory, sizeof(source_image), P_SourceData); + Layer->RenderInfo = AllocateMemory(Memory, sizeof(source_video), P_SourceData); + source_image *Source = (source_image *)Layer->RenderInfo; + Source->Raster = LoadImage(Memory, filename); + Layer->EndFrame = File.EndFrame; + Layer->x.CurrentValue.f = 1280/2; + Layer->y.CurrentValue.f = 720/2; + Layer->StartFrame = 0; + + + Layer->x.CurrentValue.f = 1280/2; + Layer->y.CurrentValue.f = 720/2; + Layer->StartFrame = 0; + Layer->EndFrame = File.EndFrame; +} +*/ + + +#endif @@ -1,6 +1,6 @@ #if DEBUG -global_variable int32 *debugnull = NULL; +static int32 *debugnull = NULL; #define Assert(Expression) if(!(Expression)) {*debugnull = 21;} enum valtype { @@ -32,7 +32,7 @@ struct project_debug bool32 ToggleRenders; }; -global_variable project_debug Debug; +static project_debug Debug; #if ARM #define DEBUG_CycleCountStart(ID) @@ -42,7 +42,7 @@ global_variable project_debug Debug; #define DEBUG_CycleCountEnd(ID) Debug.EndCycleCount[ID] += __rdtsc() - Debug.CycleCount[ID]; Debug.ExecutionAmount[ID]++; #endif -internal void +static void DebugWatchVar(char *Name, void *Address, valtype Type) { uint32 i = Debug.WatchedProperties; Debug.String[i] = Name; @@ -73,7 +73,7 @@ struct project_debug #define DEBUG_CycleCountStart(ID) #define DEBUG_CycleCountEnd(ID) -internal void +static void DebugWatchVar(char *Name, void *Address, valtype Type) { } #endif diff --git a/defines.h b/defines.h new file mode 100644 index 0000000..ccca81c --- /dev/null +++ b/defines.h @@ -0,0 +1,40 @@ +#define SwitchBool(Bool) if((Bool)) {(Bool) = 0;} else {(Bool) = 1;} +#define AmountOf(Array) sizeof((Array)) / sizeof((Array)[1]) + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; + +typedef int64_t int64; +typedef int32 bool32; + +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +typedef float real32; +typedef double real64; + +#define NORMALIZED_COL_MIN { .col = V4(0.0f, 0.0f, 0.0f, 0.0f) } +#define NORMALIZED_COL_MAX { .col = V4(1.0f, 1.0f, 1.0f, 1.0f) } +#define NORMALIZED_REAL_MIN { 0.0f } +#define NORMALIZED_REAL_MAX { 1.0f } + + +// All of these MIN/MAX values are arbitrarily chosen; they can probably be +// increased if the user requires it. + +#define PROPERTY_REAL_MAX 1000000 +#define PROPERTY_REAL_MIN -1000000 + +#define MAX_LAYERS 2048 +#define MAX_EFFECTS 32 +#define MAX_SOURCES 1024 +#define MAX_PROPERTIES_PER_EFFECT 16 +#define MAX_KEYFRAME_BLOCKS 64 +#define MAX_KEYFRAMES_PER_BLOCK 32 +#define STRING_SIZE 256 + +#define MAX_SELECTED_PROPERTIES 16 + diff --git a/effects.cpp b/effects.cpp index 6c3c946..d427778 100644 --- a/effects.cpp +++ b/effects.cpp @@ -1,4 +1,4 @@ -internal void +static void DrawColor(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { v4 FloatColor = Property[0].CurrentValue.col; @@ -177,17 +177,22 @@ DrawColor(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) } } -internal void +static void DrawGradient(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { v4 StartColor = Property[0].CurrentValue.col; v4 EndColor = Property[1].CurrentValue.col; } +static void +Levels(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) +{ +} + #if WINDOWS -global_variable effect_header EffectList[3]; +static effect_header EffectList[3]; #else -global_variable effect_header EffectList[] { +static effect_header EffectList[] { { "Solid Color", &DrawColor, 2, standard, { @@ -205,7 +210,7 @@ global_variable effect_header EffectList[] { }, { "Levels", - &DrawColor, 6, levels, { + &Levels, 6, levels, { {"Start point", {0.0f}, type_real}, {"Mid point", {1.0f}, type_real}, {"End point", {1.0f}, type_real}, @@ -275,9 +280,11 @@ global_variable effect_header EffectList[] { } #endif -internal void +static void AddEffect(project_layer *Layer, memory *Memory, uint16 EffectListIndex) { + if (Layer == NULL) + return; Layer->Effect[Layer->NumberOfEffects] = (effect *)AllocateMemory(Memory, sizeof(effect), F_Effects); effect *Effect = Layer->Effect[Layer->NumberOfEffects]; effect_header EffectHeader = EffectList[EffectListIndex]; @@ -296,13 +303,13 @@ AddEffect(project_layer *Layer, memory *Memory, uint16 EffectListIndex) Layer->NumberOfEffects++; } -internal void +static void CopyToBuffer(pixel_buffer *, uint16 asda = 0); -internal void +static void UpdateEffects(project_layer *Layer, memory *Memory) { - image_source *Source = (image_source *)Layer->RenderInfo; + source_image *Source = (source_image *)Layer->RenderInfo; if (!Source->Raster.EffectBuffer) { Source->Raster.EffectBuffer = AllocateMemory(Memory, Source->Raster.Width * Source->Raster.Height * Source->Raster.BytesPerPixel, B_Scratch); @@ -317,7 +324,7 @@ UpdateEffects(project_layer *Layer, memory *Memory) #if 0 -internal void +static void DrawColor(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { v4 FloatColor = Property[0].CurrentValue.col; @@ -344,7 +351,7 @@ DrawColor(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) } } -internal void +static void Invert(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { uint8 *Row = ((uint8 *)Buffer->EffectBuffer); @@ -368,7 +375,7 @@ Invert(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) } } -internal void +static void DrawGradient(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { v4 StartColor = Property[0].CurrentValue.col; @@ -399,7 +406,7 @@ DrawGradient(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) } } -internal void +static void DrawGrid(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { v4 StartColor = Property[0].CurrentValue.col; @@ -427,7 +434,7 @@ DrawGrid(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) } } -internal real32 +static real32 KernLoop(pixel_buffer *Buffer, int16 Xp, int16 Yp, real32 Value[8]) { real32 P[9]; @@ -457,7 +464,7 @@ KernLoop(pixel_buffer *Buffer, int16 Xp, int16 Yp, real32 Value[8]) return Sum; } -internal void +static void SpacialFilter(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { real32 P[9]; @@ -515,7 +522,7 @@ SpacialFilter(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) } -internal void +static void Gaussian(pixel_buffer *Buffer, void *FloatStorage, real32 Radius) { if (Radius < 1.0f) @@ -581,7 +588,7 @@ Gaussian(pixel_buffer *Buffer, void *FloatStorage, real32 Radius) } } -internal void +static void Canny(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { real32 SH[9] = { -1, 0, 1, @@ -711,7 +718,7 @@ Canny(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) } } -internal void +static void Levels(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { real32 Min = Property[0].CurrentValue.f; @@ -777,7 +784,7 @@ Levels(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) } -internal void +static void GaussianBlur(pixel_buffer *Buffer, memory *Memory, property_channel Property[]) { real32 Radius = Property[0].CurrentValue.f; diff --git a/video.cpp b/ffmpeg_backend.cpp index bb3e17e..e97b4da 100644 --- a/video.cpp +++ b/ffmpeg_backend.cpp @@ -1,5 +1,12 @@ -// workaround to make libav error printing work +extern "C" { +#include <libavcodec/avcodec.h> +#include <libavformat/avformat.h> +#include <libavformat/avio.h> +#include <libavutil/avutil.h> +#include <libswscale/swscale.h> +} +// workaround to make libav error printing work #ifdef av_err2str #undef av_err2str #include <string> @@ -10,21 +17,22 @@ av_always_inline std::string av_err2string(int errnum) { #define av_err2str(err) av_err2string(err).c_str() #endif // av_err2str -internal bool32 -AV_TryFrame(av_info *AV, int32 *err) +#include "ffmpeg_backend.h" + +bool32 AV_TryFrame(av_codec_info *AV, av_packet_info *AVLayer, int32 *err) { - *err = av_read_frame(AV->FileFormatContext, AV->VideoPacket); - if (*err >= 0 && AV->VideoPacket->stream_index != AV->StreamIndex) { - av_packet_unref(AV->VideoPacket); + *err = av_read_frame(AV->FileFormatContext, AVLayer->VideoPacket); + if (*err >= 0 && AVLayer->VideoPacket->stream_index != AV->VideoStream->index) { + av_packet_unref(AVLayer->VideoPacket); return 0; } if (*err < 0) - *err = avcodec_send_packet(AV->VideoCodecContext, AV->VideoPacket); + *err = avcodec_send_packet(AV->VideoCodecContext, AVLayer->VideoPacket); else { - *err = avcodec_send_packet(AV->VideoCodecContext, AV->VideoPacket); + *err = avcodec_send_packet(AV->VideoCodecContext, AVLayer->VideoPacket); } - av_packet_unref(AV->VideoPacket); + av_packet_unref(AVLayer->VideoPacket); if (*err < 0) { @@ -33,7 +41,7 @@ AV_TryFrame(av_info *AV, int32 *err) } while (*err >= 0) { - *err = avcodec_receive_frame(AV->VideoCodecContext, AV->VideoFrame); + *err = avcodec_receive_frame(AV->VideoCodecContext, AVLayer->VideoFrame); if (*err == AVERROR_EOF) { } else if (*err == AVERROR(EAGAIN)) { *err = 0; @@ -46,8 +54,7 @@ AV_TryFrame(av_info *AV, int32 *err) return 0; } -internal bool32 -TestAV(char *filename) +bool32 AV_IsFileSupported(char *filename) { int32 err = 0; @@ -77,9 +84,12 @@ TestAV(char *filename) return 1; } -internal void -InitAV(char *filename, av_info *AV) +void AV_CodecInfo_Init(char *filename, source *Source, memory *Memory) { + Source->Info.AVCodecInfo = AllocateMemory(Memory, sizeof(av_codec_info), P_AVInfo); + av_codec_info *AV = (av_codec_info *)Source->Info.AVCodecInfo; + *AV = {}; + int32 err = 0; // enum AVHWDeviceType type; @@ -106,7 +116,6 @@ InitAV(char *filename, av_info *AV) if (LocalCodecParameters->codec_type == AVMEDIA_TYPE_VIDEO) { AV->VideoCodecParameters = LocalCodecParameters; AV->VideoStream = AV->FileFormatContext->streams[i]; - AV->StreamIndex = i; break; } } @@ -151,63 +160,87 @@ InitAV(char *filename, av_info *AV) fprintf(stderr, "Libav error: (%s)\n", av_err2str(err)); } - AV->VideoPacket = av_packet_alloc(); - if (err < 0) { - fprintf(stderr, "Libav error: (%s)\n", av_err2str(err)); - } - AV->VideoFrame = av_frame_alloc(); - if (err < 0) { - fprintf(stderr, "Libav error: (%s)\n", av_err2str(err)); - } + Source->Info.FPS = (real32)AV->VideoStream->r_frame_rate.num / AV->VideoStream->r_frame_rate.den; + Source->Info.Width = AV->VideoCodecContext->width; + Source->Info.Height = AV->VideoCodecContext->height; +}; - AV->FPS = (real32)AV->VideoStream->r_frame_rate.num / AV->VideoStream->r_frame_rate.den; - AV->IntFPS = (int32)(AV->FPS + 0.5f); - AV->LastPTS = -1; +void AV_GetPTSAverage(av_codec_info *AV, av_packet_info *AVLayer, int32 *err) +{ // TODO(fox): This PTS average isn't exact and causes an occasional // frame skip. See libav remarks in forum for more details. // TODO(fox): Handle footage under five seconds. int16 TestAmount = 5; + real32 FPS = (real32)AV->VideoStream->r_frame_rate.num / AV->VideoStream->r_frame_rate.den; + int16 i = 0; + real32 AvgPTSPerSecond = 0; for (;;) { - if (AV_TryFrame(AV, &err)) { - if (i >= AV->FPS * TestAmount) { - AV->AvgPTSPerSecond = (real32)AV->VideoFrame->pts / TestAmount; - printf("frame: %i, pts: %li\n", i, AV->VideoFrame->pts); + if (AV_TryFrame(AV, AVLayer, err)) { + if (i >= FPS * TestAmount) { + AvgPTSPerSecond = (real32)AVLayer->VideoFrame->pts / TestAmount; + printf("frame: %i, pts: %li\n", i, AVLayer->VideoFrame->pts); break; } i++; - av_frame_unref(AV->VideoFrame); + av_frame_unref(AVLayer->VideoFrame); } } - AV->AvgPTSPerFrame = (real32)AV->AvgPTSPerSecond / AV->IntFPS; - printf("Avg PTS per sec: %.06f, Avg PTS per frame: %.06f\n", AV->AvgPTSPerSecond, AV->AvgPTSPerFrame); + AV->AvgPTSPerFrame = (real32)AvgPTSPerSecond / (int32)(FPS + 0.5f); + printf("Avg PTS per sec: %.06f, Avg PTS per frame: %.06f\n", AvgPTSPerSecond, AV->AvgPTSPerFrame); av_seek_frame(AV->FileFormatContext, -1, 0, AVSEEK_FLAG_BACKWARD); -}; +} -internal void + +void AV_PacketInfo_Init(layer_bitmap_info *BitmapInfo, memory *Memory) +{ + BitmapInfo->AVPacketInfo = AllocateMemory(Memory, sizeof(av_packet_info), P_AVInfo); + av_packet_info *AV = (av_packet_info *)BitmapInfo->AVPacketInfo; + *AV = {}; + printf("%li", AV->PreviousPTS); + + int32 err = 0; + + AV->VideoPacket = av_packet_alloc(); + if (err < 0) { + fprintf(stderr, "Libav error: (%s)\n", av_err2str(err)); + } + AV->VideoFrame = av_frame_alloc(); + if (err < 0) { + fprintf(stderr, "Libav error: (%s)\n", av_err2str(err)); + } +} + + +static void Convert4x4Chunk(pixel_buffer *Raster, uint8); -internal void +static void ClearBuffer(pixel_buffer *Raster, void *); -internal int16 -LoadVideoFrame(video_source *Source, memory *Memory, int32 TimelineFrame) +bool32 AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, int32 TimelineFrame) { - av_info *AV = &Source->AV; - pixel_buffer *Buffer = &Source->Raster; - int32 *CurrentlyRenderedFrame = &Source->VideoCurrentFrame; + av_codec_info *AV = (av_codec_info *)Source->Info.AVCodecInfo; + av_packet_info *AVLayer = (av_packet_info *)BitmapInfo->AVPacketInfo; + + int32 *CurrentlyRenderedFrame = &BitmapInfo->CurrentFrame; int32 err = 0; + if (!AV->AvgPTSPerFrame) { + AV_GetPTSAverage(AV, AVLayer, &err); + } + Assert(AV->AvgPTSPerFrame); + int p = 0; int i = 0; - int32 FrameToSeek = TimelineFrame - Source->VideoFrameOffset; + int32 FrameToSeek = TimelineFrame - BitmapInfo->FrameOffset; if (*CurrentlyRenderedFrame == FrameToSeek || FrameToSeek < 0) return 0; @@ -216,7 +249,7 @@ LoadVideoFrame(video_source *Source, memory *Memory, int32 TimelineFrame) // This function only seeks to the nearest "keyframe." if (*CurrentlyRenderedFrame != FrameToSeek - 1) { - int64 SeekSeconds = (int64)(FrameToSeek / AV->IntFPS * AV_TIME_BASE); + int64 SeekSeconds = (int64)(FrameToSeek / (int32)(Source->Info.FPS + 0.5f) * AV_TIME_BASE); av_seek_frame(AV->FileFormatContext, -1, SeekSeconds, AVSEEK_FLAG_BACKWARD); printf("Seek activated\n"); } else if (*CurrentlyRenderedFrame < 0) { @@ -228,58 +261,68 @@ LoadVideoFrame(video_source *Source, memory *Memory, int32 TimelineFrame) int64 SeekPTS = (int64)(AV->AvgPTSPerFrame*FrameToSeek + 0.5f); while (err >= 0) { - if (AV_TryFrame(AV, &err)) { + if (AV_TryFrame(AV, AVLayer, &err)) { // The first frame that gets loaded isn't always the actual // first frame, so we need to check until it's correct. - if (FrameToSeek == 0 && AV->VideoFrame->pts != AV->VideoStream->start_time) { - av_frame_unref(AV->VideoFrame); - printf("NON-START: avg: %li, real pts: %li", SeekPTS, AV->VideoFrame->pts); + if (FrameToSeek == 0 && AVLayer->VideoFrame->pts != AV->VideoStream->start_time) { + av_frame_unref(AVLayer->VideoFrame); + printf("NON-START: avg: %li, real pts: %li", SeekPTS, AVLayer->VideoFrame->pts); continue; } - int64 Difference = AV->VideoFrame->pts - SeekPTS; + int64 Difference = AVLayer->VideoFrame->pts - SeekPTS; if (abs(Difference) < AV->AvgPTSPerFrame) { - if (AV->LastPTS == -1) { - AV->LastPTS = AV->VideoFrame->pts; - printf("avg: %li, real pts: %li, difference: %li\n", SeekPTS, AV->VideoFrame->pts, Difference); + if (AVLayer->PreviousPTS == -1) { + AVLayer->PreviousPTS = AVLayer->VideoFrame->pts; + printf("avg: %li, real pts: %li, difference: %li\n", SeekPTS, AVLayer->VideoFrame->pts, Difference); } else { - printf("avg: %li, real pts: %li, difference: %li difference from last pts: %li\n", SeekPTS, AV->VideoFrame->pts, AV->VideoFrame->pts - SeekPTS, AV->VideoFrame->pts - AV->LastPTS); - AV->LastPTS = AV->VideoFrame->pts; + printf("avg: %li, real pts: %li, difference: %li difference from last pts: %li\n", SeekPTS, AVLayer->VideoFrame->pts, AVLayer->VideoFrame->pts - SeekPTS, AVLayer->VideoFrame->pts - AVLayer->PreviousPTS); + AVLayer->PreviousPTS = AVLayer->VideoFrame->pts; } - uint32 PixelCount = AV->VideoFrame->width*AV->VideoFrame->height; - int out_linesize[4] = { Buffer->Pitch, Buffer->Pitch, Buffer->Pitch, Buffer->Pitch }; - uint8 *dst_data[4] = { (uint8 *)Buffer->OriginalBuffer, (uint8 *)Buffer->OriginalBuffer + PixelCount, - (uint8 *)Buffer->OriginalBuffer + PixelCount*2, (uint8 *)Buffer->OriginalBuffer + PixelCount*3 }; + uint16 Width = Source->Info.Width; + uint16 Height = Source->Info.Height; + uint16 BytesPerPixel = Source->Info.BytesPerPixel; + int32 Pitch = Width*BytesPerPixel; + + void *Buffer = AllocateMemory(Memory, Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel), B_LoadedBitmaps); + + int out_linesize[4] = { Pitch, Pitch, Pitch, Pitch }; + uint8 *dst_data[4] = { (uint8 *)Buffer, (uint8 *)Buffer + Width*Height*BytesPerPixel, + (uint8 *)Buffer + Width*Height*BytesPerPixel*2, (uint8 *)Buffer + Width*Height*BytesPerPixel*3 }; // NOTE(fox): This function will be replaced in the future. - AV->RGBContext = sws_getContext(AV->VideoFrame->width, AV->VideoFrame->height, (AVPixelFormat)AV->VideoFrame->format, - AV->VideoFrame->width, AV->VideoFrame->height, AV_PIX_FMT_RGBA, SWS_BILINEAR, + AVLayer->RGBContext = sws_getContext(AVLayer->VideoFrame->width, AVLayer->VideoFrame->height, (AVPixelFormat)AVLayer->VideoFrame->format, + AVLayer->VideoFrame->width, AVLayer->VideoFrame->height, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL); - if(!AV->RGBContext) { + if(!AVLayer->RGBContext) { printf("Libav error: SwsContext creation failed."); } - sws_scale(AV->RGBContext, AV->VideoFrame->data, AV->VideoFrame->linesize, 0, AV->VideoFrame->height, + sws_scale(AVLayer->RGBContext, AVLayer->VideoFrame->data, AVLayer->VideoFrame->linesize, 0, AVLayer->VideoFrame->height, dst_data, out_linesize); - av_frame_unref(AV->VideoFrame); + av_frame_unref(AVLayer->VideoFrame); - Convert4x4Chunk(Buffer, 0); - CopyToBuffer(Buffer, 1); - ClearBuffer(Buffer, Buffer->EffectBuffer); + if (!BitmapInfo->BitmapBuffer) { + BitmapInfo->BitmapBuffer = AllocateMemory(Memory, Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel), B_LayerBitmaps); + } + void *DestBuffer = BitmapInfo->BitmapBuffer; + Bitmap_ConvertPacking(Buffer, DestBuffer, Width, Height, BytesPerPixel, 0); + // CopyToBuffer(Buffer, 1); + // Bitmap_Clear(Buffer, Source->Info.Width, Source->Info.Height, Source->Info.BytesPerPixel); - return 0; + return 1; } else { // If this gets printed when not seeking, a frame has been skipped! - printf("FRAME SKIP: avg: %li, real pts: %li, difference: %li\n", SeekPTS, AV->VideoFrame->pts, Difference); + printf("FRAME SKIP: avg: %li, real pts: %li, difference: %li\n", SeekPTS, AVLayer->VideoFrame->pts, Difference); } - av_frame_unref(AV->VideoFrame); + av_frame_unref(AVLayer->VideoFrame); } } /* diff --git a/ffmpeg_backend.h b/ffmpeg_backend.h new file mode 100644 index 0000000..d6a6a66 --- /dev/null +++ b/ffmpeg_backend.h @@ -0,0 +1,22 @@ +struct av_codec_info { + real32 AvgPTSPerFrame; + + AVFormatContext *FileFormatContext; + AVCodecParameters *VideoCodecParameters; + const AVCodec* VideoCodec; + const AVCodecHWConfig* VideoHWConfig; + // AVPixelFormat HWPixFormat; + AVCodecContext *VideoCodecContext; + AVStream *VideoStream; +}; + +struct av_packet_info { + uint64 PreviousPTS = -1; // PTS value of the previous frame, used to check timings. + + AVPacket *VideoPacket; + AVFrame *VideoFrame; + SwsContext *RGBContext; +}; + +static bool32 AV_TryFrame(av_codec_info *AV, av_packet_info *AVPacket, int32 *err); // Internal attempt to decode a frame. Typically run in a while loop until it returns true. + diff --git a/functions.h b/functions.h new file mode 100644 index 0000000..af4f109 --- /dev/null +++ b/functions.h @@ -0,0 +1,18 @@ + +// Buffer management + +static void * Layer_AllocateBuffer(memory *Memory, uint16 Width, uint16 Height, uint16 BytesPerPixel); // +static project_layer * Layer_Init(project_data *File, memory *Memory); // Initializes a layer's name and properties. Add a source manually. + + +static void Bitmap_CalcPackedDimensions(uint16 Width, uint16 Height, uint16 *WidthP, uint16 *HeightP); // Returns the dimensions a packed bitmap should be in memory. +static uint16 Bitmap_CalcByteOffset(uint16 BytesPerPixel); // Returns the amount of bytes a loop goes through depending on the InstructionMode. +static uint64 Bitmap_CalcTotalBytes(uint16 Width, uint16 Height, uint16 BytesPerPixel); // Returns the total amount of bytes a bitmap takes up. +static void Bitmap_ConvertPacking(void *Buffer, void *DestBuffer, uint16 Width, uint16 Height, uint16 BytesPerPixel, uint16 Which); + +// Libav (ffmpeg) backend for decoding video + +static bool32 AV_IsFileSupported(char *filename); // Tests whether a decoder is available for a given file. +static void AV_CodecInfo_Init(char *filename, source *Source, memory *Memory); // Initializes all internal structs and calculates average PTS. +static bool32 AV_LoadVideoFrame(source *Source, memory *Memory, int32 TimelineFrame); // Loads video frame at TimelineFrame. + diff --git a/keyframes.cpp b/keyframes.cpp index 42234d8..d2813a9 100644 --- a/keyframes.cpp +++ b/keyframes.cpp @@ -1,11 +1,11 @@ -internal keyframe* +static keyframe* KeyframeLookupMemory(property_channel *Property, int16 i) { int16 b = i / MAX_KEYFRAMES_PER_BLOCK; int16 k = i - b*MAX_KEYFRAMES_PER_BLOCK; return &Property->KeyframeBlock[b]->Keyframe[k]; } -internal keyframe* +static keyframe* KeyframeLookupIndex(property_channel *Property, int16 a) { int16 i = Property->SortedIndex[a]; int16 b = i / MAX_KEYFRAMES_PER_BLOCK; @@ -13,7 +13,7 @@ KeyframeLookupIndex(property_channel *Property, int16 a) { return &Property->KeyframeBlock[b]->Keyframe[k]; } -internal keyframe* +static keyframe* PushKeyframe(property_channel *Property) { int16 i = Property->NumberOfTotalKeyframes; int16 b = i / MAX_KEYFRAMES_PER_BLOCK; @@ -22,7 +22,7 @@ PushKeyframe(property_channel *Property) { } // (extremely bad) -internal temp_keyframe_list +static temp_keyframe_list GetSelectedKeyframes(project_data *File) { temp_keyframe_list KeyframeList; @@ -42,7 +42,7 @@ GetSelectedKeyframes(project_data *File) return KeyframeList; } -internal int32 +static int32 KeyframeMemoryToIndex(property_channel *Property, int32 a) { int32 Result = -1; @@ -56,7 +56,7 @@ KeyframeMemoryToIndex(property_channel *Property, int32 a) return Result; } -internal void +static void SelectKeyframe(project_data *File, project_layer *Layer, property_channel *Property, keyframe *Keyframe) { Layer->IsSelected = true; @@ -65,7 +65,7 @@ SelectKeyframe(project_data *File, project_layer *Layer, property_channel *Prope Keyframe->IsSelected = true; } -internal void +static void DeselectKeyframe(project_data *File, project_layer *Layer, property_channel *Property, keyframe *Keyframe) { Layer->IsSelected = true; @@ -74,7 +74,7 @@ DeselectKeyframe(project_data *File, project_layer *Layer, property_channel *Pro Keyframe->IsSelected = true; } -internal void +static void CheckKeyframeSort(property_channel *Property, int32 Increment, int32 b) { int32 i = KeyframeMemoryToIndex(Property, b); @@ -101,7 +101,7 @@ CheckKeyframeSort(property_channel *Property, int32 Increment, int32 b) } } -internal void +static void ShiftKeyframeIndex(property_channel *Property, int16 Increment, int16 StopAt) { if (Increment > 0) { int16 i = Property->NumberOfTotalKeyframes - 1; @@ -118,7 +118,7 @@ ShiftKeyframeIndex(property_channel *Property, int16 Increment, int16 StopAt) { } } -internal void +static void DeleteKeyframeFromMemory(property_channel *Property, int16 Increment, int16 StopAt) { if (Increment > 0) { int16 i = Property->NumberOfTotalKeyframes - 1; @@ -141,7 +141,7 @@ DeleteKeyframeFromMemory(property_channel *Property, int16 Increment, int16 Stop } } -internal void +static void ResortPropertyChannel(property_channel *Property) { for (int16 i = 0; i < Property->NumberOfTotalKeyframes; i++) { @@ -165,7 +165,7 @@ ResortPropertyChannel(property_channel *Property) { } } -internal void +static void DeleteSelectedKeyframes(project_data *File, memory *Memory) { for (int i = 0; i < File->NumberOfLayers; i++) { @@ -192,7 +192,7 @@ DeleteSelectedKeyframes(project_data *File, memory *Memory) } } -internal void +static void CalculatePropertyMinMax(property_channel *Property) { Property->LocalMaxVal = Property->MinVal; Property->LocalMinVal = Property->MaxVal; @@ -208,7 +208,7 @@ CalculatePropertyMinMax(property_channel *Property) { } -internal void +static void IncrementKeyframes(property_channel *Property, int16 Increment) { for (int i = 0; i < Property->NumberOfTotalKeyframes; i++) { @@ -217,7 +217,7 @@ IncrementKeyframes(property_channel *Property, int16 Increment) } } -internal void +static void IncrementKeyframesInLayer(project_layer *Layer, int16 Increment) { for (int a = 0; a < AmountOf(Layer->Property); a++) @@ -227,11 +227,11 @@ IncrementKeyframesInLayer(project_layer *Layer, int16 Increment) IncrementKeyframes(&Layer->Effect[e]->Property[a], Increment); } -internal void +static void CreateKeyframeBlock(property_channel *, memory *); // dir 0 left, 1 right -internal void +static void ClampKeyframeHandles(property_channel *Property, int16 b, int16 dir) { if (dir == 0) { if (b > 0) { @@ -262,7 +262,7 @@ ClampKeyframeHandles(property_channel *Property, int16 b, int16 dir) { } } -internal void +static void ClampSurroundingKeyframeHandles(property_channel *Property, int16 b) { ClampKeyframeHandles(Property, b, 0); ClampKeyframeHandles(Property, b, 1); @@ -278,7 +278,7 @@ ClampSurroundingKeyframeHandles(property_channel *Property, int16 b) { -internal void +static void ManualKeyframeInsertF(property_channel *Property, memory *Memory, int32 CurrentFrame, real32 Val) { if (!(Property->NumberOfTotalKeyframes % MAX_KEYFRAMES_PER_BLOCK)) { @@ -326,7 +326,7 @@ ManualKeyframeInsertF(property_channel *Property, memory *Memory, int32 CurrentF } -internal void +static void CalculateKeyframesLinearly(uint16 CurrentFrame, struct property_channel *Property) { @@ -1,4 +1,4 @@ -internal temp_layer_list +static temp_layer_list FindSelectedLayerIndex(project_data *File, int16 NumberOfSelectedLayers) { temp_layer_list List = {}; @@ -18,16 +18,16 @@ FindSelectedLayerIndex(project_data *File, int16 NumberOfSelectedLayers) return List; } -internal transform_info -CalculateTransforms(project_layer *Layer, pixel_buffer *Buffer); +static transform_info +CalculateTransforms(project_layer *Layer, comp_buffer *CompBuffer); -internal bool32 -TestPointInLayer(project_layer *Layer, pixel_buffer *Buffer, v2 UV) +static bool32 +TestPointInLayer(project_layer *Layer, comp_buffer *CompBuffer, v2 UV) { bool32 Result = false; - real32 X = UV.x*Buffer->Width; - real32 Y = UV.y*Buffer->Height; - transform_info T = CalculateTransforms(Layer, Buffer); + real32 X = UV.x*CompBuffer->Width; + real32 Y = UV.y*CompBuffer->Height; + transform_info T = CalculateTransforms(Layer, CompBuffer); real32 StartVectorX = X - T.OriginX; real32 StartVectorY = Y - T.OriginY; real32 LayerU = (StartVectorX * T.XAxisPX) + (StartVectorY * T.XAxisPY); @@ -38,10 +38,10 @@ TestPointInLayer(project_layer *Layer, pixel_buffer *Buffer, v2 UV) return Result; } -internal void +static void CalculateAnchorOffset(project_layer *, real32, uint16); -internal void +static void InteractProperty(int16 a, project_data *File, project_state *State, bool32 Ended, real32 Value, memory *Memory) { temp_layer_list List = FindSelectedLayerIndex(File, State->NumberOfSelectedLayers); @@ -67,7 +67,7 @@ InteractProperty(int16 a, project_data *File, project_state *State, bool32 Ended // Cache->Frame[File->CurrentFrame].Cached = false; } -internal void +static void TransformsInteract(project_data *File, project_state *State, ui *UI, transforms_hotkey_interact Mode) { if (UI->FocusedWindow == focus_timeline) { @@ -92,7 +92,7 @@ TransformsInteract(project_data *File, project_state *State, ui *UI, transforms_ } } -internal void +static void SelectLayer(project_layer *Layer, project_state *State, int32 i) { Layer->IsSelected = true; @@ -100,7 +100,7 @@ SelectLayer(project_layer *Layer, project_state *State, int32 i) State->MostRecentlySelectedLayer = i; } -internal void +static void DeselectAllLayers(project_data *File, project_state *State) { temp_layer_list List = FindSelectedLayerIndex(File, State->NumberOfSelectedLayers); @@ -117,7 +117,7 @@ DeselectAllLayers(project_data *File, project_state *State) // keeping an Index value in the layer and just sorting every time the order // changes probably won't be much of a performance cost. -internal void +static void MoveLayersByIncrement(project_data *File, project_state *State, int16 Increment) { bool32 AllowMove = true; @@ -170,7 +170,7 @@ MoveLayersByIncrement(project_data *File, project_state *State, int16 Increment) /* -internal bool32 +static bool32 TestSelectedLayer(project_state *State, uint16 *a, uint16 Index) { bool32 Result = 0; @@ -29,14 +29,6 @@ #define STBI_FAILURE_USERMSG #include "lib/stb_image.h" -extern "C" { -#include <libavcodec/avcodec.h> -#include <libavformat/avformat.h> -#include <libavformat/avio.h> -#include <libavutil/avutil.h> -#include <libswscale/swscale.h> -} - #if 0 #include <iacaMarks.h> #else @@ -44,60 +36,18 @@ extern "C" { #define IACA_END #endif -#define internal static -#define local_persist static -#define global_variable static - -#define SwitchBool(Bool) if((Bool)) {(Bool) = 0;} else {(Bool) = 1;} -#define AmountOf(Array) sizeof((Array)) / sizeof((Array)[1]) - -typedef int8_t int8; -typedef int16_t int16; -typedef int32_t int32; - -typedef int64_t int64; -typedef int32 bool32; - -typedef uint8_t uint8; -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint64_t uint64; - -typedef float real32; -typedef double real64; - -#define NORMALIZED_COL_MIN { .col = V4(0.0f, 0.0f, 0.0f, 0.0f) } -#define NORMALIZED_COL_MAX { .col = V4(1.0f, 1.0f, 1.0f, 1.0f) } -#define NORMALIZED_REAL_MIN { 0.0f } -#define NORMALIZED_REAL_MAX { 1.0f } - - -// All of these MIN/MAX values are arbitrarily chosen; they can probably be -// increased if the user requires it. - -#define PROPERTY_REAL_MAX 1000000 -#define PROPERTY_REAL_MIN -1000000 - -#define MAX_LAYERS 2048 -#define MAX_EFFECTS 32 -#define MAX_SOURCES 1024 -#define MAX_PROPERTIES_PER_EFFECT 16 -#define MAX_KEYFRAME_BLOCKS 64 -#define MAX_KEYFRAMES_PER_BLOCK 32 -#define STRING_SIZE 256 - -#define MAX_SELECTED_PROPERTIES 16 - +#include "defines.h" #include "my_math.h" #include "main.h" #include "debug.h" +#include "functions.h" +// #include "sharebuffer.h" SDL_atomic_t CurrentEntry; SDL_atomic_t QueuedEntries; SDL_atomic_t CompletedEntries; -global_variable bool32 IsRendering = false; -global_variable instruction_mode InstructionMode = scalar_only; - +static bool32 IsRendering = false; +static instruction_mode InstructionMode = instruction_mode_scalar; render_entry Entries[256]; @@ -105,7 +55,7 @@ SDL_Thread *thread[8]; SDL_sem *Semaphore; #include "memory.cpp" -#include "effects.cpp" +// #include "effects.cpp" #include "keyframes.cpp" #include "layer.cpp" #include "strings.cpp" @@ -114,59 +64,39 @@ SDL_sem *Semaphore; #else #endif #include "prenderer.cpp" -#include "video.cpp" +#include "ffmpeg_backend.cpp" #include "bitmap_calls.cpp" #include "createcalls.cpp" #include "my_imgui_widgets.cpp" -// #include "sharebuffer.h" - -internal void +static void MainFunction(main_sdl *Main, memory *Memory, project_state *State, project_data *File, - cache_pool *Cache, pixel_buffer *CompBuffer) + cache_pool *Cache, comp_buffer *CompBuffer) { - ClearBuffer(CompBuffer, CompBuffer->OriginalBuffer); - ClearBuffer(CompBuffer, CompBuffer->EffectBuffer); + Bitmap_Clear(CompBuffer->PackedBuffer, CompBuffer->Width, CompBuffer->Height, CompBuffer->BytesPerPixel); + Bitmap_Clear(CompBuffer->UnpackedBuffer, CompBuffer->Width, CompBuffer->Height, CompBuffer->BytesPerPixel); for (int i = 0; i < File->NumberOfLayers; i++) { project_layer *Layer = File->Layer[i]; - if (Layer->RenderInfo) { - // Keyframe updating - if (State->UpdateKeyframes) { - for (int p = 0; p < Layer->NumberOfEffects; p++) { - for (int o = 0; o < Layer->Effect[p]->NumberOfProperties; o++) { - CalculateKeyframesLinearly(File->CurrentFrame, &Layer->Effect[p]->Property[o]); - } - } - for (int r = 0; r < AmountOf(Layer->Property); r++) { - CalculateKeyframesLinearly(File->CurrentFrame, &Layer->Property[r]); - } - } - - // Video updating - if (Layer->SourceType == source_video) { // && Layer->VideoCurrentFrame != File->CurrentFrame - Layer->VideoFrameOffset) { - video_source *Source = (video_source *)Layer->RenderInfo; - LoadVideoFrame(Source, Memory, File->CurrentFrame); // TODO(fox): Make above check work! - UpdateEffects(Layer, Memory); - Source->Raster.ToUpdate = true; + if (State->UpdateKeyframes) { + for (int p = 0; p < Layer->NumberOfEffects; p++) { + for (int o = 0; o < Layer->Effect[p]->NumberOfProperties; o++) { + CalculateKeyframesLinearly(File->CurrentFrame, &Layer->Effect[p]->Property[o]); + } } - - // Effect updating - if (Layer->SourceType == source_image) { - image_source *Source = (image_source *)Layer->RenderInfo; - if (Source->Raster.ToUpdate) { - UpdateEffects(Layer, Memory); - Source->Raster.ToUpdate = false; - } + for (int r = 0; r < AmountOf(Layer->Property); r++) { + CalculateKeyframesLinearly(File->CurrentFrame, &Layer->Property[r]); } } + + Layer_UpdateBitmap(Layer->Source, &Layer->BitmapInfo, Memory, File->CurrentFrame); } State->UpdateKeyframes = false; QueueCurrentFrame(File, CompBuffer, State); } #if 0 -internal void +static void MainFunction(main_sdl *Main, project_debug *D, memory *Memory, sdl_input *Input, sdl_input *OldInput, project_state *State, brush_tool *Brush, project_data *File, cache_pool *Cache, pixel_buffer *CompBuffer) @@ -255,7 +185,7 @@ MainFunction(main_sdl *Main, project_debug *D, memory *Memory, sdl_input *Input, #endif -internal void +static void DebugPrintMemoryUsage(memory Memory) { for (int i = 0; i < 8; i++) { @@ -269,7 +199,7 @@ int main(int argc, char *argv[]) { global_memory GlobalMemory = {}; - GlobalMemory.Size = ((uint64)2 * 1024 * 1024 * 1024); + GlobalMemory.Size = ((uint64)4 * 1024 * 1024 * 1024); GlobalMemory.CurrentPosition = 0; #if WINDOWS @@ -287,42 +217,53 @@ int main(int argc, char *argv[]) { InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_UIState, "UI state"); // TODO(fox): Make clean-up functions when these get deleted! - InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_SourceData, "Image/video headers"); + InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_AVInfo, "Image/video headers"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_ProjectSettings, "Project settings"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Layers, "Layers"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Effects, "Effects"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Keyframes, "Keyframe blocks"); InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Strings, "Strings"); - InitMemoryTable(&GlobalMemory, &Memory, (uint64)2 * 1024 * 1024 * 1024, B_Scratch, "Scratch buffer"); + InitMemoryTable(&GlobalMemory, &Memory, (uint64)16 * 1024 * 1024, B_LayerBitmaps, "Layer buffer"); + InitMemoryTable(&GlobalMemory, &Memory, (uint64)1 * 1024 * 1024 * 1024, B_LoadedBitmaps, "Loaded bitmap buffer"); project_state State = {}; if (SDL_HasSSE2()) { - InstructionMode = sse_enabled; + InstructionMode = instruction_mode_sse; } if (SDL_HasAVX2()) { - InstructionMode = avx_enabled; + InstructionMode = instruction_mode_avx; } project_data File = {}; File.Width = 1280; File.Height = 720; - // File.Width = 1923; - // File.Height = 1083; File.NumberOfFrames = 65; File.FPS = 30; File.CurrentFrame = 1; File.StartFrame = 0; File.EndFrame = 65; - // CreateLayerFromSource(&File, &State, &Memory, "../asset/b.jpg"); - // char String[1024]; - // uint16 Size = 1024; - // getcwd(String, Size); - // printf("dir: %s", String); +#if DEBUG + // GDB and LLDB say this plain struct that's literally under 30 bytes is + // incomplete in the layers unless I do this... + layer_bitmap_info BitmapInfo; + BitmapInfo.ToUpdate = 0; + BitmapInfo.FrameOffset = 2; + av_packet_info BS = {}; + BS.PreviousPTS = 0; +#endif + + LoadTestFootage(&File, &State, &Memory); - pixel_buffer CompBuffer = CreateBuffer(File.Width, File.Height, &Memory); + uint16 BytesPerPixel = 4; + comp_buffer CompBuffer = {}; + CompBuffer.Width = File.Width; + CompBuffer.Height = File.Height; + CompBuffer.BytesPerPixel = BytesPerPixel; + CompBuffer.PackedBuffer = Layer_AllocateBitmap(&Memory, CompBuffer.Width, CompBuffer.Height, CompBuffer.BytesPerPixel); + CompBuffer.UnpackedBuffer = Layer_AllocateBitmap(&Memory, CompBuffer.Width, CompBuffer.Height, CompBuffer.BytesPerPixel); cache_pool Cache = {}; Cache.Interact = Inactive; @@ -451,7 +392,7 @@ int main(int argc, char *argv[]) { #if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); #endif - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, CompBuffer.Width, CompBuffer.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, CompBuffer.OriginalBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, CompBuffer.Width, CompBuffer.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, CompBuffer.PackedBuffer); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); @@ -525,11 +466,12 @@ int main(int argc, char *argv[]) { } C = SDL_AtomicGet(&CompletedEntries); if (C == 16) { - Convert4x4Chunk(&CompBuffer, 1); + Bitmap_ConvertPacking(CompBuffer.PackedBuffer, CompBuffer.UnpackedBuffer, + CompBuffer.Width, CompBuffer.Height, CompBuffer.BytesPerPixel, 1); EndRenderState(&State); glBindTexture(GL_TEXTURE_2D, textureID); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, CompBuffer.Width, CompBuffer.Height, GL_RGBA, GL_UNSIGNED_BYTE, - CompBuffer.EffectBuffer); + CompBuffer.UnpackedBuffer); // shmp->shared_framenumber = File.CurrentFrame; // if (sem_post(&shmp->sem2) == -1) @@ -1,50 +1,7 @@ -enum source_type { - source_none, - source_video, - source_image -}; - enum instruction_mode { - scalar_only, - sse_enabled, - avx_enabled -}; - -struct pixel_buffer { - void *OriginalBuffer; - void *EffectBuffer; - void *Scratch; - uint16 Width; - uint16 Height; - // IMPORTANT(fox): Since we're storing 4x4 chunks, I'm opting to pad out each - // dimension with an extra 1-3 pixels to make our lookup functions simpler. - // This has the cost of extra RAM, but it's a miniscule amount (0.2% extra - // data for a worst-case 1080p 16bpc frame, or 140 kb). - uint16 FullWidth; - uint16 FullHeight; - uint16 Pitch; - uint16 BytesPerPixel; - bool32 ToUpdate; // Set whenever effects or video frames need to be updated. -}; - -struct av_info { - AVFormatContext *FileFormatContext; - AVCodecParameters *VideoCodecParameters; - const AVCodec* VideoCodec; - const AVCodecHWConfig* VideoHWConfig; - AVPixelFormat HWPixFormat; - AVCodecContext *VideoCodecContext; - AVPacket *VideoPacket; - AVFrame *VideoFrame; - AVStream *VideoStream; - SwsContext *RGBContext; - - uint16 StreamIndex; - real32 FPS; - int32 IntFPS; - real32 AvgPTSPerSecond; - real32 AvgPTSPerFrame; - uint64 LastPTS; + instruction_mode_scalar, + instruction_mode_sse, + instruction_mode_avx }; struct cache { @@ -79,9 +36,10 @@ enum memory_table_list { F_Strings, P_UIState, - P_SourceData, + P_AVInfo, - B_Scratch, + B_LayerBitmaps, + B_LoadedBitmaps, }; struct memory_table { @@ -97,8 +55,12 @@ struct global_memory { uint64 Size; }; +struct cached_bitmap_block; + struct memory { memory_table Slot[16]; + cached_bitmap_block *CacheBlock[256]; + uint16 NumberOfCachedBlocks; }; struct property_channel; @@ -127,7 +89,7 @@ enum var_type }; -global_variable char* BlendmodeNames[] = { +static char* BlendmodeNames[] = { "Normal", "Multiply", "Color Burn", @@ -213,6 +175,8 @@ struct property_header val MaxVal; }; +struct pixel_buffer {}; + struct effect_header { char *Name; @@ -233,20 +197,63 @@ struct effect { }; -// Note how pixel_buffer is first in both so we can cast to image_source if we -// don't care about the AV info. +// Information about a particular file. -struct video_source { - struct pixel_buffer Raster; - av_info AV; - int32 VideoFrameOffset; // the "true" position of video layers, separate from StartFrame - int32 VideoCurrentFrame; +enum source_type { + source_type_none, + source_type_video, + source_type_image }; -struct image_source { - struct pixel_buffer Raster; +// Probably best to consider source_info a part of the file data so we don't +// have to re-check each source on every project load. (except for AVInfo) + +struct source_info { + // Image and video + uint16 Width; + uint16 Height; + uint16 BytesPerPixel; + + // Video only + real32 FPS; + void* AVCodecInfo; // Internal data for the video decoder library. }; +struct source { + char *Path; + source_type SourceType; + source_info Info; +}; + +// Bitmaps from files are loaded into these temporary cache blocks. + +struct cached_bitmap_block { + source *SourceOwner; // Which source the data belongs to. + void *Data; // Unpacked data loaded from the source file. + uint32 StartFrame; + uint32 NumberOfCachedFrames; +}; + +struct layer_bitmap_info { + // Image and video + void *BitmapBuffer; // Each layer has a persistent bitmap that the source data gets packed into. + bool32 ToUpdate = 1; + + // Video only + int32 FrameOffset; // the "true" position of video layers, separate from StartFrame + int32 CurrentFrame = -1; // The last frame number rendered to the bitmap. + void *AVPacketInfo; // Internal data containing current frame info +}; + +struct comp_buffer { + uint16 Width; + uint16 Height; + uint16 BytesPerPixel; + void *PackedBuffer; + void *UnpackedBuffer; +}; + + struct transform_info { real32 XAxisPX; real32 XAxisPY; @@ -288,8 +295,8 @@ struct project_layer { bool32 IsSelected; - void *RenderInfo; - source_type SourceType; + source *Source; + layer_bitmap_info BitmapInfo; effect *Effect[MAX_EFFECTS]; uint16 NumberOfEffects; @@ -303,6 +310,7 @@ struct project_layer { transform_info TransformInfo; }; + // NOTE(fox): I have no idea how people normally do selection; currently I'm // treating it more "immediate." Instead of updating a selection state as // things are selected, I'm just calling functions that go through all the @@ -336,7 +344,7 @@ struct project_data uint16 NumberOfSelectedLayers; uint16 NumberOfLayers; - char *Source[MAX_SOURCES]; + source Source[MAX_SOURCES]; uint16 NumberOfSources; }; @@ -358,7 +366,7 @@ enum transforms_hotkey_interact { struct main_sdl { - pixel_buffer Buffer; + // pixel_buffer Buffer; SDL_Texture *Texture; SDL_Event Event; SDL_Window *Window; @@ -510,7 +518,7 @@ struct render_queue { project_data *File; project_state *State; - pixel_buffer *CompBuffer; + comp_buffer *CompBuffer; }; struct thread_info @@ -1,4 +1,4 @@ -internal void +static void InitMemoryTable(global_memory *GlobalMemory, memory *Memory, uint64 Size, memory_table_list TableName, char *Name) { memory_table *Table = &Memory->Slot[TableName]; Table->Name = Name; @@ -7,7 +7,7 @@ InitMemoryTable(global_memory *GlobalMemory, memory *Memory, uint64 Size, memory GlobalMemory->CurrentPosition += Size; } -internal void* +static void* AllocateMemory(memory *Memory, uint64 Size, memory_table_list TableName) { void *Address; memory_table *Table = &Memory->Slot[TableName]; diff --git a/my_imgui_internal_widgets.cpp b/my_imgui_internal_widgets.cpp new file mode 100644 index 0000000..5ff01ee --- /dev/null +++ b/my_imgui_internal_widgets.cpp @@ -0,0 +1,294 @@ +#include "my_imgui_internal_widgets.h" + +#include "imgui.h" +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +// A modded version of ScalarSlider allowing for the minimum and maximum parts +// of the slider to be draggable by two other buttons. p_data is from range -1 +// to 1, and s_min and max are from 0-1. +#if 0 +// bool ImGui::SliderLevels(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, ImGuiSliderFlags flags) +bool ImGui::SliderLevels(const char* label, void* p_data, const void* s_min, const void* s_max) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const float MidMin = -1; + const float MidMax = 1; + const void* mid_min = &SliderMin; + const void* mid_max = &SliderMax; + ImGuiDataType data_type = ImGuiDataType_Float; + const char *format = "%f"; + + ImVec2 picker_pos = window->DC.CursorPos; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + value_changed |= SliderScalar("", data_type, p_data, mid_min, mid_max, format, ImGuiSliderFlags_Logarithmic); + SetCursorScreenPos(ImVec2(picker_pos.x + 20.0f, picker_pos.y)); + // PushItemWidth(); + value_changed |= SliderScalar("", data_type, p_data, p_min, p_max, format, ImGuiSliderFlags_Logarithmic); + // PushMultiItemsWidths(components, CalcItemWidth()); + // size_t type_size = GDataTypeInfo[data_type].Size; + // for (int i = 0; i < components; i++) + // { + // PushID(i); + // if (i > 0) + // SameLine(0, g.Style.ItemInnerSpacing.x); + // value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, flags); + // PopID(); + // PopItemWidth(); + // v = (void*)((char*)v + type_size); + // } + PopID(); + + EndGroup(); + return value_changed; +} +bool ImGui::SliderLevels(const char* label, void* p_data, void* s_left, void* s_right) +{ + ImGuiSliderFlags flags = ImGuiSliderFlags_NoInput; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const float SliderMin = -1; + const float SliderMax = 1; + const float OtherMin = 0; + const float OtherMax = 1; + const void* p_min = &SliderMin; + const void* p_max = &SliderMax; + const void* o_min = &OtherMin; + const void* o_max = &OtherMax; + ImGuiDataType data_type = ImGuiDataType_Float; + const char *format = "%f"; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImGuiID id_mid = window->GetID("asdasbdsgd"); + const ImGuiID id_L = window->GetID("ppasd"); + const ImGuiID id_R = window->GetID("adsafb"); + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + // const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; + // ItemSize(total_bb, style.FramePadding.y); + // if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0)) + // return false; + + const bool hovered = ItemHoverable(frame_bb, id_L); + + // NOTE(fox): Making bogus calls here to get these positions so we can only activate the one we want - replace with the lower-level call. + // const ImGuiID id_bogus = window->GetID("ppp"); + // ImRect test_left; + // SliderBehavior(frame_bb, id_bogus, data_type, s_left, o_min, o_max, format, ImGuiSliderFlags_NoInput, &test_left); + // ImRect test_right; + // SliderBehavior(frame_bb, id_bogus, data_type, s_right, o_min, o_max, format, ImGuiSliderFlags_NoInput, &test_right); + + const bool input_requested_by_tabbing = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool clicked = (hovered && g.IO.MouseClicked[0]); + const bool make_active = (input_requested_by_tabbing || clicked || g.NavActivateId == id_L || g.NavActivateInputId == id_L); + if (make_active) + { + SetActiveID(id_L, window); + SetFocusID(id_L, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + } + /* + else if (make_active && g.IO.MousePos.x > test_right.Min.x) { + SetActiveID(id_R, window); + SetFocusID(id_R, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + } else if (make_active) { + SetActiveID(id_mid, window); + SetFocusID(id_mid, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + } + */ + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + + // Slider behavior + ImRect L_grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id_L, data_type, s_left, o_min, o_max, format, ImGuiSliderFlags_NoInput, &L_grab_bb); + if (value_changed) + MarkItemEdited(id_L); + + // Render grab + if (L_grab_bb.Max.x > L_grab_bb.Min.x) + window->DrawList->AddRectFilled(L_grab_bb.Min, L_grab_bb.Max, GetColorU32(g.ActiveId == id_L ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + +#if 0 + // Slider behavior + ImRect R_grab_bb; + const bool value_changed2 = SliderBehavior(frame_bb, id_R, data_type, s_right, o_min, o_max, format, ImGuiSliderFlags_NoInput, &R_grab_bb); + if (value_changed2) + MarkItemEdited(id_R); + + // Render grab + if (R_grab_bb.Max.x > R_grab_bb.Min.x) + window->DrawList->AddRectFilled(R_grab_bb.Min, R_grab_bb.Max, GetColorU32(g.ActiveId == id_R ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + const ImRect range_bb(ImVec2(L_grab_bb.Min.x, frame_bb.Min.y), ImVec2(R_grab_bb.Min.x, frame_bb.Max.y)); + + // Slider behavior + ImRect grab_bb_mid; + const bool value_changed_mid = SliderBehavior(range_bb, id_mid, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Logarithmic, &grab_bb_mid); + // if (value_changed2) + // MarkItemEdited(id_bogus); + + ImVec2 asda = ImVec2(0, 5); + // // Render grab + if (grab_bb_mid.Max.x > grab_bb_mid.Min.x) + window->DrawList->AddRectFilled(grab_bb_mid.Min + asda, grab_bb_mid.Max + asda, GetColorU32(g.ActiveId == id_bogus ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); +#endif + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return value_changed; +} +#else +bool ImGui::SliderLevels(const char* label, void* p_mid, void* p_left, void* p_right) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const float SliderMin = -1; + const float SliderMax = 1; + const float OtherMin = 0; + const float OtherMax = 1; + const void* p_min = &SliderMin; + const void* p_max = &SliderMax; + const void* o_min = &OtherMin; + const void* o_max = &OtherMax; + ImGuiDataType data_type = ImGuiDataType_Float; + const char *format = "%f"; + + ImGuiSliderFlags flags = ImGuiSliderFlags_NoInput; + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImGuiID idnull = window->GetID("asdas"); + const ImGuiID id_mid = window->GetID("asdasbdsgd"); + const ImGuiID id_L = window->GetID("ppasd"); + const ImGuiID id_R = window->GetID("adsafb"); + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ImRect test_L_bb; + SliderBehavior(frame_bb, idnull, data_type, p_left, o_min, o_max, format, flags, &test_L_bb); + ImRect test_R_bb; + SliderBehavior(frame_bb, idnull, data_type, p_right, o_min, o_max, format, flags, &test_R_bb); + + ItemSize(total_bb, style.FramePadding.y); + + if (!ItemAdd(total_bb, id_L, &frame_bb, 0)) + return false; + if (!ItemAdd(total_bb, id_R, &frame_bb, 0)) + return false; + if (!ItemAdd(total_bb, id_mid, &frame_bb, 0)) + return false; + + const bool hovered = ItemHoverable(frame_bb, id); + + const bool input_requested_by_tabbing = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool clicked = (hovered && g.IO.MouseClicked[0]); + const bool make_active = (input_requested_by_tabbing || clicked || g.NavActivateId == id || g.NavActivateInputId == id); + + if (make_active) + { + if (g.IO.MousePos.x < test_L_bb.Max.x) { + SetActiveID(id_L, window); + SetFocusID(id_L, window); + } else if (g.IO.MousePos.x > test_R_bb.Min.x) { + SetActiveID(id_R, window); + SetFocusID(id_R, window); + } else { + SetActiveID(id_mid, window); + SetFocusID(id_mid, window); + } + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + } + + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id_L ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id_L); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + // Slider behavior + ImRect grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id_L, data_type, p_left, o_min, o_max, format, flags, &grab_bb); + if (value_changed) + MarkItemEdited(id_L); + + // Render grab + if (grab_bb.Max.x > grab_bb.Min.x) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id_L ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Slider behavior + ImRect grab_bb2; + const bool value_changed2 = SliderBehavior(frame_bb, id_R, data_type, p_right, o_min, o_max, format, flags, &grab_bb2); + if (value_changed2) + MarkItemEdited(id_R); + + // Render grab + if (grab_bb2.Max.x > grab_bb2.Min.x) + window->DrawList->AddRectFilled(grab_bb2.Min, grab_bb2.Max, GetColorU32(g.ActiveId == id_R ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + const ImRect mid_bb(ImVec2(grab_bb.Max.x, frame_bb.Min.y), ImVec2(grab_bb2.Min.x, frame_bb.Max.y)); + + // Slider behavior + ImRect grab_bb3; + const bool value_changed3 = SliderBehavior(mid_bb, id_mid, data_type, p_mid, p_min, p_max, format, flags, &grab_bb3); + if (value_changed3) + MarkItemEdited(id_mid); + + // Render grab + if (grab_bb3.Max.x > grab_bb3.Min.x) + window->DrawList->AddRectFilled(grab_bb3.Min, grab_bb3.Max, GetColorU32(g.ActiveId == id_mid ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_left, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return value_changed; +} +#endif diff --git a/my_imgui_internal_widgets.h b/my_imgui_internal_widgets.h new file mode 100644 index 0000000..ec106b1 --- /dev/null +++ b/my_imgui_internal_widgets.h @@ -0,0 +1,11 @@ +#pragma once + +#include <climits> + +#include <imgui.h> + +// NOTE(fox): Appending to the standard ImGui namespace so I don't have to convert all the functions to ImGui::Function() +namespace ImGui { + IMGUI_API bool SliderLevels(const char* label, void* p_data, void* p_min, void* p_max); +} + diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index f94e47c..1ee82e9 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -1,8 +1,9 @@ #include "imgui/imgui.h" +#include "my_imgui_internal_widgets.h" #include "imgui_ops.h" // 0 for timeline keyframe, 1 for graph keyframe, 2 for left graph handle, 3 for right graph handle -internal void +static void ImGui_KeyframeDragging(project_data *File, project_state *State, ui *UI, property_channel *Property, int32 b, ImGuiIO io, int16 Type) { keyframe *Keyframe = KeyframeLookupMemory(Property, b); @@ -69,7 +70,7 @@ ImGui_KeyframeDragging(project_data *File, project_state *State, ui *UI, propert } } -internal void +static void ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *Memory) { if (State->MostRecentlySelectedLayer > -1) { @@ -97,35 +98,52 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * effect *Effect = Layer->Effect[h]; ImGui::Button("V"); ImGui::SameLine(); ImGui::Text(Effect->Name); - for (int i = 0; i < Effect->NumberOfProperties; i++) { - property_channel *Property = &Effect->Property[i]; - ImGui::PushID(Property); - if (Property->VarType == type_real) - ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue.f, 0.005f, &Property->MaxVal.f, &Property->MaxVal.f, "%f"); - if (Property->VarType == type_color) - if (ImGui::ColorEdit4("color 1", &Property->CurrentValue.f, ImGuiColorEditFlags_Float)) - State->UpdateFrame = true; - if (Property->VarType == type_blendmode) - { - uint32 *item_current_idx = (uint32 *)&Property->CurrentValue.blendmode; // Here we store our selection data as an index. - if (ImGui::BeginListBox("Blend mode")) + if (Effect->DisplayType == standard) { + for (int i = 0; i < Effect->NumberOfProperties; i++) { + property_channel *Property = &Effect->Property[i]; + ImGui::PushID(Property); + if (Property->VarType == type_real) + ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue.f, 0.005f, &Property->MaxVal.f, &Property->MaxVal.f, "%f"); + if (Property->VarType == type_color) + if (ImGui::ColorEdit4("color 1", &Property->CurrentValue.f, ImGuiColorEditFlags_Float)) + State->UpdateFrame = true; + if (Property->VarType == type_blendmode) { - for (int n = 0; n < IM_ARRAYSIZE(BlendmodeNames); n++) + uint32 *item_current_idx = (uint32 *)&Property->CurrentValue.blendmode; // Here we store our selection data as an index. + if (ImGui::BeginListBox("Blend mode")) { - const bool is_selected = (*item_current_idx == n); - if (ImGui::Selectable(BlendmodeNames[n], is_selected)) { - *item_current_idx = n; - State->UpdateFrame = true; + for (int n = 0; n < IM_ARRAYSIZE(BlendmodeNames); n++) + { + const bool is_selected = (*item_current_idx == n); + if (ImGui::Selectable(BlendmodeNames[n], is_selected)) { + *item_current_idx = n; + State->UpdateFrame = true; + } + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); } - - // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if (is_selected) - ImGui::SetItemDefaultFocus(); + ImGui::EndListBox(); } - ImGui::EndListBox(); } + ImGui::PopID(); } - ImGui::PopID(); + } else if (Effect->DisplayType == levels) { + ImGui::Button("asda"); + // bool ImGui::SliderScalarasda(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) + // static int8 p = 0; + // static int8 m = 10; + // static int8 c = 2; + // ImGui::SliderScalarasda("slider s8 full", ImGuiDataType_S8, &c, &p, &m, "%d", ImGuiSliderFlags_None); + static real32 p = 0; + static real32 m = 1; + static real32 c = 2; + ImGui::SliderScalar("f2", ImGuiDataType_Float, &c, &p, &m, "%f", ImGuiSliderFlags_Logarithmic); + static real32 Max = 0.8; + static real32 Min = 0.25; + static real32 Mid = 0; // NOTE(fox): "Neutral" is zero, negative one is full black, one is full white. + ImGui::SliderLevels("f", &Mid, &Min, &Max); } } } else { @@ -138,11 +156,11 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * ImGui::End(); } -internal v2 -CalculateAnchorPointUV(project_layer *Layer, pixel_buffer *Buffer); +static v2 +CalculateAnchorPointUV(project_layer *Layer, comp_buffer *Buffer); -internal void -ImGui_Viewport(project_data File, project_state *State, ui *UI, pixel_buffer CompBuffer, +static void +ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer CompBuffer, ImGuiIO io, GLuint textureID) { ImGui::Begin("Viewport"); @@ -202,9 +220,9 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, pixel_buffer Com // } ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonMiddle); if (ImGui::BeginPopup("context")) { - if (ImGui::MenuItem("Scalar", NULL, false, InstructionMode != scalar_only)) { InstructionMode = scalar_only; State->UpdateFrame = true; } - if (ImGui::MenuItem("SSE", NULL, false, InstructionMode != sse_enabled)) { InstructionMode = sse_enabled; State->UpdateFrame = true; } - if (ImGui::MenuItem("AVX2", NULL, false, InstructionMode != avx_enabled)) { InstructionMode = avx_enabled; State->UpdateFrame = true; } + if (ImGui::MenuItem("Scalar", NULL, false, InstructionMode != instruction_mode_scalar)) { InstructionMode = instruction_mode_scalar; State->UpdateFrame = true; } + if (ImGui::MenuItem("SSE", NULL, false, InstructionMode != instruction_mode_sse)) { InstructionMode = instruction_mode_sse; State->UpdateFrame = true; } + if (ImGui::MenuItem("AVX2", NULL, false, InstructionMode != instruction_mode_avx)) { InstructionMode = instruction_mode_avx; State->UpdateFrame = true; } ImGui::EndPopup(); } if (IsActive && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1.0f) && ImGui::IsKeyDown(ImGuiKey_Z)) @@ -241,7 +259,7 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, pixel_buffer Com } // 1 for left, 2 for right, 3 for both -internal bool32 +static bool32 ImGui_SlidingLayer(project_layer *Layer, real32 *DraggingThreshold, real32 Delta, int16 TimelineZoom, int16 Side) { bool32 Result = 0; @@ -262,9 +280,8 @@ ImGui_SlidingLayer(project_layer *Layer, real32 *DraggingThreshold, real32 Delta Layer->EndFrame += Increment; if (Side == 3) { IncrementKeyframesInLayer(Layer, Increment); - if (Layer->SourceType == source_video) { - video_source *Source = (video_source *)Layer->RenderInfo; - Source->VideoFrameOffset += Increment; + if (Layer->Source->SourceType == source_type_video) { + Layer->BitmapInfo.FrameOffset += Increment; } } } @@ -275,21 +292,17 @@ ImGui_SlidingLayer(project_layer *Layer, real32 *DraggingThreshold, real32 Delta return Result; } -internal void -AddSource(project_data *File, memory *Memory, char * = NULL); - -internal void +static void ImGui_File(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io) { ImGui::Begin("Files"); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); - if (ImGui::Button("Add source")) { - AddSource(File, Memory); - } + // if (ImGui::Button("Add source")) { + // } if (State->DemoButton) { ImGui::SameLine(); if (ImGui::Button("Generate demo scene")) { - CreateDemoScene(File, Memory); + // CreateDemoScene(File, Memory); State->UpdateKeyframes = true; State->UpdateFrame = true; State->DemoButton = false; @@ -298,20 +311,17 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ui *UI, ImG if (State->GridButton) { ImGui::SameLine(); if (ImGui::Button("Generate square grid")) { - CreateGrid(File, Memory); + // CreateGrid(File, Memory); State->UpdateKeyframes = true; State->UpdateFrame = true; State->GridButton = false; } } - for (int16 i = 0; i < File->NumberOfSources; i++) { - ImGui::PushID(i); - ImGui::InputText("##source", File->Source[i], STRING_SIZE); - ImGui::SameLine(); - if (ImGui::Button("Create Layer")) { - CreateLayerFromSource(File, State, Memory, File->Source[i]); - } - ImGui::PopID(); + static char Input[1024]; + ImGui::InputText("##sourceinput", Input, STRING_SIZE); + ImGui::SameLine(); + if (ImGui::Button("Create Layer")) { + // AddSource(File, State, Memory, Input); } #if DEBUG for (int i = 0; i < Debug.WatchedProperties; i++) { @@ -327,9 +337,10 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ui *UI, ImG ImGui::End(); } -internal void +static void ImGui_EffectsPanel(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io) { +#if 0 ImGui::Begin("Effects list", NULL); if (State->RerouteEffects) { ImGui::SetKeyboardFocusHere(); @@ -349,23 +360,41 @@ ImGui_EffectsPanel(project_data *File, project_state *State, memory *Memory, ui State->filter.Build(); EffectSel = -1; } + // Enter conveniently deactivates the InputText field + if (ImGui::IsItemDeactivated() && ImGui::IsKeyPressed(ImGuiKey_Enter)) { + int32 p = 0; + for (int32 i = 0; i < AmountOf(EffectList); i++) { + if (State->filter.PassFilter(EffectList[i].Name)) { + if (EffectSel == p && State->MostRecentlySelectedLayer != -1) { + AddEffect(File->Layer[State->MostRecentlySelectedLayer], Memory, i); + } + p++; + } + } + EffectSel = -1; + } + int32 p = 0; for (int32 i = 0; i < AmountOf(EffectList); i++) { if (State->filter.PassFilter(EffectList[i].Name)) { - if (EffectSel == i) { - bool t = true; - ImGui::Selectable(EffectList[i].Name, &t); - } else { - bool s = false; - ImGui::Selectable(EffectList[i].Name, &s); + bool t = false; + if (EffectSel == p) { + t = true; } - // ImGui::Text(EffectList[i].Name); + ImGui::Selectable(EffectList[i].Name, &t); + if (ImGui::IsItemClicked()) { + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && State->MostRecentlySelectedLayer != -1) { + AddEffect(File->Layer[State->MostRecentlySelectedLayer], Memory, i); + } + } + p++; } } ImGui::End(); +#endif } -internal void +static void ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io) { ImVec2 FramePadding = ImGui::GetStyle().FramePadding; @@ -991,6 +1020,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, UI->BoxStart = {0, 0}; UI->BoxEnd = {0, 0}; UI->BoxSelectActive = false; + if (!io.KeyShift) DeselectAllLayers(File, State); } ImGui::EndChild(); @@ -1018,8 +1048,8 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, } -internal void -ImGui_ProcessInputs(project_data *File, project_state *State, pixel_buffer *CompBuffer, memory *Memory, ui *UI, ImGuiIO io) +static void +ImGui_ProcessInputs(project_data *File, project_state *State, comp_buffer *CompBuffer, memory *Memory, ui *UI, ImGuiIO io) { if (io.KeysData[ImGuiKey_Q].Down) State->IsRunning = false; @@ -1132,7 +1162,7 @@ ImGui_ProcessInputs(project_data *File, project_state *State, pixel_buffer *Comp } } -global_variable char ImGuiPrefs[] = "[Window][DockSpaceViewport_11111111]" +static char ImGuiPrefs[] = "[Window][DockSpaceViewport_11111111]" "\nPos=0,0" "\nSize=3200,1800" "\nCollapsed=0" @@ -1,5 +1,5 @@ -internal void +static void SlidingBrush(pixel_buffer *Buffer, v2i Pos, brush_tool Brush) { v2i Min = {0,0}; @@ -35,7 +35,7 @@ SlidingBrush(pixel_buffer *Buffer, v2i Pos, brush_tool Brush) } /* -internal void +static void Paint(sdl_input Input, project_layer *Layer, brush_tool Brush) { int16 X = Input.Mouse.x - UI.CompX; // convert to comp space diff --git a/prenderer.cpp b/prenderer.cpp index 5df28f4..7ce738a 100644 --- a/prenderer.cpp +++ b/prenderer.cpp @@ -1,26 +1,26 @@ -internal void +static void PushRect(rectangle RenderRegion); -internal void +static void RenderLayerNeon(project_layer *Layer, pixel_buffer *Buffer, rectangle RenderRegion); -internal void -AVX2_RenderLayer(transform_info TransformInfo, pixel_buffer *Buffer, rectangle RenderRegion); -internal void -SSE2_RenderLayer(transform_info TransformInfo, pixel_buffer *Buffer, rectangle RenderRegion); -internal void -Fallback_RenderLayer(transform_info TransformInfo, pixel_buffer *Buffer, rectangle RenderRegion); - -internal bool32 +static void +AVX2_RenderLayer(transform_info TransformInfo, comp_buffer *Buffer, rectangle RenderRegion); +static void +SSE2_RenderLayer(transform_info TransformInfo, comp_buffer *Buffer, rectangle RenderRegion); +static void +Fallback_RenderLayer(transform_info TransformInfo, comp_buffer *Buffer, rectangle RenderRegion); + +static bool32 CheckQueue(render_queue RenderInfo, uint16 Index); // for the anchor point moving UI -internal void +static void CalculateAnchorOffset(project_layer *Layer, real32 Value, uint16 Dir) { v2 Result = {}; transform_info TransformInfo; - image_source *Source = (image_source *)Layer->RenderInfo; + source *Source = Layer->Source; real32 Rad = (Layer->rotation.CurrentValue.f * (PI / 180)); real32 s = Layer->scale.CurrentValue.f; @@ -28,28 +28,28 @@ CalculateAnchorOffset(project_layer *Layer, real32 Value, uint16 Dir) if (Dir == 0) { v2 XAxis = V2(cos(Rad), sin(Rad)) * (Value / s); Layer->x.CurrentValue.f += Value; - Layer->ax.CurrentValue.f += XAxis.x/Source->Raster.Width; - Layer->ay.CurrentValue.f -= XAxis.y/Source->Raster.Height; + Layer->ax.CurrentValue.f += XAxis.x/Source->Info.Width; + Layer->ay.CurrentValue.f -= XAxis.y/Source->Info.Height; } else { v2 YAxis = V2(sin(Rad), -cos(Rad)) * (Value / -s); Layer->y.CurrentValue.f += Value; - Layer->ax.CurrentValue.f -= YAxis.x/Source->Raster.Width; - Layer->ay.CurrentValue.f += YAxis.y/Source->Raster.Height; + Layer->ax.CurrentValue.f -= YAxis.x/Source->Info.Width; + Layer->ay.CurrentValue.f += YAxis.y/Source->Info.Height; } } -internal transform_info -CalculateTransforms(project_layer *Layer, pixel_buffer *Buffer) +static transform_info +CalculateTransforms(project_layer *Layer, comp_buffer *CompBuffer) { transform_info TransformInfo; - image_source *Source = (image_source *)Layer->RenderInfo; + source *Source = Layer->Source; real32 Rad = (Layer->rotation.CurrentValue.f * (PI / 180)); real32 s = Layer->scale.CurrentValue.f; // v2 Scale = {Source->Raster.Width * s, Source->Raster.Height * s}; - v2 XAxis = (Source->Raster.Width * s)*V2(cos(Rad), sin(Rad)); - v2 YAxis = (Source->Raster.Height * -s)*V2(sin(Rad), -cos(Rad)); + v2 XAxis = (Source->Info.Width * s)*V2(cos(Rad), sin(Rad)); + v2 YAxis = (Source->Info.Height * -s)*V2(sin(Rad), -cos(Rad)); real32 AnchorX = Layer->ax.CurrentValue.f; real32 AnchorY = Layer->ay.CurrentValue.f; @@ -62,8 +62,8 @@ CalculateTransforms(project_layer *Layer, pixel_buffer *Buffer) int32 MaxX = 0; int32 MaxY = 0; - int32 MinX = Buffer->Width; - int32 MinY = Buffer->Height; + int32 MinX = CompBuffer->Width; + int32 MinY = CompBuffer->Height; v2 Points[4] = {Origin, Origin + XAxis, Origin + YAxis, Origin + XAxis + YAxis}; for (int i = 0; i < 4; i++) { @@ -77,24 +77,30 @@ CalculateTransforms(project_layer *Layer, pixel_buffer *Buffer) TransformInfo.XAxisPY = XLengthSq*XAxis.y; TransformInfo.YAxisPX = YLengthSq*YAxis.x; TransformInfo.YAxisPY = YLengthSq*YAxis.y; - TransformInfo.LayerWidth = (real32)Source->Raster.Width; - TransformInfo.LayerHeight = (real32)Source->Raster.Height; - TransformInfo.FullLayerWidth = Source->Raster.FullWidth; - TransformInfo.FullLayerHeight = Source->Raster.FullHeight; + + uint16 Width = Source->Info.Width; + uint16 Height = Source->Info.Height; + uint16 WidthP, HeightP; + Bitmap_CalcPackedDimensions(Width, Height, &WidthP, &HeightP); + + TransformInfo.LayerWidth = Width; + TransformInfo.LayerHeight = Height; + TransformInfo.FullLayerWidth = WidthP; + TransformInfo.FullLayerHeight = HeightP; TransformInfo.LayerOpacity = Layer->opacity.CurrentValue.f; TransformInfo.BlendMode =Layer->BlendMode; TransformInfo.OriginX = Origin.x; TransformInfo.OriginY = Origin.y; - TransformInfo.BufferPitch = Buffer->Pitch; - TransformInfo.LayerPitch = Source->Raster.Pitch; + TransformInfo.BufferPitch = CompBuffer->Width*CompBuffer->BytesPerPixel; + TransformInfo.LayerPitch = Source->Info.Width*Source->Info.BytesPerPixel; TransformInfo.ClipRect = {MinX - (MinX & 3), MinY, MaxX + 1, MaxY + 1}; - TransformInfo.SourceBuffer = Source->Raster.EffectBuffer; + TransformInfo.SourceBuffer = Layer->BitmapInfo.BitmapBuffer; return TransformInfo; } -internal void +static void EndRenderState(project_state *State) { IsRendering = false; @@ -113,21 +119,21 @@ EndRenderState(project_state *State) } -internal void +static void RenderLayers(render_queue *RenderInfo, rectangle RenderRegion) { for (int16 i = 0; i < RenderInfo->State->NumberOfLayersToRender; i++) { int16 Idx = RenderInfo->State->LayersToRender[i]; - if (InstructionMode == avx_enabled) + if (InstructionMode == instruction_mode_avx) AVX2_RenderLayer(RenderInfo->File->Layer[Idx]->TransformInfo, RenderInfo->CompBuffer, RenderRegion); - else if (InstructionMode == sse_enabled) + else if (InstructionMode == instruction_mode_sse) SSE2_RenderLayer(RenderInfo->File->Layer[Idx]->TransformInfo, RenderInfo->CompBuffer, RenderRegion); else Fallback_RenderLayer(RenderInfo->File->Layer[Idx]->TransformInfo, RenderInfo->CompBuffer, RenderRegion); } } -internal void -QueueCurrentFrame(project_data *File, pixel_buffer *CompBuffer, project_state *State) +static void +QueueCurrentFrame(project_data *File, comp_buffer *CompBuffer, project_state *State) { IsRendering = true; render_queue RenderInfo = {File, State, CompBuffer}; @@ -181,7 +187,7 @@ QueueCurrentFrame(project_data *File, pixel_buffer *CompBuffer, project_state *S #if ARM -internal void +static void RenderLayerNeon(project_layer *Layer, pixel_buffer *Buffer, rectangle RenderRegion) { float32x4_t XAxisPX = vdupq_n_f32(XAxisP.x); @@ -362,8 +368,8 @@ RenderLayerNeon(project_layer *Layer, pixel_buffer *Buffer, rectangle RenderRegi } #else -internal void -AVX2_RenderLayer(transform_info T, pixel_buffer *Buffer, rectangle RenderRegion) +static void +AVX2_RenderLayer(transform_info T, comp_buffer *Buffer, rectangle RenderRegion) { rectangle LayerBounds = ClipRectangle( T.ClipRect, RenderRegion ); @@ -439,10 +445,14 @@ AVX2_RenderLayer(transform_info T, pixel_buffer *Buffer, rectangle RenderRegion) __m256 StartVectorX = _mm256_sub_ps(PixelX, OriginX); + // TODO(fox): Not unwraping this function may lose a few cycles! + uint16 WidthP, HeightP; + Bitmap_CalcPackedDimensions(Buffer->Width, Buffer->Height, &WidthP, &HeightP); + uint32 XLookup = (X >> 2)*16 + (X % 4); - uint32 YLookup = (Y >> 2)*(Buffer->FullWidth*4) + (Y % 4)*4; + uint32 YLookup = (Y >> 2)*(WidthP*4) + (Y % 4)*4; uint32 PixelToSeek = XLookup + YLookup; - uint8 *Pixel = (uint8 *)Buffer->OriginalBuffer + PixelToSeek*Buffer->BytesPerPixel; + uint8 *Pixel = (uint8 *)Buffer->PackedBuffer + PixelToSeek*Buffer->BytesPerPixel; __m256 U = _mm256_add_ps(_mm256_mul_ps(StartVectorX, XAxisPX), _mm256_mul_ps(StartVectorY, XAxisPY)); __m256 V = _mm256_add_ps(_mm256_mul_ps(StartVectorX, YAxisPX), _mm256_mul_ps(StartVectorY, YAxisPY)); @@ -690,8 +700,8 @@ AVX2_RenderLayer(transform_info T, pixel_buffer *Buffer, rectangle RenderRegion) } } -internal void -SSE2_RenderLayer(transform_info T, pixel_buffer *Buffer, rectangle RenderRegion) +static void +SSE2_RenderLayer(transform_info T, comp_buffer *Buffer, rectangle RenderRegion) { rectangle LayerBounds = ClipRectangle( T.ClipRect, RenderRegion ); @@ -752,10 +762,15 @@ SSE2_RenderLayer(transform_info T, pixel_buffer *Buffer, rectangle RenderRegion) __m128 StartVectorX = _mm_sub_ps(PixelX, OriginX); + + // TODO(fox): Not unwraping this function may lose a few cycles! + uint16 WidthP, HeightP; + Bitmap_CalcPackedDimensions(Buffer->Width, Buffer->Height, &WidthP, &HeightP); + uint32 XLookup = (X >> 2)*16 + (X % 4); - uint32 YLookup = (Y >> 2)*(Buffer->FullWidth*4) + (Y % 4)*4; + uint32 YLookup = (Y >> 2)*(WidthP*4) + (Y % 4)*4; uint32 PixelToSeek = XLookup + YLookup; - uint8 *Pixel = (uint8 *)Buffer->OriginalBuffer + PixelToSeek*Buffer->BytesPerPixel; + uint8 *Pixel = (uint8 *)Buffer->PackedBuffer + PixelToSeek*Buffer->BytesPerPixel; __m128 U = _mm_add_ps(_mm_mul_ps(StartVectorX, XAxisPX), _mm_mul_ps(StartVectorY, XAxisPY)); __m128 V = _mm_add_ps(_mm_mul_ps(StartVectorX, YAxisPX), _mm_mul_ps(StartVectorY, YAxisPY)); @@ -1040,15 +1055,18 @@ SSE2_RenderLayer(transform_info T, pixel_buffer *Buffer, rectangle RenderRegion) #endif -internal void -Fallback_RenderLayer(transform_info T, pixel_buffer *Buffer, rectangle RenderRegion) +static void +Fallback_RenderLayer(transform_info T, comp_buffer *Buffer, rectangle RenderRegion) { rectangle LayerBounds = ClipRectangle( T.ClipRect, RenderRegion); Assert(LayerBounds.Max.x <= Buffer->Width); Assert(LayerBounds.Max.y <= Buffer->Height); - uint8 *Row = ((uint8 *)Buffer->OriginalBuffer + Buffer->Pitch*(int16)(LayerBounds.Min.y) ); + uint16 WidthP, HeightP; + Bitmap_CalcPackedDimensions(Buffer->Width, Buffer->Height, &WidthP, &HeightP); + + uint8 *Row = ((uint8 *)Buffer->PackedBuffer + WidthP*Buffer->BytesPerPixel*(int16)(LayerBounds.Min.y) ); uint32 Channel = (T.LayerWidth * T.LayerHeight); real32 Normalized255 = 1 / 255.0f; @@ -1123,9 +1141,9 @@ Fallback_RenderLayer(transform_info T, pixel_buffer *Buffer, rectangle RenderReg uint32 PixelD = *(uint32 *)((uint8 *)T.SourceBuffer + PixelToSeek*Buffer->BytesPerPixel); #endif XLookup = (X >> 2)*16 + (X % 4); - YLookup = (Y >> 2)*(Buffer->FullWidth*4) + (Y % 4)*4; + YLookup = (Y >> 2)*(WidthP*4) + (Y % 4)*4; PixelToSeek = XLookup + YLookup; - uint32 *Pixel = (uint32 *)((uint8 *)Buffer->OriginalBuffer + PixelToSeek*Buffer->BytesPerPixel); + uint32 *Pixel = (uint32 *)((uint8 *)Buffer->PackedBuffer + PixelToSeek*Buffer->BytesPerPixel); real32 TexRA = (real32)(PixelA & 0xFF) * Normalized255; real32 TexRB = (real32)(PixelB & 0xFF) * Normalized255; diff --git a/strings.cpp b/strings.cpp index 814a52f..c1b9c9f 100644 --- a/strings.cpp +++ b/strings.cpp @@ -1,7 +1,10 @@ -global_variable bool32 Hacko = false; -global_variable int32 EffectSel = -1; +static bool32 Hacko = false; +static int32 EffectSel = -1; -internal int +// I'm using the filter's grep functionality to sort the effects for us +// (probably severely suboptimal), so I'm just using this callback function to +// signal back to our code that tab has been pressed in the text edit. +static int EffectConsoleCallback(ImGuiInputTextCallbackData* data) { if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) diff --git a/threading.cpp b/threading.cpp index 1b89136..c1cfe5c 100644 --- a/threading.cpp +++ b/threading.cpp @@ -1,4 +1,4 @@ -internal void +static void PushRect(rectangle RenderRegion) { uint32 Q = SDL_AtomicGet(&QueuedEntries); @@ -8,10 +8,10 @@ PushRect(rectangle RenderRegion) SDL_SemPost(Semaphore); } -internal void +static void RenderLayers(render_queue *RenderInfo, rectangle RenderRegion); -internal bool32 +static bool32 CheckQueue(render_queue RenderInfo, uint16 Index) { bool32 Result = 0; @@ -31,7 +31,7 @@ CheckQueue(render_queue RenderInfo, uint16 Index) return Result; } -internal int +static int TestThread(void *ptr) { thread_info *ThreadInfo = (thread_info *)ptr; @@ -1,4 +1,4 @@ -internal void +static void InteractProperty(int16 Index, project_data *File, project_state *State, bool32 Ended, real32 Value, memory *Memory, cache_pool *Cache) { for (int r = 0; r < State->NumberOfSelectedLayers; r++) { |