Compiler settings and macOS port

Author Mitja Felicijan <mitja.felicijan@gmail.com> 2026-04-28 07:50:31 +0200
Committer Mitja Felicijan <mitja.felicijan@gmail.com> 2026-04-28 09:23:47 +0200
Commit 63eb46698b1e19d3f36944992b948c54a7a3740b (patch)
-rw-r--r-- .clangd 3
-rw-r--r-- Makefile 23
-rw-r--r-- all.h 117
-rw-r--r-- config.h 8
-rw-r--r-- game.c 306
-rw-r--r-- libraries/nonstd.h 87
-rw-r--r-- libraries/vfs.h 16
-rw-r--r-- main.c 28
-rw-r--r-- map.c 246
-rw-r--r-- maps/demo1.map 14
-rw-r--r-- textures/brushes/bricks_076c.jpg bin 93.9 KB -> 0 B
-rw-r--r-- textures/brushes/bricks_076c.png bin 0 B -> 109.2 KB
-rw-r--r-- textures/brushes/ground_068.jpg bin 126.6 KB -> 0 B
-rw-r--r-- textures/brushes/ground_068.png bin 0 B -> 126.9 KB
-rw-r--r-- textures/brushes/rock_016.jpg bin 56.5 KB -> 0 B
-rw-r--r-- textures/brushes/rock_016.png bin 0 B -> 95.4 KB
-rw-r--r-- textures/brushes/rock_030.jpg bin 86.9 KB -> 0 B
-rw-r--r-- textures/brushes/rock_030.png bin 0 B -> 120.9 KB
-rw-r--r-- textures/environment/paintedwood_008a.jpg bin 353.8 KB -> 0 B
-rw-r--r-- textures/environment/paintedwood_008a.png bin 0 B -> 466.3 KB
-rw-r--r-- textures/environment/planks_012.jpg bin 338.2 KB -> 0 B
-rw-r--r-- textures/environment/planks_012.png bin 0 B -> 412.2 KB
-rw-r--r-- textures/environment/roofingtiles_012b.jpg bin 257.3 KB -> 0 B
-rw-r--r-- textures/environment/roofingtiles_012b.png bin 0 B -> 361.6 KB
24 files changed, 734 insertions, 114 deletions
diff --git a/.clangd b/.clangd
  
1
CompileFlags:
  
2
  Add:
  
3
    - -I./vendor/raylib-6.0_linux_amd64/include
diff --git a/Makefile b/Makefile
1
OS := $(shell uname)
1
OS := $(shell uname)
2
ifeq ($(OS), Linux)
2
ifeq ($(OS), Linux)
3
SYSTEM = linux_amd64
3
	SYSTEM = linux_amd64
4
else ifeq ($(OS), Darwin)
4
else ifeq ($(OS), Darwin)
5
SYSTEM = macos
5
	SYSTEM = macos
6
else ifeq ($(OS), WindowsNT)
6
else ifeq ($(OS), WindowsNT)
7
SYSTEM = windows
7
	SYSTEM = windows
8
else
8
else
9
SYSTEM = unknown
9
	SYSTEM = unknown
10
endif
10
endif
11
  
11
  
12
CC           := clang
12
CC           := clang
13
RAYLIB_VER   := raylib-6.0_$(SYSTEM)
13
RAYLIB_VER   := raylib-6.0_$(SYSTEM)
14
CFLAGS       := -std=c99 -v -g -I./vendor/$(RAYLIB_VER)/include
14
CFLAGS       := -std=c99 -v -g -I./vendor/$(RAYLIB_VER)/include
15
LDFLAGS      := -L./vendor/$(RAYLIB_VER)/lib -Wl,-Bstatic -lraylib -Wl,-Bdynamic -lm -lpthread -ldl -lrt -lX11
15
LDFLAGS      := ./vendor/$(RAYLIB_VER)/lib/libraylib.a -lm
16
GAME         := bin/stalag
16
GAME         := bin/stalag
17
HEXDUMP      := bin/hexdump
17
HEXDUMP      := bin/hexdump
18
SOURCES      := main.c
18
SOURCES      := main.c map.c game.c
  
19
  
  
20
ifeq ($(SYSTEM), linux_amd64)
  
21
	LDFLAGS += -lX11
  
22
endif
19
  
23
  
20
# Check if macOS and then append proper CFLAGS.
  
21
ifeq ($(SYSTEM), macos)
24
ifeq ($(SYSTEM), macos)
22
CFLAGS += -framework CoreVideo -framework IOKit -framework Cocoa -framework GLUT -framework OpenGL
25
	LDFLAGS += -framework CoreVideo -framework IOKit -framework Cocoa -framework GLUT -framework OpenGL
23
endif
26
endif
24
  
27
  
25
all: info mkdirs $(HEXDUMP) $(GAME)
28
all: info mkdirs $(HEXDUMP) $(GAME)
26
  
29
  
27
.PHONY: info mkdirs clean
30
.PHONY: info mkdirs clean
28
	
31
  
29
info: # Print out information about the build
32
info: # Print out information about the build
30
	$(info CC         : $(CC))
33
	$(info CC         : $(CC))
31
	$(info SYSTEM     : $(SYSTEM))
34
	$(info SYSTEM     : $(SYSTEM))
...
43
	mkdir -p bin
46
	mkdir -p bin
44
  
47
  
45
clean:
48
clean:
46
	-rm $(GAME) $(HEXDUMP)
49
	-rm $(GAME) $(HEXDUMP)
diff --git a/all.h b/all.h
  
1
#ifndef ALL_H
  
2
#define ALL_H
  
3
  
  
4
#include "raylib.h"
  
5
#include "raymath.h"
  
6
#include "rlgl.h"
  
7
#include "config.h"
  
8
  
  
9
// Resolve conflicts between Raylib and nonstd.h
  
10
#define Color NS_Color
  
11
#include "libraries/nonstd.h"
  
12
#undef Color
  
13
  
  
14
#include "libraries/vfs.h"
  
15
#include <stdbool.h>
  
16
#include <stddef.h>
  
17
  
  
18
// --- Map Structures ---
  
19
  
  
20
typedef struct {
  
21
    Vector3 p[3];
  
22
    char texture[64];
  
23
    float shift[2];
  
24
    float rotate;
  
25
    float scale[2];
  
26
} MapPlane;
  
27
  
  
28
typedef struct {
  
29
    MapPlane *planes;
  
30
    int plane_count;
  
31
} MapBrush;
  
