summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.build.yml1
-rw-r--r--.gitmodules3
-rw-r--r--build.zig34
m---------lib/lodepng0
-rw-r--r--src/Decals.cpp1
-rw-r--r--src/GameInitDispose.cpp61
-rw-r--r--src/Sprites.cpp1
-rw-r--r--src/Text.cpp1
-rw-r--r--src/Textures.cpp73
-rw-r--r--src/Textures.h26
-rw-r--r--src/main.zig7
-rw-r--r--src/misc.h8
-rw-r--r--src/misc.zig73
13 files changed, 149 insertions, 140 deletions
diff --git a/.build.yml b/.build.yml
index e9ba3b6..85cabb6 100644
--- a/.build.yml
+++ b/.build.yml
@@ -4,7 +4,6 @@ packages:
   - glu
   - libvorbis
   - openal
-  - stb
   - zig
 sources:
   - https://git.sr.ht/~cnx/blackshades
diff --git a/.gitmodules b/.gitmodules
index 9e32438..ef47a81 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,3 +10,6 @@
 [submodule "lib/gfz"]
 	path = lib/gfz
 	url = https://git.sr.ht/~cnx/gfz
+[submodule "lodepng"]
+	path = lib/lodepng
+	url = https://git.sr.ht/~cnx/lodepng
diff --git a/build.zig b/build.zig
index 7294e1a..d43a430 100644
--- a/build.zig
+++ b/build.zig
@@ -1,6 +1,32 @@
+// Build recipe
+// Copyright (C) 2021  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 std = @import("std");
+const InstallDirectoryOptions = std.build.InstallDirectoryOptions;
+const Builder = std.build.Builder;
+
+const data = InstallDirectoryOptions{
+    .source_dir = "Data",
+    .install_dir = .{ .Custom = "share" }, // break in future Zig
+    .install_subdir = "blackshades",
+};
 
