From b4d0ad9e95226d225d5361b1182866884aaa6366 Mon Sep 17 00:00:00 2001 From: Mitja Felicijan Date: Thu, 30 Apr 2026 19:19:27 +0200 Subject: Structural refactor --- game.c | 359 +++++++++-------------------------------------------------------- 1 file changed, 48 insertions(+), 311 deletions(-) (limited to 'game.c') diff --git a/game.c b/game.c index 67767d3..40d1876 100644 --- a/game.c +++ b/game.c @@ -1,332 +1,69 @@ #include "all.h" -#include + #include -#include GameState game; -static array(CachedTexture) texture_cache; - -Texture2D GetTexture(const char *name) { - for (int i = 0; i < texture_cache.length; i++) { - if (strcmp(texture_cache.data[i].name, name) == 0) return texture_cache.data[i].tex; - } - - char lname[256]; - strncpy(lname, name, sizeof(lname)); - for (int i = 0; lname[i]; i++) lname[i] = tolower(lname[i]); - - char path[256]; - void *data = NULL; - size_t size = 0; - const char *ext = ".jpg"; - - snprintf(path, sizeof(path), "textures/%s.png", lname); - data = vfs_read(path, &size); - if (data) { - ext = ".png"; - } else { - snprintf(path, sizeof(path), "textures/%s.jpg", lname); - data = vfs_read(path, &size); - ext = ".jpg"; - } - - Texture2D tex = { 0 }; - if (data) { - Image img = LoadImageFromMemory(ext, data, (int)size); - if (img.data) { - tex = LoadTextureFromImage(img); - UnloadImage(img); - } - vfs_free(data); - } - - if (tex.id == 0) { - TraceLog(LOG_WARNING, "Failed to load texture: '%s' (tried path: '%s')", name, path); - Image img = GenImageChecked(64, 64, 8, 8, (Color){128, 128, 128, 255}, (Color){200, 200, 200, 255}); - tex = LoadTextureFromImage(img); - UnloadImage(img); - } - - if (tex.id != 0) { - GenTextureMipmaps(&tex); - SetTextureFilter(tex, TEXTURE_FILTER_BILINEAR); - SetTextureWrap(tex, TEXTURE_WRAP_REPEAT); - - CachedTexture cached; - strncpy(cached.name, name, sizeof(cached.name)); - cached.tex = tex; - array_push(texture_cache, cached); - } - - return tex; -} - -void UnloadMap(void) { - if (game.world_models) { - for (int i = 0; i < game.world_model_count; i++) { - UnloadModel(game.world_models[i]); - } - free(game.world_models); - game.world_models = NULL; - game.world_model_count = 0; - } - - for (int i = 0; i < texture_cache.length; i++) { - UnloadTexture(texture_cache.data[i].tex); - } - array_clear(texture_cache); -} - -bool LoadMap(const char *filename) { - TraceLog(LOG_INFO, "Loading map: %s", filename); - - Map map = ParseMap(filename); - if (map.entity_count == 0) { - TraceLog(LOG_ERROR, "Failed to load map or map is empty: %s", filename); - return false; - } - - UnloadMap(); - - array(TextureGroup) groups; - array_init(groups); - - // Default camera if no start found - game.camera.position = (Vector3){ 0, 10, 0 }; - game.camera.target = (Vector3){ 1, 10, 0 }; - game.camera.up = (Vector3){ 0, 1, 0 }; - game.camera.fovy = PLAYER_FOV; - game.camera.projection = CAMERA_PERSPECTIVE; - - int total_brushes = 0; - for (int i = 0; i < map.entity_count; i++) { - MapEntity *e = &map.entities[i]; - bool is_world = false; - const char *classname = ""; - for (int j = 0; j < e->property_count; j++) { - if (strcmp(e->properties[j].key, "classname") == 0) { - classname = e->properties[j].value; - if (strcmp(classname, "worldspawn") == 0) is_world = true; - } - if (strcmp(e->properties[j].key, "origin") == 0) { - float x, y, z; - sscanf(e->properties[j].value, "%f %f %f", &x, &y, &z); - if (strcmp(classname, "info_player_start") == 0) { - game.pos = (Vector3){ x, z, -y }; - game.camera.position = game.pos; - float angle = 0; - for (int k = 0; k < e->property_count; k++) { - if (strcmp(e->properties[k].key, "angle") == 0) { - angle = (float)atof(e->properties[k].value); - } - } - game.yaw = (angle + 90.0f) * DEG2RAD; - game.pitch = 0; - game.camera.target = Vector3Add(game.pos, (Vector3){sinf(game.yaw), 0, cosf(game.yaw)}); - TraceLog(LOG_INFO, "Player spawn set to: %f, %f, %f (yaw: %f)", game.pos.x, game.pos.y, game.pos.z, game.yaw); - } - } - } - - if (is_world) { - total_brushes += e->brush_count; - for (int j = 0; j < e->brush_count; j++) { - MapBrush *brush = &e->brushes[j]; - for (int p_idx = 0; p_idx < brush->plane_count; p_idx++) { - MapPlane *mp = &brush->planes[p_idx]; - Plane plane = PlaneFromPoints(mp->p[0], mp->p[1], mp->p[2]); - - if (Vector3Length(plane.normal) < 0.5f) continue; - - Polygon poly = CreateLargeQuad(plane); - for (int k = 0; k < brush->plane_count; k++) { - if (p_idx == k) continue; - Plane clipPlane = PlaneFromPoints(brush->planes[k].p[0], brush->planes[k].p[1], brush->planes[k].p[2]); - if (Vector3Length(clipPlane.normal) < 0.5f) continue; - - Polygon next = PolyClip(poly, clipPlane); - PolyFree(poly); - poly = next; - } - if (poly.count >= 3) { - TextureGroup *group = NULL; - for (int g = 0; g < groups.length; g++) { - if (strcmp(groups.data[g].texture, mp->texture) == 0) { - group = &groups.data[g]; - break; - } - } - if (!group) { - TextureGroup new_group = { 0 }; - strncpy(new_group.texture, mp->texture, sizeof(new_group.texture)); - array_init(new_group.vertices); - array_init(new_group.texcoords); - array_init(new_group.normals); - array_push(groups, new_group); - group = &groups.data[groups.length - 1]; - } - for (int v = 1; v < poly.count - 1; v++) { - Vector3 v0 = poly.verts[0]; - Vector3 v1 = poly.verts[v+1]; - Vector3 v2 = poly.verts[v]; - array_push(group->vertices, v0.x); array_push(group->vertices, v0.y); array_push(group->vertices, v0.z); - array_push(group->vertices, v1.x); array_push(group->vertices, v1.y); array_push(group->vertices, v1.z); - array_push(group->vertices, v2.x); array_push(group->vertices, v2.y); array_push(group->vertices, v2.z); - Vector2 uv0 = GetUV(v0, mp, plane); - Vector2 uv1 = GetUV(v1, mp, plane); - Vector2 uv2 = GetUV(v2, mp, plane); - array_push(group->texcoords, uv0.x); array_push(group->texcoords, uv0.y); - array_push(group->texcoords, uv1.x); array_push(group->texcoords, uv1.y); - array_push(group->texcoords, uv2.x); array_push(group->texcoords, uv2.y); - Vector3 out_normal = Vector3Scale(plane.normal, -1.0f); - array_push(group->normals, out_normal.x); array_push(group->normals, out_normal.y); array_push(group->normals, out_normal.z); - array_push(group->normals, out_normal.x); array_push(group->normals, out_normal.y); array_push(group->normals, out_normal.z); - array_push(group->normals, out_normal.x); array_push(group->normals, out_normal.y); array_push(group->normals, out_normal.z); - } - } - PolyFree(poly); - } - } - } - } - - array(Model) final_models; - array_init(final_models); - - for (int i = 0; i < groups.length; i++) { - TextureGroup *g = &groups.data[i]; - if (g->vertices.length == 0) continue; - Mesh mesh = { 0 }; - mesh.vertexCount = (int)g->vertices.length / 3; - mesh.triangleCount = mesh.vertexCount / 3; - mesh.vertices = (float *)malloc(g->vertices.length * sizeof(float)); - memcpy(mesh.vertices, g->vertices.data, g->vertices.length * sizeof(float)); - mesh.texcoords = (float *)malloc(g->texcoords.length * sizeof(float)); - memcpy(mesh.texcoords, g->texcoords.data, g->texcoords.length * sizeof(float)); - mesh.normals = (float *)malloc(g->normals.length * sizeof(float)); - memcpy(mesh.normals, g->normals.data, g->normals.length * sizeof(float)); - UploadMesh(&mesh, false); - Model model = LoadModelFromMesh(mesh); - model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = GetTexture(g->texture); - array_push(final_models, model); - array_free(g->vertices); - array_free(g->texcoords); - array_free(g->normals); - } - - game.world_models = final_models.data; - game.world_model_count = (int)final_models.length; - array_free(groups); - - FreeMap(map); - TraceLog(LOG_INFO, "Processed %d brushes into %d models", total_brushes, game.world_model_count); - return true; -} void InitGame(void) { - array_init(texture_cache); - game.world_models = NULL; - game.world_model_count = 0; - - // Load UI Font - size_t font_size = 0; - void *font_data = vfs_read("fonts/LiberationSans-Bold.ttf", &font_size); - if (font_data) { - game.font_ui = LoadFontFromMemory(".ttf", font_data, (int)font_size, 20, NULL, 0); - vfs_free(font_data); - } else { - game.font_ui = GetFontDefault(); - } - - game.mode = STATE_TITLE; - - game.cursor_captured = false; - EnableCursor(); - - game.move_mode = MOVE_NORMAL; - game.velocity = (Vector3){ 0, 0, 0 }; - game.is_grounded = false; + memset(&game, 0, sizeof(game)); + + game.font_ui = LoadFontVFS(UI_FONT_PATH, UI_FONT_SIZE); + game.mode = STATE_MENU; + game.cursor_captured = false; + EnableCursor(); + + game.player.move_mode = MOVE_NORMAL; + game.player.pos = (Vector3){ 0, 0, 0 }; + game.player.velocity = (Vector3){ 0, 0, 0 }; + game.player.is_grounded = false; + + // Camera setup + game.camera.up = (Vector3){ 0, 1, 0 }; + game.camera.fovy = PLAYER_FOV; + game.camera.projection = CAMERA_PERSPECTIVE; } void SetMap(const char *path) { - strncpy(game.map_path, path, sizeof(game.map_path) - 1); - game.map_path[sizeof(game.map_path) - 1] = '\0'; + strncpy(game.map_path, path, sizeof(game.map_path) - 1); + game.map_path[sizeof(game.map_path) - 1] = '\0'; } void UpdateGame(void) { - if (game.mode == STATE_TITLE) { - if (IsKeyPressed(KEY_ENTER)) { - if (LoadMap(game.map_path)) { - game.mode = STATE_PLAYING; - } - } - return; - } - - if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) { - game.cursor_captured = !game.cursor_captured; - if (game.cursor_captured) DisableCursor(); - else EnableCursor(); - } - - if (IsKeyPressed(KEY_ONE)) LoadMap("maps/demo1.map"); - if (IsKeyPressed(KEY_TWO)) LoadMap("maps/demo2.map"); - if (IsKeyPressed(KEY_THREE)) LoadMap("maps/demo3.map"); - - if (IsKeyPressed(KEY_V)) { - game.vsync = !game.vsync; - if (game.vsync) { - SetWindowState(FLAG_VSYNC_HINT); - SetTargetFPS(GetMonitorRefreshRate(GetCurrentMonitor())); - } else { - ClearWindowState(FLAG_VSYNC_HINT); - SetTargetFPS(0); - } - } - - UpdatePlayer(); + if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) { + game.cursor_captured = !game.cursor_captured; + if (game.cursor_captured) DisableCursor(); + else EnableCursor(); + } + + if (IsKeyPressed(KEY_V)) { + game.vsync = !game.vsync; + if (game.vsync) { + SetWindowState(FLAG_VSYNC_HINT); + SetTargetFPS(GetMonitorRefreshRate(GetCurrentMonitor())); + } else { + ClearWindowState(FLAG_VSYNC_HINT); + SetTargetFPS(0); + } + } + + UpdatePlayer(); } void DrawGame(void) { - BeginDrawing(); - ClearBackground(BLACK); + BeginDrawing(); + ClearBackground(DARKGRAY); - if (game.mode == STATE_TITLE) { - int screenWidth = GetScreenWidth(); - int screenHeight = GetScreenHeight(); + BeginMode3D(game.camera); - const char *title = "STALAG"; - const char *sub = "Press ENTER to Start"; - - int titleSize = 60; - int subSize = 20; + rlEnableBackfaceCulling(); + for (int i = 0; i < game.map.count; i++) { + DrawModel(game.map.models[i], (Vector3){ 0, 0, 0 }, 1.0f, WHITE); + } - Vector2 titlePos = { - (float)(screenWidth - MeasureTextEx(game.font_ui, title, (float)titleSize, 4).x) / 2, - (float)screenHeight / 2 - 40 - }; - Vector2 subPos = { - (float)(screenWidth - MeasureTextEx(game.font_ui, sub, (float)subSize, 2).x) / 2, - (float)screenHeight / 2 + 40 - }; + EndMode3D(); - DrawTextEx(game.font_ui, title, titlePos, (float)titleSize, 4, WHITE); - DrawTextEx(game.font_ui, sub, subPos, (float)subSize, 2, GRAY); - } else { - ClearBackground(DARKGRAY); - BeginMode3D(game.camera); - - // Enable backface culling to hide interior faces of brushes - rlEnableBackfaceCulling(); - for (int i = 0; i < game.world_model_count; i++) { - DrawModel(game.world_models[i], (Vector3){ 0, 0, 0 }, 1.0f, WHITE); - } - - EndMode3D(); - - DrawCrosshair(); - DrawDebugInfo(); - } + DrawCrosshair(); + DrawDebugInfo(); - EndDrawing(); + EndDrawing(); } -- cgit v1.2.3