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
|
// Decal construction and drawing
// Copyright (C) 2002 David Rosen
// Copyright (C) 2003 Steven Fuller
// Copyright (C) 2023 Nguyễn Gia Phong
//
// This file is part of Black Shades.
//
// Black Shades is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Black Shades is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Black Shades. If not, see <https://www.gnu.org/licenses/>.
//const f32Eps = std.math.floatEps(f32);
const XYZ = @import("geom.zig").XYZ;
const c = @import("cimport.zig");
const size = 120;
const Kind = enum(c_int) { bullet_hole, crater, blood_pool };
const Decals = extern struct {
// GLuint is always 32-bit.
hole_textures: [2]u32,
blood_textures: [11]u32,
len: u32,
kind: [size]Kind,
points: [size * 8]XYZ,
numpoints: [size]u32,
texcoordsx: [size * 8]f32,
texcoordsy: [size * 8]f32,
alive: [size]f32,
};
export fn drawDecals(d: *const Decals) void {
c.glAlphaFunc(c.GL_GREATER, 0.01);
c.glDepthFunc(c.GL_LEQUAL);
c.glEnable(c.GL_BLEND);
c.glEnable(c.GL_CULL_FACE);
c.glEnable(c.GL_TEXTURE_2D);
c.glEnable(c.GL_LIGHTING);
c.glDepthMask(0);
c.glAlphaFunc(c.GL_GREATER, 0.01);
c.glTexParameterf(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_S, c.GL_CLAMP);
c.glTexParameterf(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_T, c.GL_CLAMP);
c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
c.glEnable(c.GL_POLYGON_OFFSET_FILL);
for (0..d.len) |i| {
switch (d.kind[i]) {
.bullet_hole, .crater => |k| {
c.glColor4f(1.0, 1.0, 1.0, 1.0 - d.alive[i] / 10.0);
c.glBindTexture(c.GL_TEXTURE_2D, d.hole_textures[switch (k) {
.bullet_hole => 0,
.crater => 1,
// https://github.com/ziglang/zig/issues/12863
else => unreachable, // TODO: remove
}]);
},
.blood_pool => {
const alpha = if (d.alive[i] < 2.0)
@mod(d.alive[i], 0.2) + 0.8
else
(20.0 - d.alive[i]) / 18.0;
c.glColor4f(1.0, 1.0, 1.0, alpha);
const j: usize = @intFromFloat(d.alive[i] * 5.0);
c.glBindTexture(c.GL_TEXTURE_2D, d.blood_textures[@min(j, 10)]);
},
}
c.glPushMatrix();
c.glBegin(c.GL_TRIANGLE_FAN);
for (0..d.numpoints[i]) |j| {
c.glTexCoord2f(d.texcoordsx[i * 8 + j], d.texcoordsy[i * 8 + j]);
c.glVertex3f(d.points[i * 8 + j].x,
d.points[i * 8 + j].y, d.points[i * 8 + j].z);
}
c.glEnd();
c.glPopMatrix();
}
c.glDepthMask(1);
c.glDisable(c.GL_TEXTURE_2D);
c.glEnable(c.GL_CULL_FACE);
c.glDisable(c.GL_POLYGON_OFFSET_FILL);
c.glDepthFunc(c.GL_LEQUAL);
}
export fn updateDecals(d: *Decals) void {
for (0..d.len) |i| {
d.alive[i] += c.multiplier;
if (d.alive[i] < @as(f32, switch (d.kind[i]) {
.bullet_hole, .crater => 10.0,
.blood_pool => 20.0,
})) continue;
d.len -= 1;
const last = d.len;
d.numpoints[i] = d.numpoints[last];
d.alive[i] = d.alive[last];
d.kind[i] = d.kind[last];
for (0..d.numpoints[i]) |j| {
d.points[i * 8 + j] = d.points[last * 8 + j];
d.texcoordsx[i * 8 + j] = d.texcoordsx[last * 8 + j];
d.texcoordsy[i * 8 + j] = d.texcoordsy[last * 8 + j];
}
}
}
export fn destroyDecals(d: *const Decals) void {
c.glDeleteTextures(2, &d.hole_textures);
c.glDeleteTextures(11, &d.blood_textures);
}
|