summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-11-03 01:13:59 +0100
committerStanislaw Halik <sthalik@misaki.pl>2023-11-03 01:13:59 +0100
commitec1df0878b2f2b37055f0fce388cf9a027046c94 (patch)
tree8534555efacbb58f21d88aadc93072fc9bb66ceb
parent6c7821f538d59db2059fb83fcc7f81b28b580036 (diff)
wip
-rw-r--r--CMakeLists.txt2
-rw-r--r--doc/wall-tilesets.md48
-rw-r--r--images/wall.json4
-rw-r--r--serialize/wall-atlas.cpp62
-rw-r--r--serialize/wall-atlas.hpp15
-rw-r--r--src/tile-atlas.cpp2
-rw-r--r--src/wall-atlas.cpp54
-rw-r--r--src/wall-atlas.hpp65
8 files changed, 250 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 37bfac1b..199a4008 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -246,12 +246,12 @@ add_subdirectory(draw)
add_subdirectory(serialize)
add_subdirectory(editor)
add_subdirectory(test)
+add_subdirectory(anim-crop-tool)
find_package(benchmark QUIET)
if(TARGET benchmark::benchmark OR TARGET benchmark)
add_subdirectory(bench)
endif()
-add_subdirectory(anim-crop-tool)
install(DIRECTORY images anim scenery vobj DESTINATION "share/floormat")
diff --git a/doc/wall-tilesets.md b/doc/wall-tilesets.md
new file mode 100644
index 00000000..42ff2fd1
--- /dev/null
+++ b/doc/wall-tilesets.md
@@ -0,0 +1,48 @@
+Here's what a wall tileset looks like. For reference see this RPG Codex
+post:
+
+- <<https://rpgcodex.net/forums/threads/codexian-game-development-thread.69297/post-8726752>>
+- <<https://archive.ph/uthRB>>
+
+Note: all textures in `floormat` are flat and unprojected. The renderer
+projects then and adds any necessary effects.
+
+Notes on textures:
+
+- Can specify various seam modes.
+ 1. `"any"`: tiles are placed in arbitrary order.
+ 2. `"seamless"`: texture is made seamless from left to right, and
+ top to bottom.
+- Can have a tint specified for it. The formula is $a C + m$. Tint is
+ useful to put a bit of contrast between North and West walls.
+- Split into N tiles, width of 64 and height of 192 is used.
+- An entire set of textures can be borrowed from a different rotation,
+ either optionally mirrored and with a tint added on top of it.
+- Can have multiple Z levels (in Tiled parlance it's "layers"), with
+ optional Z = -1 layer for foundations/ground/soil. Levels are repeated
+ if there's more Z levels than the tileset has.
+
+For all NESW rotations the following separate textures are available:
+
+1. Wall texture. Split into N tiles to be used on ingame 64x64x192 tiles.
+ - The wall can be "borrowed" from a different rotation, optionally
+2. Wall's "depth" texture which specifies that the wall isn't paper-thin
+ depending on its height. Split into N variants, typically N can be 1
+ or the same amount as wall textures.
+3. Inner wall layer. This can be paint, wallpaper or decals placed on
+ top of the wall proper. A separate depth layer cannot be specified.
+ Can be partly transparent (decals such as grafitti) or translucent
+ (weathering marks made out of Perlin noise, etc).
+5. Corner decorations for beginning and end of the wall. For a right
+ angle of N+W walls, end decoration of N and beginning decoration of W
+ is used.
+6. Wall's side when the wall simply ends without forming a corner with a
+ wall from another rotation.
+7. Cut-out part for windows. With a stencil mask.
+8. Cut-out part for doors without a frame. With a stencil mask.
+
+Each texture set can be borrowed from another rotation,
+
+What about coordinates and which tile variant is picked? TODO
+
+JSON/Lisp format. TODO
diff --git a/images/wall.json b/images/wall.json
index 897ae1de..a212b90e 100644
--- a/images/wall.json
+++ b/images/wall.json
@@ -20,6 +20,10 @@
"size": "4 x 4"
},
{
+ "name": "concrete1",
+ "size": "3 x 1"
+ },
+ {
"name": "wall1",
"size": "4 x 1"
}
diff --git a/serialize/wall-atlas.cpp b/serialize/wall-atlas.cpp
new file mode 100644
index 00000000..2e0e8cb2
--- /dev/null
+++ b/serialize/wall-atlas.cpp
@@ -0,0 +1,62 @@
+#include "wall-atlas.hpp"
+#include "magnum-vector2i.hpp"
+#include "magnum-vector.hpp"
+#include "compat/exception.hpp"
+#include <Corrade/Containers/StringStl.h>
+#include <nlohmann/json.hpp>
+
+namespace floormat {
+
+namespace {
+
+constexpr StringView rotation_names[] = { "n"_s, "e"_s, "s"_s, "w"_s, };
+
+size_t rotation_from_name(StringView s)
+{
+ for (auto i = 0uz; auto n : rotation_names)
+ {
+ if (n == s)
+ return i;
+ i++;
+ }
+ fm_throw("bad rotation name '{}'"_cf, fmt::string_view{s.data(), s.size()});
+}
+
+void read_frameset_metadata(nlohmann::json& j, wall_frames& ret)
+{
+ if (j.contains("pixel-size"))
+ ret.pixel_size = j["pixel-size"];
+ if (j.contains("tint"))
+ {
+ auto& t = j["tint"];
+ fm_soft_assert(t.contains("mult") || t.contains("add"));
+ if (t.contains("mult"))
+ ret.tint_mult = Vector4(t["mult"]);
+ if (t.contains("add"))
+ ret.tint_add = Vector3(t["add"]);
+ }
+ if (j.contains("from-rotation"))
+ ret.from_rotation = (uint8_t)rotation_from_name(std::string{j["from-rotation"]});
+ if (j.contains("mirrored"))
+ ret.mirrored = j["mirrored"];
+}
+
+} // namespace
+
+} // namespace floormat
+
+namespace nlohmann {
+
+using namespace floormat;
+
+void adl_serializer<std::shared_ptr<wall_atlas>>::to_json(json& j, const std::shared_ptr<const wall_atlas>& x)
+{
+
+}
+
+void adl_serializer<std::shared_ptr<wall_atlas>>::from_json(const json& j, std::shared_ptr<wall_atlas>& x)
+{
+
+}
+
+} // namespace nlohmann
diff --git a/serialize/wall-atlas.hpp b/serialize/wall-atlas.hpp
new file mode 100644
index 00000000..5e454f87
--- /dev/null
+++ b/serialize/wall-atlas.hpp
@@ -0,0 +1,15 @@
+#pragma once
+#include "src/wall-atlas.hpp"
+#include <memory>
+#include <nlohmann/json_fwd.hpp>
+
+namespace nlohmann {
+
+template<>
+struct adl_serializer<std::shared_ptr<floormat::wall_atlas>>
+{
+ static void to_json(json& j, const std::shared_ptr<const floormat::wall_atlas>& x);
+ static void from_json(const json& j, std::shared_ptr<floormat::wall_atlas>& x);
+};
+
+} // namespace nlohmann
diff --git a/src/tile-atlas.cpp b/src/tile-atlas.cpp
index 298e7f9e..1867189f 100644
--- a/src/tile-atlas.cpp
+++ b/src/tile-atlas.cpp
@@ -20,7 +20,7 @@ tile_atlas::tile_atlas(StringView path, StringView name, const ImageView2D& imag
fm_soft_assert(size_ % Vector2ui{tile_count} == Vector2ui());
tex_.setLabel(path_)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
- .setMagnificationFilter(GL::SamplerFilter::Linear)
+ .setMagnificationFilter(GL::SamplerFilter::Nearest)
.setMinificationFilter(GL::SamplerFilter::Linear)
.setMaxAnisotropy(1)
.setBorderColor(Color4{1, 0, 0, 1})
diff --git a/src/wall-atlas.cpp b/src/wall-atlas.cpp
new file mode 100644
index 00000000..9b711f60
--- /dev/null
+++ b/src/wall-atlas.cpp
@@ -0,0 +1,54 @@
+#include "wall-atlas.hpp"
+#include "compat/assert.hpp"
+#include <utility>
+#include <Magnum/ImageView.h>
+#include <Magnum/GL/TextureFormat.h>
+
+namespace floormat {
+
+size_t wall_atlas::enum_to_index(enum rotation r)
+{
+ fm_debug_assert(r < rotation_COUNT);
+
+ auto x = uint8_t(r);
+ x >>= 1;
+ return x;
+}
+
+wall_atlas::wall_atlas(wall_info info, const ImageView2D& image,
+ ArrayView<const wall_frame_set> rotations,
+ ArrayView<const wall_frame> frames) :
+ _array{NoInit, frames.size()}, _info(std::move(info))
+{
+ fm_assert(info.depth > 0);
+ fm_assert(rotations.size() <= _rotations.size());
+ _rotation_count = (uint8_t)rotations.size();
+ for (auto i = 0uz; const auto& fr : frames)
+ _array[i++] = fr;
+ for (auto i = 0uz; const auto& r : rotations)
+ _rotations[i++] = r;
+
+ _texture.setLabel(_name)
+ .setWrapping(GL::SamplerWrapping::ClampToEdge)
+ .setMagnificationFilter(GL::SamplerFilter::Nearest)
+ .setMinificationFilter(GL::SamplerFilter::Linear)
+ .setMaxAnisotropy(1)
+ .setBorderColor(Color4{1, 0, 0, 1})
+ .setStorage(1, GL::textureFormat(image.format()), image.size())
+ .setSubImage(0, {}, image);
+}
+
+wall_atlas::wall_atlas() = default;
+wall_atlas::~wall_atlas() noexcept = default;
+const wall_frame_set& wall_atlas::frameset(size_t i) const { return _rotations[i]; }
+const wall_frame_set& wall_atlas::frameset(enum rotation r) const { return frameset(enum_to_index(r)); }
+const ArrayView<const wall_frame> wall_atlas::array() const { return _array; }
+StringView wall_atlas::name() const { return _info.name; }
+
+ArrayView<const wall_frame> wall_frames::items(const wall_atlas& a) const
+{
+ fm_debug_assert(index != (uint32_t)-1);
+ return { a.array() + index, count };
+}
+
+} // namespace floormat
diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp
new file mode 100644
index 00000000..02d0ce91
--- /dev/null
+++ b/src/wall-atlas.hpp
@@ -0,0 +1,65 @@
+#pragma once
+#include "src/rotation.hpp"
+#include <array>
+#include <Corrade/Containers/Array.h>
+#include <Corrade/Containers/String.h>
+#include <Magnum/Math/Vector2.h>
+#include <Magnum/Math/Color.h>
+#include <Magnum/GL/Texture.h>
+
+namespace floormat {
+
+struct wall_atlas;
+
+struct wall_frame
+{
+ Vector2ui offset = { (unsigned)-1, (unsigned)-1 };
+};
+
+struct wall_frames
+{
+ uint32_t index = (uint32_t)-1, count = (uint32_t)-1;
+ Vector2ui pixel_size;
+ Color4 tint_mult{1,1,1,1};
+ Color3 tint_add;
+ uint8_t from_rotation = (uint8_t)-1;
+ bool mirrored : 1 = false;
+ ArrayView<const wall_frame> items(const wall_atlas& a) const;
+};
+
+struct wall_frame_set
+{
+ wall_frames wall, overlay, side, top;
+ wall_frames corner_L, corner_R;
+};
+
+struct wall_info
+{
+ String name = "(unnamed)"_s;
+ float depth = 1;
+};
+
+struct wall_atlas final
+{
+ wall_atlas();
+ wall_atlas(wall_info info,
+ const ImageView2D& image,
+ ArrayView<const wall_frame_set> rotations,
+ ArrayView<const wall_frame> frames);
+ ~wall_atlas() noexcept;
+ static size_t enum_to_index(enum rotation x);
+ const wall_frame_set& frameset(size_t i) const;
+ const wall_frame_set& frameset(enum rotation r) const;
+ const ArrayView<const wall_frame> array() const;
+ StringView name() const;
+
+private:
+ String _name;
+ std::array<wall_frame_set, 4> _rotations;
+ Array<wall_frame> _array;
+ GL::Texture2D _texture;
+ wall_info _info;
+ uint8_t _rotation_count = 0;
+};
+
+} // namespace floormat