Add string length in pixel func, add button label
This commit is contained in:
parent
c33b37b0ea
commit
90068d2c64
@ -455,6 +455,10 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
|
|||||||
font->tex = &assetManager->textures[texlist_font];
|
font->tex = &assetManager->textures[texlist_font];
|
||||||
font->atlas = &assetManager->texAtlas[texlist_font];
|
font->atlas = &assetManager->texAtlas[texlist_font];
|
||||||
|
|
||||||
|
// NOTE(doyle): Formula derived from STB Font
|
||||||
|
font->verticalSpacing =
|
||||||
|
font->metrics.ascent - font->metrics.descent + font->metrics.lineGap;
|
||||||
|
|
||||||
for (i32 i = 0; i < numGlyphs; i++)
|
for (i32 i = 0; i < numGlyphs; i++)
|
||||||
{
|
{
|
||||||
i32 glyphBitmapSizeInBytes = CAST(i32) glyphBitmaps[i].dimensions.w *
|
i32 glyphBitmapSizeInBytes = CAST(i32) glyphBitmaps[i].dimensions.w *
|
||||||
@ -489,3 +493,25 @@ void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena,
|
|||||||
|
|
||||||
assetManager->anims[animId] = anim;
|
assetManager->anims[animId] = anim;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v2 asset_stringDimInPixels(const Font *const font, const char *const string)
|
||||||
|
{
|
||||||
|
v2 stringDim = V2(0, 0);
|
||||||
|
for (i32 i = 0; i < common_strlen(string); i++)
|
||||||
|
{
|
||||||
|
i32 codepoint = string[i];
|
||||||
|
|
||||||
|
#ifdef DENGINE_DEBUG
|
||||||
|
ASSERT(codepoint >= font->codepointRange.x &&
|
||||||
|
codepoint <= font->codepointRange.y)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
i32 relativeIndex = CAST(i32)(codepoint - font->codepointRange.x);
|
||||||
|
|
||||||
|
v2 charDim = font->charMetrics[relativeIndex].trueSize;
|
||||||
|
stringDim.x += charDim.x;
|
||||||
|
stringDim.y = (charDim.y > stringDim.y) ? charDim.y : stringDim.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringDim;
|
||||||
|
}
|
||||||
|
@ -81,7 +81,7 @@ void debug_init(MemoryArena *arena, v2 windowSize, Font font)
|
|||||||
{
|
{
|
||||||
GLOBAL_debug.font = font;
|
GLOBAL_debug.font = font;
|
||||||
GLOBAL_debug.callCount = PLATFORM_MEM_ALLOC(arena, debugcallcount_num, i32);
|
GLOBAL_debug.callCount = PLATFORM_MEM_ALLOC(arena, debugcallcount_num, i32);
|
||||||
GLOBAL_debug.stringLineGap = 1.1f * asset_getVFontSpacing(font.metrics);
|
GLOBAL_debug.stringLineGap = CAST(f32)font.verticalSpacing;
|
||||||
|
|
||||||
/* Init debug string stack */
|
/* Init debug string stack */
|
||||||
GLOBAL_debug.numDebugStrings = 0;
|
GLOBAL_debug.numDebugStrings = 0;
|
||||||
@ -357,7 +357,7 @@ void debug_drawUi(GameState *state, f32 dt)
|
|||||||
renderer_string(&state->renderer, &state->arena, camera, font,
|
renderer_string(&state->renderer, &state->arena, camera, font,
|
||||||
debugString, strPos, V2(0, 0), 0, color);
|
debugString, strPos, V2(0, 0), 0, color);
|
||||||
|
|
||||||
f32 stringLineGap = 1.1f * asset_getVFontSpacing(font->metrics);
|
f32 stringLineGap = 1.1f * font->verticalSpacing;
|
||||||
strPos.y -= GLOBAL_debug.stringLineGap;
|
strPos.y -= GLOBAL_debug.stringLineGap;
|
||||||
|
|
||||||
char entityPosStr[128];
|
char entityPosStr[128];
|
||||||
|
@ -211,7 +211,9 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
|
|||||||
v2 posInCameraSpace = v2_sub(pos, camera.pos);
|
v2 posInCameraSpace = v2_sub(pos, camera.pos);
|
||||||
|
|
||||||
pos = posInCameraSpace;
|
pos = posInCameraSpace;
|
||||||
f32 baseline = pos.y;
|
|
||||||
|
// TODO(doyle): Find why font is 1px off, might be arial font semantics
|
||||||
|
f32 baseline = pos.y - font->verticalSpacing + 1;
|
||||||
for (i32 i = 0; i < strLen; i++)
|
for (i32 i = 0; i < strLen; i++)
|
||||||
{
|
{
|
||||||
// NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint
|
// NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
#include "Dengine/UserInterface.h"
|
#include "Dengine/UserInterface.h"
|
||||||
|
#include "Dengine/AssetManager.h"
|
||||||
#include "Dengine/Assets.h"
|
#include "Dengine/Assets.h"
|
||||||
#include "Dengine/Renderer.h"
|
#include "Dengine/Renderer.h"
|
||||||
|
#include "Dengine/Debug.h"
|
||||||
|
|
||||||
i32 userInterface_button(UiState *const uiState,
|
i32 userInterface_button(UiState *const uiState,
|
||||||
|
MemoryArena *const arena,
|
||||||
AssetManager *const assetManager,
|
AssetManager *const assetManager,
|
||||||
Renderer *const renderer, const KeyInput input,
|
Renderer *const renderer,
|
||||||
const i32 id, const Rect rect)
|
Font *const font,
|
||||||
|
const KeyInput input,
|
||||||
|
const i32 id, const Rect rect, const char *const label)
|
||||||
{
|
{
|
||||||
if (math_pointInRect(rect, input.mouseP))
|
if (math_pointInRect(rect, input.mouseP))
|
||||||
{
|
{
|
||||||
@ -33,25 +38,60 @@ i32 userInterface_button(UiState *const uiState,
|
|||||||
renderer_staticRect(renderer, v2_add(V2(8, 8), rect.pos), rect.size,
|
renderer_staticRect(renderer, v2_add(V2(8, 8), rect.pos), rect.size,
|
||||||
V2(0, 0), 0, renderTex, V4(0, 0, 0, 1));
|
V2(0, 0), 0, renderTex, V4(0, 0, 0, 1));
|
||||||
|
|
||||||
|
v2 buttonOffset = V2(0, 0);
|
||||||
if (uiState->hotItem == id)
|
if (uiState->hotItem == id)
|
||||||
{
|
{
|
||||||
if (uiState->activeItem == id)
|
if (uiState->activeItem == id)
|
||||||
{
|
{
|
||||||
renderer_staticRect(renderer, v2_add(V2(2, 2), rect.pos), rect.size,
|
buttonOffset = V2(2, 2);
|
||||||
V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
|
renderer_staticRect(renderer, v2_add(buttonOffset, rect.pos),
|
||||||
|
rect.size, V2(0, 0), 0, renderTex,
|
||||||
|
V4(1, 1, 1, 1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
|
renderer_staticRect(renderer, v2_add(buttonOffset, rect.pos),
|
||||||
V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
|
rect.size, V2(0, 0), 0, renderTex,
|
||||||
|
V4(1, 1, 1, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
|
renderer_staticRect(renderer, v2_add(buttonOffset, rect.pos), rect.size,
|
||||||
V2(0, 0), 0, renderTex, V4(0.5f, 0.5f, 0.5f, 1));
|
V2(0, 0), 0, renderTex, V4(0.5f, 0.5f, 0.5f, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (label)
|
||||||
|
{
|
||||||
|
v2 labelDim = asset_stringDimInPixels(font, label);
|
||||||
|
DEBUG_PUSH_VAR("label dim: %4.2f, %4.2f", labelDim, "v2");
|
||||||
|
v2 labelPos = rect.pos;
|
||||||
|
if (labelDim.w < rect.size.w)
|
||||||
|
{
|
||||||
|
// Initially position the label to half the width of the button
|
||||||
|
labelPos.x += (rect.size.w * 0.5f);
|
||||||
|
|
||||||
|
// Move the label pos back half the length of the string (i.e.
|
||||||
|
// center it)
|
||||||
|
labelPos.x -= (CAST(f32)labelDim.w * 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelDim.h < rect.size.h)
|
||||||
|
{
|
||||||
|
labelPos.y += (rect.size.h * 0.5f);
|
||||||
|
labelPos.y -= (CAST(f32)labelDim.h * 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
labelPos = v2_add(labelPos, buttonOffset);
|
||||||
|
renderer_staticString(renderer, arena, font, label, labelPos, V2(0, 0),
|
||||||
|
0, V4(0, 0, 0, 1));
|
||||||
|
|
||||||
|
v2 rulerPos = rect.pos;
|
||||||
|
rulerPos.y -= 10;
|
||||||
|
renderer_staticRect(renderer, rulerPos, V2(10, 10), V2(0, 0), 0,
|
||||||
|
renderTex, V4(0.5f, 0.1f, 0.7f, 1));
|
||||||
|
}
|
||||||
|
|
||||||
// After renderering before click check, see if we need to process keys
|
// After renderering before click check, see if we need to process keys
|
||||||
if (uiState->kbdItem == id)
|
if (uiState->kbdItem == id)
|
||||||
{
|
{
|
||||||
@ -194,7 +234,7 @@ i32 userInterface_scrollBar(UiState *const uiState,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 userInterface_textField(UiState *const uiState, MemoryArena *arena,
|
i32 userInterface_textField(UiState *const uiState, MemoryArena *const arena,
|
||||||
AssetManager *const assetManager,
|
AssetManager *const assetManager,
|
||||||
Renderer *const renderer, Font *const font,
|
Renderer *const renderer, Font *const font,
|
||||||
KeyInput input, const i32 id, v2 pos,
|
KeyInput input, const i32 id, v2 pos,
|
||||||
@ -244,8 +284,7 @@ i32 userInterface_textField(UiState *const uiState, MemoryArena *arena,
|
|||||||
renderTex, V4(0.5f, 0.5f, 0.5f, 1));
|
renderTex, V4(0.5f, 0.5f, 0.5f, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(doyle): Figure out why we need to offset text ..
|
v2 strPos = textRect.pos;
|
||||||
v2 strPos = v2_add(textRect.pos, V2(0, -font->maxSize.h));
|
|
||||||
|
|
||||||
renderer_staticString(renderer, arena, font, string, strPos, V2(0, 0), 0,
|
renderer_staticString(renderer, arena, font, string, strPos, V2(0, 0), 0,
|
||||||
V4(0, 0, 0, 1));
|
V4(0, 0, 0, 1));
|
||||||
|
@ -1305,16 +1305,16 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
|
|
||||||
/* Draw ui */
|
/* Draw ui */
|
||||||
Rect buttonRectA = {V2(300, 500), V2(100, 50)};
|
Rect buttonRectA = {V2(300, 500), V2(100, 50)};
|
||||||
userInterface_button(&state->uiState, assetManager, renderer, state->input,
|
userInterface_button(&state->uiState, &state->arena, assetManager, renderer,
|
||||||
1, buttonRectA);
|
font, state->input, 1, buttonRectA, "HELLO WORLD");
|
||||||
|
|
||||||
Rect buttonRectB = {V2(500, 500), V2(100, 50)};
|
Rect buttonRectB = {V2(500, 500), V2(100, 50)};
|
||||||
userInterface_button(&state->uiState, assetManager, renderer, state->input,
|
userInterface_button(&state->uiState, &state->arena, assetManager, renderer,
|
||||||
2, buttonRectB);
|
font, state->input, 2, buttonRectB, "button2");
|
||||||
|
|
||||||
Rect buttonRectC = {V2(700, 500), V2(100, 50)};
|
Rect buttonRectC = {V2(700, 500), V2(100, 50)};
|
||||||
userInterface_button(&state->uiState, assetManager, renderer, state->input,
|
userInterface_button(&state->uiState, &state->arena, assetManager, renderer,
|
||||||
3, buttonRectC);
|
font, state->input, 3, buttonRectC, "button3");
|
||||||
|
|
||||||
LOCAL_PERSIST i32 scrollValue = 30;
|
LOCAL_PERSIST i32 scrollValue = 30;
|
||||||
Rect scrollRectA = {V2(900, 500), V2(16, 255)};
|
Rect scrollRectA = {V2(900, 500), V2(16, 255)};
|
||||||
@ -1356,6 +1356,9 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr,
|
renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr,
|
||||||
strPos, V2(0, 0), 0, V4(0, 0, 1, 1));
|
strPos, V2(0, 0), 0, V4(0, 0, 1, 1));
|
||||||
|
|
||||||
|
renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr,
|
||||||
|
strPos, V2(0, 0), 0, V4(0, 0, 1, 1));
|
||||||
|
|
||||||
for (i32 i = 0; i < world->maxEntities; i++)
|
for (i32 i = 0; i < world->maxEntities; i++)
|
||||||
{
|
{
|
||||||
Entity *entity = &world->entities[i];
|
Entity *entity = &world->entities[i];
|
||||||
|
@ -43,14 +43,10 @@ const i32 asset_loadShaderFiles(AssetManager *assetManager, MemoryArena *arena,
|
|||||||
const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
|
const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
|
||||||
const char *filePath);
|
const char *filePath);
|
||||||
|
|
||||||
inline i32 asset_getVFontSpacing(FontMetrics metrics)
|
|
||||||
{
|
|
||||||
i32 result = metrics.ascent - metrics.descent + metrics.lineGap;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena,
|
void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena,
|
||||||
i32 texId, i32 animId, i32 *atlasIndexes, i32 numFrames,
|
i32 texId, i32 animId, i32 *atlasIndexes, i32 numFrames,
|
||||||
f32 frameDuration);
|
f32 frameDuration);
|
||||||
|
|
||||||
|
v2 asset_stringDimInPixels(const Font *const font, const char *const string);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -118,8 +118,13 @@ typedef struct Font
|
|||||||
Texture *tex;
|
Texture *tex;
|
||||||
|
|
||||||
FontMetrics metrics;
|
FontMetrics metrics;
|
||||||
|
|
||||||
|
// NOTE(doyle): Array of character's by ASCII value starting from
|
||||||
|
// codepointRange and their metrics
|
||||||
CharMetrics *charMetrics;
|
CharMetrics *charMetrics;
|
||||||
|
|
||||||
|
i32 verticalSpacing;
|
||||||
|
|
||||||
v2 codepointRange;
|
v2 codepointRange;
|
||||||
v2 maxSize;
|
v2 maxSize;
|
||||||
|
|
||||||
|
@ -43,11 +43,16 @@ typedef struct UiState
|
|||||||
} UiState;
|
} UiState;
|
||||||
|
|
||||||
i32 userInterface_button(UiState *const uiState,
|
i32 userInterface_button(UiState *const uiState,
|
||||||
|
MemoryArena *const arena,
|
||||||
AssetManager *const assetManager,
|
AssetManager *const assetManager,
|
||||||
Renderer *const renderer, const KeyInput input,
|
Renderer *const renderer,
|
||||||
const i32 id, const Rect rect);
|
Font *const font,
|
||||||
|
const KeyInput input,
|
||||||
|
const i32 id, const Rect rect,
|
||||||
|
const char *const label);
|
||||||
|
|
||||||
i32 userInterface_textField(UiState *const uiState, MemoryArena *arena,
|
i32 userInterface_textField(UiState *const uiState,
|
||||||
|
MemoryArena *const arena,
|
||||||
AssetManager *const assetManager,
|
AssetManager *const assetManager,
|
||||||
Renderer *const renderer, Font *const font,
|
Renderer *const renderer, Font *const font,
|
||||||
KeyInput input, const i32 id, v2 pos,
|
KeyInput input, const i32 id, v2 pos,
|
||||||
|
@ -16,6 +16,11 @@
|
|||||||
/* Forward declaration */
|
/* Forward declaration */
|
||||||
typedef struct Entity Entity;
|
typedef struct Entity Entity;
|
||||||
|
|
||||||
|
typedef struct Config
|
||||||
|
{
|
||||||
|
b32 playWorldAudio;
|
||||||
|
} Config;
|
||||||
|
|
||||||
typedef struct World
|
typedef struct World
|
||||||
{
|
{
|
||||||
Entity *entities;
|
Entity *entities;
|
||||||
@ -49,6 +54,7 @@ typedef struct GameState
|
|||||||
|
|
||||||
AssetManager assetManager;
|
AssetManager assetManager;
|
||||||
AudioManager audioManager;
|
AudioManager audioManager;
|
||||||
|
Config config;
|
||||||
MemoryArena arena;
|
MemoryArena arena;
|
||||||
UiState uiState;
|
UiState uiState;
|
||||||
} GameState;
|
} GameState;
|
||||||
|
Loading…
Reference in New Issue
Block a user