/* SPDX-License-Identifier: MIT */ /* * kon3d.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 KON3D_H #define KON3D_H #include "konprogram.h" #include "kontile.h" #ifndef KONSOFREN_HAS_3D #error "this needs the 3D part of konsofren, define KONSOFREN_3D before the first include of konsofren.h (build.sh does it for -m 3d, model and sector)" #endif /*** definition ***/ /* a first person body on a tilemap. the world is one unit per tile, y is up, yaw 0 looks up the map (towards row 0) */ typedef struct kon_fp { kon_box2_t body; /* map pixels, this is what bumps into walls */ float eyeHeight; /* world units, 0.6 */ float yaw, pitch; float sensitivity; /* radians per mouse pixel, 0.0015 */ float speed; /* tiles per second, 2.5 */ float turnSpeed; /* radians per second for the arrow keys, 2 */ float fov; /* vertical, radians, 60 degrees */ float farZ; /* how far you see, 40 */ int forward, strafe, turn; /* -1, 0 or 1, set by kon_fpEvent */ float feet; /* height of the floor under you, the eyes are eyeHeight above this */ float fall; /* downward speed while dropping */ float maxSlope; /* rise over run you can walk up, 1 is 45 degrees. anything steeper is a wall */ float gravity; /* 20 */ } kon_fp_t; /* a grid of heights, one world unit per cell, x is the column and z the row like the tilemap. every cell is two triangles. edit the heights any time, it is drawn in chunks that are skipped when they are off screen */ typedef struct kon_terrain { int columns, rows; /* cells, there is one more height than that each way */ float *heights; int chunk; /* cells per chunk side, 16 */ int chunkColumns, chunkRows; float *chunkMin, *chunkMax; const kon_material_t *material; /* the texture repeats once per cell */ int faceted; /* 1 shades every triangle flat, 0 smooths the light over the corners */ } kon_terrain_t; /* what to draw for a map. solid is indexed by tile id like in kon_tilemapMove, solid tiles become walls. ceiling can be NULL, that leaves the sky colour */ typedef struct kon_level3d { const kon_tilemap_t *map; const uint8_t *solid; int solidCount; float wallHeight; const kon_material_t *wall, *floor, *ceiling; } kon_level3d_t; /*** body ***/ /* stands in the middle of the tile, looking up the map */ void kon_fpInit(kon_fp_t *fp, const kon_tilemap_t *map, int column, int row); /* returns 1 when the event was used. wasd and the arrows walk, the mouse looks once it is captured, a click grabs the mouse and tab lets go */ int kon_fpEvent(kon_fp_t *fp, kon_program_t *program, const kon_event_t *event); /* walks and turns, slides along solid tiles. lets the mouse go while the debug console is open. terrain can be NULL for flat ground, otherwise you follow it, fall off ledges and stop at slopes steeper than maxSlope */ void kon_fpUpdate(kon_fp_t *fp, kon_program_t *program, const kon_tilemap_t *map, const uint8_t *solid, int solidCount, const kon_terrain_t *terrain, double dt); /* puts your feet on the ground right away, for after kon_fpInit or a teleport */ void kon_fpPlace(kon_fp_t *fp, const kon_tilemap_t *map, const kon_terrain_t *terrain); /* where the eyes are in world units */ kon_vec3_t kon_fpEye(const kon_fp_t *fp, const kon_tilemap_t *map); kon_camera_t kon_fpCamera(const kon_fp_t *fp, const kon_tilemap_t *map); /* adds the variables sens, speed and eye and the command where */ void kon_fpDebug(kon_fp_t *fp, kon_debug_t *debug); /*** drawing ***/ /* walls, floor and ceiling. walls behind the camera and far away ones are skipped, floor and ceiling go last so the depth test throws out what the walls already cover */ void kon_drawLevel(kon_framebuffer_t *fb, const kon_camera_t *camera, const kon_level3d_t *level, const kon_light_t *light); /*** terrain ***/ /* all heights start at 0. NULL if the size is bad or there is no memory */ kon_terrain_t *kon_terrainCreate(int columns, int rows); void kon_terrainFree(kon_terrain_t *terrain); /* the corner at column, row, from 0 to columns and 0 to rows. both do nothing outside */ float kon_terrainCorner(const kon_terrain_t *terrain, int column, int row); void kon_terrainSetCorner(kon_terrain_t *terrain, int column, int row, float height); /* the exact height of the surface at x, z, the same triangles that get drawn. clamps at the edges */ float kon_terrainHeight(const kon_terrain_t *terrain, float x, float z); /* pushes the ground up (or down with a negative amount) around x, z. full strength in the middle, nothing at radius */ void kon_terrainRaise(kon_terrain_t *terrain, float x, float z, float radius, float amount); void kon_terrainFill(kon_terrain_t *terrain, float height); /* walks along the ray in small steps. returns 1 and the point if it hits the ground inside maxDistance */ int kon_terrainRay(const kon_terrain_t *terrain, kon_vec3_t origin, kon_vec3_t direction, float maxDistance, kon_vec3_t *hit); /* a text file, "kter columns rows" and then the heights, so it is easy to read and diff. returns 0 on success */ int kon_terrainSave(const kon_terrain_t *terrain, const char *path); kon_terrain_t *kon_terrainLoad(const char *path); void kon_drawTerrain(kon_framebuffer_t *fb, const kon_camera_t *camera, const kon_terrain_t *terrain, const kon_light_t *light); /* adds the commands tsave file, tload file and tfill height. the terrain has to stay where it is, a load changes it in place */ void kon_terrainDebug(kon_terrain_t *terrain, kon_debug_t *debug); /* 1 up close and less the further away, for dimming sprites. falloff 0.18 is gentle */ float kon_distanceFade(float distance, float falloff); #endif