32
  
  
33
typedef struct {
  
34
    char key[64];
  
35
    char value[256];
  
36
} MapProperty;
  
37
  
  
38
typedef struct {
  
39
    MapProperty *properties;
  
40
    int property_count;
  
41
    MapBrush *brushes;
  
42
    int brush_count;
  
43
} MapEntity;
  
44
  
  
45
typedef struct {
  
46
    MapEntity *entities;
  
47
    int entity_count;
  
48
} Map;
  
49
  
  
50
typedef struct {
  
51
    const char *data;
  
52
    size_t length;
  
53
    size_t pos;
  
54
} MapParser;
  
55
  
  
56
typedef struct {
  
57
    Vector3 normal;
  
58
    float dist;
  
59
} Plane;
  
60
  
  
61
typedef struct {
  
62
    Vector3 *verts;
  
63
    int count;
  
64
} Polygon;
  
65
  
  
66
typedef struct {
  
67
    char texture[64];
  
68
    array(float) vertices;
  
69
    array(float) texcoords;
  
70
    array(float) normals;
  
71
} TextureGroup;
  
72
  
  
73
typedef struct {
  
74
    char name[64];
  
75
    Texture2D tex;
  
76
} CachedTexture;
  
77
  
  
78
// --- Game State ---
  
79
  
  
80
typedef struct {
  
81
    Camera camera;
  
82
    Model *world_models;
  
83
    int world_model_count;
  
84
    bool cursor_captured;
  
85
    bool vsync;
  
86
} GameState;
  
87
  
  
88
extern GameState game;
  
89
  
  
90
// --- Prototypes ---
  
91
  
  
92
// Map
  
93
char map_peek(MapParser *p);
  
94
char map_get(MapParser *p);
  
95
void map_skip_whitespace(MapParser *p);
  
96
bool map_expect(MapParser *p, char expected);
  
97
void map_parse_token(MapParser *p, char *buffer, int size);
  
98
Vector3 map_parse_vector(MapParser *p);
  
99
Map ParseMap(const char *filename);
  
100
void FreeMap(Map map);
  
101
  
  
102
// Geometry
  
103
Plane PlaneFromPoints(Vector3 p1, Vector3 p2, Vector3 p3);
  
104
void PolyFree(Polygon p);
  
105
Polygon PolyClip(Polygon poly, Plane plane);
  
106
Polygon CreateLargeQuad(Plane plane);
  
107
Vector2 GetUV(Vector3 p, MapPlane *mp, Plane plane);
  
108
  
  
109
// Game
  
110
Texture2D GetTexture(const char *name);
  
111
void InitGame(void);
  
112
void UpdateGame(void);
  
113
void DrawGame(void);
  
114
bool LoadMap(const char *filename);
  
115
void UnloadMap(void);
  
116
  
  
117
#endif
diff --git a/config.h b/config.h
  
1
#ifndef CONFIG_H
  
2
#define CONFIG_H
  
3
  
  
4
#define PLAYER_MOVE_SPEED 400.0f
  
5
#define PLAYER_ROTATION_SPEED 0.05f
  
6
#define PLAYER_MOUSE_SENSITIVITY 0.003f
  
7
  
  
8
#endif
diff --git a/game.c b/game.c
  
1
#include "all.h"
  
2
#include <stdio.h>
  
3
#include <string.h>
  
4
#include <ctype.h>
  
5
  
  
6
GameState game;
  
7
static array(CachedTexture) texture_cache;
  
8
  
  
9
Texture2D GetTexture(const char *name) {
  
10
    for (int i = 0; i < texture_cache.length; i++) {
  
11
        if (strcmp(texture_cache.data[i].name, name) == 0) return texture_cache.data[i].tex;
  
12
    }
  
13
  
  
14
    char lname[256];
  
15
    strncpy(lname, name, sizeof(lname));
  
16
    for (int i = 0; lname[i]; i++) lname[i] = tolower(lname[i]);
  
17
  
  
18
    char path[256];
  
19
    void *data = NULL;
  
20
    size_t size = 0;
  
21
    const char *ext = ".jpg";
  
22
  
  
23
    snprintf(path, sizeof(path), "textures/%s.png", lname);
  
24
    data = vfs_read(path, &size);
  
25
    if (data) {
  
26
        ext = ".png";
  
27
    } else {
  
28
        snprintf(path, sizeof(path), "textures/%s.jpg", lname);
  
29
        data = vfs_read(path, &size);
  
30
        ext = ".jpg";
  
31
    }
  
32
  
  
33
    Texture2D tex = { 0 };
  
34
    if (data) {
  
35
        Image img = LoadImageFromMemory(ext, data, (int)size);
  
36
        if (img.data) {
  
37
            tex = LoadTextureFromImage(img);
  
38
            UnloadImage(img);
  
39
        }
  
40
        vfs_free(data);
  
41
    }
  
42
  
  
43
    if (tex.id == 0) {
  
44
        TraceLog(LOG_WARNING, "Failed to load texture: '%s' (tried path: '%s')", name, path);
  
45
        Image img = GenImageChecked(64, 64, 8, 8, (Color){128, 128, 128, 255}, (Color){200, 200, 200, 255});
  
46
        tex = LoadTextureFromImage(img);
  
47
        UnloadImage(img);
  
48
    }
  
49
    
  
50
    if (tex.id != 0) {
  
51
        GenTextureMipmaps(&tex);
  
52
        SetTextureFilter(tex, TEXTURE_FILTER_BILINEAR);
  
53
        SetTextureWrap(tex, TEXTURE_WRAP_REPEAT);
  
54
        
  
55
        CachedTexture cached;
  
56
        strncpy(cached.name, name, sizeof(cached.name));
  
57
        cached.tex = tex;
  
58
        array_push(texture_cache, cached);
  
59
    }
  
60
    
  
61
    return tex;
  
62
}
  
63
  
  
64
void UnloadMap(void) {
  
65
    if (game.world_models) {
  
66
        for (int i = 0; i < game.world_model_count; i++) {
  
67
            UnloadModel(game.world_models[i]);
  
68
        }
  
69
        free(game.world_models);
  
70
        game.world_models = NULL;
  
71
        game.world_model_count = 0;
  
72
    }
  
73
  
  
74
    for (int i = 0; i < texture_cache.length; i++) {
  
75
        UnloadTexture(texture_cache.data[i].tex);
  
76
    }
  
77
    array_clear(texture_cache);
  
78
}
  
