diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-04-14 18:03:34 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-04-14 18:03:34 +0100 |
commit | 5776a36b454fac04617313da011d7aa2b0e834d3 (patch) | |
tree | 1eb96d07e9a17a51e5763f397fc003f762cd2e75 /gfx/models | |
parent | Merge branch 'model-factory-textures' (diff) | |
parent | Add an asset template and use it to define all the foliage assets in the plan... (diff) | |
download | ilt-5776a36b454fac04617313da011d7aa2b0e834d3.tar.bz2 ilt-5776a36b454fac04617313da011d7aa2b0e834d3.tar.xz ilt-5776a36b454fac04617313da011d7aa2b0e834d3.zip |
Merge branch 'assimp'
Diffstat (limited to 'gfx/models')
-rw-r--r-- | gfx/models/mesh.cpp | 3 | ||||
-rw-r--r-- | gfx/models/obj.h | 38 | ||||
-rw-r--r-- | gfx/models/obj.impl.cpp | 77 | ||||
-rw-r--r-- | gfx/models/obj.ll | 116 | ||||
-rw-r--r-- | gfx/models/texture.cpp | 95 | ||||
-rw-r--r-- | gfx/models/texture.h | 40 | ||||
-rw-r--r-- | gfx/models/tga.h | 14 | ||||
-rw-r--r-- | gfx/models/vertex.hpp | 9 |
8 files changed, 132 insertions, 260 deletions
diff --git a/gfx/models/mesh.cpp b/gfx/models/mesh.cpp index 3db1ad5..2719211 100644 --- a/gfx/models/mesh.cpp +++ b/gfx/models/mesh.cpp @@ -7,7 +7,8 @@ Mesh::Mesh(const std::span<const Vertex> vertices, const std::span<const unsigned int> indices, GLenum m) :
m_numIndices {static_cast<GLsizei>(indices.size())}, mode {m}
{
- VertexArrayObject<Vertex>::configure<&Vertex::pos, &Vertex::texCoord, &Vertex::normal, &Vertex::colour>(
+ VertexArrayObject<Vertex>::configure<&Vertex::pos, &Vertex::texCoord, &Vertex::normal, &Vertex::colour,
+ &Vertex::material>(
m_vertexArrayObject, m_vertexArrayBuffers[0], m_vertexArrayBuffers[1], vertices, indices);
}
diff --git a/gfx/models/obj.h b/gfx/models/obj.h deleted file mode 100644 index e28f7de..0000000 --- a/gfx/models/obj.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#ifndef yyFlexLexer -# define yyFlexLexer objbaseFlexLexer -# include <FlexLexer.h> -#endif -#include <filesystem> -#include <fstream> -#include <glm/glm.hpp> -#include <map> -#include <memory> -#include <vector> - -class Mesh; -class Vertex; - -class ObjParser : yyFlexLexer { -public: - explicit ObjParser(const std::filesystem::path & fileName); - explicit ObjParser(std::unique_ptr<std::istream> in); - - int yylex() override; - - std::vector<glm::vec4> vertices; - std::vector<glm::vec3> texCoords; - std::vector<glm::vec3> normals; - using FaceElement = glm::vec<3, unsigned int>; - using Face = std::vector<FaceElement>; - using Faces = std::vector<Face>; - using Object = std::pair<std::string, Faces>; - std::vector<Object> objects; - glm::length_t axis {0}; - - using NamedMeshesData = std::map<std::string, std::pair<std::vector<Vertex>, std::vector<unsigned int>>>; - [[nodiscard]] NamedMeshesData createMeshData() const; - using NamedMeshes = std::map<std::string, std::shared_ptr<const Mesh>>; - [[nodiscard]] NamedMeshes createMeshes() const; -}; diff --git a/gfx/models/obj.impl.cpp b/gfx/models/obj.impl.cpp deleted file mode 100644 index 205abc8..0000000 --- a/gfx/models/obj.impl.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "obj.h" -#include <algorithm> -#include <cassert> -#include <filesystem> -#include <fstream> -#include <gfx/models/mesh.h> // IWYU pragma: keep -#include <gfx/models/vertex.hpp> -#include <glm/glm.hpp> -#include <iterator> -#include <map> -#include <memory> -#include <utility> -#include <vector> - -ObjParser::ObjParser(const std::filesystem::path & fileName) : ObjParser {std::make_unique<std::ifstream>(fileName)} { } - -ObjParser::ObjParser(std::unique_ptr<std::istream> in) : yyFlexLexer(in.get()) -{ - assert(in); - ObjParser::yylex(); - assert(in->good()); - constexpr const glm::mat4 obj2ilt { - -1, 0, 0, 0, // x - 0, 0, 1, 0, // y - 0, 1, 0, 0, // z - 0, 0, 0, 0, // w - }; - std::for_each(vertices.begin(), vertices.end(), [&obj2ilt](auto & v) { - v = v * obj2ilt; - }); - std::for_each(normals.begin(), normals.end(), [&obj2ilt](auto & v) { - v = glm::vec4 {v, 0} * obj2ilt; - }); -} - -ObjParser::NamedMeshes -ObjParser::createMeshes() const -{ - NamedMeshes out; - const auto data {createMeshData()}; - std::transform(data.begin(), data.end(), std::inserter(out, out.end()), [](auto && obj) { - return std::make_pair(obj.first, std::make_shared<Mesh>(obj.second.first, obj.second.second)); - }); - return out; -} - -ObjParser::NamedMeshesData -ObjParser::createMeshData() const -{ - NamedMeshesData out; - std::transform(objects.begin(), objects.end(), std::inserter(out, out.end()), [this](auto && obj) { - std::vector<Vertex> overtices; - std::vector<ObjParser::FaceElement> vertexOrder; - std::vector<unsigned int> indices; - for (const auto & face : obj.second) { - for (auto idx = 2U; idx < face.size(); idx += 1) { - auto f = [&](auto idx) { - const auto & fe {face[idx]}; - if (const auto existing = std::find(vertexOrder.begin(), vertexOrder.end(), fe); - existing != vertexOrder.end()) { - indices.push_back(static_cast<unsigned int>(std::distance(vertexOrder.begin(), existing))); - } - else { - indices.push_back(static_cast<unsigned int>(overtices.size())); - overtices.emplace_back(vertices[fe.x - 1], texCoords[fe.y - 1], -normals[fe.z - 1]); - vertexOrder.emplace_back(fe); - } - }; - f(0U); - f(idx); - f(idx - 1); - } - } - return std::make_pair(obj.first, std::make_pair(overtices, indices)); - }); - return out; -} diff --git a/gfx/models/obj.ll b/gfx/models/obj.ll deleted file mode 100644 index 84884fe..0000000 --- a/gfx/models/obj.ll +++ /dev/null @@ -1,116 +0,0 @@ -%option batch -%option c++ -%option noyywrap -%option 8bit -%option stack -%option yyclass="ObjParser" -%option prefix="objbase" - -%{ -#include <gfx/models/obj.h> -#include <glm/glm.hpp> -#include <memory> -#include <string> -#include <vector> -class objbaseFlexLexer; -%} - -comment #.* -float -?[0-9.]+ -index -?[0-9]+ -linestring [^\r\n]* -truthy (1|on) -falsey (0|off) - -%x FACE -%x MTLLIB -%x OBJECT -%x SMOOTH -%x USEMTL -%x VERTEX -%x NORMAL -%x TEXCOORD - -%% - -<INITIAL>{comment} { - // fprintf(stderr, "COMMENT %s\n", YYText()); -} -<INITIAL>"f " { - BEGIN(FACE); - objects.back().second.emplace_back(); - objects.back().second.back().emplace_back(); - axis = 0; -} -<INITIAL>"mtllib " { - BEGIN(MTLLIB); -} -<INITIAL>"o " { - BEGIN(OBJECT); -} -<INITIAL>"s " { - BEGIN(SMOOTH); -} -<INITIAL>"usemtl " { - BEGIN(USEMTL); -} -<INITIAL>"v " { - BEGIN(VERTEX); - vertices.emplace_back(0, 0, 0, 1); - axis = 0; -} -<INITIAL>"vn " { - BEGIN(NORMAL); - normals.emplace_back(0, 0, 0); - axis = 0; -} -<INITIAL>"vt " { - BEGIN(TEXCOORD); - texCoords.emplace_back(0, 1, 1); - axis = 0; -} -<USEMTL>{linestring} { - // fprintf(stderr, "USEMTL <%s>\n", YYText()); -} -<MTLLIB>{linestring} { - // fprintf(stderr, "MTLLIB <%s>\n", YYText()); -} -<OBJECT>{linestring} { - objects.emplace_back(YYText(), Faces{}); -} -<SMOOTH>{truthy} { - // fprintf(stderr, "Set smooth\n"); -} -<SMOOTH>{falsey} { - // fprintf(stderr, "Set flat\n"); -} -<VERTEX>{float} { - vertices.back()[axis++] = std::stof(YYText()); -} -<NORMAL>{float} { - normals.back()[axis++] = std::stof(YYText()); -} -<TEXCOORD>{float} { - texCoords.back()[axis++] = std::stof(YYText()); -} -<FACE>{index} { - objects.back().second.back().back()[axis] = std::stoi(YYText()); -} -<FACE>\/ { - axis++; -} -<FACE>[ \t] { - objects.back().second.back().emplace_back(); - axis = 0; -} - -<*>[ \t] { -} -<*>[\r\n\f] { - BEGIN(INITIAL); -} - -%% - -// Make iwyu think unistd.h is required -[[maybe_unused]]static auto x=getpid; diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp index efc76e1..e014f80 100644 --- a/gfx/models/texture.cpp +++ b/gfx/models/texture.cpp @@ -1,5 +1,6 @@ #include "texture.h"
#include "glArrays.h"
+#include "tga.h"
#include <GL/glew.h>
#include <cache.h>
#include <fcntl.h>
@@ -12,6 +13,21 @@ Cache<Texture, std::filesystem::path> Texture::cachedTexture;
+GLint
+TextureOptions::glMapMode(TextureOptions::MapMode mm)
+{
+ switch (mm) {
+ case MapMode::Repeat:
+ return GL_REPEAT;
+ case MapMode::Clamp:
+ return GL_CLAMP_TO_EDGE;
+ case MapMode::Mirror:
+ return GL_MIRRORED_REPEAT;
+ default:
+ throw std::domain_error("Invalid MapMode value");
+ }
+}
+
Texture::Texture(const std::filesystem::path & fileName, TextureOptions to) :
Texture {Image {Resource::mapPath(fileName).c_str(), STBI_rgb_alpha}, to}
{
@@ -29,8 +45,8 @@ Texture::Texture(GLsizei width, GLsizei height, const void * data, TextureOption glBindTexture(type, m_texture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexParameteri(type, GL_TEXTURE_WRAP_S, to.wrap);
- glTexParameteri(type, GL_TEXTURE_WRAP_T, to.wrap);
+ glTexParameteri(type, GL_TEXTURE_WRAP_S, TextureOptions::glMapMode(to.wrapU));
+ glTexParameteri(type, GL_TEXTURE_WRAP_T, TextureOptions::glMapMode(to.wrapV));
glTexParameteri(type, GL_TEXTURE_MIN_FILTER, to.minFilter);
glTexParameteri(type, GL_TEXTURE_MAG_FILTER, to.magFilter);
@@ -44,44 +60,91 @@ Texture::bind(GLenum unit) const glBindTexture(type, m_texture);
}
-void
-Texture::save(const glTexture & texture, GLenum format, GLenum type, const glm::ivec2 & size, unsigned short channels,
- const char * path, short tgaFormat)
+glm::ivec2
+Texture::getSize(const glTexture & texture)
{
- using TGAHead = std::array<short, 9>;
+ glm::ivec2 size;
+ glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_WIDTH, &size.x);
+ glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_HEIGHT, &size.y);
+ return size;
+}
+void
+Texture::save(
+ const glTexture & texture, GLenum format, GLenum type, uint8_t channels, const char * path, uint8_t tgaFormat)
+{
+ const auto size = getSize(texture);
const size_t dataSize = (static_cast<size_t>(size.x * size.y * channels));
const size_t fileSize = dataSize + sizeof(TGAHead);
filesystem::fh out {path, O_RDWR | O_CREAT, 0660};
out.truncate(fileSize);
auto tga = out.mmap(fileSize, 0, PROT_WRITE, MAP_SHARED);
- *tga.get<TGAHead>() = {0, tgaFormat, 0, 0, 0, 0, static_cast<short>(size.x), static_cast<short>(size.y),
- static_cast<short>(8 * channels)};
+ *tga.get<TGAHead>() = {
+ .format = tgaFormat,
+ .size = size,
+ .pixelDepth = static_cast<uint8_t>(8 * channels),
+ };
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
glGetTextureImage(texture, 0, format, type, static_cast<GLsizei>(dataSize), tga.get<TGAHead>() + 1);
tga.msync(MS_ASYNC);
}
void
-Texture::save(const glm::ivec2 & size, const char * path) const
+Texture::save(const char * path) const
{
- save(m_texture, GL_BGR, GL_UNSIGNED_BYTE, size, 3, path, 2);
+ save(m_texture, GL_BGR, GL_UNSIGNED_BYTE, 3, path, 2);
}
void
-Texture::save(const glTexture & texture, const glm::ivec2 & size, const char * path)
+Texture::save(const glTexture & texture, const char * path)
{
- save(texture, GL_BGR, GL_UNSIGNED_BYTE, size, 3, path, 2);
+ save(texture, GL_BGR, GL_UNSIGNED_BYTE, 3, path, 2);
}
void
-Texture::saveDepth(const glTexture & texture, const glm::ivec2 & size, const char * path)
+Texture::saveDepth(const glTexture & texture, const char * path)
{
- save(texture, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, size, 1, path, 3);
+ save(texture, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 1, path, 3);
}
void
-Texture::saveNormal(const glTexture & texture, const glm::ivec2 & size, const char * path)
+Texture::saveNormal(const glTexture & texture, const char * path)
+{
+ save(texture, GL_BGR, GL_BYTE, 3, path, 2);
+}
+
+TextureAtlas::TextureAtlas(GLsizei width, GLsizei height, GLuint count) : Texture(width, height, nullptr, {})
+{
+ glBindTexture(GL_TEXTURE_RECTANGLE, m_atlas);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA16UI, 2, static_cast<GLsizei>(count), 0, GL_RGBA_INTEGER,
+ GL_UNSIGNED_BYTE, nullptr);
+}
+
+void
+TextureAtlas::bind(GLenum unit) const
+{
+ Texture::bind(unit);
+ glActiveTexture(unit + 1);
+ glBindTexture(GL_TEXTURE_RECTANGLE, m_atlas);
+}
+
+GLuint
+TextureAtlas::add(glm::ivec2 position, glm::ivec2 size, void * data, TextureOptions to)
{
- save(texture, GL_BGR, GL_BYTE, size, 3, path, 2);
+ glTextureSubImage2D(m_texture, 0, position.x, position.y, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ struct Material {
+ glm::vec<2, uint16_t> position, size;
+ TextureOptions::MapMode wrapU;
+ TextureOptions::MapMode wrapV;
+ } material {position, size, to.wrapU, to.wrapV};
+ static_assert(sizeof(Material) <= 32);
+ glTextureSubImage2D(m_atlas, 0, 0, static_cast<GLsizei>(used), 2, 1, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, &material);
+ return ++used;
}
diff --git a/gfx/models/texture.h b/gfx/models/texture.h index ffc9a4a..86e76a0 100644 --- a/gfx/models/texture.h +++ b/gfx/models/texture.h @@ -9,13 +9,23 @@ class Image;
struct TextureOptions {
- GLint wrap {GL_REPEAT};
+ enum class MapMode {
+ Repeat,
+ Clamp,
+ Mirror,
+ Decal,
+ };
+ MapMode wrapU {MapMode::Repeat}, wrapV {MapMode::Repeat};
GLint minFilter {GL_LINEAR}, magFilter {GL_LINEAR};
GLenum type {GL_TEXTURE_2D};
+ static GLint glMapMode(MapMode);
};
class Texture {
public:
+ virtual ~Texture() = default;
+ DEFAULT_MOVE_NO_COPY(Texture);
+
explicit Texture(const std::filesystem::path & fileName, TextureOptions = {});
explicit Texture(const Image & image, TextureOptions = {});
explicit Texture(GLsizei width, GLsizei height, TextureOptions = {});
@@ -23,17 +33,29 @@ public: static Cache<Texture, std::filesystem::path> cachedTexture;
- void bind(GLenum unit = GL_TEXTURE0) const;
+ virtual void bind(GLenum unit = GL_TEXTURE0) const;
- void save(const glm::ivec2 & size, const char * path) const;
- static void save(const glTexture &, const glm::ivec2 & size, const char * path);
- static void saveDepth(const glTexture &, const glm::ivec2 & size, const char * path);
- static void saveNormal(const glTexture &, const glm::ivec2 & size, const char * path);
+ void save(const char * path) const;
+ static void save(const glTexture &, const char * path);
+ static void saveDepth(const glTexture &, const char * path);
+ static void saveNormal(const glTexture &, const char * path);
-private:
- static void save(const glTexture &, GLenum, GLenum, const glm::ivec2 & size, unsigned short channels,
- const char * path, short tgaFormat);
+protected:
+ static void save(const glTexture &, GLenum, GLenum, uint8_t channels, const char * path, uint8_t tgaFormat);
+ static glm::ivec2 getSize(const glTexture &);
glTexture m_texture;
GLenum type;
};
+
+class TextureAtlas : public Texture {
+public:
+ TextureAtlas(GLsizei width, GLsizei height, GLuint count);
+
+ void bind(GLenum unit = GL_TEXTURE0) const override;
+ GLuint add(glm::ivec2 position, glm::ivec2 size, void * data, TextureOptions = {});
+
+private:
+ glTexture m_atlas;
+ GLuint used {};
+};
diff --git a/gfx/models/tga.h b/gfx/models/tga.h new file mode 100644 index 0000000..1f400ef --- /dev/null +++ b/gfx/models/tga.h @@ -0,0 +1,14 @@ +#pragma once + +#include <cstdint> +#include <glm/vec2.hpp> + +struct TGAHead { + uint8_t idLength {}, colorMapType {}, format {}; + uint16_t __attribute__((packed)) colorMapFirst {}, colorMapLength {}; + uint8_t colorMapEntrySize {}; + glm::vec<2, uint16_t> origin {}, size {}; + uint8_t pixelDepth {}; + uint8_t descriptor {}; +}; +static_assert(sizeof(TGAHead) == 18); diff --git a/gfx/models/vertex.hpp b/gfx/models/vertex.hpp index 64ec3d0..181e7e7 100644 --- a/gfx/models/vertex.hpp +++ b/gfx/models/vertex.hpp @@ -1,12 +1,14 @@ #pragma once +#include <GL/glew.h> #include <glm/glm.hpp> class Vertex { public: #ifndef __cpp_aggregate_paren_init - constexpr Vertex(glm::vec3 pos, glm::vec2 texCoord, glm::vec3 normal, glm::vec4 colour = {}) : - pos {std::move(pos)}, texCoord {std::move(texCoord)}, normal {std::move(normal)}, colour {std::move(colour)} + constexpr Vertex(glm::vec3 pos, glm::vec2 texCoord, glm::vec3 normal, glm::vec4 colour = {}, GLuint material = 0) : + pos {std::move(pos)}, texCoord {std::move(texCoord)}, normal {std::move(normal)}, colour {std::move(colour)}, + material {material} { } #endif @@ -16,5 +18,6 @@ public: glm::vec3 pos; glm::vec2 texCoord; glm::vec3 normal; - glm::vec4 colour; + glm::vec4 colour {}; + GLuint material {}; }; |