Arguments
=========
-blank
- normal execution
+Runtime
+-------
-blank [-n] <n>
+[-n] <n>
terminate after <n> frames
-blank -t <t>
+-t <t>
terminate after <t> milliseconds
-blank <n> -t <t>
+[-n] <n> -t <t>
terminate after n frames, assume <t> milliseconds pass each frame
+Application
+-----------
+
+-d
+ disable double buffering
+
+-m <num>
+ set sample size to <num> (samples per pixel)
+
+--no-vsync
+ disable vsync
+
+Interface
+---------
+
+--no-keyboard
+ disable keyboard input handling
+
+--no-mouse
+ disable mouse input handling
+
+--no-hud
+ disable HUD drawing (includes the selected block outline)
+
+World
+-----
+
blank -s <seed>
use <seed> (unsigned integer) as the world seed. default is 0
namespace blank {
-Application::Application(unsigned int seed)
+Application::Application(const Config &config)
: init_sdl()
, init_img()
-, init_gl()
+, init_gl(config.doublebuf, config.multisampling)
, window()
, ctx(window.CreateContext())
, init_glew()
, program()
, cam()
-, world(seed)
-, interface(world)
+, world(config.world)
+, interface(config.interface, world)
, test_controller(MakeTestEntity(world))
, running(false) {
- GLContext::EnableVSync();
+ if (config.vsync) {
+ GLContext::EnableVSync();
+ }
glClearColor(0.0, 0.0, 0.0, 1.0);
}
class Application {
public:
- explicit Application(unsigned int seed);
+ struct Config {
+ bool vsync = true;
+ bool doublebuf = true;
+ int multisampling = 1;
+
+ Interface::Config interface = Interface::Config();
+ World::Config world = World::Config();
+ };
+
+ explicit Application(const Config &);
Application(const Application &) = delete;
Application &operator =(const Application &) = delete;
}
-ChunkLoader::ChunkLoader(const BlockTypeRegistry ®, const Generator &gen)
+ChunkLoader::ChunkLoader(const Config &config, const BlockTypeRegistry ®, const Generator &gen)
: base(0, 0, 0)
, reg(reg)
, gen(gen)
, loaded()
, to_generate()
, to_free()
-, load_dist(6)
-, unload_dist(8) {
+, load_dist(config.load_dist)
+, unload_dist(config.unload_dist) {
}
class ChunkLoader {
public:
- ChunkLoader(const BlockTypeRegistry &, const Generator &);
+ struct Config {
+ int load_dist = 6;
+ int unload_dist = 8;
+ };
+
+ ChunkLoader(const Config &, const BlockTypeRegistry &, const Generator &);
void Generate(const Chunk::Pos &from, const Chunk::Pos &to);
void GenerateSurrounding(const Chunk::Pos &);
namespace blank {
-Generator::Generator(unsigned int seed)
-: solidNoise(seed)
-, typeNoise(seed + 1)
-, stretch(64.0f)
-, solid_threshold(0.8f)
+Generator::Generator(const Config &config)
+: solidNoise(config.solid_seed)
+, typeNoise(config.type_seed)
+, stretch(config.stretch)
+, solid_threshold(config.solid_threshold)
, space(0)
, light(0)
, solids() {
class Generator {
public:
- explicit Generator(unsigned int seed);
+ struct Config {
+ unsigned int solid_seed = 0;
+ unsigned int type_seed = 0;
+ float stretch = 64.0f;
+ float solid_threshold = 0.8f;
+ };
+
+ explicit Generator(const Config &);
void operator ()(Chunk &) const;
}
-InitGL::InitGL() {
+InitGL::InitGL(bool double_buffer, int sample_size) {
if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3) != 0) {
sdl_error("SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3)");
}
sdl_error("SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE)");
}
- if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0) {
- sdl_error("SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)");
+ if (double_buffer) {
+ if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0) {
+ sdl_error("SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)");
+ }
+ }
+
+ if (sample_size > 1) {
+ if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0) {
+ sdl_error("SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS)");
+ }
+ if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, sample_size) != 0) {
+ sdl_error("SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES)");
+ }
}
}
class InitGL {
public:
- InitGL();
+ explicit InitGL(bool double_buffer = true, int sample_size = 1);
InitGL(const InitGL &) = delete;
InitGL &operator =(const InitGL &) = delete;
namespace blank {
-Interface::Interface(World &world)
+Interface::Interface(const Config &config, World &world)
: world(world)
, ctrl(world.Player())
, hud(world.BlockTypes())
, aim_normal()
, outline()
, outline_transform(1.0f)
-, move_velocity(0.005f)
-, pitch_sensitivity(-0.0025f)
-, yaw_sensitivity(-0.001f)
+, config(config)
, remove(0)
, selection(1)
, front(false)
void Interface::Handle(const SDL_KeyboardEvent &event) {
+ if (config.keyboard_disabled) return;
+
switch (event.keysym.sym) {
case SDLK_w:
front = event.state == SDL_PRESSED;
void Interface::Handle(const SDL_MouseMotionEvent &event) {
- ctrl.RotateYaw(event.xrel * yaw_sensitivity);
- ctrl.RotatePitch(event.yrel * pitch_sensitivity);
+ if (config.mouse_disabled) return;
+ ctrl.RotateYaw(event.xrel * config.yaw_sensitivity);
+ ctrl.RotatePitch(event.yrel * config.pitch_sensitivity);
}
void Interface::Handle(const SDL_MouseButtonEvent &event) {
+ if (config.mouse_disabled) return;
+
if (event.state != SDL_PRESSED) return;
if (event.button == 1) {
void Interface::Handle(const SDL_MouseWheelEvent &event) {
+ if (config.mouse_disabled) return;
+
if (event.y < 0) {
SelectNext();
} else if (event.y > 0) {
void Interface::Update(int dt) {
glm::vec3 vel;
if (right && !left) {
- vel.x = move_velocity;
+ vel.x = config.move_velocity;
} else if (left && !right) {
- vel.x = -move_velocity;
+ vel.x = -config.move_velocity;
}
if (up && !down) {
- vel.y = move_velocity;
+ vel.y = config.move_velocity;
} else if (down && !up) {
- vel.y = -move_velocity;
+ vel.y = -config.move_velocity;
}
if (back && !front) {
- vel.z = move_velocity;
+ vel.z = config.move_velocity;
} else if (front && !back) {
- vel.z = -move_velocity;
+ vel.z = -config.move_velocity;
}
ctrl.Velocity(vel);
ctrl.Update(dt);
void Interface::Render(DirectionalLighting &program) {
+ if (config.visual_disabled) return;
+
if (aim_chunk) {
program.SetM(outline_transform);
outline.Draw();
class Interface {
public:
- explicit Interface(World &);
+ struct Config {
+ float move_velocity = 0.005f;
+ float pitch_sensitivity = -0.0025f;
+ float yaw_sensitivity = -0.001f;
+
+ bool keyboard_disabled = false;
+ bool mouse_disabled = false;
+ bool visual_disabled = false;
+ };
+
+ Interface(const Config &, World &);
void Handle(const SDL_KeyboardEvent &);
void Handle(const SDL_MouseMotionEvent &);
OutlineModel outline;
glm::mat4 outline_transform;
- float move_velocity;
- float pitch_sensitivity;
- float yaw_sensitivity;
+ Config config;
Block remove;
Block selection;
, mode(NORMAL)
, n(0)
, t(0)
-, seed(0) {
+, config() {
}
options = false;
} else {
// long option
- cerr << "unknown option " << arg << endl;
- error = true;
+ if (strcmp(arg + 2, "no-vsync") == 0) {
+ config.vsync = false;
+ } else if (strcmp(arg + 2, "no-keyboard") == 0) {
+ config.interface.keyboard_disabled = true;
+ } else if (strcmp(arg + 2, "no-mouse") == 0) {
+ config.interface.mouse_disabled = true;
+ } else if (strcmp(arg + 2, "no-hud") == 0) {
+ config.interface.visual_disabled = true;
+ } else {
+ cerr << "unknown option " << arg << endl;
+ error = true;
+ }
}
} else {
// short options
for (int j = 1; arg[j] != '\0'; ++j) {
switch (arg[j]) {
+ case 'd':
+ config.doublebuf = false;
+ break;
+ case 'm':
+ ++i;
+ if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
+ cerr << "missing argument to -m" << endl;
+ error = true;
+ } else {
+ config.multisampling = strtoul(argv[i], nullptr, 10);
+ }
+ break;
case 'n':
++i;
if (i >= argc || argv[i] == nullptr || argv[i][0] == '\0') {
cerr << "missing argument to -s" << endl;
error = true;
} else {
- seed = strtoul(argv[i], nullptr, 10);
+ config.world.gen.solid_seed = strtoul(argv[i], nullptr, 10);
+ config.world.gen.type_seed = config.world.gen.solid_seed;
}
break;
case 't':
return 1;
}
- Application app(seed);
+ Application app(config);
switch (mode) {
default:
case NORMAL:
#ifndef BLANK_RUNTIME_HPP_
#define BLANK_RUNTIME_HPP_
+#include "app.hpp"
+
#include <cstddef>
Mode mode;
std::size_t n;
std::size_t t;
- unsigned int seed;
+ Application::Config config;
};
namespace blank {
-World::World(unsigned int seed)
+World::World(const Config &config)
: blockType()
, blockShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }})
, stairShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }}, { 0.0f, 0.0f })
, slabShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.0f, 0.5f }})
-, generate(seed)
-, chunks(blockType, generate)
-, player() {
+, generate(config.gen)
+, chunks(config.load, blockType, generate)
+, player()
+, entities()
+, light_direction(config.light_direction)
+, fog_density(config.fog_density) {
BlockType::Faces block_fill = { true, true, true, true, true, true };
BlockType::Faces slab_fill = { false, true, false, false, false, false };
BlockType::Faces stair_fill = { false, true, false, false, false, true };
generate.Solids({ 1, 4, 7, 10 });
player = &AddEntity();
- player->Position({ 4.0f, 4.0f, 4.0f });
+ player->Position(config.spawn);
chunks.GenerateSurrounding(player->ChunkCoords());
}
void World::Render(DirectionalLighting &program) {
- program.SetLightDirection({ -1.0f, -3.0f, -2.0f });
- // fade out reaches 1/e (0.3679) at 1/fog_density,
- // gets less than 0.01 at e/(2 * fog_density)
- // I chose 0.011 because it yields 91 and 124 for those, so
- // slightly less than 6 and 8 chunks
- program.SetFogDensity(0.011f);
+ program.SetLightDirection(light_direction);
+ program.SetFogDensity(fog_density);
program.SetView(glm::inverse(player->Transform(player->ChunkCoords())));
for (Chunk &chunk : chunks.Loaded()) {
class World {
public:
- explicit World(unsigned int seed);
+ struct Config {
+ // initial player position
+ glm::vec3 spawn = { 4.0f, 4.0f, 4.0f };
+ // direction facing towards(!) the light
+ glm::vec3 light_direction = { -1.0f, -3.0f, -2.0f };
+ // fade out reaches 1/e (0.3679) at 1/fog_density,
+ // gets less than 0.01 at e/(2 * fog_density)
+ // I chose 0.011 because it yields 91 and 124 for those, so
+ // slightly less than 6 and 8 chunks
+ float fog_density = 0.011f;
+
+ Generator::Config gen = Generator::Config();
+ ChunkLoader::Config load = ChunkLoader::Config();
+ };
+
+ explicit World(const Config &);
bool Intersection(
const Ray &,
Entity *player;
std::list<Entity> entities;
+ glm::vec3 light_direction;
+ float fog_density;
+
};
}