diff --git a/gs_libs/gs_vector_matrix.h b/gs_libs/gs_vector_matrix.h index a426543..e5d93b4 100644 --- a/gs_libs/gs_vector_matrix.h +++ b/gs_libs/gs_vector_matrix.h @@ -669,6 +669,15 @@ PointToPercentRange (v2 P, v2 Min, v2 Max) // which makes refactoring easier as you only have to change the identifier in one place #define RectExpand(r) (r).Min, (r).Max +static rect +MakeRectMinWidth(v2 Min, v2 Width) +{ + rect Rect = {0}; + Rect.Min = Min; + Rect.Max = Min + Width; + return Rect; +} + inline float Width (rect Rect) { @@ -744,6 +753,104 @@ RectOffsetByVector(rect R, v2 V) return Result; } +static void +HSplitRectAtValue(rect Bounds, r32 YValue, rect* Top, rect* Bottom) +{ + if (YValue <= Bounds.Min.y) + { + *Top = Bounds; + *Bottom = {0}; + } + else if (YValue >= Bounds.Max.y) + { + *Top = {0}; + *Bottom = Bounds; + } + else + { + Top->Max = Bounds.Max; + Top->Min = { Bounds.Min.x, YValue }; + Bottom->Max = { Bounds.Max.x, YValue }; + Bottom->Min = Bounds.Min; + } +} + +static void +HSplitRectAtDistanceFromTop(rect Bounds, r32 YDist, rect* Top, rect* Bottom) +{ + r32 YValue = Bounds.Max.y - YDist; + HSplitRectAtValue(Bounds, YValue, Top, Bottom); +} + +static void +HSplitRectAtDistanceFromBottom(rect Bounds, r32 YDist, rect* Top, rect* Bottom) +{ + r32 YValue = Bounds.Min.y + YDist; + HSplitRectAtValue(Bounds, YValue, Top, Bottom); +} + +static void +HSplitRectAtPercent(rect Bounds, r32 YPercent, rect* Top, rect* Bottom) +{ + r32 YValue = GSLerp(Bounds.Min.y, Bounds.Max.y, YPercent); + HSplitRectAtValue(Bounds, YValue, Top, Bottom); +} + + +static void +VSplitRectAtValue(rect Bounds, r32 XValue, rect* Left, rect* Right) +{ + if (XValue <= Bounds.Min.x) + { + *Left = {0}; + *Right = Bounds; + } + else if (XValue >= Bounds.Max.x) + { + *Left = Bounds; + *Right = {0}; + } + else + { + Left->Max = { XValue, Bounds.Max.y}; + Left->Min = Bounds.Min; + Right->Max = Bounds.Max; + Right->Min = { XValue, Bounds.Min.y }; + } +} + +static void +VSplitRectAtDistanceFromRight(rect Bounds, r32 XDist, rect* Left, rect* Right) +{ + r32 XValue = Bounds.Max.x - XDist; + VSplitRectAtValue(Bounds, XValue, Left, Right); +} + +static void +VSplitRectAtDistanceFromLeft(rect Bounds, r32 XDist, rect* Left, rect* Right) +{ + r32 XValue = Bounds.Min.x + XDist; + VSplitRectAtValue(Bounds, XValue, Left, Right); +} + +static void +VSplitRectAtPercent(rect Bounds, r32 XPercent, rect* Left, rect* Right) +{ + r32 XValue = GSLerp(Bounds.Min.x, Bounds.Max.x, XPercent); + VSplitRectAtValue(Bounds, XValue, Left, Right); +} + +#define TranslateRectX(r, d) TranslateRect((r), v2{(d), 0}) +#define TranslateRectY(r, d) TranslateRect((r), v2{0, (d)}) +static rect +TranslateRect(rect R, v2 Delta) +{ + rect Result = R; + Result.Min += Delta; + Result.Max += Delta; + return Result; +} + ////////////////////////////////////// // MATRIX ////////////////////////////////////// diff --git a/src/foldhaus_app.cpp b/src/foldhaus_app.cpp index 26198c5..96c87cf 100644 --- a/src/foldhaus_app.cpp +++ b/src/foldhaus_app.cpp @@ -156,7 +156,14 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Interface.ButtonColor_Active = v4{.1f, .1f, .1f, 1}; State->Interface.ButtonColor_Selected = v4{.1f, .1f, .3f, 1}; State->Interface.TextColor = WhiteV4; + State->Interface.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; + State->Interface.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; + State->Interface.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; + State->Interface.ListBGSelected = v4{.44f, .44f, .44f, 1.f }; State->Interface.Margin = v2{5, 5}; + State->Interface.RowHeight = State->Interface.Font->PixelHeight + 2 * State->Interface.Margin.y; + + State->Interface_.Style = State->Interface; State->SACN = InitializeSACN(Context); State->NetworkProtocolHeaderSize = STREAM_HEADER_SIZE; @@ -315,7 +322,6 @@ UPDATE_AND_RENDER(UpdateAndRender) { DEBUG_TRACK_FUNCTION; app_state* State = (app_state*)Context->MemoryBase; - State->WindowBounds = Context->WindowBounds; // NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient, // and need to persist beyond the end of the UpdateAndRender call. In the release version, we won't @@ -495,6 +501,10 @@ UPDATE_AND_RENDER(UpdateAndRender) PushRenderOrthographic(RenderBuffer, 0, 0, Width(State->WindowBounds), Height(State->WindowBounds)); PushRenderClearScreen(RenderBuffer); + State->WindowBounds = Context->WindowBounds; + State->Interface_.RenderBuffer = RenderBuffer; + State->Interface_.Mouse = Context->Mouse; + panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, &State->Transient); DrawAllPanels(PanelsToRender, RenderBuffer, &Context->Mouse, State, *Context); diff --git a/src/foldhaus_app.h b/src/foldhaus_app.h index 4abf7b4..47f995f 100644 --- a/src/foldhaus_app.h +++ b/src/foldhaus_app.h @@ -78,6 +78,7 @@ struct app_state input_command_queue CommandQueue; text_entry ActiveTextEntry; + ui_interface Interface_; interface_config Interface; animation_system AnimationSystem; @@ -230,6 +231,7 @@ typedef PANEL_INIT_PROC(panel_init_proc); #define PANEL_CLEANUP_PROC(name) void name(panel* Panel, app_state* State) typedef PANEL_CLEANUP_PROC(panel_cleanup_proc); +// TODO(Peter): Should be able to take the mouse out of this #define PANEL_RENDER_PROC(name) void name(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) typedef PANEL_RENDER_PROC(panel_render_proc); diff --git a/src/foldhaus_interface.cpp b/src/foldhaus_interface.cpp index c981358..fbee3ca 100644 --- a/src/foldhaus_interface.cpp +++ b/src/foldhaus_interface.cpp @@ -403,16 +403,14 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBo PushRenderQuad2D(RenderBuffer, FooterBounds.Min, v2{FooterBounds.Max.x, FooterBounds.Min.y + 25}, v4{.5f, .5f, .5f, 1.f}); PushRenderQuad2D(RenderBuffer, FooterBounds.Min, FooterBounds.Min + v2{25, 25}, WhiteV4); - v2 PanelSelectButtonMin = FooterBounds.Min + v2{30, 1}; - v2 PanelSelectButtonMax = PanelSelectButtonMin + v2{100, 23}; + rect PanelSelectBtnBounds = MakeRectMinWidth(FooterBounds.Min + v2{30, 1}, v2{100, 23}); if (Panel->PanelSelectionMenuOpen) { - v2 ButtonDimension = v2{100, 25}; - v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterBounds.Max.y}; + rect ButtonBounds = MakeRectMinWidth(v2{ PanelSelectBtnBounds.Min.x, FooterBounds.Max.y }, v2{ 100, 25 }); - v2 MenuMin = ButtonMin; - v2 MenuMax = v2{ButtonMin.x + ButtonDimension.x, ButtonMin.y + (ButtonDimension.y * GlobalPanelDefsCount)}; + v2 MenuMin = ButtonBounds.Min; + v2 MenuMax = v2{ButtonBounds.Min.x + Width(ButtonBounds), ButtonBounds.Min.y + (Height(ButtonBounds) * GlobalPanelDefsCount)}; if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && !PointIsInRange(Mouse.DownPos, MenuMin, MenuMax)) { @@ -424,24 +422,17 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBo { panel_definition Def = GlobalPanelDefs[i]; string DefName = MakeString(Def.PanelName, Def.PanelNameLength); - button_result DefinitionButton = EvaluateButton(RenderBuffer, - ButtonMin, ButtonMin + ButtonDimension, - DefName, State->Interface, Mouse); - if (DefinitionButton.Pressed) + if (ui_Button(&State->Interface_, DefName, ButtonBounds)) { SetPanelDefinition(Panel, i, State); Panel->PanelSelectionMenuOpen = false; } - ButtonMin.y += ButtonDimension.y; + ButtonBounds = TranslateRectY(ButtonBounds, Height(ButtonBounds)); } } - button_result ButtonResult = EvaluateButton(RenderBuffer, - PanelSelectButtonMin, - PanelSelectButtonMax, - MakeStringLiteral("Select"), State->Interface, Mouse); - if (ButtonResult.Pressed) + if (ui_Button(&State->Interface_, MakeStringLiteral("Select"), PanelSelectBtnBounds)) { Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen; } diff --git a/src/interface.h b/src/interface.h index 2288183..25ca59e 100644 --- a/src/interface.h +++ b/src/interface.h @@ -60,7 +60,7 @@ DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char } internal v2 -DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, char* String, s32 Length, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) +DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* String, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) { v2 RegisterPosition = InitialRegisterPosition; char* C = String; @@ -74,7 +74,7 @@ DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, char* St } internal v2 -DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, char* String, s32 Length, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) +DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* String, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) { v2 RegisterPosition = InitialRegisterPosition; char* C = String + Length - 1; @@ -104,15 +104,11 @@ DrawString (render_command_buffer* RenderBuffer, string String, bitmap_font* Fon v2 RegisterPosition = Position; if (Alignment == Align_Left) { - RegisterPosition = DrawStringLeftAligned(&BatchConstructor, - String.Memory, String.Length, - RegisterPosition, Font, Color); + RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, Color); } else if (Alignment == Align_Right) { - RegisterPosition = DrawStringRightAligned(&BatchConstructor, - String.Memory, String.Length, - RegisterPosition, Font, Color); + RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, Color); } else { @@ -151,29 +147,27 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, string String, s32 Cu v2 RegisterPosition = Position; if (Alignment == Align_Left) { - RegisterPosition = DrawStringLeftAligned(&BatchConstructor, - String.Memory, CursorPosition, - RegisterPosition, Font, Color); + RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, Color); DrawCursor(&CursorBatch, RegisterPosition, GreenV4, *Font); if (String.Length - CursorPosition > 0) { RegisterPosition = DrawStringLeftAligned(&BatchConstructor, - String.Memory + CursorPosition, String.Length - CursorPosition, + String.Memory + CursorPosition, RegisterPosition, Font, Color); } } else if (Alignment == Align_Right) { RegisterPosition = DrawStringRightAligned(&BatchConstructor, - String.Memory, CursorPosition, + CursorPosition, String.Memory, RegisterPosition, Font, Color); DrawCursor(&CursorBatch, RegisterPosition, GreenV4, *Font); if (String.Length - CursorPosition > 0) { RegisterPosition = DrawStringRightAligned(&BatchConstructor, - String.Memory + CursorPosition, String.Length - CursorPosition, + String.Memory + CursorPosition, RegisterPosition, Font, Color); } } @@ -189,154 +183,229 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, string String, s32 Cu struct interface_config { v4 PanelBGColors[4]; + v4 ButtonColor_Inactive, ButtonColor_Active, ButtonColor_Selected; + v4 TextColor; + +#define LIST_BG_COLORS_COUNT 2 + v4 ListBGColors[LIST_BG_COLORS_COUNT]; + v4 ListBGHover; + v4 ListBGSelected; + bitmap_font* Font; r32 FontSize; v2 Margin; + r32 RowHeight; }; -struct button_result +struct ui_layout { - b32 Pressed; - r32 Advance; + rect Bounds; + v2 Margin; + r32 RowHeight; + r32 RowYAt; + + b32 DrawHorizontal; + u32 RowDivisions; + u32 RowElementsCount; }; -internal button_result -EvaluateButton (render_command_buffer* RenderBuffer, - v2 Min, v2 Max, v2 Margin, string Label, - v4 IdleBGColor, v4 HotBGColor, v4 IdleTextColor, v4 HotTextColor, - bitmap_font* Font, mouse_state Mouse) +struct ui_interface { - button_result Result = {}; - Result.Pressed = false; - - v4 BGColor = IdleBGColor; - v4 TextColor = IdleTextColor; - - if (PointIsInRange(Mouse.Pos, Min, Max)) + interface_config Style; + mouse_state Mouse; + render_command_buffer* RenderBuffer; +}; + +static ui_layout +ui_CreateLayout(ui_interface Interface, rect Bounds) +{ + ui_layout Result = {0}; + Result.Bounds = Bounds; + Result.Margin = Interface.Style.Margin; + Result.RowHeight = Interface.Style.RowHeight; + Result.RowYAt = Bounds.Max.y - Result.RowHeight; + return Result; +} + +static void +ui_StartRow(ui_layout* Layout, u32 RowDivisions) +{ + Layout->DrawHorizontal = true; + Layout->RowDivisions = RowDivisions; + Layout->RowElementsCount = 0; +} + +static void +ui_StartRow(ui_layout* Layout) +{ + ui_StartRow(Layout, 0); +} + +static void +ui_EndRow(ui_layout* Layout) +{ + Layout->DrawHorizontal = false; +} + +static b32 +ui_TryReserveElementBounds(ui_layout* Layout, rect* Bounds) +{ + b32 Result = true; + if (!Layout->DrawHorizontal) { - if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) + Bounds->Min = { Layout->Bounds.Min.x, Layout->RowYAt }; + Bounds->Max = { Layout->Bounds.Max.x, Bounds->Min.y + Layout->RowHeight }; + Layout->RowYAt -= Layout->RowHeight; + } + else + { + if (Layout->RowDivisions > 0) { - Result.Pressed = true; + Assert(Layout->RowElementsCount < Layout->RowDivisions); + r32 ElementWidth = Width(Layout->Bounds) / Layout->RowDivisions; + Bounds->Min = { + Layout->Bounds.Min.x + (ElementWidth * Layout->RowElementsCount) + Layout->Margin.x, + Layout->RowYAt + }; + Bounds->Max = { + Bounds->Min.x + ElementWidth - Layout->Margin.x, + Bounds->Min.y + Layout->RowHeight + }; + Layout->RowElementsCount++; } else { - BGColor = HotBGColor; - TextColor = HotTextColor; + Result = false; } } - - PushRenderQuad2D(RenderBuffer, Min, Max, BGColor); - DrawString(RenderBuffer, Label, Font, Min + Margin, TextColor); - - Result.Advance = (Max.y - Min.y) + Margin.y; return Result; } -internal button_result -EvaluateButton (render_command_buffer* RenderBuffer, v2 Min, v2 Max, string Label, interface_config Config, mouse_state Mouse) +static rect +ui_ReserveTextLineBounds(ui_interface Interface, string Text, ui_layout* Layout) { - button_result Result = EvaluateButton(RenderBuffer, - Min, Max, Config.Margin, Label, - Config.ButtonColor_Inactive, Config.ButtonColor_Active, - Config.TextColor, Config.TextColor, - Config.Font, Mouse); - return Result; + rect Bounds = {0}; + + return Bounds; } -internal button_result -EvaluateSelectableButton (render_command_buffer* RenderBuffer, v2 Min, v2 Max, string Label, interface_config Config, mouse_state Mouse, b32 Selected) +// +// Drawing Functions +// + +static void +ui_FillRect(ui_interface* Interface, rect Bounds, v4 Color) { - v4 BGColor = Config.ButtonColor_Inactive; - if (Selected) + PushRenderQuad2D(Interface->RenderBuffer, RectExpand(Bounds), Color); +} + +static void +ui_OutlineRect(ui_interface* Interface, rect Bounds, r32 Thickness, v4 Color) +{ + PushRenderBoundingBox2D(Interface->RenderBuffer, Bounds.Min, Bounds.Max, Thickness, Color); +} + +internal void +ui_DrawString(ui_interface* Interface, string String, rect Bounds, v4 Color, string_alignment Alignment = Align_Left) +{ + DEBUG_TRACK_FUNCTION; + render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(Interface->RenderBuffer, + String.Length, + Interface->Style.Font->BitmapMemory, + Interface->Style.Font->BitmapTextureHandle, + Interface->Style.Font->BitmapWidth, + Interface->Style.Font->BitmapHeight, + Interface->Style.Font->BitmapBytesPerPixel, + Interface->Style.Font->BitmapStride); + + v2 RegisterPosition = Bounds.Min + Interface->Style.Margin; + if (Alignment == Align_Left) { - BGColor = Config.ButtonColor_Selected; + RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Interface->Style.Font, Color); + } + else if (Alignment == Align_Right) + { + RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Interface->Style.Font, Color); + } + else + { + InvalidCodePath; } - - button_result Result = EvaluateButton(RenderBuffer, - Min, Max, Config.Margin, Label, - Config.ButtonColor_Inactive, Config.ButtonColor_Active, - Config.TextColor, Config.TextColor, - Config.Font, Mouse); - return Result; } -struct multi_option_label_result +static void +ui_TextBox(ui_interface* Interface, rect Bounds, string Text, v4 BGColor, v4 TextColor) { - b32 Pressed; - s32 IndexPressed; - r32 Advance; -}; + ui_FillRect(Interface, Bounds, BGColor); + ui_DrawString(Interface, Text, Bounds, TextColor); +} -internal multi_option_label_result -EvaluateMultiOptionLabel (render_command_buffer* RenderBuffer, - v2 Min, v2 Max, string Label, string Options[], s32 OptionsCount, - interface_config Config, mouse_state Mouse) +static b32 +ui_Button(ui_interface* Interface, string Text, rect Bounds, v4 InactiveColor, v4 HoverColor, v4 ClickedColor) { - multi_option_label_result Result = {}; - Result.Pressed = false; - - DrawString(RenderBuffer, Label, Config.Font, Min + Config.Margin, Config.TextColor); - - r32 ButtonSide = (Max.y - Min.y) - (2 * Config.Margin.y); - v2 ButtonDim = v2{ButtonSide, ButtonSide}; - v2 ButtonPos = Max - (ButtonDim + Config.Margin); - - for (s32 b = 0; b < OptionsCount; b++) + b32 Pressed = false; + v4 ButtonBG = InactiveColor; + if (PointIsInRect(Interface->Mouse.Pos, Bounds)) { - button_result Button = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim, - Options[b], Config, Mouse); - if (Button.Pressed) + ButtonBG = HoverColor; + if (MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) { - Result.Pressed = true; - Result.IndexPressed = b; + ButtonBG = ClickedColor; + Pressed = true; } } - - Result.Advance = (Max.y - Min.y) + Config.Margin.y; - return Result; + ui_TextBox(Interface, Bounds, Text, ButtonBG, Interface->Style.TextColor); + return Pressed; } -// NOTE(Peter): returns IndexPressed = -1 if the button itself is pressed, as opposed -// to one of its options -internal multi_option_label_result -EvaluateMultiOptionButton (render_command_buffer* RenderBuffer, v2 Min, v2 Max, string Text, string Options[], s32 OptionsCount, b32 Selected, - interface_config Config, mouse_state Mouse) +static b32 +ui_Button(ui_interface* Interface, string Text, rect Bounds) { - multi_option_label_result Result = {}; - Result.Pressed = false; - - r32 ButtonSide = (Max.y - Min.y) - (2 * Config.Margin.y); - v2 ButtonDim = v2{ButtonSide, ButtonSide}; - - v2 FirstButtonPos = Max - ((ButtonDim + Config.Margin) * OptionsCount); - v2 NewMax = v2{FirstButtonPos.x - Config.Margin.x, Max.y}; - - button_result MainButton = EvaluateSelectableButton(RenderBuffer, Min, NewMax, Text, Config, Mouse, Selected); - if (MainButton.Pressed) - { - Result.Pressed = true; - Result.IndexPressed = -1; - } - - v2 ButtonPos = Max - (ButtonDim + Config.Margin); - - for (s32 b = 0; b < OptionsCount; b++) - { - button_result Button = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim, - Options[b], Config, Mouse); - if (Button.Pressed) - { - Result.Pressed = true; - Result.IndexPressed = b; - } - } - - Result.Advance = (Max.y - Min.y) + Config.Margin.y; - return Result; + v4 BGColor = Interface->Style.ButtonColor_Inactive; + v4 HoverColor = Interface->Style.ButtonColor_Active; + v4 SelectedColor = Interface->Style.ButtonColor_Selected; + return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor); } +static b32 +ui_LayoutButton(ui_interface* Interface, string Text, ui_layout* Layout) +{ + rect ButtonBounds = {0}; + if (!ui_TryReserveElementBounds(Layout, &ButtonBounds)) + { + ButtonBounds = ui_ReserveTextLineBounds(*Interface, Text, Layout); + } + + v4 BGColor = Interface->Style.ButtonColor_Inactive; + v4 HoverColor = Interface->Style.ButtonColor_Active; + v4 SelectedColor = Interface->Style.ButtonColor_Selected; + return ui_Button(Interface, Text, ButtonBounds, BGColor, HoverColor, SelectedColor); +} + +static b32 +ui_LayoutListEntry(ui_interface* Interface, ui_layout* Layout, string Text, u32 Index) +{ + rect Bounds = {0}; + if (!ui_TryReserveElementBounds(Layout, &Bounds)) + { + // TODO(Peter): this isn't really invalid, but I don't have a concrete use case + // for it yet. This should only fire if the Layout component is drawing a row, + // but if you're in row mode during a list, what should happen? + // Punting this till I have a use case + InvalidCodePath; + } + v4 BGColor = Interface->Style.ListBGColors[Index % LIST_BG_COLORS_COUNT]; + v4 HoverColor = Interface->Style.ListBGHover; + v4 SelectedColor = Interface->Style.ListBGSelected; + return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor); +} + +// +// OLD +// + struct slider_result { r32 Percent; @@ -383,54 +452,6 @@ EvaluateSlider (render_command_buffer* RenderBuffer, v2 Min, v2 Max, string Labe return Result; } -struct panel_result -{ - v2 NextPanelMin; - v2 ChildMin, ChildMax; -}; - -internal panel_result -EvaluatePanel (render_command_buffer* RenderBuffer, v2 Min, v2 Max, interface_config Config) -{ - panel_result Result = {}; - - Result.ChildMin = Min + Config.Margin; - Result.ChildMax = Max - Config.Margin; - Result.NextPanelMin = v2{Max.x, Min.y}; - - v4 BG = Config.PanelBGColors[0]; - PushRenderQuad2D(RenderBuffer, Min, Max, BG); - - return Result; -} - -internal panel_result -EvaluatePanel (render_command_buffer* RenderBuffer, v2 Min, v2 Max, string Label, interface_config Config) -{ - panel_result Result = EvaluatePanel(RenderBuffer, Min, Max, Config); - - v2 TextPos = v2{ - Min.x + Config.Margin.x, - Max.y - ((r32)NewLineYOffset(*Config.Font) + Config.Margin.y) - }; - DrawString(RenderBuffer, Label, Config.Font, TextPos, Config.TextColor); - Result.ChildMax = v2{Max.x, TextPos.y} - Config.Margin; - - return Result; -} - -internal panel_result -EvaluatePanel(render_command_buffer* RenderBuffer, panel_result* ParentPanel, r32 Height, string Title, interface_config Config) -{ - v2 Min = v2{ParentPanel->ChildMin.x, ParentPanel->ChildMax.y - Height}; - v2 Max = ParentPanel->ChildMax; - panel_result Result = EvaluatePanel(RenderBuffer, Min, Max, Title, Config); - - ParentPanel->ChildMax.y = Min.y - Config.Margin.y; - - return Result; -} - enum selection_state { Selection_None, @@ -566,24 +587,27 @@ struct search_lister_result typedef string search_lister_get_list_item_at_offset(u8* ListMemory, s32 ListLength, string SearchString, s32 Offset); internal search_lister_result -EvaluateSearchLister (render_command_buffer* RenderBuffer, v2 TopLeft, v2 Dimension, string Title, +EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, string Title, string* ItemList, s32* ListLUT, s32 ListLength, s32 HotItem, - string* SearchString, s32 SearchStringCursorPosition, - bitmap_font* Font, interface_config Config, mouse_state Mouse) + string* SearchString, s32 SearchStringCursorPosition) { search_lister_result Result = {}; Result.ShouldRemainOpen = true; Result.HotItem = HotItem; + // TODO(Peter): Was tired. Nothing wrong with the code below + InvalidCodePath; +#if 0 // Title Bar - PushRenderQuad2D(RenderBuffer, v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}, v4{.3f, .3f, .3f, 1.f}); - DrawString(RenderBuffer, Title, Font, v2{TopLeft.x, TopLeft.y - 25}, WhiteV4); + rect TitleBarBounds = rect{v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}}; + ui_FillRect(Interface, TitleBarBounds, v4{.3f, .3f, .3f, 1.f}); + ui_DrawString(Interface, Title, TitleBarBounds, Interface->Style.TextColor); MakeStringBuffer(DebugString, 256); PrintF(&DebugString, "Hot Item: %d | Filtered Items: %d", HotItem, ListLength); - DrawString(RenderBuffer, DebugString, Font, v2{TopLeft.x + 256, TopLeft.y - 25}, WhiteV4); - TopLeft.y -= 30; + rect DebugBounds = MakeRectMinWidth(v2{ TopLeft.x + 256, TopLeft.y - 25}, v2{256, Interface->Style.LineHeight}); + ui_DrawString(Interface, DebugString, DebugBounds, Interface->Style.TextColor); // Search Bar PushRenderQuad2D(RenderBuffer, v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}, v4{.3f, .3f, .3f, 1.f}); @@ -604,16 +628,14 @@ EvaluateSearchLister (render_command_buffer* RenderBuffer, v2 TopLeft, v2 Dimens ButtonColor = Config.ButtonColor_Active; } - button_result Button = EvaluateButton(RenderBuffer, Min, Max, Config.Margin, ListItemString, - ButtonColor, ButtonColor, Config.TextColor, Config.TextColor, - Config.Font, Mouse); - if (Button.Pressed) + if (ui_Button(Interface, ListItemString, rect{Min, Max})) { Result.SelectedItem = i; } TopLeft.y -= 30; } +#endif return Result; } diff --git a/src/node/foldhaus_node_interface.cpp b/src/node/foldhaus_node_interface.cpp index 0764eb8..0b4c3e4 100644 --- a/src/node/foldhaus_node_interface.cpp +++ b/src/node/foldhaus_node_interface.cpp @@ -30,15 +30,14 @@ RenderNodeLister(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf FilterSearchLister(&OpState->SearchLister); // Display Search Lister - search_lister_result NodeListerResult = EvaluateSearchLister (RenderBuffer, TopLeft, Dimension, + search_lister_result NodeListerResult = EvaluateSearchLister (&State->Interface_, TopLeft, Dimension, MakeStringLiteral("Nodes List"), OpState->SearchLister.SourceList, OpState->SearchLister.FilteredIndexLUT, OpState->SearchLister.FilteredListCount, OpState->SearchLister.HotItem, &State->ActiveTextEntry.Buffer, - State->ActiveTextEntry.CursorPosition, - State->Font, State->Interface, Mouse); + State->ActiveTextEntry.CursorPosition); } FOLDHAUS_INPUT_COMMAND_PROC(NodeListerNextItem) diff --git a/src/panels/foldhaus_panel_animation_timeline.h b/src/panels/foldhaus_panel_animation_timeline.h index f148ffb..d868bf6 100644 --- a/src/panels/foldhaus_panel_animation_timeline.h +++ b/src/panels/foldhaus_panel_animation_timeline.h @@ -448,43 +448,34 @@ DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, frame_range V } internal gs_list_handle -DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_state* TimelineState, rect PanelBounds, gs_list_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, app_state* State, mouse_state Mouse) +DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_state* TimelineState, rect PanelBounds, gs_list_handle SelectedBlockHandle, ui_interface* Interface, app_state* State) { string TempString = MakeString(PushArray(&State->Transient, char, 256), 256); gs_list_handle Result = SelectedBlockHandle; - r32 AnimationPanelHeight = PanelBounds.Max.y - PanelBounds.Min.y; - r32 AnimationPanelWidth = PanelBounds.Max.x - PanelBounds.Min.x; + rect LayerMenuBounds, TimelineBounds; + VSplitRectAtDistanceFromLeft(PanelBounds, 256, &LayerMenuBounds, &TimelineBounds); - rect LayerMenuBounds = {0}; - LayerMenuBounds.Min = PanelBounds.Min; - LayerMenuBounds.Max = { PanelBounds.Min.x + 256, PanelBounds.Max.y }; + // In Top To Bottom Order + rect TimelineFrameBarBounds, TimelineBlockDisplayBounds, TimelineRangeBarBounds; + HSplitRectAtDistanceFromTop(TimelineBounds, 32, &TimelineFrameBarBounds, &TimelineBounds); + HSplitRectAtDistanceFromBottom(TimelineBounds, 24, &TimelineBlockDisplayBounds, &TimelineRangeBarBounds); - rect TimeRangeBarBounds = {0}; - TimeRangeBarBounds.Min = BottomRight(LayerMenuBounds); - TimeRangeBarBounds.Max = { PanelBounds.Max.x, PanelBounds.Min.y + 24 }; - - rect FrameBarBounds = {0}; - FrameBarBounds.Min = { LayerMenuBounds.Max.x, PanelBounds.Max.y - 32 }; - FrameBarBounds.Max = PanelBounds.Max; - - rect TimelineBounds = {0}; - TimelineBounds.Min = TopLeft(TimeRangeBarBounds); - TimelineBounds.Max = BottomRight(FrameBarBounds); - - DrawLayerMenu(AnimationSystem, LayerMenuBounds, RenderBuffer, State, Mouse); + // TODO(Peter): Clean Up + DrawLayerMenu(AnimationSystem, LayerMenuBounds, Interface->RenderBuffer, State, Interface->Mouse); frame_range AdjustedViewRange = {0}; - AdjustedViewRange = DrawTimelineRangeBar(AnimationSystem, TimelineState, RenderBuffer, TimeRangeBarBounds, Mouse); + // TODO(Peter): Clean Up + AdjustedViewRange = DrawTimelineRangeBar(AnimationSystem, TimelineState, Interface->RenderBuffer, TimelineRangeBarBounds, Interface->Mouse); s32 VisibleFrameCount = AdjustedViewRange.Max - AdjustedViewRange.Min; - DrawFrameBar(AnimationSystem, RenderBuffer, AdjustedViewRange, FrameBarBounds, Mouse, State); + // TODO(Peter): Clean Up + DrawFrameBar(AnimationSystem, Interface->RenderBuffer, AdjustedViewRange, TimelineFrameBarBounds, Interface->Mouse, State); - // Timeline - PushRenderQuad2D(RenderBuffer, RectExpand(TimelineBounds), v4{.25f, .25f, .25f, 1.f}); + ui_FillRect(Interface, TimelineBlockDisplayBounds, v4{.25f, .25f, .25f, 1.0f}); // Animation Blocks - b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Mouse.LeftButtonState); + b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState); gs_list_handle DragBlockHandle = {0}; for (u32 i = 0; i < AnimationSystem->Blocks.Used; i++) { @@ -508,8 +499,9 @@ DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_sta { BlockColor = PinkV4; } - rect BlockBounds = DrawAnimationBlock(AnimationBlockAt, BlockColor, AdjustedViewRange, TimelineBounds, RenderBuffer); - if (PointIsInRange(Mouse.Pos, BlockBounds.Min, BlockBounds.Max)) + // TODO(Peter): Clean Up + rect BlockBounds = DrawAnimationBlock(AnimationBlockAt, BlockColor, AdjustedViewRange, TimelineBounds, Interface->RenderBuffer); + if (PointIsInRect(Interface->Mouse.Pos, BlockBounds)) { DragBlockHandle = CurrentBlockHandle; } @@ -519,6 +511,7 @@ DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_sta if (MouseDownAndNotHandled && ListHandleIsValid(DragBlockHandle)) { MouseDownAndNotHandled = false; + // TODO(Peter): Why are we passing state around? SelectAndBeginDragAnimationBlock(DragBlockHandle, AdjustedViewRange, TimelineBounds, State); } @@ -527,16 +520,18 @@ DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_sta { r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, AdjustedViewRange); r32 SliderX = GSLerp(TimelineBounds.Min.x, TimelineBounds.Max.x, FrameAtPercentVisibleRange); - v2 SliderMin = v2{SliderX, TimelineBounds.Min.y}; - v2 SliderMax = v2{SliderX + 1, TimelineBounds.Max.y}; - PushRenderQuad2D(RenderBuffer, SliderMin, SliderMax, TimeSliderColor); + rect SliderBounds = { + v2{ SliderX, TimelineBounds.Min.y }, + v2{ SliderX + 1, TimelineBounds.Max.y } + }; + ui_FillRect(Interface, SliderBounds, TimeSliderColor); } - PushRenderBoundingBox2D(RenderBuffer, RectExpand(TimeRangeBarBounds), 1.f, RedV4); - PushRenderBoundingBox2D(RenderBuffer, RectExpand(FrameBarBounds), 1.f, TealV4); - PushRenderBoundingBox2D(RenderBuffer, RectExpand(TimelineBounds), 1.f, PinkV4); + ui_OutlineRect(Interface, TimelineRangeBarBounds, 1.f, RedV4); + ui_OutlineRect(Interface, TimelineFrameBarBounds, 1.f, RedV4); + ui_OutlineRect(Interface, TimelineBlockDisplayBounds, 1.f, RedV4); - if (MouseDownAndNotHandled && PointIsInRect(Mouse.Pos, TimelineBounds)) + if (MouseDownAndNotHandled && PointIsInRect(Interface->Mouse.Pos, TimelineBounds)) { DeselectCurrentAnimationBlock(State); } @@ -559,42 +554,19 @@ animation_clip GlobalAnimationClips[] = { }; internal void -DrawAnimationClipsList(rect PanelBounds, mouse_state Mouse, render_command_buffer* RenderBuffer, app_state* State) +DrawAnimationClipsList(rect PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayer, animation_system* AnimationSystem) { - v4 LineBGColors[] = { - { .16f, .16f, .16f, 1.f }, - { .18f, .18f, .18f, 1.f }, - }; - - interface_list List = {}; - - List.LineBGColors = LineBGColors; - List.LineBGColorsCount = sizeof(LineBGColors) / sizeof(LineBGColors[0]); - List.LineBGHoverColor = v4{ .22f, .22f, .22f, 1.f }; - List.TextColor = WhiteV4; - List.ListBounds = PanelBounds; - List.ListElementDimensions = v2{ - Width(PanelBounds), - (r32)(State->Interface.Font->PixelHeight + 8), - }; - List.ElementLabelIndent = v2{10, 4}; - - string TitleString = MakeStringLiteral("Animation Clips"); - DrawListElement(TitleString, &List, Mouse, RenderBuffer, State->Interface); - + ui_layout Layout = ui_CreateLayout(*Interface, PanelBounds); for (s32 i = 0; i < GlobalAnimationClipsCount; i++) { animation_clip Clip = GlobalAnimationClips[i]; string ClipName = MakeString(Clip.Name, Clip.NameLength); - rect ElementBounds = DrawListElement(ClipName, &List, Mouse, RenderBuffer, State->Interface); - - if (MouseButtonTransitionedDown(Mouse.LeftButtonState) - && PointIsInRect(Mouse.DownPos, ElementBounds)) + if (ui_LayoutListEntry(Interface, &Layout, ClipName, i)) { - AddAnimationBlockAtCurrentTime(i + 1, State->SelectedAnimationLayer, &State->AnimationSystem); + AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayer, AnimationSystem); } } - + // TODO(Peter): Fill up the rest of the area with empty list entries } GSMetaTag(panel_render); @@ -603,67 +575,40 @@ internal void AnimationTimeline_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) { animation_timeline_state* TimelineState = (animation_timeline_state*)Panel.PanelStateMemory; - gs_list_handle SelectedBlockHandle = State->SelectedAnimationBlockHandle; - r32 OptionsRowHeight = 25; - rect AnimationClipListBounds = rect{ - PanelBounds.Min, - v2{PanelBounds.Min.x + 300, PanelBounds.Max.y - OptionsRowHeight}, - }; - rect TimelineBounds = rect{ - v2{AnimationClipListBounds.Max.x, PanelBounds.Min.y}, - v2{PanelBounds.Max.x, PanelBounds.Max.y - OptionsRowHeight}, - }; + ui_interface* Interface = &State->Interface_; + animation_system* AnimationSystem = &State->AnimationSystem; + + rect TitleBarBounds, PanelContentsBounds; + HSplitRectAtDistanceFromTop(PanelBounds, Interface->Style.RowHeight, &TitleBarBounds, &PanelContentsBounds); + rect AnimationListBounds, TimelineBounds; + VSplitRectAtDistanceFromLeft(PanelContentsBounds, 300, &AnimationListBounds, &TimelineBounds); + + ui_FillRect(Interface, TitleBarBounds, Interface->Style.PanelBGColors[0]); + ui_layout TitleBarLayout = ui_CreateLayout(*Interface, TitleBarBounds); + ui_StartRow(&TitleBarLayout, 3); + { + if (ui_LayoutButton(Interface, MakeStringLiteral("Pause"), &TitleBarLayout)) + { + State->AnimationSystem.TimelineShouldAdvance = true; + } + if (ui_LayoutButton(Interface, MakeStringLiteral("Play"), &TitleBarLayout)) + { + State->AnimationSystem.TimelineShouldAdvance = false; + } + if (ui_LayoutButton(Interface, MakeStringLiteral("Stop"), &TitleBarLayout)) + { + State->AnimationSystem.TimelineShouldAdvance = false; + State->AnimationSystem.CurrentFrame = 0; + } + } + ui_EndRow(&TitleBarLayout); if (Height(TimelineBounds) > 0) { - SelectedBlockHandle = DrawAnimationTimeline(&State->AnimationSystem, - TimelineState, - TimelineBounds, - SelectedBlockHandle, - RenderBuffer, State, Mouse); - DrawAnimationClipsList(AnimationClipListBounds, Mouse, RenderBuffer, State); - } - - v2 OptionsRowMin = v2{ PanelBounds.Min.x, TimelineBounds.Max.y }; - v2 OptionsRowMax = PanelBounds.Max; - panel_result AnimationPanel = EvaluatePanel(RenderBuffer, OptionsRowMin, OptionsRowMax, State->Interface); - - r32 ButtonWidth = 35; - v2 ButtonMin = v2{0, 0}; - v2 ButtonMax = v2{35, OptionsRowHeight - 2}; - v2 ButtonAt = v2{OptionsRowMin.x + 1, OptionsRowMin.y + 1}; - - button_result PauseResult = EvaluateButton(RenderBuffer, - ButtonAt + ButtonMin, ButtonAt + ButtonMax, - MakeStringLiteral("Pause"), - State->Interface, Mouse); - ButtonAt.x += ButtonWidth + 2; - button_result PlayResult = EvaluateButton(RenderBuffer, - ButtonAt + ButtonMin, ButtonAt + ButtonMax, - MakeStringLiteral("Play"), - State->Interface, Mouse); - ButtonAt.x += ButtonWidth + 2; - button_result StopResult = EvaluateButton(RenderBuffer, - ButtonAt + ButtonMin, ButtonAt + ButtonMax, - MakeStringLiteral("Stop"), - State->Interface, Mouse); - - if (PauseResult.Pressed) - { - State->AnimationSystem.TimelineShouldAdvance = false; - } - - if (PlayResult.Pressed) - { - State->AnimationSystem.TimelineShouldAdvance = true; - } - - if (StopResult.Pressed) - { - State->AnimationSystem.TimelineShouldAdvance = false; - State->AnimationSystem.CurrentFrame = 0; + SelectedBlockHandle = DrawAnimationTimeline(AnimationSystem, TimelineState, TimelineBounds, SelectedBlockHandle, Interface, State); + DrawAnimationClipsList(AnimationListBounds, Interface, State->SelectedAnimationLayer, &State->AnimationSystem); } } diff --git a/src/panels/foldhaus_panel_hierarchy.h b/src/panels/foldhaus_panel_hierarchy.h index 3733282..d0ada49 100644 --- a/src/panels/foldhaus_panel_hierarchy.h +++ b/src/panels/foldhaus_panel_hierarchy.h @@ -37,6 +37,7 @@ HierarchyView_Render(panel Panel, rect PanelBounds, render_command_buffer* Rende { .18f, .18f, .18f, 1.f }, }; + // TODO(Peter): use the new ui system interface_list List = {}; List.LineBGColors = LineBGColors; List.LineBGColorsCount = sizeof(LineBGColors) / sizeof(LineBGColors[0]); diff --git a/src/panels/foldhaus_panel_profiler.h b/src/panels/foldhaus_panel_profiler.h index 7d94b4d..b86fdb6 100644 --- a/src/panels/foldhaus_panel_profiler.h +++ b/src/panels/foldhaus_panel_profiler.h @@ -178,41 +178,39 @@ ProfilerView_Render(panel Panel, rect PanelBounds, render_command_buffer* Render FrameTotalCycles); DrawString(RenderBuffer, String, State->Interface.Font, FrameListMin - v2{0, 32}, WhiteV4); - v2 ButtonMin = v2{FrameListMax.x - 128, FrameListMin.y - 32}; - v2 ButtonMax = ButtonMin + v2{128, 28}; - button_result ShouldResumeRecording = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, - MakeString("Resume Recording"), State->Interface, Mouse); - if (ShouldResumeRecording.Pressed) + rect ResumeRecordingBtnBounds = MakeRectMinWidth(v2{ FrameListMax.x - 128, FrameListMin.y - 32 }, v2{ 128, 28 }); + if (ui_Button(&State->Interface_, MakeString("Resume Recording"), ResumeRecordingBtnBounds)) { GlobalDebugServices->RecordFrames = true; } - ButtonMin = v2{FrameListMin.x, FrameListMin.y - 60}; - ButtonMax = v2{FrameListMin.x + 128, FrameListMin.y - 42}; - button_result ActivateScopeView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, - MakeString("Scope View"), State->Interface, Mouse); + rect ScopeViewBtnBounds = { + v2{ FrameListMin.x, FrameListMin.y - 60 }, + v2{ FrameListMin.x + 128, FrameListMin.y - 42 } + }; + if (ui_Button(&State->Interface_, MakeString("Scope View"), ScopeViewBtnBounds)) + { + GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; + } - ButtonMin.x += 152; - ButtonMax.x += 152; - button_result ActivateListView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, - MakeString("List View"), State->Interface, Mouse); - - if (ActivateScopeView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; } - if (ActivateListView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; } - - v2 ViewModeMin = v2{FrameListMin.x, PanelBounds.Min.y}; - v2 ViewModeMax = v2{FrameListMax.x, FrameListMin.y - 96}; + rect ListViewBtnBounds = TranslateRectX(ScopeViewBtnBounds, 152); + if (ui_Button(&State->Interface_, MakeString("List View"), ListViewBtnBounds)) + { + GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; + } + rect ViewModeBounds = { + v2{ FrameListMin.x, PanelBounds.Min.y }, + v2{ FrameListMax.x, FrameListMin.y - 96 } + }; if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER) { - RenderProfiler_ScopeVisualization(RenderBuffer, State->Interface, Mouse, - ViewModeMin, ViewModeMax, + RenderProfiler_ScopeVisualization(RenderBuffer, State->Interface, Mouse, RectExpand(ViewModeBounds), VisibleFrame, Memory); } else { - RenderProfiler_ListVisualization(RenderBuffer, State->Interface, Mouse, - ViewModeMin, ViewModeMax, + RenderProfiler_ListVisualization(RenderBuffer, State->Interface, Mouse, RectExpand(ViewModeBounds), VisibleFrame, Memory); } } diff --git a/todo.txt b/todo.txt index be56b23..aecaccf 100644 --- a/todo.txt +++ b/todo.txt @@ -4,7 +4,7 @@ TODO FOLDHAUS - fix memory layout (remeber to profile before and after) - Make the DLL truly platform agnostic - - math.h: present for trig functions + - math.h: present for trig functions (though this is part of the c-std lib, so it should be everywhere) - windows.h: only thing left is InterlockedIncrement and InterlockedAdd - Win32 Platform Layer @@ -20,10 +20,9 @@ TODO FOLDHAUS - Make sure it works without building in Debug Mode - Buckets & Lists - - Allow them to use memory arenas - - Zero is initialization + - On second thought, I just really don't like these. Lets get rid of them, and put custom structures in place -- Rendering +- Rendering (Working on this elsewhere) - OpenGL 3 - Vertex Buffers - Layers