79
  
  
80
bool LoadMap(const char *filename) {
  
81
    TraceLog(LOG_INFO, "Loading map: %s", filename);
  
82
    
  
83
    Map map = ParseMap(filename);
  
84
    if (map.entity_count == 0) {
  
85
        TraceLog(LOG_ERROR, "Failed to load map or map is empty: %s", filename);
  
86
        return false;
  
87
    }
  
88
  
  
89
    UnloadMap();
  
90
    
  
91
    array(TextureGroup) groups;
  
92
    array_init(groups);
  
93
    
  
94
    // Default camera if no start found
  
95
    game.camera.position = (Vector3){ 0, 10, 0 };
  
96
    game.camera.target = (Vector3){ 1, 10, 0 };
  
97
    game.camera.up = (Vector3){ 0, 1, 0 };
  
98
    game.camera.fovy = 75.0f;
  
99
    game.camera.projection = CAMERA_PERSPECTIVE;
  
100
  
  
101
    int total_brushes = 0;
  
102
    for (int i = 0; i < map.entity_count; i++) {
  
103
        MapEntity *e = &map.entities[i];
  
104
        bool is_world = false;
  
105
        const char *classname = "";
  
106
        for (int j = 0; j < e->property_count; j++) {
  
107
            if (strcmp(e->properties[j].key, "classname") == 0) {
  
108
                classname = e->properties[j].value;
  
109
                if (strcmp(classname, "worldspawn") == 0) is_world = true;
  
110
            }
  
111
            if (strcmp(e->properties[j].key, "origin") == 0) {
  
112
                float x, y, z;
  
113
                sscanf(e->properties[j].value, "%f %f %f", &x, &y, &z);
  
114
                if (strcmp(classname, "info_player_start") == 0) {
  
115
                    game.camera.position = (Vector3){ x, z, -y };
  
116
                    game.camera.target = Vector3Add(game.camera.position, (Vector3){0, 0, 1});
  
117
                    TraceLog(LOG_INFO, "Player spawn set to: %f, %f, %f", game.camera.position.x, game.camera.position.y, game.camera.position.z);
  
118
                }
  
119
            }
  
120
        }
  
121
        
  
122
        if (is_world) {
  
123
            total_brushes += e->brush_count;
  
124
            for (int j = 0; j < e->brush_count; j++) {
  
125
                MapBrush *brush = &e->brushes[j];
  
126
                for (int p_idx = 0; p_idx < brush->plane_count; p_idx++) {
  
127
                    MapPlane *mp = &brush->planes[p_idx];
  
128
                    Plane plane = PlaneFromPoints(mp->p[0], mp->p[1], mp->p[2]);
  
129
                    
  
130
                    if (Vector3Length(plane.normal) < 0.5f) continue;
  
131
  
  
132
                    Polygon poly = CreateLargeQuad(plane);
  
133
                    for (int k = 0; k < brush->plane_count; k++) {
  
134
                        if (p_idx == k) continue;
  
135
                        Plane clipPlane = PlaneFromPoints(brush->planes[k].p[0], brush->planes[k].p[1], brush->planes[k].p[2]);
  
136
                        if (Vector3Length(clipPlane.normal) < 0.5f) continue;
  
137
  
  
138
                        Polygon next = PolyClip(poly, clipPlane);
  
139
                        PolyFree(poly);
  
140
                        poly = next;
  
141
                    }
  
142
                    if (poly.count >= 3) {
  
143
                        TextureGroup *group = NULL;
  
144
                        for (int g = 0; g < groups.length; g++) {
  
145
                            if (strcmp(groups.data[g].texture, mp->texture) == 0) {
  
146
                                group = &groups.data[g];
  
147
                                break;
  
148
                            }
  
149
                        }
  
150
                        if (!group) {
  
151
                            TextureGroup new_group = { 0 };
  
152
                            strncpy(new_group.texture, mp->texture, sizeof(new_group.texture));
  
153
                            array_init(new_group.vertices);
  
154
                            array_init(new_group.texcoords);
  
155
                            array_init(new_group.normals);
  
156
                            array_push(groups, new_group);
  
157
                            group = &groups.data[groups.length - 1];
  
158
                        }
  
159
                        for (int v = 1; v < poly.count - 1; v++) {
  
160
                            Vector3 v0 = poly.verts[0];
  
161
                            Vector3 v1 = poly.verts[v+1];
  
162
                            Vector3 v2 = poly.verts[v];
  
163
                            array_push(group->vertices, v0.x); array_push(group->vertices, v0.y); array_push(group->vertices, v0.z);
  
164
                            array_push(group->vertices, v1.x); array_push(group->vertices, v1.y); array_push(group->vertices, v1.z);
  
165
                            array_push(group->vertices, v2.x); array_push(group->vertices, v2.y); array_push(group->vertices, v2.z);
  
166
                            Vector2 uv0 = GetUV(v0, mp, plane);
  
167
                            Vector2 uv1 = GetUV(v1, mp, plane);
  
168
                            Vector2 uv2 = GetUV(v2, mp, plane);
  
169
                            array_push(group->texcoords, uv0.x); array_push(group->texcoords, uv0.y);
  
170
                            array_push(group->texcoords, uv1.x); array_push(group->texcoords, uv1.y);
  
171
                            array_push(group->texcoords, uv2.x); array_push(group->texcoords, uv2.y);
  
172
                            Vector3 out_normal = Vector3Scale(plane.normal, -1.0f);
  
173
                            array_push(group->normals, out_normal.x); array_push(group->normals, out_normal.y); array_push(group->normals, out_normal.z);
  
174
                            array_push(group->normals, out_normal.x); array_push(group->normals, out_normal.y); array_push(group->normals, out_normal.z);
  
175
                            array_push(group->normals, out_normal.x); array_push(group->normals, out_normal.y); array_push(group->normals, out_normal.z);
  
176
                        }
  
177
                    }
  
178
                    PolyFree(poly);
  
179
                }
  
180
            }
  
181
        }
  
182
    }
  
183
    
  
184
    array(Model) final_models;
  
185
    array_init(final_models);
  
186
    
  
187
    for (int i = 0; i < groups.length; i++) {
  
188
        TextureGroup *g = &groups.data[i];
  
189
        if (g->vertices.length == 0) continue;
  
190
        Mesh mesh = { 0 };
  
191
        mesh.vertexCount = (int)g->vertices.length / 3;
  
192
        mesh.triangleCount = mesh.vertexCount / 3;
  
193
        mesh.vertices = (float *)malloc(g->vertices.length * sizeof(float));
  
194
        memcpy(mesh.vertices, g->vertices.data, g->vertices.length * sizeof(float));
  
195
        mesh.texcoords = (float *)malloc(g->texcoords.length * sizeof(float));
  
196
        memcpy(mesh.texcoords, g->texcoords.data, g->texcoords.length * sizeof(float));
  
197
        mesh.normals = (float *)malloc(g->normals.length * sizeof(float));
  
198
        memcpy(mesh.normals, g->normals.data, g->normals.length * sizeof(float));
  
199
        UploadMesh(&mesh, false);
  
200
        Model model = LoadModelFromMesh(mesh);
  
201
        model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = GetTexture(g->texture);
  
202
        array_push(final_models, model);
  
203
        array_free(g->vertices);
  
204
        array_free(g->texcoords);
  
205
        array_free(g->normals);
  
206
    }
  
207
    
  
208
    game.world_models = final_models.data;
  
209
    game.world_model_count = (int)final_models.length;
  
210
    array_free(groups);
  
211
    
  
212
    FreeMap(map);
  
213
    TraceLog(LOG_INFO, "Processed %d brushes into %d models", total_brushes, game.world_model_count);
  
214
    return true;
  
215
}
  
