aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNguyễn Gia Phong <mcsinyx@disroot.org>2021-09-08 15:46:39 +0700
committerNguyễn Gia Phong <mcsinyx@disroot.org>2021-09-08 15:52:39 +0700
commitda79599ad5201f4eebd3edaabbe4b33498de448e (patch)
tree4f026ad0bb2ab643baadf057d8f391dbc4a9568f /src
parent67cf9f61e91462eaf8e8caeaa7d0d7d3d9d1f711 (diff)
downloadblackshades-da79599ad5201f4eebd3edaabbe4b33498de448e.tar.gz
Move configuration parsing to Zig2.1.0
The config file is now read from configuration directories instead of pwd.
Diffstat (limited to 'src')
-rw-r--r--src/Game.h4
-rw-r--r--src/GameInitDispose.cpp82
-rw-r--r--src/config.h21
-rw-r--r--src/config.zig117
-rw-r--r--src/main.zig20
5 files changed, 172 insertions, 72 deletions
diff --git a/src/Game.h b/src/Game.h
index b4dbcc5..0d819c6 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -22,6 +22,8 @@
#ifndef BLACKSHADES_GAME_H
#define BLACKSHADES_GAME_H
+#include "config.h"
+
#ifdef __cplusplus
#include <GL/gl.h>
#include <GL/glu.h>
@@ -205,7 +207,7 @@ typedef struct Game Game;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
- Game* makeGame();
+ Game* makeGame(struct Config config);
void initGl(Game*);
void initGame(Game*);
void eventLoop(Game*);
diff --git a/src/GameInitDispose.cpp b/src/GameInitDispose.cpp
index 782cf6a..b208df5 100644
--- a/src/GameInitDispose.cpp
+++ b/src/GameInitDispose.cpp
@@ -22,6 +22,7 @@
#include <AL/alc.h>
+#include "config.h"
#include "Textures.h"
#include "Game.h"
@@ -57,9 +58,21 @@ extern int aimkey;
extern int psychicaimkey;
extern int psychickey;
-Game* makeGame()
+Game* makeGame(Config config)
{
- return new Game();
+ auto game = new Game();
+ game->screenwidth = config.screen_width;
+ game->screenheight = config.screen_height;
+ game->usermousesensitivity = config.mouse_sensitivity;
+ game->debug = config.debug;
+ game->vblsync = config.vsync;
+ blood = config.blood;
+ game->blurness = config.blur;
+ game->mainmenuness = config.menu;
+ game->customlevels = config.custom_levels;
+ game->musictoggle = config.music;
+ game->azertykeyboard = config.azerty;
+ return game;
}
void LoadSounds(bool musictoggle)
@@ -1781,69 +1794,6 @@ void initGl(Game* game)
// Config
game->mousesensitivity = 1.0f;
if (!game->initialized) {
- ifstream ipstream {"config.txt"};
- // If no config, write one
- if (!ipstream) {
- ofstream opstream("config.txt");
- opstream << "Screenwidth:\n";
- opstream << (game->screenwidth = 640);
- opstream << "\nScreenheight:\n";
- opstream << (game->screenheight = 480);
- opstream << "\nMouse sensitivity:\n";
- opstream << (game->usermousesensitivity = 0.7f);
- opstream << "\nShow fps and other info:\n";
- opstream << (game->debug = false);
- opstream << "\nVBL sync:\n";
- opstream << (game->vblsync = true);
- opstream << "\nBlood:\n";
- opstream << (blood = true);
- opstream << "\nBlur:\n";
- opstream << (game->blurness = false);
- opstream << "\nMain Menu:\n";
- opstream << (game->mainmenuness = true);
- opstream << "\nCustom levels:\n";
- opstream << (game->customlevels = false);
- opstream << "\nMusic:\n";
- opstream << (game->musictoggle = true);
- opstream << "\azerty keyboard:\n";
- opstream << (game->azertykeyboard = false) << endl;
- opstream.close();
- } else {
- ipstream.ignore(256,'\n');
- ipstream >> game->screenwidth;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> game->screenheight;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> game->usermousesensitivity;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> game->debug;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> game->vblsync;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> blood;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> game->blurness;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> game->mainmenuness;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> game->customlevels;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> game->musictoggle;
- ipstream.ignore(256,'\n');
- ipstream.ignore(256,'\n');
- ipstream >> game->azertykeyboard;
- ipstream.close();
- }
-
// TODO: Read high score
ifstream ipstream2 {"highscore.txt"};
if (!ipstream2) {
@@ -1853,7 +1803,7 @@ void initGl(Game* game)
opstream.close();
} else {
ipstream2 >> game->highscore;
- ipstream.ignore(256,'\n');
+ ipstream2.ignore(256,'\n');
ipstream2 >> game->beatgame;
ipstream2.close();
}
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..fa456b2
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,21 @@
+#ifndef BLACKSHADES_CONFIG_H
+#define BLACKSHADES_CONFIG_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct Config {
+ int screen_width;
+ int screen_height;
+ float mouse_sensitivity;
+ bool debug;
+ bool vsync;
+ bool blood;
+ bool blur;
+ bool menu;
+ bool custom_levels;
+ bool music;
+ bool azerty;
+};
+
+#endif // BLACKSHADES_CONFIG_H
diff --git a/src/config.zig b/src/config.zig
new file mode 100644
index 0000000..4bde82c
--- /dev/null
+++ b/src/config.zig
@@ -0,0 +1,117 @@
+// Configuration parser
+// 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 Allocator = std.mem.Allocator;
+const createFile = std.fs.createFileAbsolute;
+const eql = std.mem.eql;
+const ini = @import("ini");
+const join = std.fs.path.join;
+const mkdir = std.os.mkdir;
+const openFile = std.fs.openFileAbsolute;
+const parseFloat = std.fmt.parseFloat;
+const parseInt = std.fmt.parseInt;
+const std = @import("std");
+
+/// Game configuration.
+pub const Config = extern struct {
+ screen_width: c_int = 640,
+ screen_height: c_int = 480,
+ mouse_sensitivity: f32 = 0.7,
+ debug: bool = false,
+ vsync: bool = true,
+ blood: bool = true,
+ blur: bool = false,
+ menu: bool = true,
+ custom_levels: bool = false,
+ music: bool = true,
+ azerty: bool = false,
+};
+
+/// Parse boolean values.
+fn parseBool(s: []const u8) !bool {
+ if (eql(u8, s, "false"))
+ return false;
+ if (eql(u8, s, "true"))
+ return true;
+ return error.InvalidCharacter;
+}
+
+/// Parse settings.ini in the given base directory.
+pub fn parse(allocator: *Allocator, base_dir: []const u8) !Config {
+ const config_dir = try join(allocator, &.{ base_dir, "blackshades" });
+ defer allocator.free(config_dir);
+ const path = try join(allocator, &.{ config_dir, "settings.ini" });
+ defer allocator.free(path);
+
+ var config = Config{};
+ const input = openFile(path, .{}) catch {
+ mkdir(config_dir, 0o644) catch |err| switch (err) {
+ error.PathAlreadyExists => {},
+ else => return err,
+ };
+ const output = try createFile(path, .{});
+ defer output.close();
+ const writer = output.writer();
+ try writer.print("screen width = {}\n", .{ config.screen_width });
+ try writer.print("screen height = {}\n", .{ config.screen_height });
+ try writer.print("mouse sensitivity = {d:.1}\n",
+ .{ config.mouse_sensitivity });
+ try writer.print("debug = {}\n", .{ config.debug });
+ try writer.print("vsync = {}\n", .{ config.vsync });
+ try writer.print("blood = {}\n", .{ config.blood });
+ try writer.print("blur = {}\n", .{ config.blur });
+ try writer.print("menu = {}\n", .{ config.menu });
+ try writer.print("custom levels = {}\n", .{ config.custom_levels });
+ try writer.print("music = {}\n", .{ config.music });
+ try writer.print("azerty = {}\n", .{ config.azerty });
+ return config;
+ };
+ defer input.close();
+
+ var parser = ini.parse(allocator, input.reader());
+ defer parser.deinit();
+
+ while (try parser.next()) |record|
+ switch (record) {
+ .property => |kv| if (eql(u8, kv.key, "screen width")) {
+ config.screen_width = try parseInt(c_int, kv.value, 10);
+ } else if (eql(u8, kv.key, "screen height")) {
+ config.screen_height = try parseInt(c_int, kv.value, 10);
+ } else if (eql(u8, kv.key, "mouse_sensitivity")) {
+ config.mouse_sensitivity = try parseFloat(f32, kv.value);
+ } else if (eql(u8, kv.key, "debug")) {
+ config.debug = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "vsync")) {
+ config.vsync = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "blood")) {
+ config.blood = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "blur")) {
+ config.blur = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "menu")) {
+ config.menu = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "custom levels")) {
+ config.custom_levels = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "music")) {
+ config.music = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "azerty")) {
+ config.azerty = try parseBool(kv.value);
+ },
+ else => unreachable,
+ };
+ return config;
+}
diff --git a/src/main.zig b/src/main.zig
index 34e3844..baca0e0 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -16,14 +16,24 @@
// 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 legacy = @cImport({ @cInclude("Game.h"); });
-const al = @import("zeal");
+const Loca = @import("loca").Loca;
+const allocator = @import("std").heap.c_allocator;
+const legacy = @cImport(@cInclude("Game.h"));
+const configuration = @import("config.zig");
+const zeal = @import("zeal");
pub fn main() !void {
- try al.init(null);
- defer al.deinit() catch unreachable;
+ const loca = try Loca.init(allocator, .{});
+ defer loca.deinit();
+ const config = try configuration.parse(allocator, loca.user_config);
- const game = legacy.makeGame();
+ const device = try zeal.Device.init(null);
+ defer device.deinit() catch unreachable;
+ const context = try zeal.Context.init(device, &.{ });
+ defer context.deinit() catch unreachable;
+ try zeal.useContext(context);
+
+ const game = legacy.makeGame(@bitCast(legacy.Config, config));
legacy.initGl(game);
legacy.initGame(game);
defer legacy.closeGame(game);