From 0ed65d37037c2340425e14c3eda6ac649e77dd9b Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sat, 21 Jun 2025 23:14:24 -0500 Subject: [PATCH] unfinished ui textbox --- data/map project.tiled-session | 6 +- data/map.tmj | 8 +- src/dusk/CMakeLists.txt | 2 + src/dusk/dusk.h | 3 +- src/dusk/entity/npc.c | 4 +- src/dusk/entity/player.c | 11 ++ src/dusk/entity/player.h | 3 + src/dusk/item/CMakeLists.txt | 10 ++ src/dusk/item/inventory.c | 68 +++++++++++ src/dusk/item/inventory.h | 63 ++++++++++ src/dusk/item/itemstack.h | 14 +++ src/dusk/item/itemtype.h | 24 ++++ src/dusk/main.c | 5 + src/dusk/ui/CMakeLists.txt | 10 ++ src/dusk/ui/font.h | 18 +++ src/dusk/ui/uitextbox.c | 128 ++++++++++++++++++++ src/dusk/ui/uitextbox.h | 70 +++++++++++ src/duskraylib/display/draw/CMakeLists.txt | 1 + src/duskraylib/display/draw/drawoverworld.c | 2 - src/duskraylib/display/draw/drawui.c | 83 +++++++++++++ src/duskraylib/display/draw/drawui.h | 24 ++++ src/duskraylib/display/render.c | 7 ++ 22 files changed, 553 insertions(+), 11 deletions(-) create mode 100644 src/dusk/item/CMakeLists.txt create mode 100644 src/dusk/item/inventory.c create mode 100644 src/dusk/item/inventory.h create mode 100644 src/dusk/item/itemstack.h create mode 100644 src/dusk/item/itemtype.h create mode 100644 src/dusk/ui/CMakeLists.txt create mode 100644 src/dusk/ui/font.h create mode 100644 src/dusk/ui/uitextbox.c create mode 100644 src/dusk/ui/uitextbox.h create mode 100644 src/duskraylib/display/draw/drawui.c create mode 100644 src/duskraylib/display/draw/drawui.h diff --git a/data/map project.tiled-session b/data/map project.tiled-session index d3c06f1..18bcdef 100644 --- a/data/map project.tiled-session +++ b/data/map project.tiled-session @@ -1,5 +1,5 @@ { - "activeFile": "overworld.tsx", + "activeFile": "map.tmj", "expandedProjectPaths": [ ".", "templates" @@ -14,7 +14,7 @@ }, "map.tmj": { "scale": 3, - "selectedLayer": 0, + "selectedLayer": 2, "viewCenter": { "x": 6520.166666666666, "y": 6836.833333333333 @@ -35,8 +35,8 @@ "project": "map project.tiled-project", "property.type": "int", "recentFiles": [ - "map.tmj", "overworld.tsx", + "map.tmj", "entities.tsx" ], "tileset.lastUsedFilter": "Tiled tileset files (*.tsx *.xml)", diff --git a/data/map.tmj b/data/map.tmj index bd88d28..0ffb465 100644 --- a/data/map.tmj +++ b/data/map.tmj @@ -425,14 +425,14 @@ "type":"player_spawn", "visible":true, "width":16, - "x":6607.58333333333, - "y":6944.25 + "x":6384.58333333333, + "y":6846.91666666667 }, { "id":7, "template":"templates\/NPC.tx", - "x":6700.25, - "y":6838.75 + "x":6383.25, + "y":6880.08333333333 }, { "id":8, diff --git a/src/dusk/CMakeLists.txt b/src/dusk/CMakeLists.txt index 3cbbb57..168bf64 100644 --- a/src/dusk/CMakeLists.txt +++ b/src/dusk/CMakeLists.txt @@ -25,6 +25,8 @@ target_sources(${DUSK_TARGET_NAME} add_subdirectory(assert) add_subdirectory(display) add_subdirectory(entity) +add_subdirectory(item) add_subdirectory(physics) +add_subdirectory(ui) add_subdirectory(util) add_subdirectory(world) \ No newline at end of file diff --git a/src/dusk/dusk.h b/src/dusk/dusk.h index 7a00120..3bbf93a 100644 --- a/src/dusk/dusk.h +++ b/src/dusk/dusk.h @@ -15,4 +15,5 @@ typedef bool bool_t; typedef int int_t; -typedef float float_t; \ No newline at end of file +typedef float float_t; +typedef char char_t; \ No newline at end of file diff --git a/src/dusk/entity/npc.c b/src/dusk/entity/npc.c index c192a7f..162a811 100644 --- a/src/dusk/entity/npc.c +++ b/src/dusk/entity/npc.c @@ -7,6 +7,8 @@ #include "npc.h" +#include "ui/uitextbox.h" + void npcInit(entity_t *entity) { } @@ -16,5 +18,5 @@ void npcUpdate(entity_t *entity) { } void npcInteract(entity_t *player, entity_t *self) { - printf("I am being interacted with!\n"); + uiTextboxSetText("Hello World"); } \ No newline at end of file diff --git a/src/dusk/entity/player.c b/src/dusk/entity/player.c index 3154c7d..e79654f 100644 --- a/src/dusk/entity/player.c +++ b/src/dusk/entity/player.c @@ -12,6 +12,10 @@ #include "world/world.h" #include "physics/physics.h" +#include "ui/uitextbox.h" + +inventory_t PLAYER_INVENTORY; + void playerInit() { entity_t *ent = &ENTITIES[0]; @@ -20,6 +24,8 @@ void playerInit() { ent->x = WORLD_PLAYER_SPAWN_X; ent->y = WORLD_PLAYER_SPAWN_Y; + + inventoryInit(&PLAYER_INVENTORY, INVENTORY_SIZE_MAX); } void playerNPCInit(entity_t *entity) { @@ -31,6 +37,11 @@ void playerNPCUpdate(entity_t *entity) { assertNotNull(entity, "Entity pointer cannot be NULL"); assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity type must be PLAYER"); + if(UI_TEXTBOX.visible) { + entity->vx = entity->vy = 0; + return; + } + if(inputIsDown(INPUT_BIND_UP)) { if(inputIsDown(INPUT_BIND_LEFT)) { entity->vx = -PLAYER_MOVE_SPEED_XY; diff --git a/src/dusk/entity/player.h b/src/dusk/entity/player.h index 564bcfa..b416bf4 100644 --- a/src/dusk/entity/player.h +++ b/src/dusk/entity/player.h @@ -8,6 +8,7 @@ #pragma once #include "dusk.h" #include "util/fixed.h" +#include "item/inventory.h" typedef struct _entity_t entity_t; @@ -23,6 +24,8 @@ typedef struct { ) #define PLAYER_INTERACT_ANGLE ((fixed248_t)175) +extern inventory_t PLAYER_INVENTORY; + /** * Initializes the player and all player-related entities. */ diff --git a/src/dusk/item/CMakeLists.txt b/src/dusk/item/CMakeLists.txt new file mode 100644 index 0000000..19db837 --- /dev/null +++ b/src/dusk/item/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +# Sources +target_sources(${DUSK_TARGET_NAME} + PRIVATE + inventory.c +) \ No newline at end of file diff --git a/src/dusk/item/inventory.c b/src/dusk/item/inventory.c new file mode 100644 index 0000000..d123cf2 --- /dev/null +++ b/src/dusk/item/inventory.c @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "inventory.h" +#include "util/memory.h" +#include "assert/assert.h" + +void inventoryInit(inventory_t *inventory, const uint8_t size) { + assertNotNull(inventory, "inventory must not be NULL"); + assertTrue(size <= INVENTORY_SIZE_MAX, "size exceeding INVENTORY_SIZE_MAX"); + assertTrue(size > 0, "size must be greater than 0"); + + memoryZero(inventory, sizeof(inventory_t)); + inventory->size = size; +} + +uint8_t inventoryItemIndexByType( + const inventory_t *inventory, + const itemtype_t type +) { + assertNotNull(inventory, "inventory must not be NULL"); + assertTrue(type > ITEM_TYPE_NULL, "type must be greater than ITEM_TYPE_NULL"); + + uint8_t item = inventory->itemCount; + while(item--) { + if(inventory->items[item].type == type) return item; + } + return INVENTORY_SIZE_MAX; +} + +uint8_t inventoryItemCount( + const inventory_t *inventory, + const itemtype_t type +) { + assertNotNull(inventory, "inventory must not be NULL"); + assertTrue(type > ITEM_TYPE_NULL, "type must be greater than ITEM_TYPE_NULL"); + + const uint8_t index = inventoryItemIndexByType(inventory, type); + if(index == INVENTORY_SIZE_MAX) return 0; + return inventory->items[index].count; +} + +void inventoryItemSet( + inventory_t *inventory, + const itemtype_t type, + const uint8_t count +) { + assertNotNull(inventory, "inventory must not be NULL"); + assertTrue(type > ITEM_TYPE_NULL, "type must be greater than ITEM_TYPE_NULL"); + assertTrue(count > 0, "count must be greater than 0"); + + const uint8_t index = inventoryItemIndexByType(inventory, type); + + if(index == INVENTORY_SIZE_MAX) { + // Item does not exist, add it + assertTrue(inventory->itemCount < inventory->size, "inventory is full"); + inventory->items[inventory->itemCount].type = type; + inventory->items[inventory->itemCount].count = count; + inventory->itemCount++; + } else { + // Item exists, update the count + inventory->items[index].count = count; + } +} \ No newline at end of file diff --git a/src/dusk/item/inventory.h b/src/dusk/item/inventory.h new file mode 100644 index 0000000..3515b96 --- /dev/null +++ b/src/dusk/item/inventory.h @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "itemstack.h" + +#define INVENTORY_SIZE_MAX UINT8_MAX + +typedef struct { + itemstack_t items[INVENTORY_SIZE_MAX]; + uint8_t itemCount; + uint8_t size; +} inventory_t; + +/** + * Initializes an inventory with a specified size. + * + * @param inventory Pointer to the inventory to initialize. + * @param size The size of the inventory (maximum is INVENTORY_SIZE_MAX). + */ +void inventoryInit(inventory_t *inventory, const uint8_t size); + +/** + * Finds the index of the item of a specified type in the inventory. + * + * @param inventory Pointer to the inventory to search. + * @param type The type of item to find. + * @return The index of the item, or INVENTORY_SIZE_MAX if not found. + */ +uint8_t inventoryItemIndexByType( + const inventory_t *inventory, + const itemtype_t type +); + +/** + * Gets the count of items of a specified type in the inventory. + * + * @param inventory Pointer to the inventory to check. + * @param type The type of item to count. + * @return The count of items of the specified type. + */ +uint8_t inventoryItemCount( + const inventory_t *inventory, + const itemtype_t type +); + +/** + * Sets the count of items of a specified type in the inventory. + * If the item does not exist, it will be added. + * + * @param inventory Pointer to the inventory to modify. + * @param type The type of item to set. + * @param count The count of items to set. + */ +void inventoryItemSet( + inventory_t *inventory, + const itemtype_t type, + const uint8_t count +); \ No newline at end of file diff --git a/src/dusk/item/itemstack.h b/src/dusk/item/itemstack.h new file mode 100644 index 0000000..b691d5d --- /dev/null +++ b/src/dusk/item/itemstack.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "itemtype.h" + +typedef struct { + itemtype_t type; + uint8_t count; +} itemstack_t; \ No newline at end of file diff --git a/src/dusk/item/itemtype.h b/src/dusk/item/itemtype.h new file mode 100644 index 0000000..3f07403 --- /dev/null +++ b/src/dusk/item/itemtype.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef enum { + ITEM_TYPE_NULL = 0, + + // MEDICINE + ITEM_TYPE_POTION, + + // INGREDIENTS + ITEM_TYPE_ONION, + ITEM_TYPE_SWEET_POTATO, + ITEM_TYPE_CARROT, + + // COOKED FOOD + ITEM_TYPE_BAKED_SWEET_POTATO, +} itemtype_t; \ No newline at end of file diff --git a/src/dusk/main.c b/src/dusk/main.c index 9e80948..0a73a98 100644 --- a/src/dusk/main.c +++ b/src/dusk/main.c @@ -12,10 +12,13 @@ #include "world/overworld.h" #include "input.h" +#include "ui/uitextbox.h" + // Press F5 to compile and run the compiled game.gb in the Emulicous Emulator/Debugger void main(void) { renderInit(); inputInit(); + uiTextboxInit(); overworldInit(); @@ -27,6 +30,8 @@ void main(void) { overworldUpdate(); + uiTextboxUpdate(); + // Update input for next frame. inputUpdate(); } diff --git a/src/dusk/ui/CMakeLists.txt b/src/dusk/ui/CMakeLists.txt new file mode 100644 index 0000000..f01c8a4 --- /dev/null +++ b/src/dusk/ui/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +# Sources +target_sources(${DUSK_TARGET_NAME} + PRIVATE + uitextbox.c +) \ No newline at end of file diff --git a/src/dusk/ui/font.h b/src/dusk/ui/font.h new file mode 100644 index 0000000..cfdd11f --- /dev/null +++ b/src/dusk/ui/font.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +#define FONT_HEIGHT 8 +#define FONT_LINE_SPACING 1 + +#define FONT_LINE_HEIGHT ( \ + FONT_HEIGHT + FONT_LINE_SPACING \ +) + +// \ No newline at end of file diff --git a/src/dusk/ui/uitextbox.c b/src/dusk/ui/uitextbox.c new file mode 100644 index 0000000..398fc26 --- /dev/null +++ b/src/dusk/ui/uitextbox.c @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "uitextbox.h" +#include "util/memory.h" +#include "assert/assert.h" +#include "input.h" + +uitextbox_t UI_TEXTBOX; + +void uiTextboxInit() { + memoryZero(&UI_TEXTBOX, sizeof(uitextbox_t)); +} + +void uiTextboxUpdate() { + if(UI_TEXTBOX.visible == false) return; + + if(UI_TEXTBOX.charsRevealed < UI_TEXTBOX.pageChars[UI_TEXTBOX.page]) { + if((RENDER_FRAME % 4) == 0) { + // printf("Revealing char\n"); + UI_TEXTBOX.charsRevealed++; + } else if(inputIsDown(INPUT_BIND_ACTION)) { + UI_TEXTBOX.charsRevealed++; + } + + } else { + if(inputPressed(INPUT_BIND_ACTION)) { + if(UI_TEXTBOX.page <= UI_TEXTBOX.pageCount - 1) { + uitextbox_t *textbox = &UI_TEXTBOX; + printf("next page?\n"); + UI_TEXTBOX.page++; + UI_TEXTBOX.charsRevealed = 0; + } else { + printf("Closing textbox\n"); + // Close the textbox + UI_TEXTBOX.visible = false; + UI_TEXTBOX.page = 0; + UI_TEXTBOX.charsRevealed = 0; + } + } + } +} + +void uiTextboxSetText(const char_t *text) { + assertNotNull(text, "Text pointer cannot be NULL, call uiTextboxClose()"); + + memoryZero(UI_TEXTBOX.text, sizeof(UI_TEXTBOX.text)); + memoryZero(UI_TEXTBOX.lineLengths, sizeof(UI_TEXTBOX.lineLengths)); + memoryZero(UI_TEXTBOX.pageChars, sizeof(UI_TEXTBOX.pageChars)); + UI_TEXTBOX.pageCount = 0; + UI_TEXTBOX.totalChars = 0; + UI_TEXTBOX.page = 0; + UI_TEXTBOX.charsRevealed = 0; + UI_TEXTBOX.visible = true; + + char_t c; + uint16_t i = 0; + uint16_t j = 0; + uint8_t line = 0; + while((c = text[i++]) != '\0') { + assertTrue(c != '\r', "Carriage return characters not allowed."); + assertTrue(c != '\t', "Tab characters not allowed."); + + if(c == '\n') { + goto newline; + } else { + goto character; + } + + newline: { + line++; + if(line >= UI_TEXTBOX_LINE_COUNT) { + goto newPage; + } + continue; + } + + character: { + UI_TEXTBOX.text[j] = c; + UI_TEXTBOX.totalChars++; + UI_TEXTBOX.lineLengths[line]++; + UI_TEXTBOX.pageChars[UI_TEXTBOX.pageCount]++; + } + + newPage: { + assertTrue( + UI_TEXTBOX.pageCount < UI_TEXTBOX_PAGE_COUNT_MAX, + "Exceeded maximum number of pages in textbox." + ); + UI_TEXTBOX.pageCount++; + line = 0; + continue; + // j = 0; // Reset character index for new page + } + + assertUnreachable("Code should not reach here, all cases handled."); + } + + + + + // Hard coded testing values + // char_t buffer[UI_TEXTBOX_CHARS_PER_LINE]; + // uint8_t line; + + // for(line = 0; line < UI_TEXTBOX_LINE_COUNT; line++) { + // // Set the text for each line + // sprintf(buffer, "HC Line %d", line); + // UI_TEXTBOX.lineLengths[line] = strlen(text); // Set line length for each line + // UI_TEXTBOX.totalChars += UI_TEXTBOX.lineLengths[line]; + // UI_TEXTBOX.pageChars[UI_TEXTBOX.pageCount] += UI_TEXTBOX.lineLengths[line]; + + // memoryCopy( + // UI_TEXTBOX.text + line * (UI_TEXTBOX_CHARS_PER_LINE), + // buffer, + // UI_TEXTBOX.lineLengths[line] + // ); + + // if(line == 3 || line == 7 || line == 11 || line == 15) { + // // Increment page count every 4 lines + // UI_TEXTBOX.pageCount++; + // } + // } +} \ No newline at end of file diff --git a/src/dusk/ui/uitextbox.h b/src/dusk/ui/uitextbox.h new file mode 100644 index 0000000..3330a4a --- /dev/null +++ b/src/dusk/ui/uitextbox.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "display/renderbase.h" +#include "ui/font.h" + +#define UI_TEXTBOX_LINES_PER_PAGE 4 +#define UI_TEXTBOX_WIDTH RENDER_WIDTH +#define UI_TEXTBOX_HEIGHT_INNER ( \ + FONT_LINE_HEIGHT * UI_TEXTBOX_LINES_PER_PAGE \ +) + +#define UI_TEXTBOX_BORDER_WIDTH 1 +#define UI_TEXTBOX_BORDER_HEIGHT 1 +#define UI_TEXTBOX_PADDING_X 1 +#define UI_TEXTBOX_PADDING_Y 1 +#define UI_TEXTBOX_WIDTH_INNER ( \ + UI_TEXTBOX_WIDTH - (UI_TEXTBOX_BORDER_WIDTH * 2) - \ + (UI_TEXTBOX_PADDING_X * 2) \ +) +#define UI_TEXTBOX_HEIGHT ( \ + UI_TEXTBOX_HEIGHT_INNER + (UI_TEXTBOX_BORDER_HEIGHT * 2) + \ + (UI_TEXTBOX_PADDING_Y * 2) \ +) + +#define UI_TEXTBOX_CHARS_PER_LINE UI_TEXTBOX_WIDTH_INNER +#define UI_TEXTBOX_PAGE_CHARS ( \ + UI_TEXTBOX_CHARS_PER_LINE * UI_TEXTBOX_LINES_PER_PAGE \ +) +#define UI_TEXTBOX_PAGE_COUNT_MAX 6 +#define UI_TEXTBOX_LINE_COUNT ( \ + UI_TEXTBOX_LINES_PER_PAGE * UI_TEXTBOX_PAGE_COUNT_MAX \ +) +#define UI_TEXTBOX_CHARS_MAX ( \ + UI_TEXTBOX_PAGE_CHARS * UI_TEXTBOX_PAGE_COUNT_MAX \ +) + +typedef struct { + char_t text[UI_TEXTBOX_CHARS_MAX]; + uint8_t lineLengths[UI_TEXTBOX_LINE_COUNT]; + uint8_t pageCount; + uint8_t pageChars[UI_TEXTBOX_PAGE_COUNT_MAX]; + uint16_t totalChars; + + uint8_t page; + uint8_t charsRevealed; + + bool_t visible; +} uitextbox_t; + +extern uitextbox_t UI_TEXTBOX; + +/** + * Initializes the UI textbox. + */ +void uiTextboxInit(void); + +/** + * Updates the UI textbox, handling text input and scrolling. + */ +void uiTextboxUpdate(void); + +void uiTextboxSetText( + const char_t *text +); \ No newline at end of file diff --git a/src/duskraylib/display/draw/CMakeLists.txt b/src/duskraylib/display/draw/CMakeLists.txt index 456174c..f01b9ec 100644 --- a/src/duskraylib/display/draw/CMakeLists.txt +++ b/src/duskraylib/display/draw/CMakeLists.txt @@ -8,4 +8,5 @@ target_sources(${DUSK_TARGET_NAME} PRIVATE drawscene.c drawoverworld.c + drawui.c ) \ No newline at end of file diff --git a/src/duskraylib/display/draw/drawoverworld.c b/src/duskraylib/display/draw/drawoverworld.c index be55c38..47b83be 100644 --- a/src/duskraylib/display/draw/drawoverworld.c +++ b/src/duskraylib/display/draw/drawoverworld.c @@ -47,7 +47,6 @@ void drawOverworldDraw(void) { }; uint8_t colorCount = sizeof(colors) / sizeof(Color); - BeginBlendMode(BLEND_ALPHA_PREMULTIPLY); do { // Base layer for(uint8_t i = 0; i < CHUNK_TILE_COUNT; i++) { @@ -99,7 +98,6 @@ void drawOverworldDraw(void) { chunk++; } while(chunk < CHUNK_MAP.chunks + CHUNK_MAP_COUNT); - EndBlendMode(); // Entities entity_t *entity = ENTITIES; diff --git a/src/duskraylib/display/draw/drawui.c b/src/duskraylib/display/draw/drawui.c new file mode 100644 index 0000000..0652f1f --- /dev/null +++ b/src/duskraylib/display/draw/drawui.c @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "drawui.h" +#include "ui/uitextbox.h" +#include "util/memory.h" +#include "assert/assert.h" + +void drawUIInit(void) { +} + +void drawUI() { + drawUITextbox(); +} + +void drawUITextbox() { + if(!UI_TEXTBOX.visible) return; + + // Semi-transparent dark blue + Color background = (Color){ 0, 0, 128, 128 }; + DrawRectangle( + 0, RENDER_HEIGHT - UI_TEXTBOX_HEIGHT, + UI_TEXTBOX_WIDTH, UI_TEXTBOX_HEIGHT, + background + ); + + BeginBlendMode(BLEND_ALPHA); + + if(UI_TEXTBOX.charsRevealed > 0) { + char_t buffer[UI_TEXTBOX_CHARS_PER_LINE + 1];// +1 for null term + uint8_t charsRendered = 0; + + // For each line + for(uint8_t i = 0; i < UI_TEXTBOX_LINES_PER_PAGE; i++) { + // Get count of chars in the line + uint8_t lineLength = UI_TEXTBOX.lineLengths[i]; + if(lineLength == 0) continue; + + // Determine how many chars left to render + uint8_t lineChars = UI_TEXTBOX.charsRevealed - charsRendered; + + // Don't render more than in line + if(lineChars > lineLength) lineChars = lineLength; + assertTrue(lineChars > 0, "Line chars must be greater than 0"); + + // Update how many rendered + charsRendered += lineChars; + + + // Copy string from VN Textbox... + memoryCopy( + buffer, + UI_TEXTBOX.text + (UI_TEXTBOX.page * UI_TEXTBOX_PAGE_CHARS) + + (i * UI_TEXTBOX_CHARS_PER_LINE), + lineChars + ); + // Null term string + buffer[lineChars] = '\0'; // Null-terminate the string + + // Render the text + DrawText( + buffer, + UI_TEXTBOX_PADDING_X + UI_TEXTBOX_BORDER_WIDTH, + ( + (RENDER_HEIGHT - UI_TEXTBOX_HEIGHT) + + UI_TEXTBOX_PADDING_Y + UI_TEXTBOX_BORDER_HEIGHT + + (i * FONT_LINE_HEIGHT) + ), + FONT_HEIGHT, + WHITE + ); + + // Check if we're done rendering text + if(UI_TEXTBOX.charsRevealed - charsRendered == 0) break; + } + } + + EndBlendMode(); +} \ No newline at end of file diff --git a/src/duskraylib/display/draw/drawui.h b/src/duskraylib/display/draw/drawui.h new file mode 100644 index 0000000..1e282cb --- /dev/null +++ b/src/duskraylib/display/draw/drawui.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "duskraylib.h" + +/** + * Initializes the UI drawing system. + */ +void drawUIInit(void); + +/** + * Draws all the UI elements to the screen in the correct order. + */ +void drawUI(void); + +/** + * Draws the UI textbox to the screen. + */ +void drawUITextbox(void); \ No newline at end of file diff --git a/src/duskraylib/display/render.c b/src/duskraylib/display/render.c index 2c47328..a706910 100644 --- a/src/duskraylib/display/render.c +++ b/src/duskraylib/display/render.c @@ -8,6 +8,7 @@ #include "render.h" #include "display/draw/drawscene.h" #include "display/draw/drawoverworld.h" +#include "display/draw/drawui.h" #include "assert/assert.h" RenderTexture2D RENDER_SCREEN_TEXTURE; @@ -32,14 +33,17 @@ void renderInit(void) { RENDER_ENTITIES_TEXTURE = LoadTexture("../data/entities.png"); drawOverworldInit(); + drawUIInit(); } void renderDraw(void) { // Draw the actual game. + BeginBlendMode(BLEND_ALPHA_PREMULTIPLY); BeginTextureMode(RENDER_SCREEN_TEXTURE); ClearBackground(BLACK); drawScene(); + drawUI(); EndTextureMode(); @@ -69,7 +73,10 @@ void renderDraw(void) { 0.0f, WHITE ); + EndDrawing(); + EndBlendMode(); + } void renderDispose(void) {