216
  
  
217
void InitGame(void) {
  
218
    array_init(texture_cache);
  
219
    game.world_models = NULL;
  
220
    game.world_model_count = 0;
  
221
    
  
222
    LoadMap("maps/demo1.map");
  
223
  
  
224
    game.cursor_captured = true;
  
225
    DisableCursor();
  
226
}
  
227
  
  
228
void UpdateGame(void) {
  
229
    float dt = GetFrameTime();
  
230
    
  
231
    if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) {
  
232
        game.cursor_captured = !game.cursor_captured;
  
233
        if (game.cursor_captured) DisableCursor();
  
234
        else EnableCursor();
  
235
    }
  
236
  
  
237
    if (IsKeyPressed(KEY_ONE)) LoadMap("maps/demo1.map");
  
238
    if (IsKeyPressed(KEY_TWO)) LoadMap("maps/demo2.map");
  
239
  
  
240
    if (IsKeyPressed(KEY_V)) {
  
241
        game.vsync = !game.vsync;
  
242
        if (game.vsync) {
  
243
            SetWindowState(FLAG_VSYNC_HINT);
  
244
            SetTargetFPS(GetMonitorRefreshRate(GetCurrentMonitor()));
  
245
        } else {
  
246
            ClearWindowState(FLAG_VSYNC_HINT);
  
247
            SetTargetFPS(0);
  
248
        }
  
249
    }
  
250
  
  
251
    // Manual first-person movement
  
252
    Vector3 forward = Vector3Normalize(Vector3Subtract(game.camera.target, game.camera.position));
  
253
    Vector3 right = Vector3Normalize(Vector3CrossProduct(forward, game.camera.up));
  
254
    
  
255
    Vector3 move = { 0 };
  
256
    if (IsKeyDown(KEY_W)) move = Vector3Add(move, forward);
  
257
    if (IsKeyDown(KEY_S)) move = Vector3Subtract(move, forward);
  
258
    if (IsKeyDown(KEY_D)) move = Vector3Add(move, right);
  
259
    if (IsKeyDown(KEY_A)) move = Vector3Subtract(move, right);
  
260
    
  
261
    if (Vector3Length(move) > 0) {
  
262
        move = Vector3Scale(Vector3Normalize(move), PLAYER_MOVE_SPEED * dt);
  
263
        game.camera.position = Vector3Add(game.camera.position, move);
  
264
        game.camera.target = Vector3Add(game.camera.target, move);
  
265
    }
  
266
    
  
267
    if (game.cursor_captured) {
  
268
        // Manual rotation
  
269
        Vector2 mouseDelta = GetMouseDelta();
  
270
        float yaw = -mouseDelta.x * PLAYER_MOUSE_SENSITIVITY;
  
271
        float pitch = -mouseDelta.y * PLAYER_MOUSE_SENSITIVITY;
  
272
        
  
273
        Vector3 view = Vector3Subtract(game.camera.target, game.camera.position);
  
274
        
  
275
        // Yaw
  
276
        view = Vector3RotateByAxisAngle(view, game.camera.up, yaw);
  
277
        
  
278
        // Pitch
  
279
        Vector3 axis = Vector3Normalize(Vector3CrossProduct(view, game.camera.up));
  
280
        view = Vector3RotateByAxisAngle(view, axis, pitch);
  
281
        
  
282
        game.camera.target = Vector3Add(game.camera.position, view);
  
283
    }
  
284
}
  
285
  
  
286
void DrawGame(void) {
  
287
    BeginDrawing();
  
288
    ClearBackground(DARKGRAY);
  
289
    BeginMode3D(game.camera);
  
290
    
  
291
    // Enable backface culling to hide interior faces of brushes
  
292
    rlEnableBackfaceCulling();
  
293
    for (int i = 0; i < game.world_model_count; i++) {
  
294
        DrawModel(game.world_models[i], (Vector3){ 0, 0, 0 }, 1.0f, WHITE);
  
295
    }
  
296
    
  
297
    EndMode3D();
  
298
    
  
299
    int screenWidth = GetScreenWidth();
  
300
    int screenHeight = GetScreenHeight();
  
301
    DrawLine(screenWidth / 2 - 10, screenHeight / 2, screenWidth / 2 + 10, screenHeight / 2, GREEN);
  
302
    DrawLine(screenWidth / 2, screenHeight / 2 - 10, screenWidth / 2, screenHeight / 2 + 10, GREEN);
  
303
    DrawFPS(10, 10);
  
304
    DrawText(TextFormat("VSync: %s", game.vsync ? "ON" : "OFF"), 10, 30, 20, GREEN);
  
305
    EndDrawing();
  
306
}
diff --git a/libraries/nonstd.h b/libraries/nonstd.h
...
77
#define UNUSED(value) (void)(value)
77
#define UNUSED(value) (void)(value)
78
#define TODO(message)                                                      \
78
#define TODO(message)                                                      \
79
	do {                                                                   \
79
	do {                                                                   \
80
		fprintf(stderr, "%s:%d: TODO: %s\n", __FILE__, __LINE__, message); \
80
		TraceLog(LOG_ERROR, "%s:%d: TODO: %s", __FILE__, __LINE__, message); \
81
		abort();                                                           \
81
		abort();                                                           \
82
	} while (0)
82
	} while (0)
