Compare commits

...

6 Commits

Author SHA1 Message Date
veclavtalica
9d0a2cab81 expose audio to twnlua 2025-01-15 04:15:08 +03:00
veclavtalica
d5b42fa242 add a todo 2025-01-15 01:01:16 +03:00
veclavtalica
851ab80292 remove ctx.update_multiplicity 2025-01-15 00:52:42 +03:00
veclavtalica
688d71953a make inputs up-to-date for game tick 2025-01-15 00:43:46 +03:00
veclavtalica
63abf3d374 disable vsync, make us rule over frames fully 2025-01-15 00:31:17 +03:00
veclavtalica
80c77424e2 /apps/demos/scenery: more detailed terrain 2025-01-15 00:30:46 +03:00
8 changed files with 63 additions and 39 deletions

View File

@ -12,7 +12,7 @@
#include <stdlib.h> #include <stdlib.h>
#define TERRAIN_FREQUENCY 0.1f #define TERRAIN_FREQUENCY 0.15f
#define TERRAIN_DISTANCE 32 #define TERRAIN_DISTANCE 32
#define HALF_TERRAIN_DISTANCE ((float)TERRAIN_DISTANCE / 2) #define HALF_TERRAIN_DISTANCE ((float)TERRAIN_DISTANCE / 2)
#define PLAYER_HEIGHT 0.6f #define PLAYER_HEIGHT 0.6f
@ -135,6 +135,7 @@ static void generate_terrain(SceneIngame *scn) {
float y = floorf(scn->pos.z - HALF_TERRAIN_DISTANCE + (float)ly); float y = floorf(scn->pos.z - HALF_TERRAIN_DISTANCE + (float)ly);
float height = stb_perlin_noise3((float)x * TERRAIN_FREQUENCY, (float)y * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 3 - 1; float height = stb_perlin_noise3((float)x * TERRAIN_FREQUENCY, (float)y * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 3 - 1;
height += stb_perlin_noise3((float)x * TERRAIN_FREQUENCY / 10, (float)y * TERRAIN_FREQUENCY / 10, 0, 0, 0, 0) * 10 - 1;
heightmap[lx][ly] = height; heightmap[lx][ly] = height;
} }

View File

@ -34,7 +34,7 @@ def default(parameter):
def to_table(typedesc, variable, indent = 0): def to_table(typedesc, variable, indent = 0):
binding = ' ' * indent + "lua_createtable(L, 0, %i);\n" % len(typedesc["fields"]) binding = ' ' * indent + "lua_createtable(L, 0, %i);\n" % len(typedesc["fields"])
for field in typedesc["fields"]: for field in typedesc["fields"]:
if field["type"] == "float": if field["type"] == "float" or field["type"] == "uint8_t":
binding += ' ' * indent + "lua_pushnumber(L, (double)(%s));\n" % (variable + ".%s" % field["name"]) binding += ' ' * indent + "lua_pushnumber(L, (double)(%s));\n" % (variable + ".%s" % field["name"])
elif field["type"] == "bool": elif field["type"] == "bool":
binding += ' ' * indent + "lua_pushboolean(L, (%s));\n" % (variable + ".%s" % field["name"]) binding += ' ' * indent + "lua_pushboolean(L, (%s));\n" % (variable + ".%s" % field["name"])
@ -50,8 +50,8 @@ def from_table(typedesc, variable, indent = 0):
binding = "" binding = ""
for field in typedesc["fields"]: for field in typedesc["fields"]:
binding += ' ' * indent + "lua_getfield(L, -1, \"%s\");\n" % field["name"] binding += ' ' * indent + "lua_getfield(L, -1, \"%s\");\n" % field["name"]
if field["type"] == "float": if field["type"] == "float" or field["type"] == "uint8_t":
binding += ' ' * indent + "%s = (float)lua_tonumber(L, -1);\n" % (variable + ".%s" % field["name"]) binding += ' ' * indent + "%s = (%s)lua_tonumber(L, -1);\n" % (variable + ".%s" % field["name"], field["type"])
elif field["type"] == "bool": elif field["type"] == "bool":
binding += ' ' * indent + "%s = lua_toboolean(L, -1);\n" % (variable + ".%s" % field["name"]) binding += ' ' * indent + "%s = lua_toboolean(L, -1);\n" % (variable + ".%s" % field["name"])
elif field["type"] in api["types"]: elif field["type"] in api["types"]:

View File

@ -9,7 +9,7 @@
/* plays audio file at specified channel or at scratch channel if NULL is passed, without ability to refer to it later */ /* plays audio file at specified channel or at scratch channel if NULL is passed, without ability to refer to it later */
/* path path must contain valid file extension to infer which file format it is */ /* path path must contain valid file extension to infer which file format it is */
/* supported formats: .ogg, .xm */ /* supported formats: .ogg, .xm */
TWN_API void audio_play(const char *path, TWN_API void audio_play(const char *audio,
const char *channel, /* optional */ const char *channel, /* optional */
bool repeat, /* default: false */ bool repeat, /* default: false */
float volume, /* default: 1.0f, range: 0.0f to 1.0f */ float volume, /* default: 1.0f, range: 0.0f to 1.0f */

View File

@ -213,6 +213,30 @@
{ "name": "textures", "type": "char *", "default": {} } { "name": "textures", "type": "char *", "default": {} }
] ]
}, },
"audio_play": {
"module": "audio",
"symbol": "play",
"header": "twn_audio.h",
"params": [
{ "name": "audio", "type": "char *" },
{ "name": "channel", "type": "char *", "default": {} },
{ "name": "repeat", "type": "bool", "default": false },
{ "name": "volume", "type": "float", "default": 1.0 },
{ "name": "panning", "type": "float", "default": 0.0 }
]
},
"audio_parameter": {
"module": "audio",
"symbol": "parameter",
"header": "twn_audio.h",
"params": [
{ "name": "channel", "type": "char *" },
{ "name": "parameter", "type": "char *" },
{ "name": "value", "type": "float" }
]
}
}, },
"types": { "types": {

View File

@ -72,11 +72,6 @@ typedef struct EngineContext {
SDL_Window *window; SDL_Window *window;
uint32_t window_id; uint32_t window_id;
/* this should be a multiple of the current ticks per second */
/* use it to simulate low framerate (e.g. at 60 tps, set to 2 for 30 fps) */
/* it can be changed at runtime; any resulting logic anomalies are bugs */
uint32_t update_multiplicity;
bool is_running; bool is_running;
bool window_size_has_changed; bool window_size_has_changed;
bool resync_flag; bool resync_flag;

View File

@ -216,11 +216,14 @@ void input_state_deinit(InputState *input) {
} }
void input_state_update(InputState *input) { void input_state_update_postframe(InputState *input) {
/* TODO: don't spam it if it happens */ /* TODO: don't spam it if it happens */
if (SDL_SetRelativeMouseMode(ctx.game_copy.mouse_capture && ctx.window_mouse_resident) != 0) if (SDL_SetRelativeMouseMode(ctx.game_copy.mouse_capture && ctx.window_mouse_resident) != 0)
log_warn("(%s) Mouse capture isn't supported.", __func__); log_warn("(%s) Mouse capture isn't supported.", __func__);
}
void input_state_update(InputState *input) {
int x, y; int x, y;
input->keyboard_state = SDL_GetKeyboardState(NULL); input->keyboard_state = SDL_GetKeyboardState(NULL);

View File

@ -76,6 +76,8 @@ void input_state_deinit(InputState *input);
void input_state_update(InputState *input); void input_state_update(InputState *input);
void input_state_update_postframe(InputState *input);
void input_reset_state(InputState *input); void input_reset_state(InputState *input);
#endif #endif

View File

@ -204,22 +204,25 @@ static void main_loop(void) {
/* finally, let's get to work */ /* finally, let's get to work */
int frames = 0; int frames = 0;
while (ctx.frame_accumulator >= ctx.desired_frametime * ctx.update_multiplicity) { while (ctx.frame_accumulator >= ctx.desired_frametime) {
frames += 1; frames += 1;
for (size_t i = 0; i < ctx.update_multiplicity; ++i) {
/* TODO: disable rendering pushes on not-last ? */ /* TODO: disable rendering pushes on not-last ? */
render_queue_clear(); render_queue_clear();
poll_events(); poll_events();
if (ctx.window_size_has_changed) if (ctx.window_size_has_changed)
update_viewport(); update_viewport();
input_state_update(&ctx.input);
game_object_tick(); game_object_tick();
input_state_update_postframe(&ctx.input);
#ifdef TWN_FEATURE_PUSH_AUDIO #ifdef TWN_FEATURE_PUSH_AUDIO
static uint8_t audio_buffer[(AUDIO_FREQUENCY / 60) * sizeof (float) * 2]; static uint8_t audio_buffer[(AUDIO_FREQUENCY / 60) * sizeof (float) * 2];
audio_callback(NULL, audio_buffer, sizeof audio_buffer); audio_callback(NULL, audio_buffer, sizeof audio_buffer);
if (SDL_QueueAudio(ctx.audio_device, audio_buffer, sizeof audio_buffer)) if (SDL_QueueAudio(ctx.audio_device, audio_buffer, sizeof audio_buffer))
CRY_SDL("Error queueing audio: "); CRY_SDL("Error queueing audio: ");
#endif #endif
input_state_update(&ctx.input);
/* TODO: ctx.game_copy = ctx.game should be placed after it, but it messes with state used in render() */
preserve_persistent_ctx_fields(); preserve_persistent_ctx_fields();
ctx.frame_accumulator -= ctx.desired_frametime; ctx.frame_accumulator -= ctx.desired_frametime;
@ -229,7 +232,6 @@ static void main_loop(void) {
ctx.game.frame_number = 0; ctx.game.frame_number = 0;
ctx.game.initialization_needed = false; ctx.game.initialization_needed = false;
} }
}
/* TODO: in some cases machine might want to assume frames will be fed as much as possible */ /* TODO: in some cases machine might want to assume frames will be fed as much as possible */
/* which for now is broken as glBufferData with NULL is used all over right after render */ /* which for now is broken as glBufferData with NULL is used all over right after render */
@ -507,8 +509,8 @@ static bool initialize(void) {
goto fail; goto fail;
} }
if (SDL_GL_SetSwapInterval(-1)) /* TODO: figure out what we ultimately prefer */
SDL_GL_SetSwapInterval(1); SDL_GL_SetSwapInterval(0);
if (!render_init()) if (!render_init())
goto fail; goto fail;
@ -552,9 +554,6 @@ static bool initialize(void) {
} }
/* you could change this at runtime if you wanted */
ctx.update_multiplicity = 1;
/* random seeding */ /* random seeding */
/* SDL_GetPerformanceCounter returns some platform-dependent number. */ /* SDL_GetPerformanceCounter returns some platform-dependent number. */
/* it should vary between game instances. i checked! random enough for me. */ /* it should vary between game instances. i checked! random enough for me. */