diff options
Diffstat (limited to 'src/decal.zig')
-rw-r--r-- | src/decal.zig | 118 |
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); +} |