83
#define UNREACHABLE(message)                                                      \
83
#define UNREACHABLE(message)                                                      \
84
	do {                                                                          \
84
	do {                                                                          \
85
		fprintf(stderr, "%s:%d: UNREACHABLE: %s\n", __FILE__, __LINE__, message); \
85
		TraceLog(LOG_ERROR, "%s:%d: UNREACHABLE: %s", __FILE__, __LINE__, message); \
86
		abort();                                                                  \
86
		abort();                                                                  \
87
	} while (0)
87
	} while (0)
88
  
88
  
...
315
NONSTD_DEF int write_file_sv(const char *filepath, stringv sv);
315
NONSTD_DEF int write_file_sv(const char *filepath, stringv sv);
316
NONSTD_DEF int write_file_sb(const char *filepath, const stringb *sb);
316
NONSTD_DEF int write_file_sb(const char *filepath, const stringb *sb);
317
  
317
  
318
// Logging
  
319
typedef enum {
  
320
	LOG_ERROR,
  
321
	LOG_WARN,
  
322
	LOG_INFO,
  
323
	LOG_DEBUG,
  
324
} LogLevel;
  
325
  
  
326
NONSTD_DEF void set_log_level(LogLevel level);
  
327
NONSTD_DEF LogLevel get_log_level_from_env(void);
  
328
NONSTD_DEF void log_message(FILE *stream, LogLevel level, const char *format, ...);
  
329
  
  
330
#define LOG_INFO_MSG(...) log_message(stdout, LOG_INFO, __VA_ARGS__)
  
331
#define LOG_DEBUG_MSG(...) log_message(stdout, LOG_DEBUG, __VA_ARGS__)
  
332
#define LOG_WARN_MSG(...) log_message(stderr, LOG_WARN, __VA_ARGS__)
  
333
#define LOG_ERROR_MSG(...) log_message(stderr, LOG_ERROR, __VA_ARGS__)
  
334
  
  
335
#define COLOR_RESET "\033[0m"
  
336
#define COLOR_INFO "\033[32m"
  
337
#define COLOR_DEBUG "\033[36m"
  
338
#define COLOR_WARNING "\033[33m"
  
339
#define COLOR_ERROR "\033[31m"
  
340
  
  
341
#ifdef NONSTD_IMPLEMENTATION
318
#ifdef NONSTD_IMPLEMENTATION
342
  
319
  
