Compare commits

...

4 Commits

Author SHA1 Message Date
veclavtalica
f3848d2d52 progress on twnlua bindgen 2025-01-09 21:47:08 +03:00
veclavtalica
8c401eda75 api changes and progress on filling in twn_api.json 2025-01-07 14:14:21 +03:00
veclavtalica
5c89c55b3e /apps/twnlua: support out of tree usage 2025-01-07 13:22:31 +03:00
veclavtalica
5b05386bb0 changes to twn.toml specification of resolution, make it optional as well 2025-01-06 21:19:26 +03:00
13 changed files with 196 additions and 68 deletions

View File

@ -5,7 +5,6 @@ app_id = "bunnymark"
dev_id = "morshy"
[game]
base_render_width = 640
base_render_height = 480
resolution = [ 640, 480 ]
[engine]

View File

@ -5,7 +5,6 @@ app_id = "platformer-demo"
dev_id = "townengine-team"
[game]
base_render_width = 640
base_render_height = 360
resolution = [ 640, 360 ]
[engine]

View File

@ -1,11 +1,10 @@
[about]
title = "Serene Scenery"
developer = "Townengine Team"
app_id = "platformer-demo"
app_id = "scenery-demo"
dev_id = "townengine-team"
[game]
base_render_width = 640
base_render_height = 360
resolution = [ 640, 360 ]
[engine]

View File

@ -159,7 +159,10 @@ static void draw_terrain(SceneIngame *scn) {
(Vec3){ (float)x, d3, (float)y - 1 },
(Vec2){ 128, 128 },
(Vec2){ 128, 0 },
(Vec2){ 0, 128 });
(Vec2){ 0, 128 },
(Color){255, 255, 255, 255},
(Color){255, 255, 255, 255},
(Color){255, 255, 255, 255});
draw_triangle("/assets/grass.png",
(Vec3){ (float)x + 1, d1, (float)y },
@ -167,7 +170,10 @@ static void draw_terrain(SceneIngame *scn) {
(Vec3){ (float)x, d3, (float)y - 1 },
(Vec2){ 128, 0 },
(Vec2){ 0, 0 },
(Vec2){ 0, 128 });
(Vec2){ 0, 128 },
(Color){255, 255, 255, 255},
(Color){255, 255, 255, 255},
(Color){255, 255, 255, 255});
draw_billboard("/assets/grasses/10.png",
(Vec3){ (float)x, d0 + 0.15f, (float)y },

View File

@ -13,8 +13,7 @@ dev_id = "you"
# Game runtime details
[game]
base_render_width = 640
base_render_height = 480
resolution = [ 640, 480 ]
#debug = true
# Engine tweaks. You probably don't need to change these

View File

@ -83,4 +83,4 @@ set(SOURCE_FILES
)
use_townengine(${PROJECT_NAME} "${SOURCE_FILES}" ${CMAKE_CURRENT_SOURCE_DIR})
use_townengine(${PROJECT_NAME} "${SOURCE_FILES}" ${CMAKE_SOURCE_DIR})

View File

@ -31,6 +31,20 @@ def default(parameter):
raise BaseException("Unhandled default value of type '%s'" % parameter["type"])
def to_table(typedesc, variable, indent = 0):
binding = ' ' * indent + "lua_newtable(L);\n"
for field in typedesc["fields"]:
if field["type"] == "float":
binding += ' ' * indent + "lua_pushnumber(L, (double)(%s));\n" % (variable + ".%s" % field["name"])
elif field["type"] in api["types"]:
binding += to_table(api["types"][field["type"]], variable + ".%s" % field["name"], indent + 4)
else:
raise BaseException("Unhandled return field type '%s'" % (field["type"]))
binding += ' ' * indent + "lua_setfield(L, -2, \"%s\");\n" % field["name"]
# binding += ' ' * indent + "lua_pop(L, 1);\n"
return binding
print('#include "twn_game_api.h"\n')
print('#define STB_DS_IMPLEMENTATION') # TODO: reuse implementation from the engine
print('#include <stb_ds.h>')
@ -115,8 +129,15 @@ for procedure, procedure_desc in api["procedures"].items():
binding += " lua_pushboolean(L, (int)%s(%s));\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"]))
elif procedure_desc["return"] == "float":
binding += " lua_pushnumber(L, (double)%s(%s));\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"]))
elif procedure_desc["return"] == "char *":
binding += " lua_pushstring(L, %s(%s));\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"]))
elif type(procedure_desc["return"]) is dict or procedure_desc["return"] in api["types"]:
# TODO: handle enums
type_desc = procedure_desc["return"] if type(procedure_desc["return"]) is dict else api["types"][procedure_desc["return"]]
binding += " %s result = %s(%s);\n" % (type_desc["c_type"], procedure, ", ".join(param["name"] for param in procedure_desc["params"]))
binding += to_table(type_desc, "result", 4)
else:
binding += " lua_warning(L, \"Unhandled return type!\", 0);\n"
raise BaseException("Unhandled return type '%s'" % (procedure_desc["return"]))
binding += " return 1;\n}\n"
else:
binding += " %s(%s);\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"]))
@ -132,9 +153,8 @@ for module in modules:
loader += " lua_newtable(L);\n"
for procedure, procedure_desc in api["procedures"].items():
if procedure_desc["module"] == module:
loader += " lua_pushstring(L, \"%s\");\n" % procedure_desc["symbol"]
loader += " lua_pushcfunction(L, binding_%s);\n" % procedure
loader += " lua_settable(L, -3);\n"
loader += " lua_setfield(L, -2, \"%s\");\n" % procedure_desc["symbol"]
loader += " lua_setglobal(L, \"%s\");\n" % module
loader += "}"

