summaryrefslogtreecommitdiffhomepage
path: root/main
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-10-06 07:11:48 +0200
committerStanislaw Halik <sthalik@misaki.pl>2022-10-06 07:11:48 +0200
commit66ee29df9c19e35b4c126e12e48bc144fe72eb22 (patch)
treec5d8a80cb917a1e33d8efdf6ffc653694e67c759 /main
parent9b2b5c5fd5880f35e2e952bb89fc709f4b814364 (diff)
a
Diffstat (limited to 'main')
-rw-r--r--main/CMakeLists.txt8
-rw-r--r--main/loader-impl.cpp89
-rw-r--r--main/main.cpp222
3 files changed, 319 insertions, 0 deletions
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
new file mode 100644
index 00000000..cb3b1f2c
--- /dev/null
+++ b/main/CMakeLists.txt
@@ -0,0 +1,8 @@
+set(self "${PROJECT_NAME}-main")
+file(GLOB sources "*.cpp" CONFIGURE_ARGS)
+
+link_libraries(${PROJECT_NAME}
+ Magnum::Application Magnum::Trade MagnumIntegration::Glm)
+corrade_add_resource(res ../resources.conf)
+add_executable(${self} WIN32 "${sources}" "${res}")
+set_property(TARGET ${self} PROPERTY OUTPUT_NAME "${PROJECT_NAME}")
diff --git a/main/loader-impl.cpp b/main/loader-impl.cpp
new file mode 100644
index 00000000..24d43fdb
--- /dev/null
+++ b/main/loader-impl.cpp
@@ -0,0 +1,89 @@
+#include "loader.hpp"
+#include "tile-atlas.hpp"
+#include "compat/assert.hpp"
+#include <Corrade/Containers/Optional.h>
+#include <Corrade/Containers/StringView.h>
+#include <Corrade/PluginManager/PluginManager.h>
+#include <Corrade/Utility/Resource.h>
+#include <Magnum/ImageView.h>
+#include <Magnum/Trade/AbstractImporter.h>
+#include <Magnum/Trade/ImageData.h>
+#include <Magnum/Trade/AbstractImageConverter.h>
+#include <unordered_map>
+#include <utility>
+#include <optional>
+
+namespace Magnum::Examples {
+
+struct loader_impl final : loader_
+{
+ std::optional<Utility::Resource> shader_res;
+ PluginManager::Manager<Trade::AbstractImporter> importer_plugins;
+ Containers::Pointer<Trade::AbstractImporter> tga_importer =
+ importer_plugins.loadAndInstantiate("AnyImageImporter");
+
+ PluginManager::Manager<Trade::AbstractImageConverter> image_converter_plugins;
+ Containers::Pointer<Trade::AbstractImageConverter> tga_converter =
+ image_converter_plugins.loadAndInstantiate("AnyImageConverter");
+
+ std::unordered_map<std::string, std::shared_ptr<struct tile_atlas>> atlas_map;
+
+ std::string shader(const Containers::StringView& filename) override;
+ Trade::ImageData2D tile_texture(const Containers::StringView& filename) override;
+ std::shared_ptr<struct tile_atlas> tile_atlas(const Containers::StringView& filename, Vector2i size) override;
+
+ explicit loader_impl();
+ ~loader_impl() override;
+};
+
+std::string loader_impl::shader(const Containers::StringView& filename)
+{
+ if (!shader_res)
+ shader_res = std::make_optional<Utility::Resource>("game/shaders");
+ auto ret = shader_res->getString(filename);
+ if (ret.isEmpty())
+ ABORT("can't find shader resource '%s'", filename.cbegin());
+ return ret;
+}
+
+std::shared_ptr<tile_atlas> loader_impl::tile_atlas(const Containers::StringView& name, Vector2i size)
+{
+ auto it = atlas_map.find(name);
+ if (it != atlas_map.end())
+ return it->second;
+ auto image = tile_texture(name);
+ auto atlas = std::make_shared<struct tile_atlas>(name, image, size);
+ atlas_map[name] = atlas;
+ return atlas;
+}
+
+Trade::ImageData2D loader_impl::tile_texture(const Containers::StringView& filename)
+{
+ if(!tga_importer || !tga_importer->openFile(filename))
+ ABORT("can't open tile image '%s'", filename.cbegin());
+ auto img = tga_importer->image2D(0);
+ if (!img)
+ ABORT("can't allocate tile image for '%s'", filename.cbegin());
+ auto ret = std::move(*img);
+ return ret;
+}
+
+void loader_::destroy()
+{
+ loader.~loader_();
+ new (&loader) loader_impl();
+}
+
+loader_impl::loader_impl() = default;
+loader_impl::~loader_impl() = default;
+
+static loader_& make_default_loader()
+{
+ static loader_impl loader_singleton{};
+ return loader_singleton;
+}
+
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+loader_& loader = make_default_loader();
+
+} // namespace Magnum::Examples
diff --git a/main/main.cpp b/main/main.cpp
new file mode 100644
index 00000000..f58228c6
--- /dev/null
+++ b/main/main.cpp
@@ -0,0 +1,222 @@
+#include "tile-atlas.hpp"
+#include "loader.hpp"
+#include "shaders/tile-shader.hpp"
+#include "tile.hpp"
+#include "chunk.hpp"
+#include "floor-mesh.hpp"
+#include "wall-mesh.hpp"
+
+#include <bitset>
+
+#include <Magnum/Magnum.h>
+#include <Magnum/Math/Vector.h>
+#include <Magnum/GL/DefaultFramebuffer.h>
+#include <Magnum/GL/Renderer.h>
+#include <Magnum/Platform/Sdl2Application.h>
+#include <Magnum/Trade/AbstractImporter.h>
+#include <Magnum/Timeline.h>
+
+namespace Magnum::Examples {
+
+template<typename enum_type>
+struct enum_bitset : std::bitset<(std::size_t)enum_type::MAX> {
+ static_assert(std::is_same_v<std::size_t, std::common_type_t<std::size_t, std::underlying_type_t<enum_type>>>);
+ static_assert(std::is_same_v<enum_type, std::decay_t<enum_type>>);
+ using std::bitset<(std::size_t)enum_type::MAX>::bitset;
+ constexpr bool operator[](enum_type x) const { return operator[]((std::size_t)x); }
+ constexpr decltype(auto) operator[](enum_type x) {
+ return std::bitset<(std::size_t)enum_type::MAX>::operator[]((std::size_t)x);
+ }
+};
+
+struct app final : Platform::Application
+{
+ using dpi_policy = Platform::Implementation::Sdl2DpiScalingPolicy;
+ using tile_atlas_ = std::shared_ptr<tile_atlas>;
+
+ explicit app(const Arguments& arguments);
+ virtual ~app();
+ void drawEvent() override;
+ void update(float dt);
+ void do_camera(float dt);
+ void reset_camera_offset();
+ void keyPressEvent(KeyEvent& event) override;
+ void keyReleaseEvent(KeyEvent& event) override;
+ void do_key(KeyEvent::Key k, KeyEvent::Modifiers m, bool pressed, bool repeated);
+ void draw_chunk(chunk& c);
+ void update_window_scale();
+
+ enum class key : int {
+ camera_up, camera_left, camera_right, camera_down, camera_reset,
+ quit,
+ MAX
+ };
+ chunk make_test_chunk();
+
+ tile_shader _shader;
+ tile_atlas_ floor1 = loader.tile_atlas("../share/game/images/metal1.tga", {2, 2});
+ tile_atlas_ floor2 = loader.tile_atlas("../share/game/images/floor1.tga", {4, 4});
+ tile_atlas_ wall1 = loader.tile_atlas("../share/game/images/metal2.tga", {2, 2});
+ tile_atlas_ wall2 = loader.tile_atlas("../share/game/images/wood1.tga", {2, 2});
+ chunk _chunk = make_test_chunk();
+ floor_mesh _floor_mesh;
+ wall_mesh _wall_mesh;
+
+ Vector2 camera_offset;
+ enum_bitset<key> keys;
+ Magnum::Timeline timeline;
+};
+
+using namespace Math::Literals;
+
+chunk app::make_test_chunk()
+{
+ constexpr auto N = TILE_MAX_DIM;
+ chunk c;
+ c.foreach_tile([&, this](tile& x, std::size_t k, local_coords pt) {
+ const auto& atlas = pt.x > N/2 && pt.y >= N/2 ? floor2 : floor1;
+ x.ground_image = { atlas, (std::uint8_t)(k % atlas->size()) };
+ });
+ constexpr auto K = N/2;
+ c[{K, K }].wall_north = { wall1, 0 };
+ c[{K, K }].wall_west = { wall2, 0 };
+ c[{K, K+1}].wall_north = { wall1, 0 };
+ c[{K+1, K }].wall_west = { wall2, 0 };
+ return c;
+}
+
+void app::update_window_scale()
+{
+ auto sz = windowSize();
+ _shader.set_scale({ (float)sz[0], (float)sz[1] });
+}
+
+void app::draw_chunk(chunk& c)
+{
+ _floor_mesh.draw(_shader, c);
+ _wall_mesh.draw(_shader, c);
+}
+
+app::app(const Arguments& arguments):
+ Platform::Application{
+ arguments,
+ Configuration{}
+ .setTitle("Test")
+ .setSize({1024, 768}, dpi_policy::Physical),
+ GLConfiguration{}
+ //.setSampleCount(16)
+ }
+{
+ reset_camera_offset();
+ timeline.start();
+}
+
+void app::drawEvent() {
+#if 0
+ GL::defaultFramebuffer.clear(GL::FramebufferClear::Color | GL::FramebufferClear::Depth);
+ GL::Renderer::setDepthMask(true);
+ GL::Renderer::setDepthFunction(GL::Renderer::DepthFunction::LessOrEqual);
+ GL::Renderer::enable(GL::Renderer::Feature::DepthTest);
+#else
+ GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);
+ GL::Renderer::setDepthFunction(GL::Renderer::DepthFunction::Never);
+#endif
+
+ update_window_scale();
+ {
+ float dt = timeline.previousFrameDuration();
+ update(dt);
+ }
+
+ draw_chunk(_chunk);
+
+ swapBuffers();
+ redraw();
+ timeline.nextFrame();
+}
+
+void app::do_camera(float dt)
+{
+ constexpr float pixels_per_second = 512;
+ if (keys[key::camera_up])
+ camera_offset += Vector2(0, 1) * dt * pixels_per_second;
+ else if (keys[key::camera_down])
+ camera_offset += Vector2(0, -1) * dt * pixels_per_second;
+ if (keys[key::camera_left])
+ camera_offset += Vector2(1, 0) * dt * pixels_per_second;
+ else if (keys[key::camera_right])
+ camera_offset += Vector2(-1, 0) * dt * pixels_per_second;
+
+ _shader.set_camera_offset(camera_offset);
+
+ if (keys[key::camera_reset])
+ reset_camera_offset();
+}
+
+void app::reset_camera_offset()
+{
+ camera_offset = _shader.project({TILE_MAX_DIM*TILE_SIZE[0]/2.f, TILE_MAX_DIM*TILE_SIZE[1]/2.f, 0});
+ //camera_offset = {};
+}
+
+void app::update(float dt)
+{
+ do_camera(dt);
+ if (keys[key::quit])
+ Platform::Sdl2Application::exit(0);
+}
+
+void app::do_key(KeyEvent::Key k, KeyEvent::Modifiers m, bool pressed, bool repeated)
+{
+ //using Mods = KeyEvent::Modifiers;
+
+ (void)m;
+ (void)repeated;
+
+ const key x = progn(switch (k) {
+ using enum KeyEvent::Key;
+ using enum key;
+
+ case W: return camera_up;
+ case A: return camera_left;
+ case S: return camera_down;
+ case D: return camera_right;
+ case Home: return camera_reset;
+ case Esc: return quit;
+ default: return MAX;
+ });
+
+ if (x != key::MAX)
+ keys[x] = pressed;
+}
+
+app::~app()
+{
+ loader_::destroy();
+}
+
+void app::keyPressEvent(Platform::Sdl2Application::KeyEvent& event)
+{
+ do_key(event.key(), event.modifiers(), true, event.isRepeated());
+}
+
+void app::keyReleaseEvent(Platform::Sdl2Application::KeyEvent& event)
+{
+ do_key(event.key(), event.modifiers(), false, false);
+}
+
+} // namespace Magnum::Examples
+
+MAGNUM_APPLICATION_MAIN(Magnum::Examples::app)
+
+#ifdef _MSC_VER
+# include <cstdlib>
+# ifdef __clang__
+# pragma clang diagnostic ignored "-Wmissing-prototypes"
+# pragma clang diagnostic ignored "-Wmain"
+# endif
+
+extern "C" int __stdcall WinMain(void*, void*, void*, int /* nCmdShow */) {
+ return main(__argc, __argv);
+}
+#endif