343
NONSTD_DEF void *safe_malloc(size_t item_size, size_t count) {
320
NONSTD_DEF void *safe_malloc(size_t item_size, size_t count) {
...
585
  
562
  
586
NONSTD_DEF int write_file_sb(const char *filepath, const stringb *sb) {
563
NONSTD_DEF int write_file_sb(const char *filepath, const stringb *sb) {
587
	return write_entire_file(filepath, sb->data, sb->length);
564
	return write_entire_file(filepath, sb->data, sb->length);
588
}
  
589
  
  
590
// Logging Implementation
  
591
  
  
592
static LogLevel max_level = LOG_INFO;
  
593
  
  
594
static const char *level_strings[] = {
  
595
	"ERROR",
  
596
	"WARN",
  
597
	"INFO",
  
598
	"DEBUG",
  
599
};
  
600
  
  
601
static const char *level_colors[] = {
  
602
	COLOR_ERROR,
  
603
	COLOR_WARNING,
  
604
	COLOR_INFO,
  
605
	COLOR_DEBUG,
  
606
};
  
607
  
  
608
NONSTD_DEF void set_log_level(LogLevel level) {
  
609
	max_level = level;
  
610
}
  
611
  
  
612
NONSTD_DEF LogLevel get_log_level_from_env(void) {
  
613
	const char *env = getenv("LOG_LEVEL");
  
614
	if (env) {
  
615
		int level = atoi(env);
  
616
		if (level >= 0 && level <= 3) {
  
617
			return (LogLevel)level;
  
618
		}
  
619
	}
  
620
  
  
621
	return max_level;
  
622
}
  
623
  
  
624
NONSTD_DEF void log_message(FILE *stream, LogLevel level, const char *format, ...) {
  
625
	if (max_level < level)
  
626
		return;
  
627
  
  
628
	struct timeval tv;
  
629
	gettimeofday(&tv, NULL);
  
630
	struct tm *tm_info = localtime(&tv.tv_sec);
  
631
  
  
632
	char time_str[24];
  
633
	strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info);
  
634
  
  
635
	const char *color = isatty(fileno(stream)) ? level_colors[level] : "";
  
636
	const char *reset = isatty(fileno(stream)) ? COLOR_RESET : "";
  
637
  
  
638
	const char *log_format = "%s[%s.%03d] [%-5s] ";
  
639
	fprintf(stream, log_format, color, time_str, (int)(tv.tv_usec / 1000), level_strings[level]);
  
640
  
  
641
	va_list args;
  
642
	va_start(args, format);
  
643
	vfprintf(stream, format, args);
  
644
	va_end(args);
  
645
  
  
646
	fprintf(stream, "%s\n", reset);
  
647
	fflush(stream);
  
648
}
565
}
649
  
566
  
650
// PPM Image Implementation
567
// PPM Image Implementation
...
diff --git a/libraries/vfs.h b/libraries/vfs.h
...
57
	const char* debug_env = getenv("DEBUG");
57
	const char* debug_env = getenv("DEBUG");
58
	if (debug_env && (strcmp(debug_env, "1") == 0 || strcmp(debug_env, "true") == 0)) {
58
	if (debug_env && (strcmp(debug_env, "1") == 0 || strcmp(debug_env, "true") == 0)) {
59
		g_disk_mode = 1;
59
		g_disk_mode = 1;
60
		log_message(stdout, LOG_INFO, "VFS: Operating in Disk Mode (DEBUG enabled)");
60
		TraceLog(LOG_INFO, "VFS: Operating in Disk Mode (DEBUG enabled)");
61
		return;
61
		return;
62
	}
62
	}
63
  
63
  
64
	FILE* f = fopen(pak_path, "rb");
64
	FILE* f = fopen(pak_path, "rb");
65
	if (!f) {
65
	if (!f) {
66
		log_message(stderr, LOG_ERROR, "VFS: Failed to open pak file: %s (Error: %s)", pak_path, strerror(errno));
66
		TraceLog(LOG_ERROR, "VFS: Failed to open pak file: %s (Error: %s)", pak_path, strerror(errno));
67
		log_message(stderr, LOG_WARN, "VFS: Falling back to Disk Mode");
67
		TraceLog(LOG_WARNING, "VFS: Falling back to Disk Mode");
68
		g_disk_mode = 1;
68
		g_disk_mode = 1;
69
		return;
69
		return;
70
	}
70
	}
71
  
71
  
72
	VfsHeader header;
72
	VfsHeader header;
73
	if (fread(&header, sizeof(VfsHeader), 1, f) != 1) {
73
	if (fread(&header, sizeof(VfsHeader), 1, f) != 1) {
74
		log_message(stderr, LOG_ERROR, "VFS: Failed to read header from %s", pak_path);
74
		TraceLog(LOG_ERROR, "VFS: Failed to read header from %s", pak_path);
75
		fclose(f);
75
		fclose(f);
76
		g_disk_mode = 1;
76
		g_disk_mode = 1;
77
		return;
77
		return;
78
	}
78
	}
79
  
79
  
80
	if (memcmp(header.magic, "DRP1", 4) != 0) {
80
	if (memcmp(header.magic, "DRP1", 4) != 0) {
81
		log_message(stderr, LOG_ERROR, "VFS: Invalid magic in %s", pak_path);
81
		TraceLog(LOG_ERROR, "VFS: Invalid magic in %s", pak_path);
82
		fclose(f);
82
		fclose(f);
83
		g_disk_mode = 1;
83
		g_disk_mode = 1;
84
		return;
84
		return;
...
87
	g_num_entries = header.num_files;
87
	g_num_entries = header.num_files;
88
	g_entries = (VfsEntry*)malloc(sizeof(VfsEntry) * g_num_entries);
88
	g_entries = (VfsEntry*)malloc(sizeof(VfsEntry) * g_num_entries);
89
	if (fread(g_entries, sizeof(VfsEntry), g_num_entries, f) != g_num_entries) {
89
	if (fread(g_entries, sizeof(VfsEntry), g_num_entries, f) != g_num_entries) {
90
		log_message(stderr, LOG_ERROR, "VFS: Failed to read index table from %s", pak_path);
90
		TraceLog(LOG_ERROR, "VFS: Failed to read index table from %s", pak_path);
91
		free(g_entries);
91
		free(g_entries);
92
		g_entries = NULL;
92
		g_entries = NULL;
93
		fclose(f);
93
		fclose(f);
...
97
  
97
  
98
	fclose(f);
98
	fclose(f);
99
	strncpy(g_pak_path, pak_path, sizeof(g_pak_path) - 1);
99
	strncpy(g_pak_path, pak_path, sizeof(g_pak_path) - 1);
100
	log_message(stdout, LOG_INFO, "VFS: Loaded %u files from %s", g_num_entries, pak_path);
100
	TraceLog(LOG_INFO, "VFS: Loaded %u files from %s", g_num_entries, pak_path);
101
}
101
}
102
  
102
  
103
void vfs_shutdown(void) {
103
void vfs_shutdown(void) {
...
137
		}
137
		}
138
	}
138
	}
139
  
139
  
140
	log_message(stderr, LOG_WARN, "VFS: File not found: %s", path);
140
	TraceLog(LOG_WARNING, "VFS: File not found: %s", path);
141
	return NULL;
141
	return NULL;
142
}
142
}
143
  
143
  
...
diff --git a/main.c b/main.c
1
#include "raylib.h"
1
#define _POSIX_C_SOURCE 200809L
  
2
#define NONSTD_IMPLEMENTATION
  
3
#define VFS_IMPLEMENTATION
  
4
#include "all.h"
2
  
5
  
3
int main(void)
6
int main(void) {
4
{
7
    SetConfigFlags(FLAG_VSYNC_HINT);
5
    InitWindow(800, 450, "raylib example - basic window");
8
    InitWindow(1920, 1080, "Stalag");
  
9
    SetTargetFPS(GetMonitorRefreshRate(GetCurrentMonitor()));
6
  
10
  
7
    while (!WindowShouldClose())
11
    vfs_init("data.pak");
8
    {
12
    InitGame();
9
        BeginDrawing();
13
    game.vsync = true;
10
            ClearBackground(RAYWHITE);
14
  
11
            DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
15
    while (!WindowShouldClose()) {
12
        EndDrawing();
16
        UpdateGame();
  
17
        DrawGame();
13
    }
18
    }
14
  
19
  
  
20
    vfs_shutdown();
15
    CloseWindow();
21
    CloseWindow();
16
  
22
  
17
    return 0;
23
    return 0;
18
}
24
}
diff --git a/map.c b/map.c
  
1
#include "all.h"
  
2
#include <ctype.h>
  
3
#include <stdlib.h>
  
4
#include <stdio.h>
  
5
  
  
6
char map_peek(MapParser *p) {
  
7
    if (p->pos >= p->length) return 0;
  
8
    return p->data[p->pos];
  
9
}
  
10
  
  
11
char map_get(MapParser *p) {
  
12
    if (p->pos >= p->length) return 0;
  
13
    return p->data[p->pos++];
  
14
}
  
15
  
  
16
void map_skip_whitespace(MapParser *p) {
  
17
    while (true) {
  
18
        char c = map_peek(p);
  
19
        if (isspace(c)) {
  
20
            map_get(p);
  
21
        } else if (c == '/' && p->data[p->pos + 1] == '/') {
  
22
            while (map_peek(p) != '\n' && map_peek(p) != 0) map_get(p);
  
23
        } else {
  
24
            break;
  
25
        }
  
26
    }
  
27
}
  
28
  
  
29
bool map_expect(MapParser *p, char expected) {
  
30
    map_skip_whitespace(p);
  
31
    if (map_get(p) == expected) return true;
  
32
    return false;
  
33
}
  