View File

@ -15,7 +15,7 @@ function game_tick()
}
draw.sprite {
path = "/assets/title.png",
texture = "/assets/title.png",
rect = {
x = 320 - (320 / 2),
y = 180 - (128 / 2),

View File

@ -5,7 +5,6 @@ app_id = "twnlua"
dev_id = "somebody"
[game]
base_render_width = 640
base_render_height = 360
resolution = [ 640, 360 ]
[engine]

View File

@ -50,22 +50,10 @@ TWN_API void draw_triangle(char const *texture,
Vec3 v2,
Vec2 uv0,
Vec2 uv1,
Vec2 uv2);
// TODO: decide whether it's needed to begin with?
// intended usage for it is baked lighting, i would think.
// TODO: instead add optional color parameters to 'draw_triangle'
/* pushes a colored textured 3d triangle onto the render queue */
// void unfurl_colored_triangle(const char *path,
// Vec3 v0,
// Vec3 v1,
// Vec3 v2,
// Vec2sh uv0,
// Vec2sh uv1,
// Vec2sh uv2,
// Color c0,
// Color c1,
// Color c2);
Vec2 uv2,
Color c0, /* optional, default: all 255 */
Color c1, /* optional, default: all 255 */
Color c2); /* optional, default: all 255 */
TWN_API void draw_billboard(const char *texture,
Vec3 position,
@ -76,7 +64,7 @@ TWN_API void draw_billboard(const char *texture,
/* sets a perspective 3d camera to be used for all 3d commands */
TWN_API void draw_camera(Vec3 position, float fov, Vec3 up, Vec3 direction);
/* same as draw_camera(), but with specific use case */
/* same as draw_camera(), but with first person controller in mind */
/* direction and up vectors are inferred from roll, pitch and yaw parameters (in radians) */
/* return value is direction and up vectors, so that you can use them in logic (such as controllers) */
typedef struct DrawCameraFromPrincipalAxesResult {
@ -90,9 +78,13 @@ TWN_API DrawCameraFromPrincipalAxesResult draw_camera_from_principal_axes(Vec3 p
float yaw);
/* expects '*' masks that will be expanded to 6 names: 'up', 'down', 'east', 'west', 'north' and 'south' */
TWN_API void draw_skybox(const char *paths);
TWN_API void draw_skybox(const char *textures);
TWN_API void draw_fog(float start, float end, float density, Color color);
/* only one for setting is supported for a frame, any call overwrites previous */
TWN_API void draw_fog(float start, /* optional, default: 0.0 */
float end, /* optional, default: 1.0 */
float density, /* optional, default: 0.0 */
Color color); /* optional, default: all 255 */
#ifndef TWN_NOT_C

View File

@ -66,7 +66,7 @@
"symbol": "sprite",
"header": "twn_draw.h",
"params": [
{ "name": "path", "type": "char *" },
{ "name": "texture", "type": "char *" },
{ "name": "rect", "type": "Rect" },
{ "name": "texture_region", "type": "Rect *", "default": {} },
{ "name": "color", "type": "Color", "default": { "r": 255, "g": 255, "b": 255, "a": 255 } },
@ -121,6 +121,103 @@
{ "name": "font", "type": "char *", "default": {} }
],
"return": "float"
},
"draw_nine_slice": {
"module": "draw",
"symbol": "nine_slice",
"header": "twn_draw.h",
"params": [
{ "name": "texture", "type": "char *" },
{ "name": "corners", "type": "Vec2" },
{ "name": "rect", "type": "Rect" },
{ "name": "border_thickness", "type": "float", "default": 0 },
{ "name": "color", "type": "Color", "default": { "r": 255, "g": 255, "b": 255, "a": 255 } }
]
},
"draw_triangle": {
"module": "draw",
"symbol": "triangle",
"header": "twn_draw.h",
"params": [
{ "name": "texture", "type": "char *" },
{ "name": "v0", "type": "Vec3" },
{ "name": "v1", "type": "Vec3" },
{ "name": "v2", "type": "Vec3" },
{ "name": "uv0", "type": "Vec2" },
{ "name": "uv1", "type": "Vec2" },
{ "name": "uv2", "type": "Vec2" },
{ "name": "c0", "type": "Color", "default": { "r": 255, "g": 255, "b": 255, "a": 255 } },
{ "name": "c1", "type": "Color", "default": { "r": 255, "g": 255, "b": 255, "a": 255 } },
{ "name": "c2", "type": "Color", "default": { "r": 255, "g": 255, "b": 255, "a": 255 } }
]
},
"draw_billboard": {
"module": "draw",
"symbol": "billboard",
"header": "twn_draw.h",
"params": [
{ "name": "texture", "type": "char *" },
{ "name": "position", "type": "Vec3" },
{ "name": "size", "type": "Vec2" },
{ "name": "color", "type": "Color", "default": { "r": 255, "g": 255, "b": 255, "a": 255 } },
{ "name": "cylindrical", "type": "bool", "default": false }
]
},
"draw_camera": {
"module": "draw",
"symbol": "camera",
"header": "twn_draw.h",
"params": [
{ "name": "position", "type": "Vec3" },
{ "name": "fov", "type": "float" },
{ "name": "up", "type": "Vec3" },
{ "name": "direction", "type": "Vec3" }
]
},
"draw_camera_from_principal_axes": {
"module": "draw",
"symbol": "camera_from_principal_axes",
"header": "twn_draw.h",
"params": [
{ "name": "position", "type": "Vec3" },
{ "name": "fov", "type": "float" },
{ "name": "roll", "type": "float" },
{ "name": "pitch", "type": "float" },
{ "name": "yaw", "type": "float" }
],
"return": {
"fields": [
{ "name": "direction", "type": "Vec3" },
{ "name": "up", "type": "Vec3" }
],
"c_type": "DrawCameraFromPrincipalAxesResult"
}
},
"draw_skybox": {
"module": "draw",
"symbol": "skybox",
"header": "twn_draw.h",
"params": [
{ "name": "textures", "type": "char *", "default": {} }
]
},
"draw_fog": {
"module": "draw",
"symbol": "fog",
"header": "twn_draw.h",
"params": [
{ "name": "start", "type": "float", "default": 0 },
{ "name": "end", "type": "float", "default": 1 },
{ "name": "density", "type": "float", "default": 0 },
{ "name": "color", "type": "Color", "default": { "r": 255, "g": 255, "b": 255, "a": 255 } }
]
}
},
@ -129,7 +226,8 @@
"fields": [
{ "name": "x", "type": "float" },
{ "name": "y", "type": "float" }
]
],
"c_type": "Vec2"
},
"Vec3": {
@ -137,7 +235,8 @@
{ "name": "x", "type": "float" },
{ "name": "y", "type": "float" },
{ "name": "z", "type": "float" }
]
],
"c_type": "Vec3"
},
"Vec4": {
@ -146,7 +245,8 @@
{ "name": "y", "type": "float" },
{ "name": "z", "type": "float" },
{ "name": "w", "type": "float" }
]
],
"c_type": "Vec4"
},
"Color": {
@ -155,7 +255,8 @@
{ "name": "g", "type": "uint8_t" },
{ "name": "b", "type": "uint8_t" },
{ "name": "a", "type": "uint8_t" }
]
],
"c_type": "Color"
},
"Rect": {
@ -164,7 +265,8 @@
{ "name": "y", "type": "float" },
{ "name": "w", "type": "float" },
{ "name": "h", "type": "float" }
]
],
"c_type": "Rect"
},
"Control": {

View File

@ -15,8 +15,14 @@ void draw_triangle(const char *path,
Vec3 v2,
Vec2 uv0,
Vec2 uv1,
Vec2 uv2)
Vec2 uv2,
Color c0,
Color c1,
Color c2)
{
// TODO: support color
(void)c0; (void)c1; (void)c2;
// TODO: order drawing by atlas id as well, so that texture rebinding is not as common
const TextureKey texture_key = textures_get_key(&ctx.texture_cache, path);

View File

@ -423,11 +423,7 @@ static bool initialize(void) {
/* debug mode defaults to being enabled */
/* pass --debug or --release to force a mode, ignoring configuration */
toml_datum_t datum_debug = toml_bool_in(game, "debug");
if (!datum_debug.ok) {
ctx.game.debug = true;
} else {
ctx.game.debug = datum_debug.u.b;
}
ctx.game.debug = datum_debug.ok ? datum_debug.u.b : true;
#ifdef EMSCRIPTEN
/* emscripten interpretes those as GL ES version against WebGL */
@ -454,10 +450,9 @@ static bool initialize(void) {
/* init got far enough to create a window */
{
toml_datum_t datum_title = toml_string_in(about, "title");
if (!datum_title.ok) {
CRY("Initialization failed", "Valid about.title expected in configuration file");
goto fail;
}
if (!datum_title.ok)
datum_title.u.s = "townengine project";
/* not yet used
toml_datum_t datum_developer = toml_string_in(about, "developer");
if (!datum_developer.ok) {
@ -465,32 +460,44 @@ static bool initialize(void) {
goto fail;
}
*/
toml_datum_t datum_base_render_width = toml_int_in(game, "base_render_width");
if (!datum_base_render_width.ok) {
CRY("Initialization failed", "Valid game.base_render_width expected in configuration file");
goto fail;
}
ctx.base_render_width = datum_base_render_width.u.i;
ctx.game.resolution.x = (float)ctx.base_render_width;
toml_datum_t datum_base_render_height = toml_int_in(game, "base_render_height");
if (!datum_base_render_height.ok) {
CRY("Initialization failed", "Valid game.base_render_height expected in configuration file");
goto fail;
toml_array_t *datum_resolution = toml_array_in(game, "resolution");
if (datum_resolution) {
toml_datum_t datum_base_render_width = toml_int_at(datum_resolution, 0);
if (!datum_base_render_width.ok) {
CRY("Initialization failed", "Valid game.resolution expected in configuration file");
goto fail;
}
toml_datum_t datum_base_render_height = toml_int_at(datum_resolution, 1);
if (!datum_base_render_height.ok) {
CRY("Initialization failed", "Valid game.resolution expected in configuration file");
goto fail;
}
ctx.base_render_width = datum_base_render_width.u.i;
ctx.base_render_height = datum_base_render_height.u.i;
} else {
ctx.base_render_width = 640;
ctx.base_render_height = 360;
}
ctx.base_render_height = datum_base_render_height.u.i;
ctx.game.resolution.x = (float)ctx.base_render_width;
ctx.game.resolution.y = (float)ctx.base_render_height;
ctx.window = SDL_CreateWindow(datum_title.u.s,
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
(int)datum_base_render_width.u.i,
(int)datum_base_render_height.u.i,
(int)ctx.base_render_width,
(int)ctx.base_render_height,
//SDL_WINDOW_ALLOW_HIGHDPI |
SDL_WINDOW_RESIZABLE |
SDL_WINDOW_OPENGL);
SDL_free(datum_title.u.s);
if (datum_title.ok)
SDL_free(datum_title.u.s);
//SDL_free(datum_developer.u.s);
}