summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2025-08-11 11:27:18 +0200
committerMitja Felicijan <mitja.felicijan@gmail.com>2025-08-11 11:27:18 +0200
commit321a8063c025c8a1c20aa16e9a3a28d8065294eb (patch)
tree7be387566e101b7928caaf4c9b6d394800a7a569
parent62e411f297e3b7ba2b09c7ac6c371590528a5011 (diff)
downloadbidi-321a8063c025c8a1c20aa16e9a3a28d8065294eb.tar.gz
Added load and draw image
-rw-r--r--README.md18
-rw-r--r--main.c104
-rw-r--r--tests/test.lua24
3 files changed, 116 insertions, 30 deletions
diff --git a/README.md b/README.md
index 9e3d055..99252ea 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,9 @@
**Bidi** is a lightweight framework and fantasy console designed for creating
tiny video games, perfect for learning and having fun. It takes heavy
inspiration from [LÖVE](https://www.love2d.org/),
-[Pico8](https://www.lexaloffle.com/pico-8.php) and [Atari
-2600](https://en.wikipedia.org/wiki/Atari_2600).
+[Pico8](https://www.lexaloffle.com/pico-8.php), [Atari
+2600](https://en.wikipedia.org/wiki/Atari_2600) and [Windows
+3.1](https://en.wikipedia.org/wiki/Windows_3.1).
You develop your games in Lua and you are only allowed to have one Lua file
where all your code lives. You can then load external assets like images and
@@ -75,7 +76,8 @@ close_window()
| `draw_circle` | `number center_x`, `number center_y`, `number radius`, `color color` | |
| `draw_ellipse` | `number center_x`, `number center_y`, `number radius_h`, `number radius_v`, `color color` | |
| `draw_triangle` | `number x1`, `number y1`, `number x2`, `number y2`, `number x3`, `number y3`, `color color` | |
-| `load_image` | `TODO` | |
+| `load_image` | `string filepath` | `string` |
+| `draw_image` | `string uid`, `number x`, `number y` | |
| `load_audio` | `TODO` | |
| `button_down` | `button button` | `bool` |
| `button_pressed` | `button button` | `bool` |
@@ -138,6 +140,16 @@ close_window()
- https://hardwaretester.com/gamepad
- https://www.raylib.com/examples/core/loader.html?name=core_input_gamepad
+## Interesting games
+
+- https://www.old-games.com/download/3873/aethra-s-chronicles
+- https://www.old-games.com/download/10746/wintrek-1992
+- https://www.old-games.com/download/3887/bard-s-tale-1
+- https://www.old-games.com/download/3902/castle-of-the-winds
+- https://www.old-games.com/download/3923/decker
+- https://www.old-games.com/download/3920/darkspyre
+- https://www.old-games.com/download/6089/exile-3-ruined-world
+
## Development references
- https://www.love2d.org/wiki/Main_Page
diff --git a/main.c b/main.c
index 3cbec87..b51d47e 100644
--- a/main.c
+++ b/main.c
@@ -3,6 +3,7 @@
#include <getopt.h>
#include <stdlib.h>
#include <time.h>
+#include <string.h>
#include "raylib.h"
#include "lua.h"
@@ -24,31 +25,43 @@
#define XBOX_ALIAS_2 "x-box"
#define PS_ALIAS "playstation"
-typedef struct {
+typedef struct ExternalImage {
char uid[UID_LENGTH + 1];
- const char* filepath;
+ Texture2D texture;
+ struct ExternalImage *next;
} ExternalImage;
typedef struct {
-} ExternalAudio;
+ ExternalImage *head;
+ ExternalImage *tail;
+ int count;
+} ImageList;
typedef struct {
Font font;
int font_size;
Camera2D camera;
- ExternalImage *images;
- ExternalAudio *audio;
+ ImageList images;
} Context;
// Setting up global context.
Context ctx = {0};
-static void generate_uid(char *uid) {
- const char *chars = "0123456789abcdef";
- for (size_t i = 0; i < UID_LENGTH; i++) {
- uid[i] = chars[rand() % 16];
+static void generate_uid(char *str, size_t length) {
+ static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ size_t charset_size = sizeof(charset) - 1; // exclude null terminator
+
+ for (size_t i = 0; i < length; i++) {
+ int key = rand() % charset_size;
+ str[i] = charset[key];
}
- uid[UID_LENGTH + 1] = '\0';
+ str[length] = '\0';
+}
+
+void init_image_list(ImageList *list) {
+ list->head = NULL;
+ list->tail = NULL;
+ list->count = 0;
}
static int lua_getfield_int(lua_State *L, int index, const char *key) {
@@ -67,7 +80,7 @@ static int lua_getfield_int_opt(lua_State *L, int index, const char *key, int de
static int load_embedded_module(lua_State *L, const char *module_code, size_t code_len, const char *module_name) {
if (luaL_loadbuffer(L, module_code, code_len, module_name) || lua_pcall(L, 0, 1, 0)) {
- fprintf(stderr, "Error loading %s: %s\n", module_name, lua_tostring(L, -1));
+ TraceLog(LOG_FATAL, "Error loading %s: %s\n", module_name, lua_tostring(L, -1));
return 0;
}
lua_setglobal(L, module_name);
@@ -380,13 +393,64 @@ static int l_button_pressed(lua_State *L) {
}
static int l_load_image(lua_State *L) {
- return 0;
+ const char *filepath = luaL_checkstring(L, 1);
+
+ ExternalImage *img = malloc(sizeof(ExternalImage));
+ if (!img) {
+ TraceLog(LOG_FATAL, "Out of memory!");
+ return 0;
+ }
+
+ Image image = LoadImage(filepath);
+ if (!image.data) {
+ TraceLog(LOG_FATAL, "Failed to load image: %s\n", filepath);
+ free(img);
+ return 0;
+ }
+
+ img->texture = LoadTextureFromImage(image);
+ UnloadImage(image);
+
+ generate_uid(img->uid, UID_LENGTH);
+ img->next = NULL;
+
+ if (ctx.images.tail) {
+ ctx.images.tail->next = img;
+ ctx.images.tail = img;
+ } else {
+ ctx.images.head = img;
+ ctx.images.tail = img;
+ }
+ ctx.images.count++;
+
+ TraceLog(LOG_WARNING, "[adding]\t %s (%d)", img->uid, strlen(img->uid));
+
+ lua_pushstring(L, img->uid);
+ return 1;
}
static int l_load_audio(lua_State *L) {
return 0;
}
+static int l_draw_image(lua_State *L) {
+ const char *uid = luaL_checkstring(L, 1);
+ int x = luaL_checknumber(L, 2);
+ int y = luaL_checknumber(L, 3);
+
+ ExternalImage *current = ctx.images.head;
+ while (current) {
+ if (strncmp(current->uid, uid, UID_LENGTH) == 0) {
+ /* TraceLog(LOG_WARNING, "[match]\t %s (%d)", uid, strlen(uid)); */
+ DrawTexture(current->texture, x, y, WHITE);
+ break;
+ }
+ current = current->next;
+ }
+
+ return 0;
+}
+
static void help(const char *argv0) {
printf("Usage: %s [options]\n"
"\nAvailable options:\n"
@@ -404,6 +468,7 @@ static void version(const char *argv0) {
int main(int argc, char *argv[]) {
srand(time(NULL));
+ init_image_list(&ctx.images);
TraceLogLevel debug_level = LOG_WARNING;
const char *run_file = NULL;
@@ -472,6 +537,12 @@ int main(int argc, char *argv[]) {
lua_register(L, "get_width", l_get_width);
lua_register(L, "get_height", l_get_height);
+ lua_register(L, "load_image", l_load_image);
+ lua_register(L, "load_audio", l_load_audio);
+
+ lua_register(L, "button_down", l_button_down);
+ lua_register(L, "button_pressed", l_button_pressed);
+
lua_register(L, "draw_info", l_draw_info);
lua_register(L, "draw_rect", l_draw_rect);
lua_register(L, "draw_text", l_draw_text);
@@ -480,16 +551,11 @@ int main(int argc, char *argv[]) {
lua_register(L, "draw_circle", l_draw_circle);
lua_register(L, "draw_ellipse", l_draw_ellipse);
lua_register(L, "draw_triangle", l_draw_triangle);
-
- lua_register(L, "load_image", l_load_image);
- lua_register(L, "load_audio", l_load_audio);
-
- lua_register(L, "button_down", l_button_down);
- lua_register(L, "button_pressed", l_button_pressed);
+ lua_register(L, "draw_image", l_draw_image);
// Interpreting and running input file Lua script.
if (luaL_loadfile(L, run_file) || lua_pcall(L, 0, 0, 0)) {
- fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
+ TraceLog(LOG_FATAL, "Error: %s\n", lua_tostring(L, -1));
return 1;
}
diff --git a/tests/test.lua b/tests/test.lua
index f85b644..372b221 100644
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -1,16 +1,15 @@
math.randomseed(os.time())
+open_window(800, 800, "Sample Window")
+set_fps(60)
+
test_button_square = { x = 400, y = 400 }
test_button_color = color.RED
test_button_speed = 200
-
test_camera_position = { x = 0, y = 0 }
test_camera_speed = 200
-
test_images_asset1 = load_image("tests/icons/icon_1.png")
-
-open_window(800, 800, "Sample Window")
-set_fps(60)
+test_images_asset2 = load_image("tests/icons/icon_2.png")
function test_api()
draw_rect(100, 100, 300, 200, color.YELLOW)
@@ -26,10 +25,10 @@ end
function get_random_color()
local keys = {}
for k in pairs(color) do
- table.insert(keys, k) -- Collect all keys
+ table.insert(keys, k)
end
- local randomKey = keys[math.random(1, #keys)] -- Select a random key
- return color[randomKey] -- Return the corresponding color
+ local randomKey = keys[math.random(1, #keys)]
+ return color[randomKey]
end
function test_json()
@@ -140,6 +139,14 @@ function test_camera()
draw_text("This text doesn't move!", 10, 10, 20, color.VIOLET)
end
+function test_images()
+ draw_text(string.format("uid: %s", test_images_asset1), 50, 50, 20, color.VIOLET)
+ draw_text(string.format("uid: %s", test_images_asset2), 50, 80, 20, color.VIOLET)
+
+ draw_image(test_images_asset1, 150, 150)
+ draw_image(test_images_asset2, 200, 200)
+end
+
while window_running() do
start_drawing()
clear_window(color.BLACK)
@@ -148,6 +155,7 @@ while window_running() do
-- test_api()
-- test_buttons()
-- test_camera()
+ -- test_images()
draw_info()
stop_drawing()