diff options
| author | KonAki <konaki@anokonaki.org> | 2026-10-09 17:51:49 +0800 |
|---|---|---|
| committer | KonAki <konaki@anokonaki.org> | 2026-10-09 17:51:49 +0800 |
| commit | eca47efac07ffa6c4e35708031dea8a7da4e7ed8 (patch) | |
| tree | 5d16ccd0309b97c77a3960c20c1a3137753678bd /kon/konprogram.c | |
| parent | 3e4acddeb4df4d21ad89b8926aa2eafc634daa25 (diff) | |
Add konprogram and use it in engine.c
Diffstat (limited to 'kon/konprogram.c')
| -rw-r--r-- | kon/konprogram.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/kon/konprogram.c b/kon/konprogram.c new file mode 100644 index 0000000..33e1f15 --- /dev/null +++ b/kon/konprogram.c @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: MIT */ +/* + * konprogram.c + * + * Copyright (c) 2026 KonAki + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdlib.h> +#include <string.h> + +/* the debug functions only exist with the debug module, without KON_DEVELOPER the header gives empty ones instead */ +#if defined(KON_DEVELOPER) && !defined(KON_MODULE_DEBUG) +#undef KON_DEVELOPER +#endif + +#include "konprogram.h" +#include "kontime.h" + +/*** definition ***/ + +typedef struct kon_programState { + kon_program_t pub; + kon_programConfig_t config; + kon_time last; + float shakeLeft; + int shakeX, shakeY; +} kon_programState_t; + +/*** console commands ***/ + +#ifdef KON_DEVELOPER + +static void kon_cmdOpacity_(kon_debug_t *debug, void *user, int argc, char **argv) { + kon_programState_t *state = user; + + (void)debug; + if (argc > 1) kon_setWindowOpacity(state->pub.window, (float)atof(argv[1])); +} + +static void kon_cmdTopmost_(kon_debug_t *debug, void *user, int argc, char **argv) { + kon_programState_t *state = user; + + (void)debug; + if (argc > 1) kon_setWindowTopmost(state->pub.window, atoi(argv[1]) != 0); +} + +static void kon_cmdBorderless_(kon_debug_t *debug, void *user, int argc, char **argv) { + kon_programState_t *state = user; + + (void)debug; + if (argc > 1) kon_setWindowDecorated(state->pub.window, atoi(argv[1]) == 0); +} + +static void kon_cmdClickThrough_(kon_debug_t *debug, void *user, int argc, char **argv) { + kon_programState_t *state = user; + + (void)debug; + if (argc > 1) kon_setWindowClickThrough(state->pub.window, atoi(argv[1]) != 0); +} + +static void kon_cmdMessage_(kon_debug_t *debug, void *user, int argc, char **argv) { + (void)debug; (void)user; + kon_messageBox("konengine", argc > 1 ? argv[1] : "hello", KON_MESSAGE_INFO); +} + +static void kon_cmdShake_(kon_debug_t *debug, void *user, int argc, char **argv) { + kon_programState_t *state = user; + + (void)debug; (void)argc; (void)argv; + kon_getWindowPos(state->pub.window, &state->shakeX, &state->shakeY); + state->shakeLeft = 0.5f; +} + +static void kon_addWindowCommands_(kon_programState_t *state) { + kon_debug_t *debug = state->pub.debug; + + kon_debugCommand(debug, "opacity", "window opacity 0 to 1", kon_cmdOpacity_, state); + kon_debugCommand(debug, "topmost", "topmost 0 or 1", kon_cmdTopmost_, state); + kon_debugCommand(debug, "borderless", "borderless 0 or 1", kon_cmdBorderless_, state); + kon_debugCommand(debug, "clickthrough", "clickthrough 0 or 1", kon_cmdClickThrough_, state); + kon_debugCommand(debug, "message", "message \"text\"", kon_cmdMessage_, state); + kon_debugCommand(debug, "shake", "shake the window", kon_cmdShake_, state); +} + +#endif + +/*** loop ***/ + +static void kon_frame_(void *data) { + kon_programState_t *state = data; + kon_program_t *program = &state->pub; + const kon_programConfig_t *config = &state->config; + kon_display_t *display = program->display; + kon_event_t ev; + kon_time now, dt; + + while (kon_pollEvent(program->window, &ev)) { + if (kon_debugFeedEvent(program->debug, &ev)) continue; + if (ev.type == KON_EVENT_RESIZE) kon_resizeDisplay(display, ev.width, ev.height); + if (config->event) config->event(program, &ev, config->user); + } + + now = kon_getTime(); + dt = now - state->last; + state->last = now; + /* a long stall, like dragging the window, shouldn't make the game jump */ + if (dt > 0.25) dt = 0.25; + program->time += dt; + + if (state->shakeLeft > 0.0f) { + state->shakeLeft -= (float)dt; + if (state->shakeLeft > 0.0f) kon_setWindowPos(program->window, state->shakeX + rand() % 21 - 10, state->shakeY + rand() % 21 - 10); + else kon_setWindowPos(program->window, state->shakeX, state->shakeY); + } + + if (config->update) config->update(program, dt, config->user); + kon_clearFramebuffer(display->game, KON_BACKGROUND_COLOR); + if (config->draw) config->draw(program, display->game, config->user); + + kon_presentDisplay(display); + if (config->drawScreen) config->drawScreen(program, display->screen, config->user); + kon_debugFrame(program->debug); + if (kon_debugQuitRequested(program->debug)) kon_setShouldClose(program->window, true); + kon_debugDraw(program->debug, display->screen); + kon_blitPixels(program->window, display->screen->data, display->screen->width, display->screen->height); + kon_sleep(0.008); +} + +void kon_programQuit(kon_program_t *program) { + if (program) kon_setShouldClose(program->window, true); +} + +int kon_programRun(const kon_programConfig_t *config) { + kon_programState_t *state; + kon_program_t *program; + int gameWidth, gameHeight, windowWidth, windowHeight; + + if (!config) return 1; + state = calloc(1, sizeof *state); + if (!state) return 1; + program = &state->pub; + state->config = *config; + + gameWidth = config->gameWidth > 0 ? config->gameWidth : 320; + gameHeight = config->gameHeight > 0 ? config->gameHeight : 180; + windowWidth = config->windowWidth > 0 ? config->windowWidth : gameWidth * 3; + windowHeight = config->windowHeight > 0 ? config->windowHeight : gameHeight * 3; + + if (!kon_init()) goto fail; + program->window = kon_createWindow(config->title ? config->title : "konengine", 0, 0, windowWidth, windowHeight, KON_WINDOW_CENTER | KON_WINDOW_RESIZABLE); + if (!program->window) goto fail; +#ifdef KON_DEVELOPER + kon_setExitKey(program->window, KON_KEY_F10); +#else + kon_setExitKey(program->window, KON_KEY_ESCAPE); +#endif + program->display = kon_createDisplay(gameWidth, gameHeight, windowWidth, windowHeight); + if (!program->display) goto fail; + +#ifdef KON_MODULE_PACK + if (config->packPath) program->pack = kon_packOpen(config->packPath, NULL); +#endif +#ifdef KON_MODULE_ASSETS + program->assets = kon_assetsCreate(program->pack, config->assetDir ? config->assetDir : "assets"); +#endif +#ifdef KON_MODULE_FONT + { + kon_blob_t *ttf = program->assets ? kon_assetBlob(program->assets, "font.ttf") : NULL; + + if (ttf) program->font = kon_loadFont(ttf->data, ttf->size, 14.0f); + if (!program->font) program->font = kon_loadBuiltinFont(1); + } +#endif +#ifdef KON_MODULE_DEBUG + program->debug = kon_debugCreate(program->font); + kon_debugSetAssets(program->debug, program->assets); +#ifdef KON_DEVELOPER + kon_addWindowCommands_(state); +#endif +#endif + + state->last = kon_getTime(); + if (config->init && !config->init(program, config->user)) goto fail; + + kon_runMainLoop(program->window, kon_frame_, state); + + if (config->shutdown) config->shutdown(program, config->user); + kon_debugDestroy(program->debug); +#ifdef KON_MODULE_FONT + kon_freeFont(program->font); +#endif +#ifdef KON_MODULE_ASSETS + kon_assetsDestroy(program->assets); +#endif +#ifdef KON_MODULE_PACK + if (program->pack) kon_packClose(program->pack); +#endif + kon_freeDisplay(program->display); + kon_destroyWindow(program->window); + kon_deinit(); + free(state); + return 0; + +fail: + if (program->display) kon_freeDisplay(program->display); + if (program->window) kon_destroyWindow(program->window); + free(state); + return 1; +} |
