static void IncrementFrame(project_data *File, int16 Amount) { if ((File->CurrentFrame <= 0 && Amount < File->StartFrame) || (File->CurrentFrame >= File->EndFrame)) { File->CurrentFrame = 0; } else { File->CurrentFrame += Amount; } } static void Bitmap_CalcPackedDimensions(uint16 Width, uint16 Height, uint16 *WidthP, uint16 *HeightP) { uint16 ExtraWidth = 4 - (Width % 4); if (ExtraWidth == 4) ExtraWidth = 0; uint16 ExtraHeight = 4 - (Height % 4); if (ExtraHeight == 4) ExtraHeight = 0; *WidthP = Width + ExtraWidth; *HeightP = Height + ExtraHeight; } static uint16 Bitmap_CalcByteOffset(uint16 BytesPerPixel) { uint16 ByteOffset = BytesPerPixel; if (InstructionMode == instruction_mode_avx) ByteOffset = 8*BytesPerPixel; if (InstructionMode == instruction_mode_sse) ByteOffset = 4*BytesPerPixel; return ByteOffset; } 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) { 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; Found = true; } if (Found) { Source->Info.BytesPerPixel = 4; Source->Path = Path; File->NumberOfSources++; return 1; } return 0; } /* static pixel_buffer LoadImage(memory *Memory, char *filename) { pixel_buffer Buffer = {}; Buffer.BytesPerPixel = 4; int n = 0; int h, w; void *temp = stbi_load(filename, &w, &h, &n, 4); // printf("%s", stbi_failure_reason()); Buffer.Height = h; Buffer.Width = w; CalculateFull(&Buffer); Buffer.Pitch = Buffer.FullWidth*Buffer.BytesPerPixel; // TODO(fox): Implement custom malloc in stbi so we don't have to do this. Buffer.OriginalBuffer = MoveImportToBitmap(Memory, &Buffer, temp); stbi_image_free(temp); Buffer.EffectBuffer = AllocateMemory(Memory, Buffer.FullWidth * Buffer.FullHeight * Buffer.BytesPerPixel, B_Scratch); BitmapPackRGB(&Buffer); Buffer.ToUpdate = true; return Buffer; } */ 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; Property.CurrentValue.f = Val; Property.MinVal.f = MinVal; Property.MaxVal.f = MaxVal; Property.ScrubVal.f = ScrubVal; Property.VarType = type_real; Property.GraphWindowHeight = 300; return Property; } static void CreateKeyframeBlock(property_channel *Property, memory *Memory) { int16 a = Property->NumberOfKeyframeBlocks++; Assert(a < MAX_KEYFRAME_BLOCKS); Property->KeyframeBlock[a] = (keyframe_block *)AllocateMemory(Memory, sizeof(keyframe_block), F_Keyframes); } 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; } static 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(source_image), P_SourceData); source_image *Source = (source_image *)Layer->RenderInfo; Source->Raster = CreateDebugBitmap(Memory, Width, Height); Layer->SourceType = source_type_image; return Layer; } */ 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; } project_layer * Layer_Init(project_data *File, memory *Memory) { int16 a = File->NumberOfLayers++; Assert(a < MAX_LAYERS); File->Layer[a] = (project_layer *)AllocateMemory(Memory, sizeof(project_layer), F_Layers); File->Layer[a]->Name = (char *)AllocateMemory(Memory, 256, F_Strings); sprintf(File->Layer[a]->Name, "Layer %i", a); File->Layer[a]->x = InitFloatProperty("X Position", 0.0f, 1.0f); File->Layer[a]->y = InitFloatProperty("Y Position", 0.0f, 1.0f); File->Layer[a]->ax = InitFloatProperty("Anchor X", 0.5f, 0.005f); File->Layer[a]->ay = InitFloatProperty("Anchor Y", 0.5f, 0.005f); File->Layer[a]->scale = InitFloatProperty("Scale", 1.0f, 0.005f); File->Layer[a]->rotation = InitFloatProperty("Rotation", 0.0f, 1.0f); File->Layer[a]->opacity = InitFloatProperty("Opacity", 1.0f, 0.005f, 0.0f, 1.0f); File->Layer[a]->time = InitFloatProperty("Frame Number", 0.0f, 1.0f, 0, 100000); File->Layer[a]->EndFrame = File->NumberOfFrames; return File->Layer[a]; } static cached_bitmap * Cache_CheckBitmap(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, int32 TimelineFrame) { memory_table *Table = &Memory->Slot[B_LoadedBitmaps]; int32 FrameToSeek = TimelineFrame - BitmapInfo->FrameOffset; if (FrameToSeek < 0) { FrameToSeek = 0; }; for (int i = 0; i < Table->NumberOfPointers; i++) { cached_bitmap *Bitmap = &Memory->Bitmap[i]; if (Bitmap->Frame == FrameToSeek && Bitmap->SourceOwner == Source) { return Bitmap; } } return 0; } static void Layer_UpdateBitmap(project_layer *Layer, memory *Memory, int32 CurrentFrame) { source *Source = Layer->Source; layer_bitmap_info *BitmapInfo = &Layer->BitmapInfo; cached_bitmap *Bitmap = Cache_CheckBitmap(Source, BitmapInfo, Memory, CurrentFrame); if (Bitmap) { uint16 Width = Source->Info.Width; uint16 Height = Source->Info.Height; uint16 BytesPerPixel = Source->Info.BytesPerPixel; void *DestBuffer = BitmapInfo->BitmapBuffer; Bitmap_ConvertPacking(Bitmap->Data, DestBuffer, Width, Height, BytesPerPixel, 0); } else { AV_LoadVideoFrame(Source, BitmapInfo, Memory, CurrentFrame); } for (int i = 0; i < Layer->NumberOfEffects; i++) { if (Layer->Effect[i]->IsActive) Layer->Effect[i]->func(Source, BitmapInfo, Memory, Layer->Effect[i]->Property); } } static void Layer_InitSource(project_layer *Layer, source *Source, memory *Memory) { Layer->Source = Source; uint16 Height = Source->Info.Height; uint16 Width = Source->Info.Width; uint16 BytesPerPixel = Source->Info.BytesPerPixel; Layer->BitmapInfo.BitmapBuffer = Layer_AllocateBitmap(Memory, Width, Height, BytesPerPixel); } static void Layer_PositionCenter(project_layer *Layer, uint16 Width, uint16 Height) { Layer->x.CurrentValue.f = Width/2; Layer->y.CurrentValue.f = Height/2; } static void Layer_CreateFromSource(project_data *File, project_state *State, memory *Memory, source *Source) { project_layer *Layer = Layer_Init(File, Memory); AV_Init(Source, &Layer->BitmapInfo, Memory); Layer_InitSource(Layer, Source, Memory); Layer_PositionCenter(Layer, File->Width, File->Height); State->UpdateFrame = true; } static void LoadTestFootage(project_data *File, project_state *State, memory *Memory) { if (!Source_Generate(File, Memory, "../asset/24.mp4")) PostMsg(State, "File open fail..."); source *Source = &File->Source[0]; Layer_CreateFromSource(File, State, Memory, Source); SelectLayer(File->Layer[0], State, 0); AddEffect(File->Layer[0], Memory, 2); property_channel *Property = &File->Layer[0]->x; ManualKeyframeInsertF(Property, Memory, 1, 500); ManualKeyframeInsertF(Property, Memory, 30, 800); ManualKeyframeInsertF(Property, Memory, 15, 400); ManualKeyframeInsertF(Property, Memory, 20, 100); Property->IsToggled = true; Property->IsGraphToggled = true; Property->GraphLength = 150; Property->GraphYOffset = (Property->GraphWindowHeight - Property->GraphLength)/2; // Layer_CreateFromSource(File, State, Memory, Source); if (!Source_Generate(File, Memory, "../asset/p.mp4")) PostMsg(State, "File open fail..."); source *Source2 = &File->Source[1]; project_layer *Layer2 = Layer_Init(File, Memory); AV_Init(Source2, &Layer2->BitmapInfo, Memory); Layer_InitSource(Layer2, Source2, Memory); Layer2->StartFrame = 11; Layer2->EndFrame = 23; // 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; // Layer1->y.CurrentValue.f = 4; // Layer1->StartFrame = 0; // Layer1->EndFrame = File.EndFrame; } 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; Layer1->StartFrame = 0; Layer1->EndFrame = File->EndFrame; project_layer *Layer2 = CreateSolidLayer(File, Memory, 499, 503, V4(0.0, 1.0, 0.4, 1.0)); Layer2->x.CurrentValue.f = 1280/2; Layer2->y.CurrentValue.f = 720/2; Layer2->StartFrame = 0; Layer2->EndFrame = File->EndFrame; ManualKeyframeInsertF(&Layer2->rotation, Memory, 2, 0); ManualKeyframeInsertF(&Layer2->rotation, Memory, 50, 360); Layer2->rotation.IsToggled = true; Layer2->scale.IsToggled = true; project_layer *Layer3 = CreateSolidLayer(File, Memory, 157, 163, V4(1.0, 0.3, 0.2, 1.0)); Layer3->x.CurrentValue.f = 1280/4; Layer3->y.CurrentValue.f = 720/4; Layer3->opacity.CurrentValue.f = 0.5f; Layer3->StartFrame = 0; Layer3->EndFrame = File->EndFrame; ManualKeyframeInsertF(&Layer3->x, Memory, 2, Layer3->x.CurrentValue.f); ManualKeyframeInsertF(&Layer3->x, Memory, 30, Layer3->x.CurrentValue.f+(1280/2)); ManualKeyframeInsertF(&Layer3->x, Memory, 60, Layer3->x.CurrentValue.f+(1280/3)); Layer3->x.IsToggled = true; Layer3->y.IsToggled = true; #endif } #if 0 static void CreateGrid(project_data *File, memory *Memory) { uint16 Amount = 8; real32 XInc = File->Width / Amount; real32 YInc = File->Height / Amount; for (int16 j = 0; j < 8; j++) { for (int16 i = 0; i < 8; i++) { project_layer *Layer = CreateSolidLayer(File, Memory, 400, 400, V4(0.6, 0.3, 0.4, 1.0)); Layer->x.CurrentValue.f = (XInc*i); Layer->y.CurrentValue.f = (XInc*j); Layer->opacity.CurrentValue.f = 0.25; Layer->StartFrame = 0; Layer->EndFrame = File->EndFrame; ManualKeyframeInsertF(&Layer->rotation, Memory, i, 0); ManualKeyframeInsertF(&Layer->rotation, Memory, 40+i, 360); } } } #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