enum instruction_mode { instruction_mode_scalar, instruction_mode_sse, instruction_mode_avx }; struct cache { void *Address; bool32 Cached; }; enum whattocallthis { Inactive, Active, Clear }; struct cache_pool { cache Frame[2048]; cache Intermediate[3]; whattocallthis Interact; int16 InteractIndex; }; enum memory_table_list { // F = file attributes // P = persistent data, but not file-based // B = cached data, often cleared P_AVInfo, P_VectorPoints, P_UndoBuffer, P_MiscCache, // The structs that these four blocks correspond to (project_layer, effect, // keyframe_block, char[STRING_SIZE]) are guranteed equal size. F_Layers, F_Effects, F_Keyframes, F_Strings, B_LayerBitmaps, B_LoadedBitmaps, }; struct memory_table { char *Name; void *Address; uint64 CurrentPosition; uint64 Size; uint32 NumberOfPointers; uint32 PointerIndex; }; struct global_memory { void *Address; uint64 CurrentPosition; uint64 Size; }; struct source; struct cached_bitmap { source *SourceOwner; // Which source it belongs to. Currently used to dereference the bitmap. void *Data; // Unpacked data loaded from the source file. uint32 Frame; // What frame it is. }; struct memory { memory_table Slot[16]; cached_bitmap Bitmap[4096]; void *Scratch; // 64 MB of data }; struct property_channel; struct project_layer; enum display_type { standard, levels }; enum keyframe_type { linear, bezier, hold }; // NOTE(fox): One val slot holds 16 bytes of data. enum var_type { type_real, type_color, type_blendmode }; static char* BlendmodeNames[] = { "Normal", "Multiply", "Color Burn", "Linear Burn", "Add", "Screen", "Overlay", "Soft Light", "Hard Light", "Subtract", "Divide", "Difference" }; enum blend_mode { blend_normal, blend_multiply, blend_colorburn, blend_linearburn, blend_add, blend_screen, blend_overlay, blend_softlight, blend_hardlight, blend_subtract, blend_divide, blend_difference }; struct gl_effect { uint32 ShaderProgram; }; struct gl_vertex_shader { uint32 VertexArrayObject; uint32 VertexBufferObject; }; struct default_gl_vertex_object { uint32 VertexArrayObject; uint32 VertexBufferObject; uint32 ElementBufferObject; }; static default_gl_vertex_object DefaultVerts; static uint32 DefaultVertexShader; static uint32 DefaultShaderProgram; static uint32 MaskShaderProgram; float DefaultVertices[] = { 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, }; struct gl_effect_layer { GLuint Texture; GLuint FramebufferObject; uint32 Color_Renderbuffer; }; static gl_vertex_shader GL_Vertices; enum action_change_type { action_change_u16, action_change_i16, action_change_u32, action_change_i32, action_change_r32, action_change_u64, action_change_ptr, action_change_string, }; union val { real32 f; v4 col; blend_mode blendmode; }; struct keyframe { val Value; int32 FrameNumber; keyframe_type Type; bool32 IsSelected; // The X coordinate for the tangent is in keyframes, and the Y is in units. // Probably should think of something smarter. v2 TangentLeft; v2 TangentRight; // NOTE(fox): We need some sort of unique constant to give to ImGui in // order for dragging to work. uint32 ImguiID; }; struct keyframe_block { keyframe Keyframe[MAX_KEYFRAMES_PER_BLOCK]; }; struct property_channel { char *Name; keyframe_block *KeyframeBlock[MAX_KEYFRAME_BLOCKS]; uint16 NumberOfKeyframeBlocks; uint16 NumberOfSelectedKeyframes; uint16 NumberOfTotalKeyframes; val CurrentValue; val MaxVal; val MinVal; val ScrubVal; // increment when dragging on sliders, etc. var_type VarType; // TODO(fox): Probably shouldn't store these in the file... // UI val LocalMaxVal; val LocalMinVal; bool32 IsToggled; bool32 IsGraphToggled; real32 GraphLength; // represented in actual screen pixels real32 GraphYOffset; // The size of the window enclosing the graph uint16 GraphWindowHeight; }; struct property_header { char *Name; val Value; var_type VarType; val MinVal; val MaxVal; }; // Information about a particular file. enum source_type { source_type_none, source_type_video, source_type_image }; // 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; real32 AvgPTSPerFrame; // set by Libav }; struct source { char *Path; source_type SourceType; source_info Info; }; // Bitmaps from files are loaded into these temporary cache blocks. 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; gl_effect_layer Test; // TODO(fox): Find a better place to store this. Either give effects a more // fleshed-out API to add things to a struct like this or integrate into ImGui. void *HistogramVals; // 256*5 packed floats (all channel average + RGBA). uint16 LevelsSelector; // Which channel is currently active // 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 *AVInfo; // Internal data containing current frame info }; // NOTE(fox): I use the term "comp" (composition) to mean the canvas that is // being rendered to, since it's what I'm used to from AE. struct comp_buffer { uint16 Width; uint16 Height; uint16 BytesPerPixel; void *PackedBuffer; void *UnpackedBuffer; }; struct effect_header { char *Name; void (*func)(source *, layer_bitmap_info *, memory *, property_channel []); uint16 NumberOfProperties; display_type DisplayType; property_header PropertyHeader[MAX_PROPERTIES_PER_EFFECT]; }; struct effect { char *Name; void (*func)(source *, layer_bitmap_info *, memory *, property_channel []); uint16 NumberOfProperties; display_type DisplayType; gl_effect GL_Effect; property_channel Property[MAX_PROPERTIES_PER_EFFECT]; bool32 UIIsCollapsed = 0; bool32 IsActive = 1; }; struct transform_info { real32 XAxisPX; real32 XAxisPY; real32 YAxisPX; real32 YAxisPY; real32 LayerWidth; real32 LayerHeight; uint32 FullLayerWidth; uint32 FullLayerHeight; real32 LayerOpacity; blend_mode BlendMode; real32 OriginX; real32 OriginY; uint32 BufferPitch; uint32 LayerPitch; rectangle ClipRect; void *SourceBuffer; }; struct mask_point { v2 Pos; bool32 HandleBezier; bool32 IsSelected; v2 TangentLeft; v2 TangentRight; }; struct mask { mask_point Point[16]; uint16 NumberOfPoints; uint16 NumberOfSelectedPoints; void *TriangulatedPointCache; uint32 NumberOfVerts; }; struct project_layer { char *Name; blend_mode BlendMode; union { property_channel Property[8]; struct { property_channel x; property_channel y; property_channel ax; property_channel ay; property_channel rotation; property_channel scale; property_channel opacity; property_channel time; }; }; bool32 IsSelected; source *Source; layer_bitmap_info BitmapInfo; effect *Effect[MAX_EFFECTS]; uint16 NumberOfEffects; mask Mask[MAX_MASKS]; uint16 NumberOfMasks; int32 StartFrame; int32 EndFrame; uint32 LayerColor; // For rendering 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 // layers and keyframes to look for the IsSelected bool. If this causes // lag I'll switch it to the former. struct temp_layer_list { int16 LayerIndex[MAX_LAYERS]; }; struct temp_keyframe_list { keyframe *SelectedKeyframe[50]; uint16 Amount; }; struct project_data { uint16 Width; uint16 Height; uint16 FPS; uint32 NumberOfFrames; int32 StartFrame; int32 EndFrame; int32 CurrentFrame; // NOTE(fox): Currently I'm handling layer sorting by just saying that // their order in memory is the order of the index and manually moving // their positions. project_layer *Layer[MAX_LAYERS]; uint16 NumberOfSelectedLayers; uint16 NumberOfLayers; source Source[MAX_SOURCES]; uint32 SourceSelected; uint16 NumberOfSources; }; enum transforms_hotkey_interact { sliding_position, sliding_anchorpoint, sliding_scale, sliding_rotation }; struct main_sdl { SDL_Texture *Texture; SDL_Event Event; SDL_Window *Window; SDL_Renderer *Renderer; }; // used to determine what to copy/paste, delete, etc enum selection_type { selection_none, selection_layer, selection_effect, selection_keyframe, selection_maskpoint, selection_source }; enum tool { tool_default, tool_pen, tool_count }; struct pen_state { bool32 IsActive; }; struct project_state { bool32 UpdateKeyframes = 1; bool32 UpdateFrame = 1; // only refreshes frame; set UpdateKeyframes to update animation bool32 DebugDisableCache = 1; tool Tool = tool_default; pen_state Pen = {}; uint16 LayersToRender[MAX_LAYERS]; uint16 NumberOfLayersToRender; bool32 IsRunning = 1; bool32 IsPlaying; bool32 DemoButton = 1; bool32 GridButton = 1; uint16 NumberOfSelectedLayers; int16 MostRecentlySelectedLayer = -1; // convenience for the properties panel selection_type RecentSelectionType = selection_none; bool32 IsInteracting; transforms_hotkey_interact TransformsHotkeyInteract; int32 MsgTime; // currently in "frames" char *Msg; ImGuiTextFilter filter; // This filter API is pretty ballin'. bool32 RerouteEffects; // Allows shift+space hotkey to gain focus on the effects panel. }; struct brush_tool { real32 Size; real32 Opacity; real32 Hardness; }; enum focused_window { focus_viewport, focus_properties, focus_timeline }; struct ui { real32 TimelineSplit = 600; real32 TimelineZoom; // Note that I don't use "zoom" to mean the scale in relation to the // original (i.e. default = 1.0f); it's the literal screen size in pixels // of the composition in the UI. ImVec2 CompZoom; ImVec2 CompPos; // Used to set UI values on the first frame. Some UI setup in Docking takes // more than 1 frame for some reason, so I'm temporarily extending it. bool32 Initializing = 4; // Custom scrolling for the timeline, as ImGui's didn't work well real32 ScrollXOffset; real32 ScrollYOffset; // NOTE(fox): Keeping track of mouse delta myself since the ImGui threshold // dragging API doesn't let you do things like subtract the delta easily. real32 DraggingKeyframeThreshold; real32 DraggingLayerThreshold; real32 DraggingTimelineThreshold; real32 KeyframeSpacing = 6; ImVec2 BoxStart = ImVec2(0,0); ImVec2 BoxEnd = ImVec2(0,0); bool32 BoxSelectActive = false; // Temporary varibles used when zooming in/out v2 TempZoomRatio = V2(1, 1); real32 TempZoomRatioTimeline = 0; real32 TempZoomRatioGraph = 0; focused_window FocusedWindow; // Convenience for adding window-specific hotkeys. bool32 TemporaryUpdateOverride; }; struct imgui_buttonstate { bool32 IsItemHovered; bool32 IsItemActive; bool32 IsItemActivated; bool32 IsItemDeactivated; bool32 LeftClick; bool32 RightClick; }; struct timeline_properties { rectangle Timeline; v2i MainWindow; uint16 WindowPadding; rectangle EffectPanel; rectangle Toolbar; rectangle ColorPanel; bool32 RenderSlidingBrush; uint16 CompX; uint16 CompY; uint16 TimelineZoom; uint16 CompScale; uint16 FramePadding; uint16 LayerPadding; uint16 TimelineCurrentFrame; int16 TimelineCurrentLayer; uint16 InfoTimelineSplit; bool32 DrawTimeline; bool32 DrawEffectPanel; bool32 DrawComp; }; struct sdl_button { bool32 IsDown; bool32 SingleClick; // More precisely, when button is released and no dragging/selecting events are happening. int HeldLength; }; struct sdl_input { v2i Mouse; sdl_button MouseButton[3]; rectangle Selection; }; struct render_queue { project_data *File; project_state *State; comp_buffer *CompBuffer; }; struct thread_info { render_queue *RenderInfo; uint16 Index; }; struct work_queue_entry { char *StringToPrint; }; struct render_entry { rectangle RenderRegion; };