internal 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; } } internal void CalculateFull(pixel_buffer *Buffer) { uint16 ExtraWidth = 4 - (Buffer->Width % 4); if (ExtraWidth == 4) ExtraWidth = 0; uint16 ExtraHeight = 4 - (Buffer->Height % 4); if (ExtraHeight == 4) ExtraHeight = 0; Buffer->FullWidth = Buffer->Width + ExtraWidth; Buffer->FullHeight = Buffer->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; } internal void AddSource(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; } } internal 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; } 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 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; } 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) { 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; int32 Width = Source->AV.VideoCodecContext->width; int32 Height = Source->AV.VideoCodecContext->height; Source->Raster = CreateBuffer(Width, Height, Memory); Layer->x.CurrentValue.f = 1280/2; Layer->y.CurrentValue.f = 720/2; Layer->StartFrame = 0; Layer->EndFrame = File.EndFrame; } else { Assert(0); } } internal 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); } internal project_layer * CreateLayer(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]; } 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; } internal project_layer * CreateDebugLayer(project_data *File, memory *Memory, uint16 Width, uint16 Height) { 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 LoadTestFootage(project_data *File, project_state *State, memory *Memory) { CreateLayerFromSource(File, State, Memory, "../asset/24.mp4"); // 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; } internal void CreateDemoScene(project_data *File, memory *Memory) { 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; } internal 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, 200, 200, 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); } } }