34
  
  
35
void map_parse_token(MapParser *p, char *buffer, int size) {
  
36
    map_skip_whitespace(p);
  
37
    int i = 0;
  
38
    bool quoted = false;
  
39
    if (map_peek(p) == '"') {
  
40
        quoted = true;
  
41
        map_get(p);
  
42
    }
  
43
  
  
44
    while (true) {
  
45
        char c = map_peek(p);
  
46
        if (c == 0) break;
  
47
        if (quoted) {
  
48
            if (c == '"') {
  
49
                map_get(p);
  
50
                break;
  
51
            }
  
52
        } else {
  
53
            if (isspace(c) || c == '(' || c == ')' || c == '{' || c == '}') break;
  
54
        }
  
55
        if (i < size - 1) buffer[i++] = map_get(p);
  
56
        else map_get(p);
  
57
    }
  
58
    buffer[i] = 0;
  
59
}
  
60
  
  
61
Vector3 map_parse_vector(MapParser *p) {
  
62
    map_expect(p, '(');
  
63
    char buf[64];
  
64
    map_parse_token(p, buf, sizeof(buf));
  
65
    float x = (float)atof(buf);
  
66
    map_parse_token(p, buf, sizeof(buf));
  
67
    float y = (float)atof(buf);
  
68
    map_parse_token(p, buf, sizeof(buf));
  
69
    float z = (float)atof(buf);
  
70
    map_expect(p, ')');
  
71
    return (Vector3){ x, z, -y };
  
72
}
  
73
  
  
74
Map ParseMap(const char *filename) {
  
75
    size_t size;
  
76
    char *data = read_entire_file(filename, &size);
  
77
    Map map = { 0 };
  
78
    if (!data) return map;
  
79
  
  
80
    MapParser p = { data, size, 0 };
  
81
    array(MapEntity) entities;
  
82
    array_init(entities);
  
83
  
  
84
    while (true) {
  
85
        map_skip_whitespace(&p);
  
86
        if (map_peek(&p) == 0) break;
  
87
  
  
88
        if (map_expect(&p, '{')) {
  
89
            MapEntity entity = { 0 };
  
90
            array(MapProperty) props;
  
91
            array(MapBrush) brushes;
  
92
            array_init(props);
  
93
            array_init(brushes);
  
94
  
  
95
            while (true) {
  
96
                map_skip_whitespace(&p);
  
97
                char c = map_peek(&p);
  
98
                if (c == '}') {
  
99
                    map_get(&p);
  
100
                    break;
  
101
                } else if (c == '"') {
  
102
                    MapProperty prop;
  
103
                    map_parse_token(&p, prop.key, sizeof(prop.key));
  
104
                    map_parse_token(&p, prop.value, sizeof(prop.value));
  
105
                    array_push(props, prop);
  
106
                } else if (c == '{') {
  
107
                    map_get(&p);
  
108
                    MapBrush brush = { 0 };
  
109
                    array(MapPlane) planes;
  
110
                    array_init(planes);
  
111
                    while (true) {
  
112
                        map_skip_whitespace(&p);
  
113
                        if (map_peek(&p) == '}') {
  
114
                            map_get(&p);
  
115
                            break;
  
116
                        }
  
117
                        MapPlane plane;
  
118
                        plane.p[0] = map_parse_vector(&p);
  
119
                        plane.p[1] = map_parse_vector(&p);
  
120
                        plane.p[2] = map_parse_vector(&p);
  
121
                        map_parse_token(&p, plane.texture, sizeof(plane.texture));
  
122
                        
  
123
                        char buf[64];
  
124
                        map_parse_token(&p, buf, sizeof(buf)); plane.shift[0] = (float)atof(buf);
  
125
                        map_parse_token(&p, buf, sizeof(buf)); plane.shift[1] = (float)atof(buf);
  
126
                        map_parse_token(&p, buf, sizeof(buf)); plane.rotate = (float)atof(buf);
  
127
                        map_parse_token(&p, buf, sizeof(buf)); plane.scale[0] = (float)atof(buf);
  
128
                        map_parse_token(&p, buf, sizeof(buf)); plane.scale[1] = (float)atof(buf);
  
129
                        
  
130
                        array_push(planes, plane);
  
131
                    }
  
132
                    brush.planes = planes.data;
  
133
                    brush.plane_count = (int)planes.length;
  
134
                    array_push(brushes, brush);
  
135
                } else {
  
136
                    map_get(&p);
  
137
                }
  
138
            }
  
139
            entity.properties = props.data;
  
140
            entity.property_count = (int)props.length;
  
141
            entity.brushes = brushes.data;
  
142
            entity.brush_count = (int)brushes.length;
  
143
            array_push(entities, entity);
  
144
        }
  
145
    }
  
146
  
  
147
    map.entities = entities.data;
  
148
    map.entity_count = (int)entities.length;
  
149
    free(data);
  
150
    return map;
  
151
}
  
152
  
  
153
void FreeMap(Map map) {
  
154
    for (int i = 0; i < map.entity_count; i++) {
  
155
        MapEntity *e = &map.entities[i];
  
156
        if (e->properties) free(e->properties);
  
157
        for (int j = 0; j < e->brush_count; j++) {
  
158
            if (e->brushes[j].planes) free(e->brushes[j].planes);
  
159
        }
  
160
        if (e->brushes) free(e->brushes);
  
161
    }
  
162
    if (map.entities) free(map.entities);
  
163
}
  
164
  
  
165
Plane PlaneFromPoints(Vector3 p1, Vector3 p2, Vector3 p3) {
  
166
    Vector3 v1 = Vector3Subtract(p2, p1);
  
167
    Vector3 v2 = Vector3Subtract(p3, p1);
  
168
    Vector3 normal = Vector3Normalize(Vector3CrossProduct(v1, v2));
  
169
    return (Plane){ normal, Vector3DotProduct(normal, p1) };
  
170
}
  
171
  
  
172
void PolyFree(Polygon p) {
  
173
    if (p.verts) free(p.verts);
  
174
}
  
