summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKonAki <konaki@anokonaki.org>2026-10-07 19:03:04 +0800
committerKonAki <konaki@anokonaki.org>2026-10-07 19:03:04 +0800
commitdfa9a616c3d89a935a4c0bf68f7801581d8b5037 (patch)
treedbedd97ded9a227751555744fc246943af6e6c77 /src
parent5eaa99c67ca44bd48d8e2eae7f906c942d565d67 (diff)
Move headers to kon/ and add per-lib implementation stubs
Diffstat (limited to 'src')
-rw-r--r--src/konfont.h197
-rw-r--r--src/koninput.h142
-rw-r--r--src/konsofren.h1012
-rw-r--r--src/kontime.h85
-rw-r--r--src/kontoml.h649
-rw-r--r--src/konwinlib.h1357
6 files changed, 0 insertions, 3442 deletions
diff --git a/src/konfont.h b/src/konfont.h
deleted file mode 100644
index 822e1f3..0000000
--- a/src/konfont.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * konfont.h
- *
- * 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.
- */
-
-#ifndef KONFONT_H
-#define KONFONT_H
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-#include "konsofren.h"
-
-#define KON_FONT_FIRST_CHAR 32
-#define KON_FONT_NUM_CHARS 95
-
-typedef struct kon_font kon_font_t;
-
-/*** font declarations ***/
-
-kon_font_t *kon_loadFont(const uint8_t *ttf_data, size_t size, float pixelHeight);
-void kon_freeFont(kon_font_t *font);
-
-kon_image *kon_fontGetAtlas(kon_font_t *font);
-
-/*** text draw declarations ***/
-
-void kon_drawText(kon_framebuffer_t *fb, kon_font_t *font, int x, int y, const char *text, uint32_t color);
-void kon_measureText(kon_font_t *font, const char *text, int *outWidth, int *outHeight);
-
-/*** implementatoin ***/
-
-#ifdef KONFONT_IMPLEMENTATION
-
-#include "stb_truetype.h"
-
-struct kon_font {
- stbtt_bakedchar chardata[KON_FONT_NUM_CHARS];
- uint8_t *atlasPixels;
- int atlasSize;
- float pixelHeight;
-};
-
-/*** private helpers ***/
-
-static bool kon_fontBakeAtlas(kon_font_t *font, const uint8_t *ttf_data, float pixelHeight) {
- int sizes[] = {256, 512, 1024, 2048};
-
- for (int i = 0; i < 4; i++) {
- int atlasSize = sizes[i];
-
- uint8_t *bitmap = malloc((size_t)atlasSize * (size_t)atlasSize);
- if (!bitmap) return false;
-
- int result = stbtt_BakeFontBitmap(ttf_data, 0, pixelHeight, bitmap, atlasSize, atlasSize, KON_FONT_FIRST_CHAR, KON_FONT_NUM_CHARS, font->chardata);
-
- if (result > 0) {
- font->atlasPixels = bitmap;
- font->atlasSize = atlasSize;
- return true;
- }
-
- free(bitmap);
- }
-
- return false;
-}
-
-/*** font implementation ***/
-
-kon_font_t *kon_loadFont(const uint8_t *ttf_data, size_t size, float pixelHeight) {
- (void)size;
-
- if (!ttf_data || pixelHeight <= 0.0f) return NULL;
-
- kon_font_t *font = malloc(sizeof(kon_font_t));
- if (!font) return NULL;
-
- font->atlasPixels = NULL;
- font->pixelHeight = pixelHeight;
-
- if (!kon_fontBakeAtlas(font, ttf_data, pixelHeight)) {
- free(font);
- return NULL;
- }
-
- return font;
-}
-
-void kon_freeFont(kon_font_t *font) {
- if (!font) return;
-
- free(font->atlasPixels);
- free(font);
-}
-
-kon_image *kon_fontGetAtlas(kon_font_t *font) {
- if (!font) return NULL;
-
- int n = font->atlasSize * font->atlasSize;
- uint8_t *rgba = malloc((size_t)n * 4);
- if (!rgba) return NULL;
-
- for (int i = 0; i < n; i++) {
- uint8_t a = font->atlasPixels[i];
- rgba[i * 4 + 0] = 255;
- rgba[i * 4 + 1] = 255;
- rgba[i * 4 + 2] = 255;
- rgba[i * 4 + 3] = a;
- }
-
- kon_image *img = kon_loadImage(rgba, font->atlasSize, font->atlasSize, konFormatRGBA8);
- free(rgba);
- return img;
-}
-
-/*** text draw implementation ***/
-
-void kon_drawText(kon_framebuffer_t *fb, kon_font_t *font, int x, int y, const char *text, uint32_t color) {
- if (!fb || !font || !text) return;
-
- uint32_t baseColor = color & 0x00FFFFFF;
-
- float cursorX = (float)x;
- float cursorY = (float)y;
-
- for (const char *p = text; *p; p++) {
- unsigned char c = (unsigned char)*p;
-
- if (c < KON_FONT_FIRST_CHAR || c >= KON_FONT_FIRST_CHAR + KON_FONT_NUM_CHARS) continue;
-
- stbtt_aligned_quad q;
- stbtt_GetBakedQuad(font->chardata, font->atlasSize, font->atlasSize, c - KON_FONT_FIRST_CHAR, &cursorX, &cursorY, &q, 0);
-
- int src_x0 = (int)(q.s0 * font->atlasSize);
- int src_y0 = (int)(q.t0 * font->atlasSize);
- int glyphW = (int)(q.x1 - q.x0);
- int glyphH = (int)(q.y1 - q.y0);
-
- for (int gy = 0; gy < glyphH; gy++) {
- for (int gx = 0; gx < glyphW; gx++) {
- uint8_t alpha = font->atlasPixels[(src_y0 + gy) * font->atlasSize + (src_x0 + gx)];
- if (alpha == 0) continue;
-
- kon_putPixel(fb, (int)q.x0 + gx, (int)q.y0 + gy, ((uint32_t)alpha << 24) | baseColor);
- }
- }
- }
-}
-
-void kon_measureText(kon_font_t *font, const char *text, int *outWidth, int *outHeight) {
- if (!font || !text) return;
-
- float cursorX = 0.0f;
- float cursorY = 0.0f;
- float maxX = 0.0f;
-
- for (const char *p = text; *p; p++) {
- unsigned char c = (unsigned char)*p;
-
- if (c < KON_FONT_FIRST_CHAR || c >= KON_FONT_FIRST_CHAR + KON_FONT_NUM_CHARS) continue;
-
- stbtt_aligned_quad q;
- stbtt_GetBakedQuad(font->chardata, font->atlasSize, font->atlasSize, c - KON_FONT_FIRST_CHAR, &cursorX, &cursorY, &q, 0);
-
- if (cursorX > maxX) maxX = cursorX;
- }
-
- if (outWidth) *outWidth = (int)maxX;
- if (outHeight) *outHeight = (int)font->pixelHeight;
-}
-
-#endif /* KONFONT_IMPLEMENTATION */
-
-#endif /* KONFONT_H */
diff --git a/src/koninput.h b/src/koninput.h
deleted file mode 100644
index 5008c06..0000000
--- a/src/koninput.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
-
-MIT License
-
-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.
-
-*/
-
-#ifndef KONINPUT_H
-#define KONINPUT_H
-
-#include "konwinlib.h"
-
-typedef struct kon_input {
- bool down[KON_KEY_COUNT];
- bool downPrev[KON_KEY_COUNT];
-
- bool mouseDown[3];
- bool mouseDownPrev[3];
-
- int mouseX, mouseY;
-} kon_input_t;
-
-void kon_inputBeginFrame(kon_input_t *input);
-
-void kon_inputFeedEvent(kon_input_t *input, const kon_event_t *event);
-
-bool kon_isKeyDown(const kon_input_t *input, kon_key_t key);
-bool kon_isKeyPressed(const kon_input_t *input, kon_key_t key);
-bool kon_isKeyReleased(const kon_input_t *input, kon_key_t key);
-
-bool kon_isMouseDown(const kon_input_t *input, kon_mouseButton_t button);
-bool kon_isMousePressed(const kon_input_t *input, kon_mouseButton_t button);
-bool kon_isMouseReleased(const kon_input_t *input, kon_mouseButton_t button);
-
-void kon_getMousePos(const kon_input_t *input, int *x, int *y);
-
-/*** implementation ***/
-
-#ifdef KONINPUT_IMPLEMENTATION
-
-void kon_inputBeginFrame(kon_input_t *input) {
- if (!input) return;
-
- for (int i = 0; i < KON_KEY_COUNT; i++) {
- input->downPrev[i] = input->down[i];
- }
- for (int i = 0; i < 3; i++) {
- input->mouseDownPrev[i] = input->mouseDown[i];
- }
-}
-
-void kon_inputFeedEvent(kon_input_t *input, const kon_event_t *event) {
- if (!input || !event) return;
-
- switch (event->type) {
- case KON_EVENT_KEY_DOWN:
- if (event->key >= 0 && event->key < KON_KEY_COUNT)
- input->down[event->key] = true;
- break;
- case KON_EVENT_KEY_UP:
- if (event->key >= 0 && event->key < KON_KEY_COUNT)
- input->down[event->key] = false;
- break;
- case KON_EVENT_MOUSE_DOWN:
- if (event->mouseButton >= 0 && event->mouseButton < 3)
- input->mouseDown[event->mouseButton] = true;
- input->mouseX = event->mouseX;
- input->mouseY = event->mouseY;
- break;
- case KON_EVENT_MOUSE_UP:
- if (event->mouseButton >= 0 && event->mouseButton < 3)
- input->mouseDown[event->mouseButton] = false;
- input->mouseX = event->mouseX;
- input->mouseY = event->mouseY;
- break;
- case KON_EVENT_MOUSE_MOVE:
- input->mouseX = event->mouseX;
- input->mouseY = event->mouseY;
- break;
- default:
- break;
- }
-}
-
-bool kon_isKeyDown(const kon_input_t *input, kon_key_t key) {
- if (!input || key < 0 || key >= KON_KEY_COUNT) return false;
- return input->down[key];
-}
-
-bool kon_isKeyPressed(const kon_input_t *input, kon_key_t key) {
- if (!input || key < 0 || key >= KON_KEY_COUNT) return false;
- return input->down[key] && !input->downPrev[key];
-}
-
-bool kon_isKeyReleased(const kon_input_t *input, kon_key_t key) {
- if (!input || key < 0 || key >= KON_KEY_COUNT) return false;
- return !input->down[key] && input->downPrev[key];
-}
-
-bool kon_isMouseDown(const kon_input_t *input, kon_mouseButton_t button) {
- if (!input || button < 0 || button >= 3) return false;
- return input->mouseDown[button];
-}
-
-bool kon_isMousePressed(const kon_input_t *input, kon_mouseButton_t button) {
- if (!input || button < 0 || button >= 3) return false;
- return input->mouseDown[button] && !input->mouseDownPrev[button];
-}
-
-bool kon_isMouseReleased(const kon_input_t *input, kon_mouseButton_t button) {
- if (!input || button < 0 || button >= 3) return false;
- return !input->mouseDown[button] && input->mouseDownPrev[button];
-}
-
-void kon_getMousePos(const kon_input_t *input, int *x, int *y) {
- if (!input) return;
- if (x) *x = input->mouseX;
- if (y) *y = input->mouseY;
-}
-
-#endif /* KONINPUT_IMPLEMENTATION */
-
-#endif /* KONINPUT_H */
diff --git a/src/konsofren.h b/src/konsofren.h
deleted file mode 100644
index b7ab033..0000000
--- a/src/konsofren.h
+++ /dev/null
@@ -1,1012 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * konsofren.h
- *
- * 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.
- */
-
-#ifndef KONSOFREN_H
-#define KONSOFREN_H
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <math.h>
-
-#define KON_BACKGROUND_COLOR 0xFF05050A
-
-typedef struct kon_framebuffer {
- int width, height;
- uint32_t *data;
-} kon_framebuffer_t;
-
-typedef kon_framebuffer_t kon_image;
-
-typedef enum kon_imageFormat {
- konFormatRGBA8 = 0,
- konFormatABGR8,
- konFormatARGB8,
- konFormatBGRA8
-} kon_imageFormat_t;
-
-#define KON_PI 3.14159265358979323846f
-#define KON_TAU (2.0f * KON_PI)
-
-#define KON_DEG2RAD(d) ((float)(d) * (KON_PI / 180.0f))
-#define KON_RAD2DEG(r) ((float)(r) * (180.0f / KON_PI))
-
-/* kon_vec3_t built from degrees, handy for rotations: KON_DEG3(0, 45, 0) */
-#define KON_DEG3(x, y, z) ((kon_vec3_t){KON_DEG2RAD(x), KON_DEG2RAD(y), KON_DEG2RAD(z)})
-
-#define KON_VEC2(x, y) ((kon_vec2_t){(float)(x), (float)(y)})
-#define KON_VEC3(x, y, z) ((kon_vec3_t){(float)(x), (float)(y), (float)(z)})
-#define KON_VEC4(x, y, z, w) ((kon_vec4_t){(float)(x), (float)(y), (float)(z), (float)(w)})
-
-#define KON_VEC3_ZERO KON_VEC3(0, 0, 0)
-#define KON_VEC3_ONE KON_VEC3(1, 1, 1)
-#define KON_VEC3_UP KON_VEC3(0, 1, 0)
-
-/* right-handed, +Y up, camera looks down -Z, column-major: m[column * 4 + row] */
-
-typedef struct kon_vec2 { float x, y; } kon_vec2_t;
-typedef struct kon_vec3 { float x, y, z; } kon_vec3_t;
-typedef struct kon_vec4 { float x, y, z, w; } kon_vec4_t;
-typedef struct kon_mat4 { float m[16]; } kon_mat4_t;
-
-/* game is the fixed-size framebuffer you draw into, screen always matches the window */
-typedef struct kon_display {
- kon_framebuffer_t *game;
- kon_framebuffer_t *screen;
- int integerOnly;
-
- /* where the game image sits inside screen, kept up to date by the functions below */
- int viewX, viewY, viewWidth, viewHeight;
- int *columnMap;
-} kon_display_t;
-
-typedef enum kon_projection {
- KON_PROJECTION_PERSPECTIVE = 0,
- KON_PROJECTION_ORTHOGRAPHIC
-} kon_projection_t;
-
-typedef struct kon_camera {
- kon_vec3_t position;
- kon_vec3_t target;
- kon_vec3_t up;
- kon_projection_t projection;
- float fov; /* vertical field of view in radians, perspective only */
- float orthoSize; /* half the visible height in world units, orthographic only */
- float nearZ, farZ;
-} kon_camera_t;
-
-/* edges holds pairs of indices into vertices */
-typedef struct kon_wireMesh {
- const kon_vec3_t *vertices;
- const uint16_t *edges;
- int edgeCount;
-} kon_wireMesh_t;
-
-/*** 2D declarations ***/
-
-/*** framebuffer declarations ***/
-
-kon_framebuffer_t *kon_createFramebuffer(int width, int height);
-void kon_freeFramebuffer(kon_framebuffer_t *fb);
-void kon_putPixel(kon_framebuffer_t *fb, int x, int y, uint32_t color);
-void kon_clearFramebuffer(kon_framebuffer_t *fb, uint32_t color);
-void kon_resizeFramebuffer(kon_framebuffer_t *fb, int width, int height);
-void kon_exportPixels(kon_framebuffer_t *fb, kon_imageFormat_t format, uint8_t *out);
-
-/*** image declarations ***/
-
-kon_image *kon_loadImage(const uint8_t *pixels, int width, int height, kon_imageFormat_t format);
-void kon_freeImage(kon_image *image);
-
-void kon_drawImage(kon_framebuffer_t *fb, int x, int y, int width, int height, kon_image *image);
-
-/*** draw function declarations ***/
-
-void kon_drawRectangle(kon_framebuffer_t *fb, int x, int y, int width, int height, uint32_t color);
-void kon_fillRectangle(kon_framebuffer_t *fb, int x, int y, int width, int height, uint32_t color);
-void kon_drawLine(kon_framebuffer_t *fb, int x0, int y0, int x1, int y1, uint32_t color);
-void kon_drawCircle(kon_framebuffer_t *fb, int center_x, int center_y, int radius, uint32_t color);
-void kon_fillCircle(kon_framebuffer_t *fb, int center_x, int center_y, int radius, uint32_t color);
-
-/*** math declarations ***/
-
-/*** scalar declarations ***/
-
-float kon_clamp(float v, float min, float max);
-float kon_lerp(float a, float b, float t);
-
-/*** vec2 declarations ***/
-
-kon_vec2_t kon_vec2Add(kon_vec2_t a, kon_vec2_t b);
-kon_vec2_t kon_vec2Sub(kon_vec2_t a, kon_vec2_t b);
-kon_vec2_t kon_vec2Scale(kon_vec2_t a, float s);
-float kon_vec2Dot(kon_vec2_t a, kon_vec2_t b);
-
-/*** vec3 declarations ***/
-
-kon_vec3_t kon_vec3Add(kon_vec3_t a, kon_vec3_t b);
-kon_vec3_t kon_vec3Sub(kon_vec3_t a, kon_vec3_t b);
-kon_vec3_t kon_vec3Scale(kon_vec3_t a, float s);
-float kon_vec3Dot(kon_vec3_t a, kon_vec3_t b);
-kon_vec3_t kon_vec3Cross(kon_vec3_t a, kon_vec3_t b);
-float kon_vec3Length(kon_vec3_t a);
-kon_vec3_t kon_vec3Normalize(kon_vec3_t a);
-kon_vec3_t kon_vec3Lerp(kon_vec3_t a, kon_vec3_t b, float t);
-
-/*** mat4 declarations ***/
-
-kon_mat4_t kon_mat4Identity(void);
-kon_mat4_t kon_mat4Mul(kon_mat4_t a, kon_mat4_t b);
-kon_vec4_t kon_mat4MulVec4(kon_mat4_t m, kon_vec4_t v);
-kon_vec3_t kon_mat4MulPoint(kon_mat4_t m, kon_vec3_t p);
-
-/* like blender's local/global: the plain versions work along the model's own axes,
- the World versions along the world's axes. neither rotate nor scale ever moves the model's position.
- angles are euler angles in radians (x = pitch, y = yaw, z = roll), see KON_DEG3 */
-kon_mat4_t kon_mat4Translate(kon_mat4_t m, kon_vec3_t v);
-kon_mat4_t kon_mat4Rotate(kon_mat4_t m, kon_vec3_t angles);
-kon_mat4_t kon_mat4Scale(kon_mat4_t m, kon_vec3_t v);
-kon_mat4_t kon_mat4TranslateWorld(kon_mat4_t m, kon_vec3_t v);
-kon_mat4_t kon_mat4RotateWorld(kon_mat4_t m, kon_vec3_t angles);
-kon_mat4_t kon_mat4ScaleWorld(kon_mat4_t m, kon_vec3_t v);
-
-kon_mat4_t kon_mat4FromTranslation(kon_vec3_t v);
-kon_mat4_t kon_mat4FromRotation(kon_vec3_t angles);
-kon_mat4_t kon_mat4FromAxisAngle(kon_vec3_t axis, float angle);
-kon_mat4_t kon_mat4FromScale(kon_vec3_t v);
-kon_mat4_t kon_mat4FromTransform(kon_vec3_t position, kon_vec3_t angles, kon_vec3_t scale);
-
-kon_mat4_t kon_mat4LookAt(kon_vec3_t eye, kon_vec3_t target, kon_vec3_t up);
-kon_mat4_t kon_mat4Perspective(float fovY, float aspect, float nearZ, float farZ);
-kon_mat4_t kon_mat4Ortho(float left, float right, float bottom, float top, float nearZ, float farZ);
-
-/*** display declarations ***/
-
-
-kon_display_t *kon_createDisplay(int gameWidth, int gameHeight, int windowWidth, int windowHeight);
-void kon_freeDisplay(kon_display_t *display);
-
-void kon_setGameResolution(kon_display_t *display, int gameWidth, int gameHeight);
-void kon_setIntegerScaling(kon_display_t *display, int integerOnly);
-void kon_resizeDisplay(kon_display_t *display, int windowWidth, int windowHeight);
-
-/* scales game into screen, then blit display->screen to the window */
-void kon_presentDisplay(kon_display_t *display);
-
-/* returns 0 if the window position is on a bar, outside the game image */
-int kon_windowToGame(const kon_display_t *display, int windowX, int windowY, int *gameX, int *gameY);
-
-/*** 3D declarations ***/
-
-/*** camera declarations ***/
-
-kon_camera_t kon_cameraDefault(void);
-kon_mat4_t kon_cameraView(const kon_camera_t *camera);
-kon_mat4_t kon_cameraProjection(const kon_camera_t *camera, int width, int height);
-kon_mat4_t kon_cameraViewProjection(const kon_camera_t *camera, int width, int height);
-
-/*** 3D draw declarations ***/
-
-/* returns 0 if the point is behind the camera */
-int kon_worldToScreen(const kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_vec3_t point, kon_vec2_t *out);
-
-void kon_drawLine3D(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_vec3_t a, kon_vec3_t b, uint32_t color);
-void kon_drawWireMesh(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_mat4_t model, const kon_wireMesh_t *mesh, uint32_t color);
-
-/*** implementation ***/
-
-#ifdef KONSOFREN_IMPLEMENTATION
-
-
-/*** private helper ***/
-
-static inline uint32_t kon_blendColor(uint32_t dst, uint32_t src) {
-
- uint8_t src_a = (uint8_t)((src >> 24) & 0xFF);
- uint8_t src_r = (uint8_t)((src >> 16) & 0xFF);
- uint8_t src_g = (uint8_t)((src >> 8) & 0xFF);
- uint8_t src_b = (uint8_t)((src >> 0) & 0xFF);
-
- if (src_a == 0xFF) {
- return src;
- }
-
- uint8_t dst_a = (uint8_t)((dst >> 24) & 0xFF);
- uint8_t dst_r = (uint8_t)((dst >> 16) & 0xFF);
- uint8_t dst_g = (uint8_t)((dst >> 8) & 0xFF);
- uint8_t dst_b = (uint8_t)((dst >> 0) & 0xFF);
-
- uint8_t inv_a = (uint8_t)(255 - src_a);
-
- uint8_t out_r = (uint8_t)((src_r * src_a + dst_r * inv_a) / 255);
- uint8_t out_g = (uint8_t)((src_g * src_a + dst_g * inv_a) / 255);
- uint8_t out_b = (uint8_t)((src_b * src_a + dst_b * inv_a) / 255);
-
- return ((uint32_t)dst_a << 24) | ((uint32_t)out_r << 16) | ((uint32_t)out_g << 8) | (uint32_t)out_b;
-}
-
-/* Cohen-Sutherland: clips the line to the framebuffer, returns 0 if nothing is visible */
-static int kon_outCode_(double x, double y, int width, int height) {
- int code = 0;
- if (x < 0) code |= 1; else if (x > width - 1) code |= 2;
- if (y < 0) code |= 4; else if (y > height - 1) code |= 8;
- return code;
-}
-
-static int kon_clipLine_(int width, int height, int *x0, int *y0, int *x1, int *y1) {
- double ax = *x0, ay = *y0, bx = *x1, by = *y1;
- double maxX = width - 1, maxY = height - 1;
- int ca = kon_outCode_(ax, ay, width, height);
- int cb = kon_outCode_(bx, by, width, height);
-
- while (ca | cb) {
- if (ca & cb) return 0;
-
- int out = ca ? ca : cb;
- double x, y;
-
- if (out & 8) {
- x = ax + (bx - ax) * (maxY - ay) / (by - ay);
- y = maxY;
- } else if (out & 4) {
- x = ax + (bx - ax) * (0 - ay) / (by - ay);
- y = 0;
- } else if (out & 2) {
- y = ay + (by - ay) * (maxX - ax) / (bx - ax);
- x = maxX;
- } else {
- y = ay + (by - ay) * (0 - ax) / (bx - ax);
- x = 0;
- }
-
- if (out == ca) {
- ax = x; ay = y;
- ca = kon_outCode_(ax, ay, width, height);
- } else {
- bx = x; by = y;
- cb = kon_outCode_(bx, by, width, height);
- }
- }
-
- *x0 = (int)(ax + 0.5); *y0 = (int)(ay + 0.5);
- *x1 = (int)(bx + 0.5); *y1 = (int)(by + 0.5);
- return 1;
-}
-
-/*** framebuffer implementation ***/
-
-kon_framebuffer_t *kon_createFramebuffer(int width, int height) {
- kon_framebuffer_t *fb = malloc(sizeof(kon_framebuffer_t));
- if (!fb) return NULL;
-
- fb->data = calloc((size_t)width * (size_t)height, sizeof(uint32_t));
- if (!fb->data) {
- free(fb);
- return NULL;
- }
-
- fb->width = width;
- fb->height = height;
- return fb;
-}
-
-void kon_freeFramebuffer(kon_framebuffer_t *fb) {
- if (!fb) return;
-
- free(fb->data);
- free(fb);
-}
-
-void kon_putPixel(kon_framebuffer_t *fb, int x, int y, uint32_t color) {
- if (!fb) return;
-
- if (x < 0 || x >= fb->width || y < 0 || y >= fb->height) return;
-
- uint32_t dst = fb->data[y * fb->width + x];
- fb->data[y * fb->width + x] = kon_blendColor(dst, color);
-}
-
-void kon_clearFramebuffer(kon_framebuffer_t *fb, uint32_t color) {
- if (!fb) return;
-
- for (int i = 0; i < fb->width * fb->height; i++) {
- /* did it directly to not check overhead because of the if in bounds check */
- fb->data[i] = color;
- }
-}
-
-void kon_resizeFramebuffer(kon_framebuffer_t *fb, int width, int height) {
- if (!fb) return;
-
- uint32_t *tmp = realloc(fb->data, (size_t)width * (size_t)height * sizeof(uint32_t));
- if (!tmp) return;
-
- fb->data = tmp;
- fb->width = width;
- fb->height = height;
-
- kon_clearFramebuffer(fb, KON_BACKGROUND_COLOR);
-}
-
-void kon_exportPixels(kon_framebuffer_t *fb, kon_imageFormat_t format, uint8_t *out) {
- if (!fb || !out) return;
-
- int fbSize = fb->width * fb->height;
-
- for (int i = 0; i < fbSize; i++) {
- uint32_t color = fb->data[i];
-
- uint8_t a = (color >> 24) & 0xFF;
- uint8_t r = (color >> 16) & 0xFF;
- uint8_t g = (color >> 8) & 0xFF;
- uint8_t b = (color >> 0) & 0xFF;
-
- switch (format) {
- case konFormatRGBA8:
- out[i * 4 + 0] = r;
- out[i * 4 + 1] = g;
- out[i * 4 + 2] = b;
- out[i * 4 + 3] = a;
- break;
- case konFormatABGR8:
- out[i * 4 + 0] = a;
- out[i * 4 + 1] = b;
- out[i * 4 + 2] = g;
- out[i * 4 + 3] = r;
- break;
- case konFormatARGB8:
- out[i * 4 + 0] = a;
- out[i * 4 + 1] = r;
- out[i * 4 + 2] = g;
- out[i * 4 + 3] = b;
- break;
- case konFormatBGRA8:
- out[i * 4 + 0] = b;
- out[i * 4 + 1] = g;
- out[i * 4 + 2] = r;
- out[i * 4 + 3] = a;
- break;
- default:
- return;
- }
- }
-}
-
-/*** draw functions implementation ***/
-
-void kon_drawRectangle(kon_framebuffer_t *fb, int x, int y, int width, int height, uint32_t color) {
- if (!fb) return;
-
- kon_drawLine(fb, x, y, x + width, y, color);
- kon_drawLine(fb, x, y + height, x + width, y + height, color);
- kon_drawLine(fb, x, y, x, y + height, color);
- kon_drawLine(fb, x + width, y, x + width, y + height, color);
-}
-
-void kon_fillRectangle(kon_framebuffer_t *fb, int x, int y, int width, int height, uint32_t color) {
- if (!fb) return;
-
- if (width < 0 || height < 0) return;
-
- if (x < 0) {
- width += x;
- x = 0;
- }
- if (y < 0) {
- height += y;
- y = 0;
- }
-
- if (x + width > fb->width ) width = fb->width - x;
- if (y + height > fb->height) height = fb->height - y;
-
- for (int offset_y = 0; offset_y < height; offset_y++) {
- for (int offset_x = 0; offset_x < width; offset_x++) {
- uint32_t dst = fb->data[(offset_y + y) * fb->width + (offset_x + x)];
- fb->data[(y + offset_y) * fb->width + (x + offset_x)] = kon_blendColor(dst, color);
-
- }
- }
-}
-
-void kon_drawLine(kon_framebuffer_t *fb, int x0, int y0, int x1, int y1, uint32_t color) {
- if (!fb) return;
-
- if (!kon_clipLine_(fb->width, fb->height, &x0, &y0, &x1, &y1)) return;
-
- int dx = abs(x1 - x0);
- int dy = abs(y1 - y0);
-
- int sx = (x0 < x1) ? 1 : -1;
- int sy = (y0 < y1) ? 1 : -1;
-
- int err = dx - dy;
-
- for (;;) {
- kon_putPixel(fb, x0, y0, color);
-
- if (x0 == x1 && y0 == y1) break;
-
- int e2 = 2 * err;
-
- if (e2 > -dy) {
- err -= dy;
- x0 += sx;
- }
-
- if (e2 < dx) {
- err += dx;
- y0 += sy;
- }
- }
-}
-
-void kon_drawCircle(kon_framebuffer_t *fb, int center_x, int center_y, int radius, uint32_t color) {
- if (!fb) return;
- if (radius <= 0) return;
-
- int x = radius;
- int y = 0;
- int err = 1 - radius;
-
- while (x >= y) {
- kon_putPixel(fb, center_x + x, center_y + y, color);
- kon_putPixel(fb, center_x + y, center_y + x, color);
- kon_putPixel(fb, center_x - y, center_y + x, color);
- kon_putPixel(fb, center_x - x, center_y + y, color);
- kon_putPixel(fb, center_x - x, center_y - y, color);
- kon_putPixel(fb, center_x - y, center_y - x, color);
- kon_putPixel(fb, center_x + y, center_y - x, color);
- kon_putPixel(fb, center_x + x, center_y - y, color);
-
- y += 1;
-
- if (err < 0) {
- err += 2 * y + 1;
- } else {
- x -= 1;
- err += 2 * (y - x) + 1;
- }
- }
-}
-
-void kon_fillCircle(kon_framebuffer_t *fb, int center_x, int center_y, int radius, uint32_t color) {
- if (!fb) return;
- if (radius <= 0) return;
-
- int x = radius;
- int y = 0;
- int err = 1 - radius;
-
- while (x >= y) {
- kon_drawLine(fb, center_x - x, center_y + y, center_x + x, center_y + y, color);
- kon_drawLine(fb, center_x - x, center_y - y, center_x + x, center_y - y, color);
- kon_drawLine(fb, center_x - y, center_y + x, center_x + y, center_y + x, color);
- kon_drawLine(fb, center_x - y, center_y - x, center_x + y, center_y - x, color);
-
- y += 1;
-
- if (err < 0) {
- err += 2 * y + 1;
- } else {
- x -= 1;
- err += 2 * (y - x) + 1;
- }
- }
-}
-
-/*** image implementation ***/
-
-kon_image *kon_loadImage(const uint8_t *pixels, int width, int height, kon_imageFormat_t format) {
- kon_image *image = malloc(sizeof(kon_image));
- if (!image) return NULL;
-
- image->data = malloc((size_t)width * (size_t)height * sizeof(uint32_t));
- if (!image->data) {
- free(image);
- return NULL;
- }
-
- image->width = width;
- image->height = height;
-
- for (int i = 0; i < width * height; i++) {
- uint8_t r, g, b, a;
-
- switch(format) {
- case konFormatRGBA8:
- r = pixels[i * 4 + 0];
- g = pixels[i * 4 + 1];
- b = pixels[i * 4 + 2];
- a = pixels[i * 4 + 3];
- break;
- case konFormatABGR8:
- a = pixels[i * 4 + 0];
- b = pixels[i * 4 + 1];
- g = pixels[i * 4 + 2];
- r = pixels[i * 4 + 3];
- break;
- case konFormatARGB8:
- a = pixels[i * 4 + 0];
- r = pixels[i * 4 + 1];
- g = pixels[i * 4 + 2];
- b = pixels[i * 4 + 3];
- break;
- case konFormatBGRA8:
- b = pixels[i * 4 + 0];
- g = pixels[i * 4 + 1];
- r = pixels[i * 4 + 2];
- a = pixels[i * 4 + 3];
- break;
- default:
- free(image->data);
- free(image);
- return NULL;
- }
-
- image->data[i] = ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
- }
-
- return image;
-}
-void kon_freeImage(kon_image *image) {
- kon_freeFramebuffer(image);
-}
-
-void kon_drawImage(kon_framebuffer_t *fb, int x, int y, int width, int height, kon_image *image) {
- if (!fb || !image) return;
-
- /* just trying to not draw when it's unnecessary */
- if (image->width <= 0 || image->height <= 0) return;
- if (width <= 0 || height <= 0) return;
- if (x >= fb->width || y >= fb->height) return;
-
- /* using this loop to make sure we only the parts of the image that are on screen */
- for (int iy = 0; iy < height; iy++) {
- for (int ix = 0; ix < width; ix++) {
- int src_x = ix * image->width / width;
- int src_y = iy * image->height / height;
-
- uint32_t color = image->data[src_y * image->width + src_x];
- kon_putPixel(fb, x+ix, y+iy, color);
- }
- }
-}
-
-/*** math implementation ***/
-
-
-/*** scalar ***/
-
-float kon_clamp(float v, float min, float max) { return v < min ? min : (v > max ? max : v); }
-float kon_lerp(float a, float b, float t) { return a + (b - a) * t; }
-
-/*** vec2 ***/
-
-kon_vec2_t kon_vec2Add(kon_vec2_t a, kon_vec2_t b) { return (kon_vec2_t){a.x + b.x, a.y + b.y}; }
-kon_vec2_t kon_vec2Sub(kon_vec2_t a, kon_vec2_t b) { return (kon_vec2_t){a.x - b.x, a.y - b.y}; }
-kon_vec2_t kon_vec2Scale(kon_vec2_t a, float s) { return (kon_vec2_t){a.x * s, a.y * s}; }
-float kon_vec2Dot(kon_vec2_t a, kon_vec2_t b) { return a.x * b.x + a.y * b.y; }
-
-/*** vec3 ***/
-
-kon_vec3_t kon_vec3Add(kon_vec3_t a, kon_vec3_t b) { return (kon_vec3_t){a.x + b.x, a.y + b.y, a.z + b.z}; }
-kon_vec3_t kon_vec3Sub(kon_vec3_t a, kon_vec3_t b) { return (kon_vec3_t){a.x - b.x, a.y - b.y, a.z - b.z}; }
-kon_vec3_t kon_vec3Scale(kon_vec3_t a, float s) { return (kon_vec3_t){a.x * s, a.y * s, a.z * s}; }
-float kon_vec3Dot(kon_vec3_t a, kon_vec3_t b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
-
-kon_vec3_t kon_vec3Cross(kon_vec3_t a, kon_vec3_t b) {
- return (kon_vec3_t){
- a.y * b.z - a.z * b.y,
- a.z * b.x - a.x * b.z,
- a.x * b.y - a.y * b.x
- };
-}
-
-float kon_vec3Length(kon_vec3_t a) { return sqrtf(kon_vec3Dot(a, a)); }
-
-kon_vec3_t kon_vec3Normalize(kon_vec3_t a) {
- float len = kon_vec3Length(a);
- return len > 0.0f ? kon_vec3Scale(a, 1.0f / len) : a;
-}
-
-kon_vec3_t kon_vec3Lerp(kon_vec3_t a, kon_vec3_t b, float t) {
- return (kon_vec3_t){kon_lerp(a.x, b.x, t), kon_lerp(a.y, b.y, t), kon_lerp(a.z, b.z, t)};
-}
-
-/*** mat4 ***/
-
-kon_mat4_t kon_mat4Identity(void) {
- kon_mat4_t r = {{0}};
- r.m[0] = r.m[5] = r.m[10] = r.m[15] = 1.0f;
- return r;
-}
-
-/* returns a * b, b is applied first */
-kon_mat4_t kon_mat4Mul(kon_mat4_t a, kon_mat4_t b) {
- kon_mat4_t r;
- for (int c = 0; c < 4; c++) {
- for (int row = 0; row < 4; row++) {
- float sum = 0.0f;
- for (int k = 0; k < 4; k++) {
- sum += a.m[k * 4 + row] * b.m[c * 4 + k];
- }
- r.m[c * 4 + row] = sum;
- }
- }
- return r;
-}
-
-kon_vec4_t kon_mat4MulVec4(kon_mat4_t m, kon_vec4_t v) {
- return (kon_vec4_t){
- m.m[0] * v.x + m.m[4] * v.y + m.m[8] * v.z + m.m[12] * v.w,
- m.m[1] * v.x + m.m[5] * v.y + m.m[9] * v.z + m.m[13] * v.w,
- m.m[2] * v.x + m.m[6] * v.y + m.m[10] * v.z + m.m[14] * v.w,
- m.m[3] * v.x + m.m[7] * v.y + m.m[11] * v.z + m.m[15] * v.w
- };
-}
-
-kon_vec3_t kon_mat4MulPoint(kon_mat4_t m, kon_vec3_t p) {
- kon_vec4_t r = kon_mat4MulVec4(m, (kon_vec4_t){p.x, p.y, p.z, 1.0f});
- return (kon_vec3_t){r.x, r.y, r.z};
-}
-
-kon_mat4_t kon_mat4FromTranslation(kon_vec3_t v) {
- kon_mat4_t r = kon_mat4Identity();
- r.m[12] = v.x;
- r.m[13] = v.y;
- r.m[14] = v.z;
- return r;
-}
-
-kon_mat4_t kon_mat4FromScale(kon_vec3_t v) {
- kon_mat4_t r = kon_mat4Identity();
- r.m[0] = v.x;
- r.m[5] = v.y;
- r.m[10] = v.z;
- return r;
-}
-
-kon_mat4_t kon_mat4FromAxisAngle(kon_vec3_t axis, float angle) {
- kon_vec3_t a = kon_vec3Normalize(axis);
- float c = cosf(angle), s = sinf(angle), t = 1.0f - c;
- kon_mat4_t r = kon_mat4Identity();
- r.m[0] = t * a.x * a.x + c;
- r.m[1] = t * a.x * a.y + s * a.z;
- r.m[2] = t * a.x * a.z - s * a.y;
- r.m[4] = t * a.x * a.y - s * a.z;
- r.m[5] = t * a.y * a.y + c;
- r.m[6] = t * a.y * a.z + s * a.x;
- r.m[8] = t * a.x * a.z + s * a.y;
- r.m[9] = t * a.y * a.z - s * a.x;
- r.m[10] = t * a.z * a.z + c;
- return r;
-}
-
-/* applied in order roll (z), pitch (x), yaw (y) */
-kon_mat4_t kon_mat4FromRotation(kon_vec3_t angles) {
- kon_mat4_t x = kon_mat4FromAxisAngle(KON_VEC3(1, 0, 0), angles.x);
- kon_mat4_t y = kon_mat4FromAxisAngle(KON_VEC3(0, 1, 0), angles.y);
- kon_mat4_t z = kon_mat4FromAxisAngle(KON_VEC3(0, 0, 1), angles.z);
- return kon_mat4Mul(y, kon_mat4Mul(x, z));
-}
-
-kon_mat4_t kon_mat4FromTransform(kon_vec3_t position, kon_vec3_t angles, kon_vec3_t scale) {
- kon_mat4_t r = kon_mat4Mul(kon_mat4FromRotation(angles), kon_mat4FromScale(scale));
- return kon_mat4Mul(kon_mat4FromTranslation(position), r);
-}
-
-kon_mat4_t kon_mat4Translate(kon_mat4_t m, kon_vec3_t v) { return kon_mat4Mul(m, kon_mat4FromTranslation(v)); }
-kon_mat4_t kon_mat4Rotate(kon_mat4_t m, kon_vec3_t angles) { return kon_mat4Mul(m, kon_mat4FromRotation(angles)); }
-kon_mat4_t kon_mat4Scale(kon_mat4_t m, kon_vec3_t v) { return kon_mat4Mul(m, kon_mat4FromScale(v)); }
-kon_mat4_t kon_mat4TranslateWorld(kon_mat4_t m, kon_vec3_t v) { return kon_mat4Mul(kon_mat4FromTranslation(v), m); }
-
-/* pre-multiplying would also swing the position around the world origin, so put it back */
-kon_mat4_t kon_mat4RotateWorld(kon_mat4_t m, kon_vec3_t angles) {
- kon_mat4_t r = kon_mat4Mul(kon_mat4FromRotation(angles), m);
- r.m[12] = m.m[12];
- r.m[13] = m.m[13];
- r.m[14] = m.m[14];
- return r;
-}
-
-kon_mat4_t kon_mat4ScaleWorld(kon_mat4_t m, kon_vec3_t v) {
- kon_mat4_t r = kon_mat4Mul(kon_mat4FromScale(v), m);
- r.m[12] = m.m[12];
- r.m[13] = m.m[13];
- r.m[14] = m.m[14];
- return r;
-}
-
-kon_mat4_t kon_mat4LookAt(kon_vec3_t eye, kon_vec3_t target, kon_vec3_t up) {
- kon_vec3_t f = kon_vec3Normalize(kon_vec3Sub(target, eye));
- kon_vec3_t s = kon_vec3Normalize(kon_vec3Cross(f, up));
- kon_vec3_t u = kon_vec3Cross(s, f);
-
- kon_mat4_t r = kon_mat4Identity();
- r.m[0] = s.x; r.m[4] = s.y; r.m[8] = s.z; r.m[12] = -kon_vec3Dot(s, eye);
- r.m[1] = u.x; r.m[5] = u.y; r.m[9] = u.z; r.m[13] = -kon_vec3Dot(u, eye);
- r.m[2] = -f.x; r.m[6] = -f.y; r.m[10] = -f.z; r.m[14] = kon_vec3Dot(f, eye);
- return r;
-}
-
-/* fovY in radians, aspect = width / height */
-kon_mat4_t kon_mat4Perspective(float fovY, float aspect, float nearZ, float farZ) {
- kon_mat4_t r = {{0}};
- float f = 1.0f / tanf(fovY * 0.5f);
- r.m[0] = f / aspect;
- r.m[5] = f;
- r.m[10] = (farZ + nearZ) / (nearZ - farZ);
- r.m[11] = -1.0f;
- r.m[14] = (2.0f * farZ * nearZ) / (nearZ - farZ);
- return r;
-}
-
-kon_mat4_t kon_mat4Ortho(float left, float right, float bottom, float top, float nearZ, float farZ) {
- kon_mat4_t r = kon_mat4Identity();
- r.m[0] = 2.0f / (right - left);
- r.m[5] = 2.0f / (top - bottom);
- r.m[10] = -2.0f / (farZ - nearZ);
- r.m[12] = -(right + left) / (right - left);
- r.m[13] = -(top + bottom) / (top - bottom);
- r.m[14] = -(farZ + nearZ) / (farZ - nearZ);
- return r;
-}
-
-
-/*** display implementation ***/
-
-static void kon_updateView_(kon_display_t *display) {
- int gameWidth = display->game->width, gameHeight = display->game->height;
- int windowWidth = display->screen->width, windowHeight = display->screen->height;
-
- int scaleX = windowWidth / gameWidth;
- int scaleY = windowHeight / gameHeight;
- int scale = (scaleX < scaleY) ? scaleX : scaleY;
-
- if (display->integerOnly && scale >= 1) {
- display->viewWidth = gameWidth * scale;
- display->viewHeight = gameHeight * scale;
- } else if ((int64_t)windowWidth * gameHeight <= (int64_t)windowHeight * gameWidth) {
- /* window is narrower than the game: bars on top and bottom */
- display->viewWidth = windowWidth;
- display->viewHeight = (int)((int64_t)windowWidth * gameHeight / gameWidth);
- } else {
- /* window is wider than the game: bars on the sides */
- display->viewHeight = windowHeight;
- display->viewWidth = (int)((int64_t)windowHeight * gameWidth / gameHeight);
- }
-
- display->viewX = (windowWidth - display->viewWidth) / 2;
- display->viewY = (windowHeight - display->viewHeight) / 2;
-
- /* which game column each view column shows, worked out once instead of for every pixel */
- int *map = realloc(display->columnMap, (size_t)windowWidth * sizeof(int));
- if (!map) {
- display->viewWidth = 0;
- return;
- }
- display->columnMap = map;
-
- for (int x = 0; x < display->viewWidth; x++) {
- map[x] = (int)((int64_t)x * gameWidth / display->viewWidth);
- }
-}
-
-kon_display_t *kon_createDisplay(int gameWidth, int gameHeight, int windowWidth, int windowHeight) {
- if (gameWidth <= 0 || gameHeight <= 0 || windowWidth <= 0 || windowHeight <= 0) return NULL;
-
- kon_display_t *display = calloc(1, sizeof(kon_display_t));
- if (!display) return NULL;
-
- display->game = kon_createFramebuffer(gameWidth, gameHeight);
- display->screen = kon_createFramebuffer(windowWidth, windowHeight);
- if (!display->game || !display->screen) {
- kon_freeDisplay(display);
- return NULL;
- }
-
- kon_clearFramebuffer(display->game, KON_BACKGROUND_COLOR);
- kon_updateView_(display);
- return display;
-}
-
-void kon_freeDisplay(kon_display_t *display) {
- if (!display) return;
-
- kon_freeFramebuffer(display->game);
- kon_freeFramebuffer(display->screen);
- free(display->columnMap);
- free(display);
-}
-
-void kon_setGameResolution(kon_display_t *display, int gameWidth, int gameHeight) {
- if (!display || gameWidth <= 0 || gameHeight <= 0) return;
-
- kon_resizeFramebuffer(display->game, gameWidth, gameHeight);
- kon_updateView_(display);
-}
-
-void kon_setIntegerScaling(kon_display_t *display, int integerOnly) {
- if (!display) return;
-
- display->integerOnly = integerOnly;
- kon_updateView_(display);
-}
-
-void kon_resizeDisplay(kon_display_t *display, int windowWidth, int windowHeight) {
- if (!display || windowWidth <= 0 || windowHeight <= 0) return;
-
- kon_resizeFramebuffer(display->screen, windowWidth, windowHeight);
- kon_updateView_(display);
-}
-
-void kon_presentDisplay(kon_display_t *display) {
- if (!display) return;
-
- const uint32_t barColor = 0xFF000000;
- kon_framebuffer_t *game = display->game;
- kon_framebuffer_t *screen = display->screen;
- int rightX = display->viewX + display->viewWidth;
-
- for (int y = 0; y < screen->height; y++) {
- uint32_t *row = &screen->data[(size_t)y * (size_t)screen->width];
-
- if (display->viewWidth <= 0 || y < display->viewY || y >= display->viewY + display->viewHeight) {
- for (int x = 0; x < screen->width; x++) row[x] = barColor;
- continue;
- }
-
- int srcY = (int)((int64_t)(y - display->viewY) * game->height / display->viewHeight);
- const uint32_t *srcRow = &game->data[(size_t)srcY * (size_t)game->width];
-
- for (int x = 0; x < display->viewX; x++) row[x] = barColor;
- for (int x = 0; x < display->viewWidth; x++) row[display->viewX + x] = srcRow[display->columnMap[x]];
- for (int x = rightX; x < screen->width; x++) row[x] = barColor;
- }
-}
-
-int kon_windowToGame(const kon_display_t *display, int windowX, int windowY, int *gameX, int *gameY) {
- if (!display || display->viewWidth <= 0 || display->viewHeight <= 0) return 0;
-
- int localX = windowX - display->viewX;
- int localY = windowY - display->viewY;
- if (localX < 0 || localX >= display->viewWidth || localY < 0 || localY >= display->viewHeight) return 0;
-
- if (gameX) *gameX = (int)((int64_t)localX * display->game->width / display->viewWidth);
- if (gameY) *gameY = (int)((int64_t)localY * display->game->height / display->viewHeight);
- return 1;
-}
-
-/*** 3D implementation ***/
-
-
-/*** private helper ***/
-
-static kon_vec2_t kon_clipToScreen_(const kon_framebuffer_t *fb, kon_vec4_t clip) {
- /* clamped so the later float to int conversion can't overflow */
- float ndcX = kon_clamp(clip.x / clip.w, -1.0e5f, 1.0e5f);
- float ndcY = kon_clamp(clip.y / clip.w, -1.0e5f, 1.0e5f);
-
- /* screen +Y points down, NDC +Y points up */
- return KON_VEC2((ndcX + 1.0f) * 0.5f * (float)fb->width, (1.0f - ndcY) * 0.5f * (float)fb->height);
-}
-
-/*** camera implementation ***/
-
-kon_camera_t kon_cameraDefault(void) {
- kon_camera_t camera;
- camera.position = KON_VEC3(0, 0, 5);
- camera.target = KON_VEC3_ZERO;
- camera.up = KON_VEC3_UP;
- camera.projection = KON_PROJECTION_PERSPECTIVE;
- camera.fov = KON_DEG2RAD(60);
- camera.orthoSize = 5.0f;
- camera.nearZ = 0.1f;
- camera.farZ = 100.0f;
- return camera;
-}
-
-kon_mat4_t kon_cameraView(const kon_camera_t *camera) {
- return kon_mat4LookAt(camera->position, camera->target, camera->up);
-}
-
-kon_mat4_t kon_cameraProjection(const kon_camera_t *camera, int width, int height) {
- float aspect = (height > 0) ? (float)width / (float)height : 1.0f;
-
- if (camera->projection == KON_PROJECTION_ORTHOGRAPHIC) {
- float halfH = camera->orthoSize;
- float halfW = halfH * aspect;
- return kon_mat4Ortho(-halfW, halfW, -halfH, halfH, camera->nearZ, camera->farZ);
- }
-
- return kon_mat4Perspective(camera->fov, aspect, camera->nearZ, camera->farZ);
-}
-
-kon_mat4_t kon_cameraViewProjection(const kon_camera_t *camera, int width, int height) {
- return kon_mat4Mul(kon_cameraProjection(camera, width, height), kon_cameraView(camera));
-}
-
-/*** 3D draw implementation ***/
-
-int kon_worldToScreen(const kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_vec3_t point, kon_vec2_t *out) {
- if (!fb || !out) return 0;
-
- kon_vec4_t clip = kon_mat4MulVec4(viewProjection, KON_VEC4(point.x, point.y, point.z, 1));
-
- /* in front of the near plane when z >= -w */
- if (clip.z < -clip.w || clip.w <= 0.0f) return 0;
-
- *out = kon_clipToScreen_(fb, clip);
- return 1;
-}
-
-void kon_drawLine3D(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_vec3_t a, kon_vec3_t b, uint32_t color) {
- if (!fb) return;
-
- kon_vec4_t ca = kon_mat4MulVec4(viewProjection, KON_VEC4(a.x, a.y, a.z, 1));
- kon_vec4_t cb = kon_mat4MulVec4(viewProjection, KON_VEC4(b.x, b.y, b.z, 1));
-
- /* clip against the near plane (z + w >= 0) before dividing, so points behind the camera never get projected */
- float da = ca.z + ca.w;
- float db = cb.z + cb.w;
-
- if (da < 0.0f && db < 0.0f) return;
-
- if (da < 0.0f || db < 0.0f) {
- float t = da / (da - db);
- kon_vec4_t hit = KON_VEC4(
- ca.x + (cb.x - ca.x) * t,
- ca.y + (cb.y - ca.y) * t,
- ca.z + (cb.z - ca.z) * t,
- ca.w + (cb.w - ca.w) * t
- );
-
- if (da < 0.0f) ca = hit;
- else cb = hit;
- }
-
- if (ca.w <= 0.0f || cb.w <= 0.0f) return;
-
- kon_vec2_t sa = kon_clipToScreen_(fb, ca);
- kon_vec2_t sb = kon_clipToScreen_(fb, cb);
-
- kon_drawLine(fb, (int)sa.x, (int)sa.y, (int)sb.x, (int)sb.y, color);
-}
-
-void kon_drawWireMesh(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_mat4_t model, const kon_wireMesh_t *mesh, uint32_t color) {
- if (!fb || !mesh) return;
-
- kon_mat4_t mvp = kon_mat4Mul(viewProjection, model);
-
- for (int i = 0; i < mesh->edgeCount; i++) {
- kon_vec3_t a = mesh->vertices[mesh->edges[i * 2 + 0]];
- kon_vec3_t b = mesh->vertices[mesh->edges[i * 2 + 1]];
- kon_drawLine3D(fb, mvp, a, b, color);
- }
-}
-
-#endif /* end of KONSOFREN_IMPLEMENTATION */
-
-#endif
diff --git a/src/kontime.h b/src/kontime.h
deleted file mode 100644
index da46ddd..0000000
--- a/src/kontime.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * kontime.h
- *
- * 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.
- */
-
-#ifndef KONTIME_H
-#define KONTIME_H
-
-/*** definition ***/
-
-typedef double kon_time;
-
-kon_time kon_getTime(void);
-
-void kon_sleep(kon_time seconds);
-
-/*** implementation ***/
-
-#ifdef KONTIME_IMPLEMENTATION
-
-#if defined(__linux__) || defined(__unix__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
-
-#define _POSIX_C_SOURCE 200809L
-#include <time.h>
-
-kon_time kon_getTime(void) {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
-
- return (kon_time)ts.tv_sec + (kon_time)ts.tv_nsec / 1e9;
-}
-
-void kon_sleep(kon_time seconds) {
- struct timespec ts;
- ts.tv_sec = (time_t)seconds;
- ts.tv_nsec = (long)((seconds - ts.tv_sec) * 1e9);
-
- nanosleep(&ts, NULL);
-}
-
-#elif defined(_WIN32)
-
-#include <windows.h>
-
-kon_time kon_getTime(void) {
- LARGE_INTEGER freq, now;
- QueryPerformanceFrequency(&freq);
- QueryPerformanceCounter(&now);
-
- return (kon_time)now.QuadPart / (kon_time)freq.QuadPart;
-}
-
-void kon_sleep(kon_time seconds) {
- Sleep((DWORD)(seconds * 1000.0));
-}
-
-#else
-#error "kontime.h: unsupported platform!"
-
-#endif
-
-#endif /* end of KONTIME_IMPLEMENTATION */
-
-
-#endif
diff --git a/src/kontoml.h b/src/kontoml.h
deleted file mode 100644
index 88a7e68..0000000
--- a/src/kontoml.h
+++ /dev/null
@@ -1,649 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * kontoml.h
- *
- * 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.
- */
-
-#ifndef KONTOML_H
-#define KONTOML_H
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-typedef enum kon_tomlType {
- konTomlString,
- konTomlInt,
- konTomlFloat,
- konTomlBool,
- konTomlArray
-} kon_tomlType_t;
-
-typedef struct kon_tomlEntry {
- char *section;
- char *key;
- kon_tomlType_t type;
- char *str_value;
- long long int_value;
- double float_value;
- bool bool_value;
-
- kon_tomlType_t array_type;
- int array_count;
- char **array_str;
- long long *array_int;
- double *array_float;
- bool *array_bool;
-} kon_tomlEntry_t;
-
-typedef struct kon_toml {
- kon_tomlEntry_t *entries;
- int count;
- int capacity;
-} kon_toml_t;
-
-kon_toml_t *kon_parseToml(const char *text);
-kon_toml_t *kon_parseTomlFile(const char *path);
-void kon_freeToml(kon_toml_t *toml);
-
-const char *kon_tomlGetString(kon_toml_t *toml, const char *section, const char *key, const char *def);
-long long kon_tomlGetInt(kon_toml_t *toml, const char *section, const char *key, long long def);
-double kon_tomlGetFloat(kon_toml_t *toml, const char *section, const char *key, double def);
-bool kon_tomlGetBool(kon_toml_t *toml, const char *section, const char *key, bool def);
-
-const char *const *kon_tomlGetStringArray(kon_toml_t *toml, const char *section, const char *key, int *out_count);
-const long long *kon_tomlGetIntArray(kon_toml_t *toml, const char *section, const char *key, int *out_count);
-const double *kon_tomlGetFloatArray(kon_toml_t *toml, const char *section, const char *key, int *out_count);
-const bool *kon_tomlGetBoolArray(kon_toml_t *toml, const char *section, const char *key, int *out_count);
-
-/*** implementation ***/
-
-#ifdef KONTOML_IMPLEMENTATION
-
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
-
-static char *kon__tomlStrdup(const char *s) {
- size_t len = strlen(s) + 1;
- char *out = malloc(len);
- if (!out) return NULL;
- memcpy(out, s, len);
- return out;
-}
-
-static char *kon__tomlStrndup(const char *s, size_t n) {
- char *out = malloc(n + 1);
- if (!out) return NULL;
- memcpy(out, s, n);
- out[n] = '\0';
- return out;
-}
-
-static char *kon__tomlTrim(char *s) {
- char *end;
-
- while (*s == ' ' || *s == '\t') s++;
- if (*s == '\0') return s;
-
- end = s + strlen(s) - 1;
- while (end > s && (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\n')) {
- *end = '\0';
- end--;
- }
-
- return s;
-}
-
-static kon_tomlEntry_t *kon__tomlPushEntry(kon_toml_t *toml) {
- if (toml->count == toml->capacity) {
- int newCap = toml->capacity ? toml->capacity * 2 : 16;
- kon_tomlEntry_t *tmp = realloc(toml->entries, (size_t)newCap * sizeof(kon_tomlEntry_t));
- if (!tmp) return NULL;
-
- toml->entries = tmp;
- toml->capacity = newCap;
- }
-
- kon_tomlEntry_t *entry = &toml->entries[toml->count];
- memset(entry, 0, sizeof(kon_tomlEntry_t));
- toml->count++;
-
- return entry;
-}
-
-static int kon__tomlParseString(const char **p, char **out) {
- const char *s = *p;
- char quote = *s;
- int literal = (quote == '\'');
- s++;
-
- char *buf = malloc(strlen(s) + 1);
- if (!buf) return -1;
-
- size_t bi = 0;
-
- while (*s && *s != quote) {
- if (!literal && *s == '\\') {
- s++;
- switch (*s) {
- case 'n':
- buf[bi++] = '\n';
- break;
- case 't':
- buf[bi++] = '\t';
- break;
- case 'r':
- buf[bi++] = '\r';
- break;
- case '"':
- buf[bi++] = '"';
- break;
- case '\\':
- buf[bi++] = '\\';
- break;
- case '\0':
- free(buf);
- return -1;
- default:
- buf[bi++] = *s;
- break;
- }
- s++;
- } else {
- buf[bi++] = *s;
- s++;
- }
- }
-
- if (*s != quote) {
- free(buf);
- return -1;
- }
- s++;
-
- buf[bi] = '\0';
- *out = buf;
- *p = s;
-
- return 0;
-}
-
-static char *kon__tomlStripUnderscores(const char *s) {
- char *out = malloc(strlen(s) + 1);
- if (!out) return NULL;
-
- size_t oi = 0;
- for (size_t i = 0; s[i]; i++) {
- if (s[i] != '_') out[oi++] = s[i];
- }
- out[oi] = '\0';
-
- return out;
-}
-
-static char **kon__tomlSplitArrayElements(const char *content, int *outCount) {
- int cap = 8;
- int count = 0;
- char **elems = malloc((size_t)cap * sizeof(char *));
- if (!elems) return NULL;
-
- const char *start = content;
- const char *p = content;
- char inQuote = 0;
-
- while (*p) {
- if (inQuote) {
- if (inQuote == '"' && *p == '\\' && *(p + 1) != '\0') {
- p += 2;
- continue;
- }
- if (*p == inQuote) inQuote = 0;
- p++;
- continue;
- }
-
- if (*p == '"' || *p == '\'') {
- inQuote = *p;
- p++;
- continue;
- }
-
- if (*p == ',') {
- if (count == cap) {
- cap *= 2;
- char **tmp = realloc(elems, (size_t)cap * sizeof(char *));
- if (!tmp) { free(elems); return NULL; }
- elems = tmp;
- }
- elems[count++] = kon__tomlStrndup(start, (size_t)(p - start));
- p++;
- start = p;
- continue;
- }
-
- p++;
- }
-
- {
- char *raw = kon__tomlStrndup(start, (size_t)(p - start));
- char *checkTrim = raw ? kon__tomlTrim(raw) : NULL;
-
- if (raw && *checkTrim != '\0') {
- if (count == cap) {
- cap += 1;
- char **tmp = realloc(elems, (size_t)cap * sizeof(char *));
- if (!tmp) { free(raw); free(elems); return NULL; }
- elems = tmp;
- }
- elems[count++] = raw;
- } else {
- free(raw);
- }
- }
-
- *outCount = count;
- return elems;
-}
-
-static int kon__tomlParseArrayValue(kon_tomlEntry_t *entry, const char *valueStr) {
- const char *open = strchr(valueStr, '[');
- const char *close = strchr(valueStr, ']');
- if (!open || !close || close <= open) return -1;
-
- char *content = kon__tomlStrndup(open + 1, (size_t)(close - open - 1));
- if (!content) return -1;
-
- int rawCount = 0;
- char **rawElems = kon__tomlSplitArrayElements(content, &rawCount);
- free(content);
- if (!rawElems) return -1;
-
- if (rawCount == 0) {
- free(rawElems);
- entry->type = konTomlArray;
- entry->array_type = konTomlInt;
- entry->array_count = 0;
- return 0;
- }
-
- kon_tomlType_t elemType = konTomlInt;
- char **strArr = NULL;
- long long *intArr = NULL;
- double *floatArr = NULL;
- bool *boolArr = NULL;
- int ok = 1;
-
- for (int i = 0; i < rawCount && ok; i++) {
- char *trimmed = kon__tomlTrim(rawElems[i]);
-
- kon_tomlType_t thisType;
- char *decodedStr = NULL;
- long long thisInt = 0;
- double thisFloat = 0.0;
- bool thisBool = false;
-
- if (*trimmed == '"' || *trimmed == '\'') {
- const char *vp = trimmed;
- thisType = konTomlString;
- if (kon__tomlParseString(&vp, &decodedStr) != 0) { ok = 0; break; }
- } else if (strcmp(trimmed, "true") == 0) {
- thisType = konTomlBool;
- thisBool = true;
- } else if (strcmp(trimmed, "false") == 0) {
- thisType = konTomlBool;
- thisBool = false;
- } else {
- char *clean = kon__tomlStripUnderscores(trimmed);
- if (!clean) { ok = 0; break; }
-
- int isFloat = (strchr(clean, '.') || strchr(clean, 'e') || strchr(clean, 'E'));
- if (isFloat) {
- thisType = konTomlFloat;
- thisFloat = strtod(clean, NULL);
- } else {
- thisType = konTomlInt;
- thisInt = strtoll(clean, NULL, 10);
- }
- free(clean);
- }
-
- if (i == 0) {
- elemType = thisType;
- switch (elemType) {
- case konTomlString:
- strArr = malloc((size_t)rawCount * sizeof(char *));
- break;
- case konTomlInt:
- intArr = malloc((size_t)rawCount * sizeof(long long));
- break;
- case konTomlFloat:
- floatArr = malloc((size_t)rawCount * sizeof(double));
- break;
- case konTomlBool:
- boolArr = malloc((size_t)rawCount * sizeof(bool));
- break;
- default:
- break;
- }
- } else if (thisType != elemType) {
- free(decodedStr);
- ok = 0;
- break;
- }
-
- switch (elemType) {
- case konTomlString:
- strArr[i] = decodedStr;
- break;
- case konTomlInt:
- intArr[i] = thisInt;
- break;
- case konTomlFloat:
- floatArr[i] = thisFloat;
- break;
- case konTomlBool:
- boolArr[i] = thisBool;
- break;
- default:
- break;
- }
- }
-
- for (int i = 0; i < rawCount; i++) free(rawElems[i]);
- free(rawElems);
-
- if (!ok) {
- if (strArr) {
- for (int i = 0; i < rawCount; i++)
- free(strArr[i]);
-
- free(strArr);
- }
- free(intArr);
- free(floatArr);
- free(boolArr);
- return -1;
- }
-
- entry->type = konTomlArray;
- entry->array_type = elemType;
- entry->array_count = rawCount;
- entry->array_str = strArr;
- entry->array_int = intArr;
- entry->array_float = floatArr;
- entry->array_bool = boolArr;
-
- return 0;
-}
-
-static int kon__tomlParseLine(kon_toml_t *toml, char *line, char **currentSection) {
- char *trimmed = kon__tomlTrim(line);
-
- if (*trimmed == '\0' || *trimmed == '#') return 0;
-
- if (*trimmed == '[') {
- char *close = strchr(trimmed, ']');
- if (!close) return -1;
-
- free(*currentSection);
- *currentSection = kon__tomlStrndup(trimmed + 1, (size_t)(close - trimmed - 1));
-
- return 0;
- }
-
- char *eq = strchr(trimmed, '=');
- if (!eq) return -1;
-
- *eq = '\0';
- char *key = kon__tomlTrim(trimmed);
- char *valueStr = kon__tomlTrim(eq + 1);
-
- if (*valueStr != '"' && *valueStr != '\'') {
- char *hash = strchr(valueStr, '#');
- if (hash) {
- *hash = '\0';
- valueStr = kon__tomlTrim(valueStr);
- }
- }
-
- if (*key == '\0' || *valueStr == '\0') return -1;
-
- kon_tomlEntry_t *entry = kon__tomlPushEntry(toml);
- if (!entry) return -1;
-
- entry->section = *currentSection ? kon__tomlStrdup(*currentSection) : kon__tomlStrdup("");
- entry->key = kon__tomlStrdup(key);
-
- if (*valueStr == '[') {
- if (kon__tomlParseArrayValue(entry, valueStr) != 0) return -1;
- } else if (*valueStr == '"' || *valueStr == '\'') {
- const char *vp = valueStr;
- char *decoded = NULL;
-
- if (kon__tomlParseString(&vp, &decoded) != 0) return -1;
-
- entry->type = konTomlString;
- entry->str_value = decoded;
- } else if (strcmp(valueStr, "true") == 0) {
- entry->type = konTomlBool;
- entry->bool_value = true;
- } else if (strcmp(valueStr, "false") == 0) {
- entry->type = konTomlBool;
- entry->bool_value = false;
- } else {
- char *clean = kon__tomlStripUnderscores(valueStr);
- if (!clean) return -1;
-
- int isFloat = (strchr(clean, '.') || strchr(clean, 'e') || strchr(clean, 'E'));
-
- if (isFloat) {
- entry->type = konTomlFloat;
- entry->float_value = strtod(clean, NULL);
- } else {
- entry->type = konTomlInt;
- entry->int_value = strtoll(clean, NULL, 10);
- }
-
- free(clean);
- }
-
- return 0;
-}
-
-kon_toml_t *kon_parseToml(const char *text) {
- if (!text) return NULL;
-
- kon_toml_t *toml = malloc(sizeof(kon_toml_t));
- if (!toml) return NULL;
-
- toml->entries = NULL;
- toml->count = 0;
- toml->capacity = 0;
-
- char *currentSection = NULL;
-
- const char *lineStart = text;
- while (*lineStart) {
- const char *lineEnd = strchr(lineStart, '\n');
- size_t len = lineEnd ? (size_t)(lineEnd - lineStart) : strlen(lineStart);
-
- char *line = kon__tomlStrndup(lineStart, len);
- if (line) {
- kon__tomlParseLine(toml, line, &currentSection);
- free(line);
- }
-
- if (!lineEnd) break;
- lineStart = lineEnd + 1;
- }
-
- free(currentSection);
-
- return toml;
-}
-
-kon_toml_t *kon_parseTomlFile(const char *path) {
- FILE *f = fopen(path, "rb");
- if (!f) return NULL;
-
- fseek(f, 0, SEEK_END);
- long size = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (size < 0) {
- fclose(f);
- return NULL;
- }
-
- char *buf = malloc((size_t)size + 1);
- if (!buf) {
- fclose(f);
- return NULL;
- }
-
- size_t read = fread(buf, 1, (size_t)size, f);
- buf[read] = '\0';
- fclose(f);
-
- kon_toml_t *toml = kon_parseToml(buf);
- free(buf);
-
- return toml;
-}
-
-void kon_freeToml(kon_toml_t *toml) {
- if (!toml) return;
-
- for (int i = 0; i < toml->count; i++) {
- kon_tomlEntry_t *e = &toml->entries[i];
-
- free(e->section);
- free(e->key);
-
- if (e->type == konTomlString) {
- free(e->str_value);
- } else if (e->type == konTomlArray) {
- if (e->array_str) {
- for (int j = 0; j < e->array_count; j++) free(e->array_str[j]);
- free(e->array_str);
- }
- free(e->array_int);
- free(e->array_float);
- free(e->array_bool);
- }
- }
-
- free(toml->entries);
- free(toml);
-}
-
-static kon_tomlEntry_t *kon__tomlFind(kon_toml_t *toml, const char *section, const char *key) {
- if (!toml) return NULL;
-
- const char *sec = section ? section : "";
-
- for (int i = 0; i < toml->count; i++) {
- kon_tomlEntry_t *e = &toml->entries[i];
- if (strcmp(e->section, sec) == 0 && strcmp(e->key, key) == 0) {
- return e;
- }
- }
-
- return NULL;
-}
-
-const char *kon_tomlGetString(kon_toml_t *toml, const char *section, const char *key, const char *def) {
- kon_tomlEntry_t *e = kon__tomlFind(toml, section, key);
- if (!e || e->type != konTomlString) return def;
- return e->str_value;
-}
-
-long long kon_tomlGetInt(kon_toml_t *toml, const char *section, const char *key, long long def) {
- kon_tomlEntry_t *e = kon__tomlFind(toml, section, key);
- if (!e) return def;
-
- if (e->type == konTomlInt) return e->int_value;
- if (e->type == konTomlFloat) return (long long)e->float_value;
-
- return def;
-}
-
-double kon_tomlGetFloat(kon_toml_t *toml, const char *section, const char *key, double def) {
- kon_tomlEntry_t *e = kon__tomlFind(toml, section, key);
- if (!e) return def;
-
- if (e->type == konTomlFloat) return e->float_value;
- if (e->type == konTomlInt) return (double)e->int_value;
-
- return def;
-}
-
-bool kon_tomlGetBool(kon_toml_t *toml, const char *section, const char *key, bool def) {
- kon_tomlEntry_t *e = kon__tomlFind(toml, section, key);
- if (!e || e->type != konTomlBool) return def;
- return e->bool_value;
-}
-
-const char *const *kon_tomlGetStringArray(kon_toml_t *toml, const char *section, const char *key, int *out_count) {
- kon_tomlEntry_t *e = kon__tomlFind(toml, section, key);
- if (!e || e->type != konTomlArray || e->array_type != konTomlString) {
- if (out_count) *out_count = 0;
- return NULL;
- }
- if (out_count) *out_count = e->array_count;
- return (const char *const *)e->array_str;
-}
-
-const long long *kon_tomlGetIntArray(kon_toml_t *toml, const char *section, const char *key, int *out_count) {
- kon_tomlEntry_t *e = kon__tomlFind(toml, section, key);
- if (!e || e->type != konTomlArray || e->array_type != konTomlInt) {
- if (out_count) *out_count = 0;
- return NULL;
- }
- if (out_count) *out_count = e->array_count;
- return e->array_int;
-}
-
-const double *kon_tomlGetFloatArray(kon_toml_t *toml, const char *section, const char *key, int *out_count) {
- kon_tomlEntry_t *e = kon__tomlFind(toml, section, key);
- if (!e || e->type != konTomlArray || e->array_type != konTomlFloat) {
- if (out_count) *out_count = 0;
- return NULL;
- }
- if (out_count) *out_count = e->array_count;
- return e->array_float;
-}
-
-const bool *kon_tomlGetBoolArray(kon_toml_t *toml, const char *section, const char *key, int *out_count) {
- kon_tomlEntry_t *e = kon__tomlFind(toml, section, key);
- if (!e || e->type != konTomlArray || e->array_type != konTomlBool) {
- if (out_count) *out_count = 0;
- return NULL;
- }
- if (out_count) *out_count = e->array_count;
- return e->array_bool;
-}
-
-#endif /* END of KONTOML_IMPLEMENTATION */
-
-#endif
diff --git a/src/konwinlib.h b/src/konwinlib.h
deleted file mode 100644
index c50f828..0000000
--- a/src/konwinlib.h
+++ /dev/null
@@ -1,1357 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * konwinlib.h
- *
- * 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.
- */
-
-#ifndef KONWINLIB_H
-#define KONWINLIB_H
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-/*** definitions ***/
-
-typedef struct kon_context kon_context_t;
-
-bool kon_init(void);
-void kon_deinit(void);
-
-typedef struct kon_window kon_window_t;
-
-typedef enum kon_windowFlags {
- KON_WINDOW_NONE = 0,
- KON_WINDOW_TRANSPARENT = 1 << 0,
- KON_WINDOW_NO_DECOR = 1 << 1,
- KON_WINDOW_ALWAYS_ONTOP = 1 << 2,
- KON_WINDOW_CENTER = 1 << 3,
- KON_WINDOW_RESIZABLE = 1 << 4
-} kon_windowFlags_t;
-
-typedef enum kon_eventType {
- KON_EVENT_NONE = 0,
- KON_EVENT_CLOSE,
- KON_EVENT_RESIZE,
- KON_EVENT_KEY_DOWN,
- KON_EVENT_KEY_UP,
- KON_EVENT_MOUSE_DOWN,
- KON_EVENT_MOUSE_UP,
- KON_EVENT_MOUSE_MOVE
-} kon_eventType_t;
-
-typedef enum kon_mouseButton {
- KON_MOUSE_LEFT = 0,
- KON_MOUSE_MIDDLE,
- KON_MOUSE_RIGHT
-} kon_mouseButton_t;
-
-typedef enum kon_key {
- KON_KEY_UNKNOWN = 0,
-
- KON_KEY_A, KON_KEY_B, KON_KEY_C, KON_KEY_D, KON_KEY_E, KON_KEY_F, KON_KEY_G,
- KON_KEY_H, KON_KEY_I, KON_KEY_J, KON_KEY_K, KON_KEY_L, KON_KEY_M, KON_KEY_N, KON_KEY_O, KON_KEY_P,
- KON_KEY_Q, KON_KEY_R, KON_KEY_S, KON_KEY_T, KON_KEY_U, KON_KEY_V,
- KON_KEY_W, KON_KEY_X, KON_KEY_Y, KON_KEY_Z,
-
- KON_KEY_0, KON_KEY_1, KON_KEY_2, KON_KEY_3, KON_KEY_4, KON_KEY_5, KON_KEY_6, KON_KEY_7, KON_KEY_8, KON_KEY_9,
-
- KON_KEY_F1, KON_KEY_F2, KON_KEY_F3, KON_KEY_F4, KON_KEY_F5, KON_KEY_F6,
- KON_KEY_F7, KON_KEY_F8, KON_KEY_F9, KON_KEY_F10, KON_KEY_F11, KON_KEY_F12,
-
- KON_KEY_LEFT, KON_KEY_RIGHT, KON_KEY_UP, KON_KEY_DOWN,
-
- KON_KEY_SPACE, KON_KEY_ENTER, KON_KEY_TAB, KON_KEY_BACKSPACE,
- KON_KEY_ESCAPE, KON_KEY_DELETE,
-
- KON_KEY_LEFT_SHIFT, KON_KEY_RIGHT_SHIFT,
- KON_KEY_LEFT_CTRL, KON_KEY_RIGHT_CTRL,
- KON_KEY_LEFT_ALT, KON_KEY_RIGHT_ALT,
-
- KON_KEY_MINUS, KON_KEY_EQUAL,
- KON_KEY_LEFT_BRACKET, KON_KEY_RIGHT_BRACKET,
- KON_KEY_SEMICOLON, KON_KEY_APOSTROPHE,
- KON_KEY_COMMA, KON_KEY_PERIOD, KON_KEY_SLASH, KON_KEY_BACKSLASH,
- KON_KEY_GRAVE,
-
- KON_KEY_COUNT
-} kon_key_t;
-
-typedef struct kon_event {
- kon_eventType_t type;
- int width, height; /* will be used to store data for resize events */
- int key;
- int mouseX, mouseY;
- kon_mouseButton_t mouseButton;
-} kon_event_t;
-
-kon_window_t *kon_createWindow(const char *title, int x, int y, int width, int height, kon_windowFlags_t flags);
-void kon_destroyWindow(kon_window_t *window);
-
-bool kon_windowShouldClose(kon_window_t *window);
-
-void kon_setExitKey(kon_window_t *window, int key);
-
-void kon_setWindowPos(kon_window_t *window, int x, int y);
-void kon_setWindowSize(kon_window_t *window, int width, int height);
-
-void kon_getWindowPos(kon_window_t *window, int *x, int *y);
-void kon_getWindowSize(kon_window_t *window, int *width, int *height);
-
-int kon_pollEvent(kon_window_t *window, kon_event_t *event);
-void kon_blitPixels(kon_window_t *window, const uint32_t *pixels, int width, int height);
-
-// added these for web dev
-typedef void (*kon_mainLoopFn)(void *userData);
-void kon_runMainLoop(kon_window_t *window, kon_mainLoopFn callback, void *userData);
-
-/*** implementation ***/
-
-#ifdef KONWINLIB_IMPLEMENTATION
-
-static kon_context_t *kon_ctx;
-
-#define KON_EVENT_QUEUE_SIZE 256
-
-typedef struct kon_eventQueue {
- kon_event_t events[KON_EVENT_QUEUE_SIZE];
- int head, count;
-} kon_eventQueue_t;
-
-static void kon_pushEvent_(kon_eventQueue_t *q, const kon_event_t *event) {
- /* only the newest mouse move or resize matters, so overwrite instead of piling up */
- if (q->count > 0 && (event->type == KON_EVENT_MOUSE_MOVE || event->type == KON_EVENT_RESIZE)) {
- kon_event_t *last = &q->events[(q->head + q->count - 1) % KON_EVENT_QUEUE_SIZE];
- if (last->type == event->type) {
- *last = *event;
- return;
- }
- }
-
- if (q->count == KON_EVENT_QUEUE_SIZE) return;
- q->events[(q->head + q->count) % KON_EVENT_QUEUE_SIZE] = *event;
- q->count++;
-}
-
-static bool kon_popEvent_(kon_eventQueue_t *q, kon_event_t *event) {
- if (q->count == 0) return false;
- *event = q->events[q->head];
- q->head = (q->head + 1) % KON_EVENT_QUEUE_SIZE;
- q->count--;
- return true;
-}
-
-#ifdef __EMSCRIPTEN__
-
-#include <emscripten/emscripten.h>
-#include <emscripten/html5.h>
-#include <string.h>
-
-struct kon_context {
- int initialized;
-};
-
-struct kon_window {
- char canvasID[64];
- bool shouldClose;
- int exitKey;
-
- bool hasKeyEvent;
- kon_eventType_t keyEventType;
- int keyEventKey;
-
- bool hasResizeEvent;
- int resizeWidth, resizeHeight;
-
- bool hasMouseEvent;
- kon_eventType_t mouseEventType;
- int mouseEventX, mouseEventY;
- kon_mouseButton_t mouseEventButton;
-};
-
-static kon_key_t kon_translateEmKey_(int keyCode) {
- switch (keyCode) {
- case 65: return KON_KEY_A;
- case 66: return KON_KEY_B;
- case 67: return KON_KEY_C;
- case 68: return KON_KEY_D;
- case 69: return KON_KEY_E;
- case 70: return KON_KEY_F;
- case 71: return KON_KEY_G;
- case 72: return KON_KEY_H;
- case 73: return KON_KEY_I;
- case 74: return KON_KEY_J;
- case 75: return KON_KEY_K;
- case 76: return KON_KEY_L;
- case 77: return KON_KEY_M;
- case 78: return KON_KEY_N;
- case 79: return KON_KEY_O;
- case 80: return KON_KEY_P;
- case 81: return KON_KEY_Q;
- case 82: return KON_KEY_R;
- case 83: return KON_KEY_S;
- case 84: return KON_KEY_T;
- case 85: return KON_KEY_U;
- case 86: return KON_KEY_V;
- case 87: return KON_KEY_W;
- case 88: return KON_KEY_X;
- case 89: return KON_KEY_Y;
- case 90: return KON_KEY_Z;
-
- case 48: return KON_KEY_0;
- case 49: return KON_KEY_1;
- case 50: return KON_KEY_2;
- case 51: return KON_KEY_3;
- case 52: return KON_KEY_4;
- case 53: return KON_KEY_5;
- case 54: return KON_KEY_6;
- case 55: return KON_KEY_7;
- case 56: return KON_KEY_8;
- case 57: return KON_KEY_9;
-
- case 112: return KON_KEY_F1;
- case 113: return KON_KEY_F2;
- case 114: return KON_KEY_F3;
- case 115: return KON_KEY_F4;
- case 116: return KON_KEY_F5;
- case 117: return KON_KEY_F6;
- case 118: return KON_KEY_F7;
- case 119: return KON_KEY_F8;
- case 120: return KON_KEY_F9;
- case 121: return KON_KEY_F10;
- case 122: return KON_KEY_F11;
- case 123: return KON_KEY_F12;
-
- case 37: return KON_KEY_LEFT;
- case 39: return KON_KEY_RIGHT;
- case 38: return KON_KEY_UP;
- case 40: return KON_KEY_DOWN;
-
- case 32: return KON_KEY_SPACE;
- case 13: return KON_KEY_ENTER;
- case 9: return KON_KEY_TAB;
- case 8: return KON_KEY_BACKSPACE;
- case 27: return KON_KEY_ESCAPE;
- case 46: return KON_KEY_DELETE;
-
- case 16: return KON_KEY_LEFT_SHIFT;
- case 17: return KON_KEY_LEFT_CTRL;
- case 18: return KON_KEY_LEFT_ALT;
-
- case 189: return KON_KEY_MINUS;
- case 187: return KON_KEY_EQUAL;
- case 219: return KON_KEY_LEFT_BRACKET;
- case 221: return KON_KEY_RIGHT_BRACKET;
- case 186: return KON_KEY_SEMICOLON;
- case 222: return KON_KEY_APOSTROPHE;
- case 188: return KON_KEY_COMMA;
- case 190: return KON_KEY_PERIOD;
- case 191: return KON_KEY_SLASH;
- case 220: return KON_KEY_BACKSLASH;
- case 192: return KON_KEY_GRAVE;
-
- default: return KON_KEY_UNKNOWN;
- }
-}
-bool kon_init(void) {
- kon_context_t *ctx = malloc(sizeof(kon_context_t));
- if (!ctx) return false;
-
- ctx->initialized = 1;
- kon_ctx = ctx;
- return true;
-}
-
-void kon_deinit(void) {
- if (!kon_ctx) return;
-
- free(kon_ctx);
- kon_ctx = NULL;
-}
-
-static EM_BOOL kon_keyDownCallback_(int eventType, const EmscriptenKeyboardEvent *e, void *userData) {
- (void)eventType;
- kon_window_t *window = (kon_window_t *)userData;
-
- window->hasKeyEvent = true;
- window->keyEventType = KON_EVENT_KEY_DOWN;
- window->keyEventKey = kon_translateEmKey_(e->keyCode);
-
- if (window->exitKey != 0 && window->keyEventKey == window->exitKey) {
- window->shouldClose = true;
- }
-
- return EM_TRUE;
-}
-
-static EM_BOOL kon_keyUpCallback_(int eventType, const EmscriptenKeyboardEvent *e, void *userData) {
- (void)eventType;
- kon_window_t *window = (kon_window_t *)userData;
-
- window->hasKeyEvent = true;
- window->keyEventType = KON_EVENT_KEY_UP;
- window->keyEventKey = kon_translateEmKey_(e->keyCode);
-
- return EM_TRUE;
-}
-
-static EM_BOOL kon_mouseDownCallback_(int eventType, const EmscriptenMouseEvent *e, void *userData) {
- (void)eventType;
- kon_window_t *window = (kon_window_t *)userData;
-
- if (e->button > KON_MOUSE_RIGHT) return EM_FALSE;
-
- window->hasMouseEvent = true;
- window->mouseEventType = KON_EVENT_MOUSE_DOWN;
- window->mouseEventButton = (kon_windowButton_t)e->button;
- window->mouseEventX = e->targetX;
- window->mouseEventY = e->targetY;
-
- return EM_TRUE;
-}
-
-static EM_BOOL kon_mouseUpCallback_(int eventType, const EmscriptenMouseEvent *e, void *userData) {
- (void)eventType;
- kon_window_t *window = (kon_window_t *)userData;
-
- if (e->button > KON_MOUSE_RIGHT) return EM_FALSE:
-
- window->hasMouseEvent = true;
- window->mouseEventType = KON_EVENT_MOUSE_UP;
- window->mouseEventButton = (kon_windowButton_t)e->button;
- window->mouseEventX = e->targetX;
- window->mouseEventY = e->targetY;
-
- return EM_TRUE;
-}
-
-static EM_BOOL kon_mouseMoveCallback_(int eventType, const EmscriptenMouseEvent *e, void *userData) {
- (void)eventType;
- kon_window_t *window = (kon_window_t *)userData;
-
- window->hasMouseEvent = true;
- window->mouseEventType = KON_EVENT_MOUSE_MOVE;
- window->mouseEventX = e->targetX;
- window->mouseEventY = e->targetY;
-
- return EM_TRUE;
-}
-
-kon_window_t *kon_createWindow(const char *title, int x, int y, int width, int height, kon_windowFlags_t flags) {
- (void)x; (void)y; (void)flags;
-
- if (!kon_ctx) {
- fprintf(stderr, "kon_createWindow: error creating window, no ctx\n");
- return NULL;
- }
-
- kon_window_t *window = malloc(sizeof(kon_window_t));
- if (!window) return NULL;
-
- strncpy(window->canvasID, "#canvas", sizeof(window->canvasID) - 1);
- window->canvasID[sizeof(window->canvasID) - 1] = '\0';
-
- window->shouldClose = false;
- window->exitKey = 0;
- window->hasKeyEvent = false;
- window->hasResizeEvent = false;
- window->hasMouseEvent = false;
-
- emscripten_set_canvas_element_size(window->canvasID, width, height);
-
- EM_ASM({
- try { document.title = UTF8ToString($0); } catch (e) {}
- }, title);
-
- emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, window, EM_FALSE, kon_keyDownCallback_);
- emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, window, EM_FALSE, kon_keyUpCallback_);
- emscripten_set_mousedown_callback(window->canvasID, window, EM_FALSE, kon_mouseDownCallback_);
- emscripten_set_mouseup_callback(window->canvasID, window, EM_FALSE, kon_mouseUpCallback_);
- emscripten_set_mousemove_callback(window->canvasID, window, EM_FALSE, kon_mouseMoveCallback_);
-
- return window;
-}
-
-void kon_destroyWindow(kon_window_t *window) {
- if (!window) return;
-
- emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, NULL);
- emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, NULL);
- emscripten_set_mousedown_callback(window->canvasID, NULL, EM_FALSE, NULL);
- emscripten_set_mouseup_callback(window->canvasID, NULL, EM_FALSE, NULL);
- emscripten_set_mousemove_callback(window->canvasID, NULL, EM_FALSE, NULL);
-
- free(window);
-}
-
-bool kon_windowShouldClose(kon_window_t *window) {
- if (!window) return true;
- return window->shouldClose;
-}
-
-void kon_setExitKey(kon_window_t *window, int key) {
- if (!window) return;
- window->exitKey = key;
-}
-
-void kon_setWindowPos(kon_window_t *window, int x, int y) {
- (void)window; (void)x; (void)y;
-}
-
-void kon_setWindowSize(kon_window_t *window, int width, int height) {
- if (!window) return;
- emscripten_set_canvas_element_size(window->canvasID, width, height);
-}
-
-void kon_getWindowPos(kon_window_t *window, int *x, int *y) {
- (void)window;
- if (x) *x = 0;
- if (y) *y = 0;
-}
-
-void kon_getWindowSize(kon_window_t *window, int *width, int *height) {
- if (!window || !width || !height) return;
-
- double w, h;
- emscripten_get_element_css_size(window->canvasID, &w, &h);
- *width = (int)w;
- *height = (int)h;
-}
-
-int kon_pollEvent(kon_window_t *window, kon_event_t *event) {
- if (!window || !event) return 0;
-
- event->type = KON_EVENT_NONE;
-
- if (window->hasResizeEvent) {
- event->type = KON_EVENT_RESIZE;
- event->width = window->resizeWidth;
- event->height = window->resizeHeight;
- window->hasResizeEvent = false;
- return 1;
- }
-
- if (window->hasKeyEvent) {
- event->type = window->keyEventType;
- event->key = window->keyEventKey;
- window->hasKeyEvent = false;
- return 1;
- }
-
- if (window->hasMouseEvent) {
- event->type = window->mouseEventType;
- event->mouseX = window->mouseEventX;
- event->mouseY = window-<mouseEventY;
- event->mouseButton = window->mouseEventButton;
- window->hasMouseEvent = false;
- return 1;
- }
-
- return 0;
-}
-
-EM_JS(void, kon_jsBlit_, (const char *canvasID, uint32_t *pixels, int width, int height), {
- var sel = UTF8ToString(canvasID);
- var canvas = document.querySelector(sel);
- if (!canvas) return;
-
- if (!canvas.__konCtx) canvas.__konCtx = canvas.getContext('2d');
- var ctx = canvas.__konCtx;
-
- if (!canvas.__konImgData || canvas.__konImgData.width !== width || canvas.__konImgData.height !== height) {
- canvas.__konImgData = ctx.createImageData(width, height);
- }
- var imgData = canvas.__konImgData;
-
- var dst = new Uint32Array(imgData.data.buffer);
- var srcIdx = pixels >> 2;
- var count = width * height;
-
- for (var i = 0; i < count; i++) {
- var px = HEAPU32[srcIdx + i];
- dst[i] = (px & 0xFF00FF00) | ((px & 0x00FF0000) >>> 16) | ((px & 0x000000FF) << 16);
- }
-
- ctx.putImageData(imgData, 0, 0);
-});
-
-void kon_blitPixels(kon_window_t *window, const uint32_t *pixels, int width, int height) {
- if (!window || !pixels) return;
- kon_jsBlit_(window->canvasID, (uint32_t *)pixels, width, height);
-}
-
-#elif defined(__linux__) || defined(__unix__)
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-#include <X11/extensions/Xrandr.h>
-#include <X11/keysym.h>
-#include <string.h>
-
-static kon_key_t kon_translateX11Key_(KeySym sym) {
- switch (sym) {
- case XK_a: return KON_KEY_A;
- case XK_b: return KON_KEY_B;
- case XK_c: return KON_KEY_C;
- case XK_d: return KON_KEY_D;
- case XK_e: return KON_KEY_E;
- case XK_f: return KON_KEY_F;
- case XK_g: return KON_KEY_G;
- case XK_h: return KON_KEY_H;
- case XK_i: return KON_KEY_I;
- case XK_j: return KON_KEY_J;
- case XK_k: return KON_KEY_K;
- case XK_l: return KON_KEY_L;
- case XK_m: return KON_KEY_M;
- case XK_n: return KON_KEY_N;
- case XK_o: return KON_KEY_O;
- case XK_p: return KON_KEY_P;
- case XK_q: return KON_KEY_Q;
- case XK_r: return KON_KEY_R;
- case XK_s: return KON_KEY_S;
- case XK_t: return KON_KEY_T;
- case XK_u: return KON_KEY_U;
- case XK_v: return KON_KEY_V;
- case XK_w: return KON_KEY_W;
- case XK_x: return KON_KEY_X;
- case XK_y: return KON_KEY_Y;
- case XK_z: return KON_KEY_Z;
-
- case XK_0: return KON_KEY_0;
- case XK_1: return KON_KEY_1;
- case XK_2: return KON_KEY_2;
- case XK_3: return KON_KEY_3;
- case XK_4: return KON_KEY_4;
- case XK_5: return KON_KEY_5;
- case XK_6: return KON_KEY_6;
- case XK_7: return KON_KEY_7;
- case XK_8: return KON_KEY_8;
- case XK_9: return KON_KEY_9;
-
- case XK_F1: return KON_KEY_F1;
- case XK_F2: return KON_KEY_F2;
- case XK_F3: return KON_KEY_F3;
- case XK_F4: return KON_KEY_F4;
- case XK_F5: return KON_KEY_F5;
- case XK_F6: return KON_KEY_F6;
- case XK_F7: return KON_KEY_F7;
- case XK_F8: return KON_KEY_F8;
- case XK_F9: return KON_KEY_F9;
- case XK_F10: return KON_KEY_F10;
- case XK_F11: return KON_KEY_F11;
- case XK_F12: return KON_KEY_F12;
-
- case XK_Left: return KON_KEY_LEFT;
- case XK_Right: return KON_KEY_RIGHT;
- case XK_Up: return KON_KEY_UP;
- case XK_Down: return KON_KEY_DOWN;
-
- case XK_space: return KON_KEY_SPACE;
- case XK_Return: return KON_KEY_ENTER;
- case XK_Tab: return KON_KEY_TAB;
- case XK_BackSpace: return KON_KEY_BACKSPACE;
- case XK_Escape: return KON_KEY_ESCAPE;
- case XK_Delete: return KON_KEY_DELETE;
-
- case XK_Shift_L: return KON_KEY_LEFT_SHIFT;
- case XK_Shift_R: return KON_KEY_RIGHT_SHIFT;
- case XK_Control_L: return KON_KEY_LEFT_CTRL;
- case XK_Control_R: return KON_KEY_RIGHT_CTRL;
- case XK_Alt_L: return KON_KEY_LEFT_ALT;
- case XK_Alt_R: return KON_KEY_RIGHT_ALT;
-
- case XK_minus: return KON_KEY_MINUS;
- case XK_equal: return KON_KEY_EQUAL;
- case XK_bracketleft: return KON_KEY_LEFT_BRACKET;
- case XK_bracketright: return KON_KEY_RIGHT_BRACKET;
- case XK_semicolon: return KON_KEY_SEMICOLON;
- case XK_apostrophe: return KON_KEY_APOSTROPHE;
- case XK_comma: return KON_KEY_COMMA;
- case XK_period: return KON_KEY_PERIOD;
- case XK_slash: return KON_KEY_SLASH;
- case XK_backslash: return KON_KEY_BACKSLASH;
- case XK_grave: return KON_KEY_GRAVE;
-
- default: return KON_KEY_UNKNOWN;
- }
-}
-
-struct kon_context {
- Display *display;
-};
-
-bool kon_init(void) {
- kon_context_t *ctx = malloc(sizeof(kon_context_t));
- if (!ctx) return false;
- ctx->display = XOpenDisplay(NULL);
- if (!ctx->display) return false;
- kon_ctx = ctx;
- return true;
-}
-
-void kon_deinit(void) {
- if (!kon_ctx) return;
-
- XCloseDisplay(kon_ctx->display);
- free(kon_ctx);
- kon_ctx=NULL;
-}
-
-struct kon_window {
- Window window;
- GC gc;
- Visual *visual;
- int depth;
- Colormap colormap;
- bool owns_colormap;
- Atom wm_delete;
- bool shouldClose;
- int exitKey;
-};
-
-kon_window_t *kon_createWindow(const char *title, int x, int y, int width, int height, kon_windowFlags_t flags) {
- if (!kon_ctx) {
- fprintf(stderr, "kon_createWindow: There appears to be no kon_ctx. \nPlease, do kon_init(); before doing anything with konwinlib, thank you.\n");
- return NULL;
- }
-
- kon_window_t *window = malloc(sizeof(kon_window_t));
- if (!window) return NULL;
-
- int screen = DefaultScreen(kon_ctx->display);
-
- if (flags & KON_WINDOW_CENTER) {
- Window root = RootWindow(kon_ctx->display, screen);
-
- int mon_x = 0, mon_y = 0;
- int mon_width = DisplayWidth(kon_ctx->display, screen);
- int mon_height = DisplayHeight(kon_ctx->display, screen);
-
- Window root_ret, child_ret;
- int root_x, root_y, win_x, win_y;
- unsigned int mask;
- XQueryPointer(kon_ctx->display, root, &root_ret, &child_ret, &root_x, &root_y, &win_x, &win_y, &mask);
-
- XRRScreenResources *res = XRRGetScreenResourcesCurrent(kon_ctx->display, root);
- if (res) {
- for (int i = 0; i < res->noutput; i++) {
- XRROutputInfo *out_info = XRRGetOutputInfo(kon_ctx->display, res, res->outputs[i]);
-
- if (out_info && out_info->crtc) {
- XRRCrtcInfo *crtc = XRRGetCrtcInfo(kon_ctx->display, res, out_info->crtc);
- if (crtc) {
-
- if (root_x >= crtc->x && root_x < crtc->x + (int)crtc->width &&
- root_y >= crtc->y && root_y < crtc->y + (int)crtc->height) {
- mon_x = crtc->x;
- mon_y = crtc->y;
- mon_width = crtc->width;
- mon_height = crtc->height;
- XRRFreeCrtcInfo(crtc);
- if (out_info) XRRFreeOutputInfo(out_info);
- break;
- }
- XRRFreeCrtcInfo(crtc);
- }
- }
- if (out_info) XRRFreeOutputInfo(out_info);
- }
- XRRFreeScreenResources(res);
- }
-
- x = mon_x + (mon_width - width ) / 2;
- y = mon_y + (mon_height - height) / 2;
- }
-
- if (flags & KON_WINDOW_TRANSPARENT) {
- XVisualInfo vinfo;
- if (!XMatchVisualInfo(kon_ctx->display, screen, 32, TrueColor, &vinfo)) {
- free(window);
- return NULL;
- }
-
- window->visual = vinfo.visual;
- window->depth = vinfo.depth;
- window->colormap = XCreateColormap(kon_ctx->display, RootWindow(kon_ctx->display, screen), window->visual, AllocNone);
-
- XSetWindowAttributes attrs;
- attrs.colormap = window->colormap;
- attrs.background_pixel = 0;
- attrs.border_pixel = 0;
-
- window->window = XCreateWindow(
- kon_ctx->display, RootWindow(kon_ctx->display, screen),
- x, y, width, height, 0, window->depth, InputOutput,
- window->visual, CWColormap | CWBackPixel | CWBorderPixel, &attrs);
-
- window->owns_colormap = true;
- } else {
- window->visual = DefaultVisual(kon_ctx->display, screen);
- window->depth = DefaultDepth(kon_ctx->display, screen);
- window->colormap = DefaultColormap(kon_ctx->display, screen);
-
- window->window = XCreateSimpleWindow(
- kon_ctx->display, RootWindow(kon_ctx->display, screen),
- x, y, width, height, 0, 0, 0);
-
- window->owns_colormap = false;
- }
-
- if (!window->window) {
- if (window->owns_colormap) {
- XFreeColormap(kon_ctx->display, window->colormap);
- }
- free(window);
- return NULL;
- }
-
- XStoreName(kon_ctx->display, window->window, title);
- XSelectInput(kon_ctx->display, window->window, ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
-
- if (flags & KON_WINDOW_NO_DECOR) {
- Atom motif_hints = XInternAtom(kon_ctx->display, "_MOTIF_WM_HINTS", False);
- struct { unsigned long flags, functions, decorations; long input_mode; unsigned long status; } hints;
- memset(&hints, 0, sizeof(hints));
- hints.flags = 2;
- hints.decorations = 0;
- XChangeProperty(kon_ctx->display, window->window, motif_hints,
- motif_hints, 32, PropModeReplace, (unsigned char *)&hints, 5);
- }
-
- if (flags & KON_WINDOW_ALWAYS_ONTOP) {
- Atom wm_state = XInternAtom(kon_ctx->display, "_NET_WM_STATE", False);
- Atom wm_above = XInternAtom(kon_ctx->display, "_NET_WM_STATE_ABOVE", False);
- XChangeProperty(kon_ctx->display, window->window, wm_state, XA_ATOM, 32,
- PropModeReplace, (unsigned char *)&wm_above, 1);
- }
-
- if (!(flags & KON_WINDOW_RESIZABLE)) {
- XSizeHints hints;
- hints.flags = PMinSize | PMaxSize;
- hints.min_width = hints.max_width = width;
- hints.min_height = hints.max_height = height;
- XSetWMNormalHints(kon_ctx->display, window->window, &hints);
- }
-
- window->wm_delete = XInternAtom(kon_ctx->display, "WM_DELETE_WINDOW", False);
- XSetWMProtocols(kon_ctx->display, window->window, &window->wm_delete, 1);
-
- window->gc = XCreateGC(kon_ctx->display, window->window, 0, NULL);
-
- XMapWindow(kon_ctx->display, window->window);
- XFlush(kon_ctx->display);
-
- window->exitKey = 0;
-
- window->shouldClose = false;
-
- return window;
-}
-
-void kon_destroyWindow(kon_window_t *window) {
- if (!window) return;
- if (!kon_ctx) { free(window); return; }
-
- if (window->gc) XFreeGC(kon_ctx->display, window->gc);
- if (window->window) XDestroyWindow(kon_ctx->display, window->window);
- if (window->owns_colormap && window->colormap) XFreeColormap(kon_ctx->display, window->colormap);
-
- XFlush(kon_ctx->display);
-
- free(window);
-}
-
-void kon_setExitKey(kon_window_t *window, int key) {
- if (!window) return;
- window->exitKey = key;
-}
-
-void kon_setWindowPos(kon_window_t *window, int x, int y) {
- if (!window || !kon_ctx) return;
-
- XMoveWindow(kon_ctx->display, window->window, x, y);
- XFlush(kon_ctx->display);
-}
-
-void kon_setWindowSize(kon_window_t *window, int width, int height) {
- if (!window || !kon_ctx) return;
-
- XResizeWindow(kon_ctx->display, window->window, width, height);
- XFlush(kon_ctx->display);
-}
-
-void kon_getWindowPos(kon_window_t *window, int *x, int *y) {
- if (!window || !kon_ctx || !x || !y) return;
-
- Window child;
- XTranslateCoordinates(kon_ctx->display, window->window, RootWindow(kon_ctx->display, DefaultScreen(kon_ctx->display)),
- 0, 0, x, y, &child);
-}
-
-void kon_getWindowSize(kon_window_t *window, int *width, int *height) {
- if (!window || !kon_ctx || !width || !height) return;
-
- XWindowAttributes attrs;
- XGetWindowAttributes(kon_ctx->display, window->window, &attrs);
- *width = attrs.width;
- *height = attrs.height;
-}
-
-int kon_pollEvent(kon_window_t *window, kon_event_t *event) {
- if (!window || !kon_ctx || !event) return 0;
-
- event->type = KON_EVENT_NONE;
-
- if (!XPending(kon_ctx->display)) return 0;
-
- XEvent xev;
- XNextEvent(kon_ctx->display, &xev);
-
- if (xev.type == ClientMessage) {
- if ((Atom)xev.xclient.data.l[0] == window->wm_delete) {
- event->type = KON_EVENT_CLOSE;
- window->shouldClose = true;
- }
- }
-
- if (xev.type == ConfigureNotify) {
- event->type = KON_EVENT_RESIZE;
- event->width = xev.xconfigure.width;
- event->height = xev.xconfigure.height;
- return 1;
- }
-
- if (xev.type == KeyPress) {
- event->type = KON_EVENT_KEY_DOWN;
- event->key = (int)kon_translateX11Key_(XLookupKeysym(&xev.xkey, 0));
- if (window->exitKey != 0 && event->key == window->exitKey) {
- window->shouldClose = true;
- }
- return 1;
- }
-
- if (xev.type == KeyRelease) {
- event->type = KON_EVENT_KEY_UP;
- event->key = (int)kon_translateX11Key_(XLookupKeysym(&xev.xkey, 0));
- return 1;
- }
-
- if (xev.type == ButtonPress || xev.type == ButtonRelease) {
- int konButton = -1;
- switch (xev.xbutton.button) {
- case Button1:
- konButton = KON_MOUSE_LEFT;
- break;
- case Button2:
- konButton = KON_MOUSE_MIDDLE;
- break;
- case Button3:
- konButton = KON_MOUSE_RIGHT;
- break;
- default:
- break;
- }
-
- if (konButton != -1) {
- event->type = (xev.type == ButtonPress) ? KON_EVENT_MOUSE_DOWN : KON_EVENT_MOUSE_UP;
- event->mouseButton = (kon_mouseButton_t)konButton;
- event->mouseX = xev.xbutton.x;
- event->mouseY = xev.xbutton.y;
- }
- return 1;
- }
-
- if (xev.type == MotionNotify) {
- event->type = KON_EVENT_MOUSE_MOVE;
- event->mouseX = xev.xmotion.x;
- event->mouseY = xev.xmotion.y;
- return 1;
- }
-
- return 1;
-}
-
-bool kon_windowShouldClose(kon_window_t *window) {
- if (!window || !kon_ctx) return true;
- return window->shouldClose;
-}
-
-/* TODO: implement the rest of these */
-
-void kon_blitPixels(kon_window_t *window, const uint32_t *pixels, int width, int height) {
- if (!window || !kon_ctx || !pixels) return;
-
- XImage *ximg = XCreateImage(kon_ctx->display, window->visual, window->depth, ZPixmap, 0, (char *)pixels, width, height, 32, 0);
- if (!ximg) return;
-
- XPutImage(kon_ctx->display, window->window, window->gc, ximg, 0, 0, 0, 0, width, height);
-
- ximg->data = NULL;
- XDestroyImage(ximg);
-
- XFlush(kon_ctx->display);
-}
-
-/*** windows implementation ***/
-
-#elif defined(_WIN32)
-
-#include <windows.h>
-#include <string.h>
-
-struct kon_context {
- HINSTANCE hInstance;
-};
-
-struct kon_window {
- HWND hwnd;
- bool shouldClose;
- bool isTransparent;
- int exitKey;
- kon_eventQueue_t queue;
-};
-
-static kon_key_t kon_translateWin32Key_(WPARAM vk, LPARAM lParam) {
- if (vk == VK_SHIFT) {
- UINT scancode = (lParam >> 16) & 0xFF;
- UINT lshift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);
- return (scancode == lshift) ? KON_KEY_LEFT_SHIFT : KON_KEY_RIGHT_SHIFT;
- }
- if (vk == VK_CONTROL) {
- return (lParam & 0x01000000) ? KON_KEY_RIGHT_CTRL : KON_KEY_LEFT_CTRL;
- }
- if (vk == VK_MENU) {
- return (lParam & 0x01000000) ? KON_KEY_RIGHT_ALT : KON_KEY_LEFT_ALT;
- }
-
- switch (vk) {
- case 'A': return KON_KEY_A;
- case 'B': return KON_KEY_B;
- case 'C': return KON_KEY_C;
- case 'D': return KON_KEY_D;
- case 'E': return KON_KEY_E;
- case 'F': return KON_KEY_F;
- case 'G': return KON_KEY_G;
- case 'H': return KON_KEY_H;
- case 'I': return KON_KEY_I;
- case 'J': return KON_KEY_J;
- case 'K': return KON_KEY_K;
- case 'L': return KON_KEY_L;
- case 'M': return KON_KEY_M;
- case 'N': return KON_KEY_N;
- case 'O': return KON_KEY_O;
- case 'P': return KON_KEY_P;
- case 'Q': return KON_KEY_Q;
- case 'R': return KON_KEY_R;
- case 'S': return KON_KEY_S;
- case 'T': return KON_KEY_T;
- case 'U': return KON_KEY_U;
- case 'V': return KON_KEY_V;
- case 'W': return KON_KEY_W;
- case 'X': return KON_KEY_X;
- case 'Y': return KON_KEY_Y;
- case 'Z': return KON_KEY_Z;
-
- case '0': return KON_KEY_0;
- case '1': return KON_KEY_1;
- case '2': return KON_KEY_2;
- case '3': return KON_KEY_3;
- case '4': return KON_KEY_4;
- case '5': return KON_KEY_5;
- case '6': return KON_KEY_6;
- case '7': return KON_KEY_7;
- case '8': return KON_KEY_8;
- case '9': return KON_KEY_9;
-
- case VK_F1: return KON_KEY_F1;
- case VK_F2: return KON_KEY_F2;
- case VK_F3: return KON_KEY_F3;
- case VK_F4: return KON_KEY_F4;
- case VK_F5: return KON_KEY_F5;
- case VK_F6: return KON_KEY_F6;
- case VK_F7: return KON_KEY_F7;
- case VK_F8: return KON_KEY_F8;
- case VK_F9: return KON_KEY_F9;
- case VK_F10: return KON_KEY_F10;
- case VK_F11: return KON_KEY_F11;
- case VK_F12: return KON_KEY_F12;
-
- case VK_LEFT: return KON_KEY_LEFT;
- case VK_RIGHT: return KON_KEY_RIGHT;
- case VK_UP: return KON_KEY_UP;
- case VK_DOWN: return KON_KEY_DOWN;
-
- case VK_SPACE: return KON_KEY_SPACE;
- case VK_RETURN: return KON_KEY_ENTER;
- case VK_TAB: return KON_KEY_TAB;
- case VK_BACK: return KON_KEY_BACKSPACE;
- case VK_ESCAPE: return KON_KEY_ESCAPE;
- case VK_DELETE: return KON_KEY_DELETE;
-
- case VK_OEM_MINUS: return KON_KEY_MINUS;
- case VK_OEM_PLUS: return KON_KEY_EQUAL;
- case VK_OEM_4: return KON_KEY_LEFT_BRACKET;
- case VK_OEM_6: return KON_KEY_RIGHT_BRACKET;
- case VK_OEM_1: return KON_KEY_SEMICOLON;
- case VK_OEM_7: return KON_KEY_APOSTROPHE;
- case VK_OEM_COMMA: return KON_KEY_COMMA;
- case VK_OEM_PERIOD: return KON_KEY_PERIOD;
- case VK_OEM_2: return KON_KEY_SLASH;
- case VK_OEM_5: return KON_KEY_BACKSLASH;
- case VK_OEM_3: return KON_KEY_GRAVE;
-
- default: return KON_KEY_UNKNOWN;
- }
-}
-
-LRESULT CALLBACK kon_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
- kon_window_t *window = (kon_window_t *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
-
- switch (msg) {
- case WM_NCCREATE: {
- CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams);
- break;
- }
- case WM_KEYDOWN:
- if (window) {
- kon_event_t ev = {0};
- ev.type = KON_EVENT_KEY_DOWN;
- ev.key = (int)kon_translateWin32Key_(wParam, lParam);
- kon_pushEvent_(&window->queue, &ev);
- if (window->exitKey != 0 && ev.key == window->exitKey) {
- window->shouldClose = true;
- ev.type = KON_EVENT_CLOSE;
- kon_pushEvent_(&window->queue, &ev);
- }
- }
- break;
- case WM_KEYUP:
- if (window) {
- kon_event_t ev = {0};
- ev.type = KON_EVENT_KEY_UP;
- ev.key = (int)kon_translateWin32Key_(wParam, lParam);
- kon_pushEvent_(&window->queue, &ev);
- }
- break;
- case WM_LBUTTONDOWN: case WM_LBUTTONUP:
- case WM_RBUTTONDOWN: case WM_RBUTTONUP:
- case WM_MBUTTONDOWN: case WM_MBUTTONUP:
- if (window) {
- kon_event_t ev = {0};
- ev.type = (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN)
- ? KON_EVENT_MOUSE_DOWN : KON_EVENT_MOUSE_UP;
- ev.mouseButton = (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) ? KON_MOUSE_LEFT
- : (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP) ? KON_MOUSE_RIGHT
- : KON_MOUSE_MIDDLE;
- ev.mouseX = (int)(short)LOWORD(lParam);
- ev.mouseY = (int)(short)HIWORD(lParam);
- kon_pushEvent_(&window->queue, &ev);
- }
- break;
- case WM_MOUSEMOVE:
- if (window) {
- kon_event_t ev = {0};
- ev.type = KON_EVENT_MOUSE_MOVE;
- ev.mouseX = (int)(short)LOWORD(lParam);
- ev.mouseY = (int)(short)HIWORD(lParam);
- kon_pushEvent_(&window->queue, &ev);
- }
- break;
- case WM_CLOSE:
- if (window) {
- kon_event_t ev = {0};
- ev.type = KON_EVENT_CLOSE;
- window->shouldClose = true;
- kon_pushEvent_(&window->queue, &ev);
- }
- break;
- case WM_SIZE:
- /* minimizing reports 0x0, which would wreck the framebuffer */
- if (window && wParam != SIZE_MINIMIZED && LOWORD(lParam) > 0 && HIWORD(lParam) > 0) {
- kon_event_t ev = {0};
- ev.type = KON_EVENT_RESIZE;
- ev.width = LOWORD(lParam);
- ev.height = HIWORD(lParam);
- kon_pushEvent_(&window->queue, &ev);
- }
- break;
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- break;
- case WM_ERASEBKGND:
- return 1;
- }
- return DefWindowProc(hwnd, msg, wParam, lParam);
-}
-
-bool kon_init(void) {
- kon_context_t *ctx = malloc(sizeof(kon_context_t));
- if (!ctx) return false;
-
- ctx->hInstance = GetModuleHandle(NULL);
-
- WNDCLASSEX wc = {0};
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.lpfnWndProc = kon_wndProc;
- wc.hInstance = ctx->hInstance;
- wc.lpszClassName = "KonWinLibClass";
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
-
- if (!RegisterClassEx(&wc)) {
- free(ctx);
- return false;
- }
-
- kon_ctx = ctx;
- return true;
-}
-
-void kon_deinit(void) {
- if (!kon_ctx) return;
-
- free(kon_ctx);
- kon_ctx = NULL;
-}
-
-
-kon_window_t *kon_createWindow(const char *title, int x, int y, int width, int height, kon_windowFlags_t flags) {
- if (!kon_ctx) return NULL;
-
- kon_window_t *window = calloc(1, sizeof(kon_window_t));
- if (!window) return NULL;
-
- window->isTransparent = (flags & KON_WINDOW_TRANSPARENT);
- window->exitKey = 0;
-
- DWORD style;
- if (flags & KON_WINDOW_NO_DECOR) {
- style = WS_POPUP;
- } else {
- style = WS_OVERLAPPEDWINDOW;
- if (!(flags & KON_WINDOW_RESIZABLE)) {
- style &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
- }
- }
-
- DWORD exStyle = 0;
- if (flags & KON_WINDOW_ALWAYS_ONTOP) exStyle |= WS_EX_TOPMOST;
- if (flags & KON_WINDOW_TRANSPARENT) exStyle |= WS_EX_LAYERED;
-
- RECT adj = { 0, 0, width, height };
- AdjustWindowRectEx(&adj, style, FALSE, exStyle);
- int winW = adj.right - adj.left;
- int winH = adj.bottom - adj.top;
-
- if (flags & KON_WINDOW_CENTER) {
- POINT cursor;
- GetCursorPos(&cursor);
-
- HMONITOR hmon = MonitorFromPoint(cursor, MONITOR_DEFAULTTONEAREST);
-
- MONITORINFO mi;
- mi.cbSize = sizeof(MONITORINFO);
- GetMonitorInfo(hmon, &mi);
-
- int mon_x = mi.rcMonitor.left;
- int mon_y = mi.rcMonitor.top;
- int mon_width = mi.rcMonitor.right - mi.rcMonitor.left;
- int mon_height = mi.rcMonitor.bottom - mi.rcMonitor.top;
-
- x = mon_x + (mon_width - winW) / 2;
- y = mon_y + (mon_height - winH) / 2;
- }
-
- window->hwnd = CreateWindowEx(exStyle, "KonWinLibClass", title, style, x, y, winW, winH, NULL, NULL, kon_ctx->hInstance, window);
-
- if (!window->hwnd) {
- free(window);
- return NULL;
- }
-
- ShowWindow(window->hwnd, SW_SHOW);
-
- return window;
-}
-
-void kon_destroyWindow(kon_window_t *window) {
- if (!window) return;
- if (window->hwnd) DestroyWindow(window->hwnd);
- free(window);
-}
-
-bool kon_windowShouldClose(kon_window_t *window) {
- if (!window) return true;
- return window->shouldClose;
-}
-
-
-void kon_setExitKey(kon_window_t *window, int key) {
- if (!window) return;
- window->exitKey = key;
-}
-
-void kon_setWindowPos(kon_window_t *window, int x, int y) {
- if (!window || !kon_ctx) return;
-
- SetWindowPos(window->hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
-}
-
-void kon_setWindowSize(kon_window_t *window, int width, int height) {
- if (!window || !kon_ctx) return;
-
- RECT r = { 0, 0, width, height };
- AdjustWindowRectEx(&r, (DWORD)GetWindowLongPtr(window->hwnd, GWL_STYLE), FALSE, (DWORD)GetWindowLongPtr(window->hwnd, GWL_EXSTYLE));
- SetWindowPos(window->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE | SWP_NOZORDER);
-}
-
-
-void kon_getWindowPos(kon_window_t *window, int *x, int *y) {
- if (!window || !x || !y) return;
-
- RECT rect;
- GetWindowRect(window->hwnd, &rect);
- *x = rect.left;
- *y = rect.top;
-}
-
-void kon_getWindowSize(kon_window_t *window, int *width, int *height) {
- if (!window || !width || !height) return;
-
- RECT rect;
- GetClientRect(window->hwnd, &rect);
- *width = rect.right - rect.left;
- *height = rect.bottom - rect.top;
-}
-
-int kon_pollEvent(kon_window_t *window, kon_event_t *event) {
- if (!window || !event) return 0;
-
- MSG msg;
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- if (!kon_popEvent_(&window->queue, event)) {
- event->type = KON_EVENT_NONE;
- return 0;
- }
- return 1;
-}
-
-void kon_blitPixels(kon_window_t *window, const uint32_t *pixels, int width, int height) {
- if (!window || !pixels) return;
-
- BITMAPINFO bmi = {0};
- bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmi.bmiHeader.biWidth = width;
- bmi.bmiHeader.biHeight = -height; /* top-down */
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 32;
- bmi.bmiHeader.biCompression = BI_RGB;
-
- if (window->isTransparent) {
- HDC screenDC = GetDC(NULL);
- HDC memDC = CreateCompatibleDC(screenDC);
-
- void *dibPixels;
- HBITMAP hbm = CreateDIBSection(screenDC, &bmi, DIB_RGB_COLORS, &dibPixels, NULL, 0);
- if (hbm) {
- memcpy(dibPixels, pixels, (size_t)width * height * 4);
- HBITMAP oldBmp = (HBITMAP)SelectObject(memDC, hbm);
-
- RECT winRect;
- GetWindowRect(window->hwnd, &winRect);
- POINT dstPos = { winRect.left, winRect.top };
- POINT srcPos = { 0, 0 };
- SIZE size = { width, height };
- BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
-
- UpdateLayeredWindow(window->hwnd, screenDC, &dstPos, &size, memDC, &srcPos, 0, &blend, ULW_ALPHA);
-
- SelectObject(memDC, oldBmp);
- DeleteObject(hbm);
- }
-
- DeleteDC(memDC);
- ReleaseDC(NULL, screenDC);
- } else {
- HDC winDC = GetDC(window->hwnd);
- SetDIBitsToDevice(winDC, 0, 0, width, height, 0, 0, 0, height, pixels, &bmi, DIB_RGB_COLORS);
- ReleaseDC(window->hwnd, winDC);
- }
-}
-
-#else
- #error "konwinlib.h: unsupported platform"
-#endif /* end of platform switch */
-
-/*** main loop ***/
-
-#ifdef __EMSCRIPTEN__
-
-typedef struct {
- kon_window_t *window;
- kon_mainLoopFn callback;
- void *userData;
-} kon_mainLoopCtx_;
-
-static void kon_mainLoopTrampoline_(void *arg) {
- kon_mainLoopCtx_ *ctx = (kon_mainLoopCtx_ *)arg;
-
- if (kon_windowShouldClose(ctx->window)) {
- emscripten_cancel_main_loop();
- free(ctx);
- return;
- }
-
- ctx->callback(ctx->userData);
-}
-
-void kon_runMainLoop(kon_window_t *window, kon_mainLoopFn callback, void *userData) {
- kon_mainLoopCtx_ *ctx = malloc(sizeof(kon_mainLoopCtx_));
- if (!ctx) return;
-
- ctx->window = window;
- ctx->callback = callback;
- ctx->userData = userData;
-
- emscripten_set_main_loop_arg(kon_mainLoopTrampoline_, ctx, 0, 1);
-}
-
-#else
-
-void kon_runMainLoop(kon_window_t *window, kon_mainLoopFn callback, void *userData) {
- while (!kon_windowShouldClose(window)) {
- callback(userData);
- }
-}
-
-#endif /* __EMSCRIPTEN__ */
-
-#endif /* end of KONWINLIB_IMPLEMENTATION */
-
-#endif