Began working on a new ui layout system. Deprecated a lot of old ui code, in favor of new ui_ code

This commit is contained in:
Peter Slattery 2020-03-20 00:55:13 -07:00
parent 803f5c82ae
commit cb98100a94
10 changed files with 418 additions and 344 deletions

View File

@ -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
//////////////////////////////////////

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
interface_config Style;
mouse_state Mouse;
render_command_buffer* RenderBuffer;
};
v4 BGColor = IdleBGColor;
v4 TextColor = IdleTextColor;
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;
}
if (PointIsInRange(Mouse.Pos, Min, Max))
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;
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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]);

View File

@ -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);
}
}

View File

@ -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