-pub fn build(b: *std.build.Builder) void {
+pub fn build(b: *Builder) void {
     const exe = b.addExecutable("blackshades", "src/main.zig");
     exe.addIncludeDir("src");
 
@@ -22,8 +48,9 @@ pub fn build(b: *std.build.Builder) void {
     exe.addCSourceFile("src/Sprites.cpp", &cxxflags);
     exe.addCSourceFile("src/Support.cpp", &cxxflags);
     exe.addCSourceFile("src/Text.cpp", &cxxflags);
-    exe.addCSourceFile("src/Textures.cpp", &cxxflags);
 
+    exe.addCSourceFile("lib/lodepng/lodepng.c", &.{ "-ansi", "-pedantic" });
+    exe.addIncludeDir("lib/lodepng");
     exe.addPackage(.{ .name = "gfz", .path = "lib/gfz/src/gfz.zig" });
     exe.linkSystemLibrary("glfw");
     exe.addPackage(.{ .name = "ini", .path = "lib/ini/src/ini.zig" });
@@ -46,6 +73,9 @@ pub fn build(b: *std.build.Builder) void {
     // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
     exe.setBuildMode(b.standardReleaseOptions());
 
+    const data_dir = b.getInstallPath(data.install_dir, data.install_subdir);
+    exe.addBuildOption([]const u8, "data_dir", data_dir);
+    b.installDirectory(data);
     exe.install();
 
     const run_cmd = exe.run();
diff --git a/lib/lodepng b/lib/lodepng
new file mode 160000
+Subproject b9be5ef13d426142cb6075977ef8eef999fd578
diff --git a/src/Decals.cpp b/src/Decals.cpp
index ad98343..60014b3 100644
--- a/src/Decals.cpp
+++ b/src/Decals.cpp
@@ -1,5 +1,4 @@
 #include "Decals.h"
-#include "Textures.h"
 
 extern float multiplier;
 extern bool slomo;
diff --git a/src/GameInitDispose.cpp b/src/GameInitDispose.cpp
index 027d74b..3930a05 100644
--- a/src/GameInitDispose.cpp
+++ b/src/GameInitDispose.cpp
@@ -23,7 +23,7 @@
 #include <AL/alc.h>
 
 #include "config.h"
-#include "Textures.h"
+#include "misc.h"
 #include "Game.h"
 
 extern unsigned int gSourceID[100];
@@ -1602,35 +1602,6 @@ void initGame(Game* game)
 	glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
 	glEnable(GL_LIGHT0);
 
-	// Load some textures
-	if (!game->initialized) {
-		game->personspritetextureptr = loadTexture((char*) ":Data:Textures:Personsprite.png");
-		game->deadpersonspritetextureptr = loadTexture((char*) ":Data:Textures:DeadPersonsprite.png");
-		game->scopetextureptr = loadTexture((char*) ":Data:Textures:Scope.png");
-		game->flaretextureptr = loadTexture((char*) ":Data:Textures:Flare.png");
-
-		sprites.flaretextureptr = loadTexture((char*) ":Data:Textures:HitFlash.png");
-		sprites.muzzleflaretextureptr = loadTexture((char*) ":Data:Textures:MuzzleFlash.png");
-		sprites.smoketextureptr = loadTexture((char*) ":Data:Textures:Smoke.png");
-		sprites.bloodtextureptr = loadTexture((char*) ":Data:Textures:Blood.png");
-		sprites.raintextureptr = loadTexture((char*) ":Data:Textures:rain.png");
-		sprites.snowtextureptr = loadTexture((char*) ":Data:Textures:snow.png");
-
-		decals.bulletholetextureptr = loadTexture((char*) ":Data:Textures:BulletHole.png");
-		decals.cratertextureptr = loadTexture((char*) ":Data:Textures:Crater.png");
-		decals.bloodtextureptr[0] = loadTexture((char*) ":Data:Textures:Blood:Blood1.png");
-		decals.bloodtextureptr[1] = loadTexture((char*) ":Data:Textures:Blood:Blood2.png");
-		decals.bloodtextureptr[2] = loadTexture((char*) ":Data:Textures:Blood:Blood3.png");
-		decals.bloodtextureptr[3] = loadTexture((char*) ":Data:Textures:Blood:Blood4.png");
-		decals.bloodtextureptr[4] = loadTexture((char*) ":Data:Textures:Blood:Blood5.png");
-		decals.bloodtextureptr[5] = loadTexture((char*) ":Data:Textures:Blood:Blood6.png");
-		decals.bloodtextureptr[6] = loadTexture((char*) ":Data:Textures:Blood:Blood7.png");
-		decals.bloodtextureptr[7] = loadTexture((char*) ":Data:Textures:Blood:Blood8.png");
-		decals.bloodtextureptr[8] = loadTexture((char*) ":Data:Textures:Blood:Blood9.png");
-		decals.bloodtextureptr[9] = loadTexture((char*) ":Data:Textures:Blood:Blood10.png");
-		decals.bloodtextureptr[10] = loadTexture((char*) ":Data:Textures:Blood:Blood11.png");
-	}
-
 	// Setup clip plane equation
 	game->eqn[0] = 0;
 	game->eqn[1] = 1;
@@ -1654,12 +1625,38 @@ void initGame(Game* game)
 
 void initGl(Game* game)
 {
-	game->text.FontTexture = loadTexture((char*) ":Data:Textures:Font.png");
-	game->text.BuildFont();
 	glAlphaFunc(GL_GREATER, 0.01);
 	glDepthFunc(GL_LESS);
 	glPolygonOffset(-8,0);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+	game->text.FontTexture = loadTexture("Font.png");
+	game->text.BuildFont();
+	game->personspritetextureptr = loadTexture("Personsprite.png");
+	game->deadpersonspritetextureptr = loadTexture("DeadPersonsprite.png");
+	game->scopetextureptr = loadTexture("Scope.png");
+	game->flaretextureptr = loadTexture("Flare.png");
+
+	sprites.flaretextureptr = loadTexture("HitFlash.png");
+	sprites.muzzleflaretextureptr = loadTexture("MuzzleFlash.png");
+	sprites.smoketextureptr = loadTexture("Smoke.png");
+	sprites.bloodtextureptr = loadTexture("Blood.png");
+	sprites.raintextureptr = loadTexture("rain.png");
+	sprites.snowtextureptr = loadTexture("snow.png");
+
+	decals.bulletholetextureptr = loadTexture("BulletHole.png");
+	decals.cratertextureptr = loadTexture("Crater.png");
+	decals.bloodtextureptr[0] = loadTexture("Blood/Blood1.png");
+	decals.bloodtextureptr[1] = loadTexture("Blood/Blood2.png");
+	decals.bloodtextureptr[2] = loadTexture("Blood/Blood3.png");
+	decals.bloodtextureptr[3] = loadTexture("Blood/Blood4.png");
+	decals.bloodtextureptr[4] = loadTexture("Blood/Blood5.png");
+	decals.bloodtextureptr[5] = loadTexture("Blood/Blood6.png");
+	decals.bloodtextureptr[6] = loadTexture("Blood/Blood7.png");
+	decals.bloodtextureptr[7] = loadTexture("Blood/Blood8.png");
+	decals.bloodtextureptr[8] = loadTexture("Blood/Blood9.png");
+	decals.bloodtextureptr[9] = loadTexture("Blood/Blood10.png");
+	decals.bloodtextureptr[10] = loadTexture("Blood/Blood11.png");
 }
 
 GLvoid Game::ReSizeGLScene(float fov, float near)
diff --git a/src/Sprites.cpp b/src/Sprites.cpp
index df8eeb1..574bc0e 100644
--- a/src/Sprites.cpp
+++ b/src/Sprites.cpp
@@ -1,5 +1,4 @@
 #include "Sprites.h"
-#include "Textures.h"
 
 extern float multiplier;
 extern bool slomo;
diff --git a/src/Text.cpp b/src/Text.cpp
index 5da702b..1123bfd 100644
--- a/src/Text.cpp
+++ b/src/Text.cpp
@@ -1,6 +1,5 @@
 /**> HEADER FILES <**/
 #include "Text.h"
-#include "Textures.h"
 
 void Text::BuildFont()								// Build Our Font Display List
 {
diff --git a/src/Textures.cpp b/src/Textures.cpp
deleted file mode 100644
index 78808a1..0000000
--- a/src/Textures.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// Texture loader implementation
-// Copyright (C) 2021  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/>.
-
-#include <stdio.h>
-
-#define STB_IMAGE_IMPLEMENTATION
-#include <stb/stb_image.h>
-#include <GL/glu.h>
-
-#include "Textures.h"
-
-GLuint loadTexture(const char* filename_)
-{
-	// TODO: get rid of the :Data: thing
-	char filename[1024];
-	strcpy(filename, filename_+1);
-	while (true) {
-		char *c = strchr(filename, ':');
-		if (!c) break;
-		*c = '/';
-	}
-
-	int req_format = STBI_rgb_alpha;
-	int width, height, orig_format;
-	unsigned char* data = stbi_load(filename, &width, &height,
-		&orig_format, req_format);
-	if (data == nullptr) {
-		fprintf(stderr, "Loading image failed: %s\n",
-			stbi_failure_reason());
-		return 0;
-	}
-
-	GLuint tex = 0;
-	glGenTextures(1, &tex);
-	glBindTexture(GL_TEXTURE_2D, tex);
-	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
-	GLint internal_format;
-	GLenum pixel_format;
-	if (req_format == STBI_rgb) {
-		internal_format = 3;
-		pixel_format = GL_RGB;
-	} else { // STBI_rgb_alpha (RGBA)
-		internal_format = 4;
-		pixel_format = GL_RGBA;
-	}
-
-	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-	glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0,
-		pixel_format, GL_UNSIGNED_BYTE, data);
-	gluBuild2DMipmaps(GL_TEXTURE_2D, internal_format, width, height,
-		pixel_format, GL_UNSIGNED_BYTE, data);
-
-	stbi_image_free(data);
-	return tex;
-}
diff --git a/src/Textures.h b/src/Textures.h
deleted file mode 100644
index abed931..0000000
--- a/src/Textures.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Texture loader header
-// Copyright (C) 2021  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/>.
-
-#ifndef BLACKSHADES_TEXTURES_H
-#define BLACKSHADES_TEXTURES_H
-
-#include <GL/gl.h>
-
-GLuint loadTexture(const char*);
-
-#endif // BLACKSHADES_TEXTURES_H
diff --git a/src/main.zig b/src/main.zig
index b964536..5c4e1c2 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -17,12 +17,12 @@
 // along with Black Shades.  If not, see <https://www.gnu.org/licenses/>.
 
 const Loca = @import("loca").Loca;
+const al = @import("zeal");
 const allocator = @import("std").heap.c_allocator;
-const gf = @import("gfz");
-const legacy = @cImport(@cInclude("Game.h"));
 const configuration = @import("config.zig");
-const al = @import("zeal");
+const gf = @import("gfz");
 const gl = @import("zgl");
+const legacy = @cImport(@cInclude("Game.h"));
 
 var game: *legacy.Game = undefined;
 
@@ -75,6 +75,7 @@ pub fn main() !void {
     defer context.deinit() catch unreachable;
     try al.useContext(context);
 
+    _ = @import("misc.zig").loadTexture("Font.png"); // work around laziness
     legacy.initGame(game);
     defer legacy.closeGame(game);
     while (!try window.shouldClose()) {
diff --git a/src/misc.h b/src/misc.h
new file mode 100644
index 0000000..b3a7f43
--- /dev/null
+++ b/src/misc.h
@@ -0,0 +1,8 @@
+#ifndef BLACKSHADES_MISC_H
+#define BLACKSHADES_MISC_H
+
+#include <GL/gl.h>
+
+extern "C" GLuint loadTexture(const char*);
+
+#endif // BLACKSHADES_MISC_H
diff --git a/src/misc.zig b/src/misc.zig
new file mode 100644
index 0000000..ff45adc
--- /dev/null
+++ b/src/misc.zig
@@ -0,0 +1,73 @@
+// Miscellaneous functions
+// Copyright (C) 2021  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/>.
+
+usingnamespace @cImport({
+    @cInclude("GL/gl.h");
+    @cInclude("GL/glu.h");
+    @cInclude("lodepng.h");
+});
+
+const allocator = std.heap.c_allocator;
+const cwd = std.fs.cwd;
+const data_dir = @import("build_options").data_dir;
+const free = std.c.free;
+const sep = std.fs.path.sep;
+const maxInt = std.math.maxInt;
+const std = @import("std");
+const span = std.mem.span;
+
+const max_size = maxInt(usize); // don't judge me, take care of me
+const texture_dir = data_dir ++ [_]u8{ sep } ++ "textures";
+
+fn check(errorString: fn (c_uint) callconv(.C) [*c]const u8,
+         status: anytype) void {
+    if (status != 0)
+        @panic(span(errorString(@intCast(c_uint, status))));
+}
+
+pub export fn loadTexture(filename: [*:0]const u8) GLuint {
+    var dir = cwd().openDir(texture_dir, .{}) catch unreachable;
+    defer dir.close();
+    var file = dir.readFileAlloc(allocator, span(filename), max_size)
+        catch unreachable;
+    defer allocator.free(file);
+
+    var data: [*c]u8 = undefined;
+    var w: c_uint = undefined;
+    var h: c_uint = undefined;
+    check(lodepng_error_text,
+          lodepng_decode32(&data, &w, &h, file.ptr, file.len));
+    defer free(data);
+
+    var texture: GLuint = undefined;
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    defer glBindTexture(GL_TEXTURE_2D, 0);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+    const width = @intCast(GLint, w);
+    const height = @intCast(GLint, h);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height,
+                 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+    check(gluErrorString, gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height,
+                                            GL_RGBA, GL_UNSIGNED_BYTE, data));
+    return texture;
+}