175
  
  
176
Polygon PolyClip(Polygon poly, Plane plane) {
  
177
    if (poly.count == 0) return poly;
  
178
    
  
179
    array(Vector3) out_verts;
  
180
    array_init(out_verts);
  
181
  
  
182
    for (int i = 0; i < poly.count; i++) {
  
183
        Vector3 p1 = poly.verts[i];
  
184
        Vector3 p2 = poly.verts[(i + 1) % poly.count];
  
185
  
  
186
        float d1 = Vector3DotProduct(plane.normal, p1) - plane.dist;
  
187
        float d2 = Vector3DotProduct(plane.normal, p2) - plane.dist;
  
188
  
  
189
        // Using a smaller epsilon and more robust logic
  
190
        const float eps = 0.001f;
  
191
  
  
192
        if (d1 >= -eps) {
  
193
            if (d2 >= -eps) {
  
194
                array_push(out_verts, p2);
  
195
            } else {
  
196
                float t = d1 / (d1 - d2);
  
197
                Vector3 intersect = Vector3Add(p1, Vector3Scale(Vector3Subtract(p2, p1), t));
  
198
                array_push(out_verts, intersect);
  
199
            }
  
200
        } else {
  
201
            if (d2 >= -eps) {
  
202
                float t = d1 / (d1 - d2);
  
203
                Vector3 intersect = Vector3Add(p1, Vector3Scale(Vector3Subtract(p2, p1), t));
  
204
                array_push(out_verts, intersect);
  
205
                array_push(out_verts, p2);
  
206
            }
  
207
        }
  
208
    }
  
209
  
  
210
    Polygon res;
  
211
    res.verts = out_verts.data;
  
212
    res.count = (int)out_verts.length;
  
213
    return res;
  
214
}
  
215
  
  
216
Polygon CreateLargeQuad(Plane plane) {
  
217
    Vector3 n = plane.normal;
  
218
    Vector3 up = (fabsf(n.y) < 0.999f) ? (Vector3){ 0, 1, 0 } : (Vector3){ 1, 0, 0 };
  
219
    Vector3 right = Vector3Normalize(Vector3CrossProduct(up, n));
  
220
    up = Vector3CrossProduct(n, right);
  
221
  
  
222
    Vector3 center = Vector3Scale(n, plane.dist);
  
223
    float size = 10000.0f;
  
224
    
  
225
    Polygon poly;
  
226
    poly.verts = ALLOC(Vector3, 4);
  
227
    poly.count = 4;
  
228
    poly.verts[0] = Vector3Add(center, Vector3Add(Vector3Scale(right, size), Vector3Scale(up, size)));
  
229
    poly.verts[1] = Vector3Add(center, Vector3Add(Vector3Scale(right, -size), Vector3Scale(up, size)));
  
230
    poly.verts[2] = Vector3Add(center, Vector3Add(Vector3Scale(right, -size), Vector3Scale(up, -size)));
  
231
    poly.verts[3] = Vector3Add(center, Vector3Add(Vector3Scale(right, size), Vector3Scale(up, -size)));
  
232
    
  
233
    return poly;
  
234
}
  
235
  
  
236
Vector2 GetUV(Vector3 p, MapPlane *mp, Plane plane) {
  
237
    Vector3 n = plane.normal;
  
238
    Vector3 up = (fabsf(n.y) < 0.999f) ? (Vector3){ 0, 1, 0 } : (Vector3){ 1, 0, 0 };
  
239
    Vector3 right = Vector3Normalize(Vector3CrossProduct(up, n));
  
240
    up = Vector3CrossProduct(n, right);
  
241
    
  
242
    float u = Vector3DotProduct(p, right) * (1.0f / (mp->scale[0] ? mp->scale[0] : 1.0f)) + mp->shift[0];
  
243
    float v = Vector3DotProduct(p, up) * (1.0f / (mp->scale[1] ? mp->scale[1] : 1.0f)) + mp->shift[1];
  
244
    
  
245
    return (Vector2){ u / 64.0f, v / 64.0f };
  
246
}
diff --git a/maps/demo1.map b/maps/demo1.map
...
30
( -16 336 16 ) ( -15 336 16 ) ( -16 336 17 ) environment/planks_012 0 0 0 1 1
30
( -16 336 16 ) ( -15 336 16 ) ( -16 336 17 ) environment/planks_012 0 0 0 1 1
31
( -16 112 16 ) ( -16 112 17 ) ( -16 113 16 ) environment/planks_012 16 0 0 1 1
31
( -16 112 16 ) ( -16 112 17 ) ( -16 113 16 ) environment/planks_012 16 0 0 1 1
32
}
32
}
  
33
// brush 3
  
34
{
  
35
( -16 272 0 ) ( -16 273 0 ) ( -16 272 1 ) environment/planks_012 0 0 0 1 1
  
36
( -16 272 0 ) ( -16 272 1 ) ( -15 272 0 ) environment/planks_012 0 0 0 1 1
  
37
( -16 272 0 ) ( -15 272 0 ) ( -16 273 0 ) environment/planks_012 0 0 0 1 1
  
38
( 80 336 64 ) ( 80 337 64 ) ( 81 336 64 ) environment/planks_012 0 0 0 1 1
  
39
( 80 336 16 ) ( 81 336 16 ) ( 80 336 17 ) environment/planks_012 0 0 0 1 1
  
40
( 80 336 16 ) ( 80 336 17 ) ( 80 337 16 ) environment/planks_012 0 0 0 1 1
  
41
}
  
42
}
  
43
// entity 1
  
44
{
  
45
"classname" "info_player_start"
  
46
"origin" "-112 -16 40"
33
}
47
}
diff --git a/textures/brushes/bricks_076c.jpg b/textures/brushes/bricks_076c.jpg
diff --git a/textures/brushes/bricks_076c.png b/textures/brushes/bricks_076c.png
diff --git a/textures/brushes/ground_068.jpg b/textures/brushes/ground_068.jpg
diff --git a/textures/brushes/ground_068.png b/textures/brushes/ground_068.png
diff --git a/textures/brushes/rock_016.jpg b/textures/brushes/rock_016.jpg
diff --git a/textures/brushes/rock_016.png b/textures/brushes/rock_016.png
diff --git a/textures/brushes/rock_030.jpg b/textures/brushes/rock_030.jpg
diff --git a/textures/brushes/rock_030.png b/textures/brushes/rock_030.png
diff --git a/textures/environment/paintedwood_008a.jpg b/textures/environment/paintedwood_008a.jpg
diff --git a/textures/environment/paintedwood_008a.png b/textures/environment/paintedwood_008a.png
diff --git a/textures/environment/planks_012.jpg b/textures/environment/planks_012.jpg
diff --git a/textures/environment/planks_012.png b/textures/environment/planks_012.png
diff --git a/textures/environment/roofingtiles_012b.jpg b/textures/environment/roofingtiles_012b.jpg
diff --git a/textures/environment/roofingtiles_012b.png b/textures/environment/roofingtiles_012b.png