summary refs log tree commit diff
path: root/src/decal.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/decal.zig')
-rw-r--r--src/decal.zig118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/decal.zig b/src/decal.zig
new file mode 100644
index 0000000..de4d9e8
--- /dev/null
+++ b/src/decal.zig
@@ -0,0 +1,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);
+}