-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathquakemap.zig
More file actions
349 lines (295 loc) · 13.4 KB
/
quakemap.zig
File metadata and controls
349 lines (295 loc) · 13.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
const std = @import("std");
const delve = @import("delve");
const app = delve.app;
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const ArrayListManaged = std.array_list.Managed;
const graphics = delve.platform.graphics;
const math = delve.math;
var camera: delve.graphics.camera.Camera = undefined;
var shader: delve.platform.graphics.Shader = undefined;
var fallback_material: graphics.Material = undefined;
var fallback_quake_material: delve.utils.quakemap.QuakeMaterial = undefined;
var materials: std.StringHashMap(delve.utils.quakemap.QuakeMaterial) = undefined;
var quake_map: delve.utils.quakemap.QuakeMap = undefined;
var map_meshes: std.ArrayList(delve.graphics.mesh.Mesh) = undefined;
var entity_meshes: std.ArrayList(delve.graphics.mesh.Mesh) = undefined;
var cube_mesh: delve.graphics.mesh.Mesh = undefined;
var map_transform: math.Mat4 = undefined;
var bounding_box_size: math.Vec3 = math.Vec3.new(2, 3, 2);
var player_pos: math.Vec3 = math.Vec3.zero;
var player_vel: math.Vec3 = math.Vec3.zero;
var on_ground = true;
var gravity: f32 = -0.5;
pub fn main() !void {
const example = delve.modules.Module{
.name = "quakemap_example",
.init_fn = on_init,
.tick_fn = on_tick,
.draw_fn = on_draw,
.cleanup_fn = on_cleanup,
};
// Pick the allocator to use depending on platform
const builtin = @import("builtin");
if (builtin.os.tag == .wasi or builtin.os.tag == .emscripten) {
// Web builds hack: use the C allocator to avoid OOM errors
// See https://github.com/ziglang/zig/issues/19072
try delve.init(std.heap.c_allocator);
} else {
// Using the default allocator will let us detect memory leaks
try delve.init(delve.mem.createDefaultAllocator());
}
try delve.modules.registerModule(example);
try delve.module.fps_counter.registerModule();
// test out registering a console command and a console variable
try delve.debug.registerConsoleCommand("setGravity", setGravityCmd, "Changes gravity");
try delve.debug.registerConsoleVariable("gravity", &gravity, "Amount of gravity");
try app.start(app.AppConfig{ .title = "Delve Framework - Quake Map Example" });
}
pub fn on_init() !void {
const fallback_tex = graphics.createDebugTexture();
const test_map_file =
\\// Game: Generic
\\// Format: Standard
\\// entity 0
\\{
\\"classname" "worldspawn"
\\// brush 0
\\{
\\( -64 -64 -16 ) ( -64 -63 -16 ) ( -64 -64 -15 ) tech_14 0 0 0 1 1
\\( -64 -64 -16 ) ( -64 -64 -15 ) ( -63 -64 -16 ) tech_14 0 0 0 1 1
\\( -64 -64 -16 ) ( -63 -64 -16 ) ( -64 -63 -16 ) tech_14 0 0 0 1 1
\\( 64 64 16 ) ( 64 65 16 ) ( 65 64 16 ) tech_11 0 0 0 1 1
\\( 64 64 16 ) ( 65 64 16 ) ( 64 64 17 ) tech_14 0 0 0 1 1
\\( 64 64 16 ) ( 64 64 17 ) ( 64 65 16 ) tech_14 0 0 0 1 1
\\}
\\// brush 1
\\{
\\( -64 32 16 ) ( -64 33 16 ) ( -64 32 17 ) tech_9 0 0 0 1 1
\\( -64 32 16 ) ( -64 32 17 ) ( -63 32 16 ) tech_2 0 0 0 1 1
\\( -64 32 16 ) ( -63 32 16 ) ( -64 33 16 ) tech_2 0 0 0 1 1
\\( 64 64 96 ) ( 64 65 96 ) ( 65 64 96 ) tech_2 16 0 0 1 1
\\( 64 64 32 ) ( 65 64 32 ) ( 64 64 33 ) tech_2 0 0 0 1 1
\\( 64 64 32 ) ( 64 64 33 ) ( 64 65 32 ) tech_2 0 0 0 1 1
\\}
\\// brush 2
\\{
\\( -176 32 80 ) ( -176 33 80 ) ( -176 32 81 ) tech_2 0 0 0 1 1
\\( -176 32 80 ) ( -176 32 81 ) ( -175 32 80 ) tech_2 0 0 0 1 1
\\( -176 32 80 ) ( -175 32 80 ) ( -176 33 80 ) tech_2 0 0 0 1 1
\\( -64 64 96 ) ( -64 65 96 ) ( -63 64 96 ) tech_2 0 0 0 1 1
\\( -64 64 96 ) ( -63 64 96 ) ( -64 64 97 ) tech_2 0 0 0 1 1
\\( -64 64 96 ) ( -64 64 97 ) ( -64 65 96 ) tech_2 0 0 0 1 1
\\}
\\// brush 3
\\{
\\( -176 32 96 ) ( -176 33 96 ) ( -176 32 97 ) tech_2 0 0 0 1 1
\\( -176 32 96 ) ( -176 32 97 ) ( -175 32 96 ) tech_2 0 0 0 1 1
\\( -176 32 96 ) ( -175 32 96 ) ( -176 33 96 ) tech_2 0 0 0 1 1
\\( -144 64 192 ) ( -144 65 192 ) ( -143 64 192 ) tech_2 0 0 0 1 1
\\( -144 64 112 ) ( -143 64 112 ) ( -144 64 113 ) tech_2 0 0 0 1 1
\\( -144 64 112 ) ( -144 64 113 ) ( -144 65 112 ) tech_2 0 0 90 1 1
\\}
\\// brush 4
\\{
\\( -144 32 176 ) ( -144 33 176 ) ( -144 32 177 ) __TB_empty 0 0 0 1 1
\\( -144 32 176 ) ( -144 32 177 ) ( -143 32 176 ) tech_3 0 0 0 1 1
\\( -144 32 176 ) ( -143 32 176 ) ( -144 33 176 ) tech_12 0 0 0 1 1
\\( -112 48 192 ) ( -112 49 192 ) ( -111 48 192 ) tech_3 0 0 0 1 1
\\( -112 48 192 ) ( -111 48 192 ) ( -112 48 193 ) tech_3 0 0 0 1 1
\\( 0 48 192 ) ( 0 48 193 ) ( 0 49 192 ) tech_3 0 0 0 1 1
\\}
\\// brush 5
\\{
\\( 0 32 128 ) ( 0 48 128 ) ( -32 48 176 ) tech_9 0 0 0 1 1
\\( 0 32 176 ) ( 16 32 128 ) ( 0 32 128 ) tech_13 0 0 0 1 1
\\( 16 32 128 ) ( 16 48 128 ) ( 0 48 128 ) tech_9 0 0 0 1 1
\\( -32 48 176 ) ( 0 48 176 ) ( 0 32 176 ) __TB_empty 0 0 0 1 1
\\( 0 48 128 ) ( 16 48 128 ) ( 0 48 176 ) tech_9 0 0 0 1 1
\\( 0 48 176 ) ( 16 48 128 ) ( 16 32 128 ) tech_9 0 0 0 1 1
\\}
\\// brush 6
\\{
\\( -144 64 112 ) ( -144 32 112 ) ( -144 32 96 ) tech_2 0 0 0 1 1
\\( -128 32 112 ) ( -112 32 96 ) ( -144 32 96 ) tech_14 0 0 0 1 1
\\( -112 32 96 ) ( -112 64 96 ) ( -144 64 96 ) tech_2 0 0 0 1 1
\\( -144 64 112 ) ( -128 64 112 ) ( -128 32 112 ) tech_10 0 0 0 1 1
\\( -144 64 96 ) ( -112 64 96 ) ( -128 64 112 ) tech_14 0 0 0 1 1
\\( -128 64 112 ) ( -112 64 96 ) ( -112 32 96 ) tech_12 0 0 90 1 1
\\}
\\// brush 7
\\{
\\( -64 32 80 ) ( -64 0 80 ) ( -64 -48 16 ) tech_2 0 0 0 1 1
\\( -64 0 80 ) ( -32 0 80 ) ( -32 -48 16 ) tech_6 0 0 90 1 1
\\( -32 -48 16 ) ( -32 32 16 ) ( -64 32 16 ) __TB_empty 0 0 0 1 1
\\( -64 32 80 ) ( -32 32 80 ) ( -32 0 80 ) tech_7 0 0 0 1 1
\\( -32 32 16 ) ( -32 32 80 ) ( -64 32 80 ) __TB_empty 0 0 0 1 1
\\( -32 0 80 ) ( -32 32 80 ) ( -32 32 16 ) tech_2 0 0 0 1 1
\\}
\\}
;
const translate = delve.math.Mat4.translate(delve.math.Vec3.x_axis.scale(10.0));
map_transform = delve.math.Mat4.scale(delve.math.Vec3.new(0.1, 0.1, 0.1)).mul(translate).mul(delve.math.Mat4.rotate(-90, delve.math.Vec3.x_axis));
// const allocator = gpa.allocator();
const allocator = std.heap.c_allocator;
var err: delve.utils.quakemap.ErrorInfo = undefined;
quake_map = try delve.utils.quakemap.QuakeMap.read(allocator, test_map_file, map_transform, &err);
shader = try graphics.Shader.initFromBuiltin(.{ .vertex_attributes = delve.graphics.mesh.getShaderAttributes() }, delve.shaders.default_mesh);
// Create a material out of the texture
fallback_material = try graphics.Material.init(.{
.shader = shader,
.texture_0 = fallback_tex,
.samplers = &[_]graphics.FilterMode{.NEAREST},
});
fallback_quake_material = .{ .material = fallback_material };
// create our camera
camera = delve.graphics.camera.Camera.initThirdPerson(90.0, 0.01, 512, 16.0, math.Vec3.up);
camera.position.y = 10.0;
// set our player position too
player_pos = camera.position;
materials = std.StringHashMap(delve.utils.quakemap.QuakeMaterial).init(allocator);
for (quake_map.worldspawn.solids.items) |solid| {
for (solid.faces.items) |face| {
var mat_name = ArrayListManaged(u8).init(allocator);
var tex_path = ArrayListManaged(u8).init(allocator);
try mat_name.writer().print("{s}", .{face.texture_name});
try mat_name.append(0);
try tex_path.writer().print("assets/textures/{s}.png", .{face.texture_name});
try tex_path.append(0);
const mat_name_owned = try mat_name.toOwnedSlice();
const mat_name_null = mat_name_owned[0 .. mat_name_owned.len - 1 :0];
const found = materials.get(mat_name_null);
if (found == null) {
const texpath = try tex_path.toOwnedSlice();
const tex_path_null = texpath[0 .. texpath.len - 1 :0];
var tex_img: delve.images.Image = delve.images.loadFile(tex_path_null) catch {
delve.debug.log("Could not load image: {s}", .{tex_path_null});
try materials.put(mat_name_null, .{ .material = fallback_material });
continue;
};
defer tex_img.deinit();
const tex = graphics.Texture.init(tex_img);
const mat = try graphics.Material.init(.{
.shader = shader,
.samplers = &[_]graphics.FilterMode{.NEAREST},
.texture_0 = tex,
});
try materials.put(mat_name_null, .{ .material = mat, .tex_size_x = @intCast(tex.width), .tex_size_y = @intCast(tex.height) });
// delve.debug.log("Loaded image: {s}", .{tex_path_null});
}
}
}
// make meshes out of the quake map, one per material
const delve_allocator = delve.mem.getAllocator();
map_meshes = try quake_map.buildWorldMeshes(delve_allocator, math.Mat4.identity, &materials, &fallback_quake_material);
entity_meshes = try quake_map.buildEntityMeshes(delve_allocator, math.Mat4.identity, &materials, &fallback_quake_material);
// make a bounding box cube
cube_mesh = try delve.graphics.mesh.createCube(math.Vec3.new(0, 0, 0), bounding_box_size, delve.colors.red, fallback_material);
// set a bg color
delve.platform.graphics.setClearColor(delve.colors.examples_bg_light);
delve.platform.app.captureMouse(true);
}
pub fn on_tick(delta: f32) void {
if (delve.platform.input.isKeyJustPressed(.ESCAPE))
delve.platform.app.exit();
do_player_move(delta);
// update camera position to new player pos
camera.position = player_pos;
camera.runSimpleCamera(0, 60 * delta, true);
}
pub fn on_draw() void {
const view_mats = camera.update();
const model = math.Mat4.identity;
for (0..map_meshes.items.len) |idx| {
map_meshes.items[idx].draw(view_mats, model);
}
for (0..entity_meshes.items.len) |idx| {
entity_meshes.items[idx].draw(view_mats, model);
}
cube_mesh.draw(view_mats, math.Mat4.translate(camera.position));
}
pub fn do_player_move(delta: f32) void {
// gravity!
player_vel.y += gravity * delta;
// get our forward input direction
var move_dir: math.Vec3 = math.Vec3.zero;
if (delve.platform.input.isKeyPressed(.W)) {
var dir = camera.direction;
dir.y = 0.0;
dir = dir.norm();
move_dir = move_dir.add(dir);
}
if (delve.platform.input.isKeyPressed(.S)) {
var dir = camera.direction;
dir.y = 0.0;
dir = dir.norm();
move_dir = move_dir.sub(dir);
}
// get our sideways input direction
if (delve.platform.input.isKeyPressed(.D)) {
const right_dir = camera.getRightDirection();
move_dir = move_dir.add(right_dir);
}
if (delve.platform.input.isKeyPressed(.A)) {
const right_dir = camera.getRightDirection();
move_dir = move_dir.sub(right_dir);
}
// jumnp and fly
if (delve.platform.input.isKeyJustPressed(.SPACE) and on_ground) player_vel.y = 0.3;
if (delve.platform.input.isKeyPressed(.F)) player_vel.y = 0.1;
move_dir = move_dir.norm();
player_vel = player_vel.add(move_dir.scale(10.0).scale(delta));
// horizontal collisions
const check_bounds_x = delve.spatial.BoundingBox.init(player_pos.add(math.Vec3.new(player_vel.x, 0, 0)), bounding_box_size);
var did_collide_x = false;
for (quake_map.worldspawn.solids.items) |solid| {
did_collide_x = solid.checkBoundingBoxCollision(check_bounds_x);
if (did_collide_x)
break;
}
if (did_collide_x)
player_vel.x = 0.0;
const check_bounds_z = delve.spatial.BoundingBox.init(player_pos.add(math.Vec3.new(player_vel.x, 0, player_vel.z)), bounding_box_size);
var did_collide_z = false;
for (quake_map.worldspawn.solids.items) |solid| {
did_collide_z = solid.checkBoundingBoxCollision(check_bounds_z);
if (did_collide_z)
break;
}
if (did_collide_z)
player_vel.z = 0.0;
// vertical collision
const check_bounds_y = delve.spatial.BoundingBox.init(player_pos.add(math.Vec3.new(player_vel.x, player_vel.y, player_vel.z)), bounding_box_size);
var did_collide_y = false;
for (quake_map.worldspawn.solids.items) |solid| {
did_collide_y = solid.checkBoundingBoxCollision(check_bounds_y);
if (did_collide_y)
break;
}
if (did_collide_y) {
on_ground = player_vel.y < 0.0;
player_vel.y = 0.0;
} else {
on_ground = false;
}
// velocity has been clipped to collisions, can move now
player_pos = player_pos.add(player_vel);
// dumb friction!
player_vel.x = 0.0;
player_vel.z = 0.0;
}
pub fn setGravityCmd(new_gravity: f32) void {
gravity = new_gravity;
delve.debug.log("Changed gravity to {d}", .{gravity});
}
pub fn on_cleanup() !void {
const allocator = delve.mem.getAllocator();
map_meshes.deinit(allocator);
entity_meshes.deinit(allocator);
var it = materials.valueIterator();
while (it.next()) |mat_ptr| {
mat_ptr.material.deinit();
}
materials.deinit();
shader.destroy();
quake_map.deinit();
}