diff --git a/Dengine.vcxproj b/Dengine.vcxproj
index 810de60..417bcf5 100644
--- a/Dengine.vcxproj
+++ b/Dengine.vcxproj
@@ -129,6 +129,7 @@
+
@@ -153,6 +154,7 @@
+
diff --git a/Dengine.vcxproj.filters b/Dengine.vcxproj.filters
index 98651a6..ca60c51 100644
--- a/Dengine.vcxproj.filters
+++ b/Dengine.vcxproj.filters
@@ -48,6 +48,9 @@
Source Files
+
+ Source Files
+
@@ -101,5 +104,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/src/AssetManager.c b/src/AssetManager.c
index 1b9d983..c4aac3d 100644
--- a/src/AssetManager.c
+++ b/src/AssetManager.c
@@ -36,7 +36,8 @@ AudioVorbis *asset_getVorbis(AssetManager *assetManager,
return NULL;
}
-Texture *asset_getTexture(AssetManager *assetManager, const enum TexList type)
+Texture *asset_getTexture(AssetManager *const assetManager,
+ const enum TexList type)
{
if (type < texlist_count)
return &assetManager->textures[type];
diff --git a/src/Renderer.c b/src/Renderer.c
index 709fa87..e4edefc 100644
--- a/src/Renderer.c
+++ b/src/Renderer.c
@@ -168,7 +168,7 @@ INTERNAL v2 mapWorldToCameraSpace(v2 worldPos, v4 cameraBounds)
return posInCameraSpace;
}
-RenderTex renderer_createNullRenderTex(AssetManager *assetManager)
+RenderTex renderer_createNullRenderTex(AssetManager *const assetManager)
{
Texture *emptyTex = asset_getTexture(assetManager, texlist_empty);
RenderTex result = {emptyTex, V4(0, 1, 1, 0)};
diff --git a/src/UserInterface.c b/src/UserInterface.c
new file mode 100644
index 0000000..94aa87d
--- /dev/null
+++ b/src/UserInterface.c
@@ -0,0 +1,295 @@
+#include "Dengine/UserInterface.h"
+#include "Dengine/Assets.h"
+#include "Dengine/Renderer.h"
+
+i32 userInterface_button(UiState *const uiState,
+ AssetManager *const assetManager,
+ Renderer *const renderer, const KeyInput input,
+ const i32 id, const Rect rect)
+{
+ if (math_pointInRect(rect, input.mouseP))
+ {
+ uiState->hotItem = id;
+ if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
+ uiState->activeItem = id;
+ }
+
+ RenderTex renderTex = renderer_createNullRenderTex(assetManager);
+
+ /* If no widget has keyboard focus, take it */
+ if (uiState->kbdItem == 0)
+ uiState->kbdItem = id;
+
+ /* If we have keyboard focus, show it */
+ if (uiState->kbdItem == id)
+ {
+ // Draw outline
+ renderer_staticRect(renderer, v2_add(V2(-6, -6), rect.pos),
+ v2_add(V2(20, 20), rect.size), V2(0, 0), 0, renderTex,
+ V4(1.0f, 0, 0, 1));
+ }
+
+ // Draw shadow
+ renderer_staticRect(renderer, v2_add(V2(8, 8), rect.pos), rect.size,
+ V2(0, 0), 0, renderTex, V4(0, 0, 0, 1));
+
+ if (uiState->hotItem == id)
+ {
+ if (uiState->activeItem == id)
+ {
+ renderer_staticRect(renderer, v2_add(V2(2, 2), rect.pos), rect.size,
+ V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
+ }
+ else
+ {
+ renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
+ V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
+ }
+ }
+ else
+ {
+ renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
+ V2(0, 0), 0, renderTex, V4(0.5f, 0.5f, 0.5f, 1));
+ }
+
+ // After renderering before click check, see if we need to process keys
+ if (uiState->kbdItem == id)
+ {
+ switch (uiState->keyEntered)
+ {
+ case keycode_tab:
+ // Set focus to nothing and let next widget get focus
+ uiState->kbdItem = 0;
+ if (uiState->keyMod == keycode_leftShift)
+ uiState->kbdItem = uiState->lastWidget;
+
+ // Clear key state so next widget doesn't auto grab
+ uiState->keyEntered = keycode_null;
+ break;
+ case keycode_enter:
+ return 1;
+ default:
+ break;
+ }
+ }
+
+ uiState->lastWidget = id;
+
+ if (!input.keys[keycode_mouseLeft].endedDown &&
+ uiState->hotItem == id &&
+ uiState->activeItem == id)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+i32 userInterface_scrollBar(UiState *const uiState,
+ AssetManager *const assetManager,
+ Renderer *const renderer, const KeyInput input,
+ const i32 id, const Rect scrollBarRect,
+ i32 *const value, const i32 maxValue)
+{
+#ifdef DENGINE_DEBUG
+ ASSERT(*value <= maxValue);
+#endif
+
+ if (math_pointInRect(scrollBarRect, input.mouseP))
+ {
+ uiState->hotItem = id;
+ if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
+ uiState->activeItem = id;
+ }
+
+ RenderTex renderTex = renderer_createNullRenderTex(assetManager);
+
+ /* If no widget has keyboard focus, take it */
+ if (uiState->kbdItem == 0)
+ uiState->kbdItem = id;
+
+ /* If we have keyboard focus, show it */
+ if (uiState->kbdItem == id)
+ {
+ // Draw outline
+ renderer_staticRect(renderer, v2_add(V2(-6, -6), scrollBarRect.pos),
+ v2_add(V2(20, 20), scrollBarRect.size), V2(0, 0), 0,
+ renderTex, V4(1.0f, 0, 0, 1));
+ }
+
+ // Render scroll bar background
+ renderer_staticRect(renderer, scrollBarRect.pos, scrollBarRect.size,
+ V2(0, 0), 0, renderTex, V4(0.75f, 0.5f, 0.5f, 1));
+
+ // Render scroll bar slider
+ v2 sliderSize = V2(16, 16);
+ v4 sliderColor = V4(0, 0, 0, 1);
+
+ f32 sliderPercentageOffset = (CAST(f32) *value / CAST(f32) maxValue);
+ f32 sliderYOffsetToBar =
+ (scrollBarRect.size.h - sliderSize.h) * sliderPercentageOffset;
+ v2 sliderPos = v2_add(scrollBarRect.pos, V2(0, sliderYOffsetToBar));
+
+ if (uiState->hotItem == id || uiState->activeItem == id)
+ sliderColor = V4(1.0f, 0, 0, 1);
+ else
+ sliderColor = V4(0.0f, 1.0f, 0, 1);
+
+ renderer_staticRect(renderer, sliderPos, sliderSize, V2(0, 0), 0, renderTex,
+ sliderColor);
+
+ if (uiState->kbdItem == id)
+ {
+ switch (uiState->keyEntered)
+ {
+ case keycode_tab:
+ uiState->kbdItem = 0;
+ if (uiState->keyMod == keycode_leftShift)
+ uiState->kbdItem = uiState->lastWidget;
+
+ // Clear key state so next widget doesn't auto grab
+ uiState->keyEntered = keycode_null;
+ break;
+ case keycode_up:
+ // TODO(doyle): Fix input for this to work, i.e. proper rate limited input poll
+ if (*value < maxValue)
+ {
+ (*value)++;
+ return 1;
+ }
+ case keycode_down:
+ if (*value > 0)
+ {
+ (*value)--;
+ return 1;
+ }
+ default:
+ break;
+ }
+ }
+
+ uiState->lastWidget = id;
+
+ if (uiState->activeItem == id)
+ {
+ f32 mouseYRelToRect = input.mouseP.y - scrollBarRect.pos.y;
+
+ // Bounds check
+ if (mouseYRelToRect < 0)
+ mouseYRelToRect = 0;
+ else if (mouseYRelToRect > scrollBarRect.size.h)
+ mouseYRelToRect = scrollBarRect.size.h;
+
+ f32 newSliderPercentOffset =
+ (CAST(f32) mouseYRelToRect / scrollBarRect.size.h);
+
+ i32 newValue = CAST(i32)(newSliderPercentOffset * CAST(f32)maxValue);
+ if (newValue != *value)
+ {
+ *value = newValue;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+i32 userInterface_textField(UiState *const uiState, MemoryArena *arena,
+ AssetManager *const assetManager,
+ Renderer *const renderer, Font *const font,
+ KeyInput input, const i32 id, v2 pos,
+ char *const string)
+{
+ i32 strLen = common_strlen(string);
+ b32 changed = FALSE;
+
+ Rect textRect = {0};
+ textRect.pos = pos;
+ textRect.size = V2(30 * font->maxSize.w, font->maxSize.h);
+ if (math_pointInRect(textRect, input.mouseP))
+ {
+ uiState->hotItem = id;
+ if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
+ {
+ uiState->activeItem = id;
+ }
+ }
+
+ /* If no widget has keyboard focus, take it */
+ if (uiState->kbdItem == 0)
+ uiState->kbdItem = id;
+
+ RenderTex renderTex = renderer_createNullRenderTex(assetManager);
+ /* If we have keyboard focus, show it */
+ if (uiState->kbdItem == id)
+ {
+ // Draw outline
+ renderer_staticRect(renderer, v2_add(V2(-4, -4), textRect.pos),
+ v2_add(V2(16, 16), textRect.size), V2(0, 0), 0,
+ renderTex, V4(1.0f, 0, 0, 1));
+ }
+
+ // Render text field
+ renderer_staticRect(renderer, textRect.pos, textRect.size, V2(0, 0), 0,
+ renderTex, V4(0.75f, 0.5f, 0.5f, 1));
+
+ if (uiState->activeItem == id || uiState->hotItem == id)
+ {
+ renderer_staticRect(renderer, textRect.pos, textRect.size, V2(0, 0), 0,
+ renderTex, V4(0.75f, 0.75f, 0.0f, 1));
+ }
+ else
+ {
+ renderer_staticRect(renderer, textRect.pos, textRect.size, V2(0, 0), 0,
+ renderTex, V4(0.5f, 0.5f, 0.5f, 1));
+ }
+
+ // TODO(doyle): Figure out why we need to offset text ..
+ v2 strPos = v2_add(textRect.pos, V2(0, -font->maxSize.h));
+
+ renderer_staticString(renderer, arena, font, string, strPos, V2(0, 0), 0,
+ V4(0, 0, 0, 1));
+
+ if (uiState->kbdItem == id)
+ {
+ switch (uiState->keyEntered)
+ {
+ case keycode_tab:
+ uiState->kbdItem = 0;
+ if (uiState->keyMod == keycode_leftShift)
+ uiState->kbdItem = uiState->lastWidget;
+
+ uiState->keyEntered = keycode_null;
+ break;
+
+ case keycode_backspace:
+ if (strLen > 0)
+ {
+ string[--strLen] = 0;
+ changed = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (uiState->keyChar >= keycode_space &&
+ uiState->keyChar <= keycode_tilda && strLen < 30)
+ {
+ string[strLen++] = uiState->keyChar + ' ';
+ string[strLen] = 0;
+ changed = TRUE;
+ }
+ }
+
+ if (!input.keys[keycode_mouseLeft].endedDown &&
+ uiState->hotItem == id &&
+ uiState->activeItem == id)
+ {
+ uiState->kbdItem = id;
+ }
+
+ uiState->lastWidget = id;
+ return changed;
+}
+
diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c
index fbac794..663cbdc 100644
--- a/src/WorldTraveller.c
+++ b/src/WorldTraveller.c
@@ -3,6 +3,7 @@
#include "Dengine/Debug.h"
#include "Dengine/Entity.h"
#include "Dengine/Platform.h"
+#include "Dengine/UserInterface.h"
enum State
{
@@ -1001,289 +1002,6 @@ INTERNAL void sortWorldEntityList(World *world, i32 numDeadEntities)
world->freeEntityIndex -= numDeadEntities;
}
-INTERNAL i32 button(UiState *uiState, AssetManager *assetManager,
- Renderer *renderer, KeyInput input, i32 id, Rect rect)
-{
- if (math_pointInRect(rect, input.mouseP))
- {
- uiState->hotItem = id;
- if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
- uiState->activeItem = id;
- }
-
- RenderTex renderTex = renderer_createNullRenderTex(assetManager);
-
- /* If no widget has keyboard focus, take it */
- if (uiState->kbdItem == 0)
- uiState->kbdItem = id;
-
- /* If we have keyboard focus, show it */
- if (uiState->kbdItem == id)
- {
- // Draw outline
- renderer_staticRect(renderer, v2_add(V2(-6, -6), rect.pos),
- v2_add(V2(20, 20), rect.size), V2(0, 0), 0, renderTex,
- V4(1.0f, 0, 0, 1));
- }
-
- // Draw shadow
- renderer_staticRect(renderer, v2_add(V2(8, 8), rect.pos), rect.size,
- V2(0, 0), 0, renderTex, V4(0, 0, 0, 1));
-
- if (uiState->hotItem == id)
- {
- if (uiState->activeItem == id)
- {
- renderer_staticRect(renderer, v2_add(V2(2, 2), rect.pos), rect.size,
- V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
- }
- else
- {
- renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
- V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
- }
- }
- else
- {
- renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
- V2(0, 0), 0, renderTex, V4(0.5f, 0.5f, 0.5f, 1));
- }
-
- // After renderering before click check, see if we need to process keys
- if (uiState->kbdItem == id)
- {
- switch (uiState->keyEntered)
- {
- case keycode_tab:
- // Set focus to nothing and let next widget get focus
- uiState->kbdItem = 0;
- if (uiState->keyMod == keycode_leftShift)
- uiState->kbdItem = uiState->lastWidget;
-
- // Clear key state so next widget doesn't auto grab
- uiState->keyEntered = keycode_null;
- break;
- case keycode_enter:
- return 1;
- default:
- break;
- }
- }
-
- uiState->lastWidget = id;
-
- if (!input.keys[keycode_mouseLeft].endedDown &&
- uiState->hotItem == id &&
- uiState->activeItem == id)
- {
- return 1;
- }
-
- return 0;
-}
-
-INTERNAL i32 scrollBar(UiState *uiState, AssetManager *assetManager,
- Renderer *renderer, KeyInput input, i32 id,
- Rect scrollBarRect, i32 *value, i32 maxValue)
-{
-#ifdef DENGINE_DEBUG
- ASSERT(*value <= maxValue);
-#endif
-
- if (math_pointInRect(scrollBarRect, input.mouseP))
- {
- uiState->hotItem = id;
- if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
- uiState->activeItem = id;
- }
-
- RenderTex renderTex = renderer_createNullRenderTex(assetManager);
-
- /* If no widget has keyboard focus, take it */
- if (uiState->kbdItem == 0)
- uiState->kbdItem = id;
-
- /* If we have keyboard focus, show it */
- if (uiState->kbdItem == id)
- {
- // Draw outline
- renderer_staticRect(renderer, v2_add(V2(-6, -6), scrollBarRect.pos),
- v2_add(V2(20, 20), scrollBarRect.size), V2(0, 0), 0,
- renderTex, V4(1.0f, 0, 0, 1));
- }
-
- // Render scroll bar background
- renderer_staticRect(renderer, scrollBarRect.pos, scrollBarRect.size,
- V2(0, 0), 0, renderTex, V4(0.75f, 0.5f, 0.5f, 1));
-
- // Render scroll bar slider
- v2 sliderSize = V2(16, 16);
- v4 sliderColor = V4(0, 0, 0, 1);
-
- f32 sliderPercentageOffset = (CAST(f32) *value / CAST(f32) maxValue);
- f32 sliderYOffsetToBar =
- (scrollBarRect.size.h - sliderSize.h) * sliderPercentageOffset;
- v2 sliderPos = v2_add(scrollBarRect.pos, V2(0, sliderYOffsetToBar));
-
- if (uiState->hotItem == id || uiState->activeItem == id)
- sliderColor = V4(1.0f, 0, 0, 1);
- else
- sliderColor = V4(0.0f, 1.0f, 0, 1);
-
- renderer_staticRect(renderer, sliderPos, sliderSize, V2(0, 0), 0, renderTex,
- sliderColor);
-
- if (uiState->kbdItem == id)
- {
- switch (uiState->keyEntered)
- {
- case keycode_tab:
- uiState->kbdItem = 0;
- if (uiState->keyMod == keycode_leftShift)
- uiState->kbdItem = uiState->lastWidget;
-
- // Clear key state so next widget doesn't auto grab
- uiState->keyEntered = keycode_null;
- break;
- case keycode_up:
- // TODO(doyle): Fix input for this to work, i.e. proper rate limited input poll
- if (*value < maxValue)
- {
- (*value)++;
- return 1;
- }
- case keycode_down:
- if (*value > 0)
- {
- (*value)--;
- return 1;
- }
- default:
- break;
- }
- }
-
- uiState->lastWidget = id;
-
- if (uiState->activeItem == id)
- {
- f32 mouseYRelToRect = input.mouseP.y - scrollBarRect.pos.y;
-
- // Bounds check
- if (mouseYRelToRect < 0)
- mouseYRelToRect = 0;
- else if (mouseYRelToRect > scrollBarRect.size.h)
- mouseYRelToRect = scrollBarRect.size.h;
-
- f32 newSliderPercentOffset =
- (CAST(f32) mouseYRelToRect / scrollBarRect.size.h);
-
- i32 newValue = CAST(i32)(newSliderPercentOffset * CAST(f32)maxValue);
- if (newValue != *value)
- {
- *value = newValue;
- return 1;
- }
- }
-
- return 0;
-}
-
-INTERNAL i32 textField(UiState *const uiState, MemoryArena *arena,
- AssetManager *const assetManager,
- Renderer *const renderer, Font *const font,
- KeyInput input, const i32 id, v2 pos, char *const string)
-{
- i32 strLen = common_strlen(string);
- b32 changed = FALSE;
-
- Rect textRect = {0};
- textRect.pos = pos;
- textRect.size = V2(30 * font->maxSize.w, font->maxSize.h);
- if (math_pointInRect(textRect, input.mouseP))
- {
- uiState->hotItem = id;
- if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
- {
- uiState->activeItem = id;
- }
- }
-
- /* If no widget has keyboard focus, take it */
- if (uiState->kbdItem == 0)
- uiState->kbdItem = id;
-
- RenderTex renderTex = renderer_createNullRenderTex(assetManager);
- /* If we have keyboard focus, show it */
- if (uiState->kbdItem == id)
- {
- // Draw outline
- renderer_staticRect(renderer, v2_add(V2(-4, -4), textRect.pos),
- v2_add(V2(16, 16), textRect.size), V2(0, 0), 0,
- renderTex, V4(1.0f, 0, 0, 1));
- }
-
- // Render
- renderer_staticRect(renderer, textRect.pos, textRect.size, V2(0, 0), 0,
- renderTex, V4(0.75f, 0.5f, 0.5f, 1));
-
- if (uiState->activeItem == id || uiState->hotItem == id)
- {
- renderer_staticRect(renderer, textRect.pos, textRect.size, V2(0, 0), 0,
- renderTex, V4(0.75f, 0.75f, 0.0f, 1));
- }
- else
- {
- renderer_staticRect(renderer, textRect.pos, textRect.size, V2(0, 0), 0,
- renderTex, V4(0.5f, 0.5f, 0.5f, 1));
- }
-
- renderer_staticString(renderer, arena, font, string, textRect.pos, V2(0, 0),
- 0, V4(0, 0, 0, 1));
-
- if (uiState->kbdItem == id)
- {
- switch (uiState->keyEntered)
- {
- case keycode_tab:
- uiState->kbdItem = 0;
- if (uiState->keyMod == keycode_leftShift)
- uiState->kbdItem = uiState->lastWidget;
-
- uiState->keyEntered = keycode_null;
- break;
-
- case keycode_backspace:
- if (strLen > 0)
- {
- string[--strLen] = 0;
- changed = TRUE;
- }
- break;
- default:
- break;
- }
-
- if (uiState->keyChar >= keycode_space &&
- uiState->keyChar <= keycode_tilda && strLen < 30)
- {
- string[strLen++] = uiState->keyChar + ' ';
- string[strLen] = 0;
- changed = TRUE;
- }
- }
-
- if (!input.keys[keycode_mouseLeft].endedDown &&
- uiState->hotItem == id &&
- uiState->activeItem == id)
- {
- uiState->kbdItem = id;
- }
-
- uiState->lastWidget = id;
- return changed;
-}
-
void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
{
if (dt >= 1.0f) dt = 1.0f;
@@ -1535,25 +1253,26 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
/* Draw ui */
Rect buttonRectA = {V2(300, 500), V2(100, 50)};
- button(&state->uiState, assetManager, renderer, state->input, 1,
- buttonRectA);
+ userInterface_button(&state->uiState, assetManager, renderer, state->input,
+ 1, buttonRectA);
Rect buttonRectB = {V2(500, 500), V2(100, 50)};
- button(&state->uiState, assetManager, renderer, state->input, 2,
- buttonRectB);
+ userInterface_button(&state->uiState, assetManager, renderer, state->input,
+ 2, buttonRectB);
Rect buttonRectC = {V2(700, 500), V2(100, 50)};
- button(&state->uiState, assetManager, renderer, state->input, 3,
- buttonRectC);
+ userInterface_button(&state->uiState, assetManager, renderer, state->input,
+ 3, buttonRectC);
LOCAL_PERSIST i32 scrollValue = 30;
- Rect scrollRectA = {V2(900, 500), V2(16, 255)};
- scrollBar(&state->uiState, assetManager, renderer, state->input, 4,
- scrollRectA, &scrollValue, 160);
+ Rect scrollRectA = {V2(900, 500), V2(16, 255)};
+ userInterface_scrollBar(&state->uiState, assetManager, renderer,
+ state->input, 4, scrollRectA, &scrollValue, 160);
LOCAL_PERSIST char fieldString[80] = "Hello world";
- textField(&state->uiState, &state->arena, assetManager, renderer, font,
- state->input, 5, V2(1000, 500), fieldString);
+ userInterface_textField(&state->uiState, &state->arena, assetManager,
+ renderer, font, state->input, 5, V2(1000, 500),
+ fieldString);
// RESET IMGUI
if (!state->input.keys[keycode_mouseLeft].endedDown)
diff --git a/src/include/Dengine/AssetManager.h b/src/include/Dengine/AssetManager.h
index a775813..b8c96d5 100644
--- a/src/include/Dengine/AssetManager.h
+++ b/src/include/Dengine/AssetManager.h
@@ -22,7 +22,8 @@ typedef struct AssetManager
AudioVorbis *asset_getVorbis(AssetManager *assetManager,
const enum AudioList type);
-Texture *asset_getTexture(AssetManager *assetManager, const enum TexList type);
+Texture *asset_getTexture(AssetManager *const assetManager,
+ const enum TexList type);
Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type);
TexAtlas *asset_getTextureAtlas(AssetManager *assetManager,
const enum TexList type);
diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h
index 91a13b6..c7c3080 100644
--- a/src/include/Dengine/Renderer.h
+++ b/src/include/Dengine/Renderer.h
@@ -28,7 +28,7 @@ typedef struct RenderTex
v4 texRect;
} RenderTex;
-RenderTex renderer_createNullRenderTex(AssetManager *assetManager);
+RenderTex renderer_createNullRenderTex(AssetManager *const assetManager);
// TODO(doyle): Clean up lines
// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
diff --git a/src/include/Dengine/UserInterface.h b/src/include/Dengine/UserInterface.h
new file mode 100644
index 0000000..4a66fac
--- /dev/null
+++ b/src/include/Dengine/UserInterface.h
@@ -0,0 +1,43 @@
+#ifndef DENGINE_USER_INTERFACE_H
+#define DENGINE_USER_INTERFACE_H
+
+#include "Dengine/Common.h"
+#include "Dengine/Math.h"
+#include "Dengine/Platform.h"
+
+/* Forward Declaration */
+typedef struct AssetManager AssetManager;
+typedef struct Font Font;
+typedef struct MemoryArena MemoryArena;
+typedef struct Renderer Renderer;
+
+typedef struct UiState
+{
+ i32 hotItem;
+ i32 activeItem;
+
+ i32 kbdItem;
+ enum KeyCode keyEntered;
+ enum KeyCode keyMod;
+ enum KeyCode keyChar;
+
+ i32 lastWidget;
+} UiState;
+
+i32 userInterface_button(UiState *const uiState,
+ AssetManager *const assetManager,
+ Renderer *const renderer, const KeyInput input,
+ const i32 id, const Rect rect);
+
+i32 userInterface_textField(UiState *const uiState, MemoryArena *arena,
+ AssetManager *const assetManager,
+ Renderer *const renderer, Font *const font,
+ KeyInput input, const i32 id, v2 pos,
+ char *const string);
+
+i32 userInterface_scrollBar(UiState *const uiState,
+ AssetManager *const assetManager,
+ Renderer *const renderer, const KeyInput input,
+ const i32 id, const Rect scrollBarRect,
+ i32 *const value, const i32 maxValue);
+#endif
diff --git a/src/include/Dengine/WorldTraveller.h b/src/include/Dengine/WorldTraveller.h
index bce4458..a86e22e 100644
--- a/src/include/Dengine/WorldTraveller.h
+++ b/src/include/Dengine/WorldTraveller.h
@@ -4,27 +4,17 @@
#include "Dengine/AssetManager.h"
#include "Dengine/Audio.h"
#include "Dengine/Common.h"
-#include "Dengine/Entity.h"
#include "Dengine/Math.h"
#include "Dengine/MemoryArena.h"
#include "Dengine/Platform.h"
#include "Dengine/Renderer.h"
+#include "Dengine/UserInterface.h"
#define NUM_KEYS 1024
#define METERS_TO_PIXEL 240
-typedef struct UiState
-{
- i32 hotItem;
- i32 activeItem;
-
- i32 kbdItem;
- enum KeyCode keyEntered;
- enum KeyCode keyMod;
- enum KeyCode keyChar;
-
- i32 lastWidget;
-} UiState;
+/* Forward declaration */
+typedef struct Entity Entity;
typedef struct World
{