Add string length in pixel func, add button label

This commit is contained in:
Doyle Thai 2016-08-19 00:25:43 +10:00
parent c33b37b0ea
commit 90068d2c64
9 changed files with 110 additions and 28 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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