Work in progress - glTF resource loader

This commit is contained in:
2022-10-16 16:51:35 +02:00
parent 7a53bac2c9
commit 18df6dae18
12 changed files with 332 additions and 11 deletions

3
.gitmodules vendored
View File

@@ -16,3 +16,6 @@
[submodule "lib/fx-gltf"]
path = lib/fx-gltf
url = https://github.com/jessey-git/fx-gltf.git
[submodule "lib/sail"]
path = lib/sail
url = https://github.com/HappySeaFox/sail.git

5
lib/CMakeLists.txt vendored
View File

@@ -10,3 +10,8 @@ option(FX_GLTF_INSTALL "" OFF)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/fx-gltf)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stb)
option(SAIL_BUILD_EXAMPLES "" OFF)
option(SAIL_BUILD_TESTS "" OFF)
option(SAIL_BUILD_APPS "" OFF)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/sail)

1
lib/sail vendored Submodule

Submodule lib/sail added at c0c1e57d8f

View File

@@ -15,6 +15,7 @@ add_library(fever_engine
resources/Model.cpp
util/Log.cpp
image.cpp
gltf_loader.cpp
)
target_compile_features(fever_engine PUBLIC cxx_std_20)
@@ -31,6 +32,7 @@ target_link_libraries(
spdlog
fx-gltf::fx-gltf
stb
sail
)
add_executable(Fall-Fever

View File

@@ -7,6 +7,7 @@
#include "ShaderProgram.h"
#include "Window.h"
#include "definitions/attribute_locations.h"
#include "gltf_loader.h"
#include "resources/Model.h"
#include "util/Log.h"
@@ -17,18 +18,37 @@
#include <glad/gl.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <utility>
struct MyRes
{
MyRes(std::filesystem::path const &path, int)
{
std::cout << "Path: " << std::filesystem::weakly_canonical(path) << std::endl;
};
int x = 0;
};
using namespace entt::literals;
Controller::Controller()
: m_gameWindow(std::make_shared<Window>()),
m_postProcessFrameBuffer(
m_gameWindow->dimensions().first, m_gameWindow->dimensions().second, postProcessingProgram)
{
// auto gltf = fx::gltf::LoadFromBinary("ABeautifulGame/ABeautifulGame.glb",
// {.MaxFileSize = 512 * 1024 * 1024, .MaxBufferByteLength = 512 * 1024 *
// 1024});
gltf_loader<fx::gltf::Document>()("Lantern/glTF-Binary/Lantern.glb");
auto gltf_path = std::filesystem::path("Lantern/glTF/Lantern.gltf");
auto gltf = fx::gltf::LoadFromText(gltf_path);
fx::gltf::ReadQuotas read_quotas{.MaxFileSize = 512 * 1024 * 1024, .MaxBufferByteLength = 512 * 1024 * 1024};
// auto gltf_path = std::filesystem::path("Lantern/glTF/Lantern.gltf");
auto gltf_path = std::filesystem::path("WaterBottle/glTF/WaterBottle.gltf");
auto gltf = [&]() {
if (gltf_path.extension() == ".gltf") {
return fx::gltf::LoadFromText(gltf_path, read_quotas);
}
return fx::gltf::LoadFromBinary(gltf_path, read_quotas);
}();
defaultProgram.bind();
AttributeLocations locations{};

16
src/color.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
struct Color
{
double r{}, g{}, b{};
double a = 1.0;
bool linear = false;
};
namespace ColorConstant {
static constexpr Color WHITE{.r = 1.0, .g = 1.0, .b = 1.0};
static constexpr Color BLACK{.r = 0.0, .g = 0.0, .b = 0.0};
static constexpr Color RED{.r = 1.0, .g = 0.0, .b = 0.0};
static constexpr Color GREEN{.r = 0.0, .g = 1.0, .b = 0.0};
static constexpr Color BLUE{.r = 0.0, .g = 0.0, .b = 1.0};
} // namespace ColorConstant

83
src/gltf_loader.cpp Normal file
View File

@@ -0,0 +1,83 @@
#include "gltf_loader.h"
static void load_texture(fx::gltf::Texture const &texture,
fx::gltf::Document const &gltf,
std::filesystem::path const &document_path,
Image::ColorFormat colorFormat,
entt::resource_cache<Image> &image_cache)
{
auto const &gltf_image = gltf.images.at(texture.source);
auto const base_directory = document_path.parent_path();
if (gltf_image.uri.empty()) {
auto const &image_buffer_view = gltf.bufferViews.at(gltf_image.bufferView);
auto const &image_buffer = gltf.buffers.at(image_buffer_view.buffer);
std::string const image_name = document_path.string() + ".image." + std::to_string(texture.source);
entt::hashed_string image_hash(image_name.c_str());
image_cache.load(
image_hash,
std::span{image_buffer.data}.subspan(image_buffer_view.byteOffset, image_buffer_view.byteLength),
colorFormat);
} else {
auto const image_path = base_directory / gltf_image.uri;
std::size_t const image_size = std::filesystem::file_size(image_path);
auto image_ifstream = std::ifstream(image_path, std::ios::binary);
std::vector<uint8_t> image_data;
image_data.reserve(image_size);
std::copy(std::istreambuf_iterator<char>(image_ifstream),
std::istreambuf_iterator<char>(),
std::back_inserter(image_data));
entt::hashed_string image_hash(image_path.c_str());
image_cache.load(image_hash, image_data, colorFormat);
}
}
static void load_material(fx::gltf::Material const &material,
fx::gltf::Document const &gltf,
std::filesystem::path const &document_path,
entt::resource_cache<Image> &image_cache)
{
auto base_color_texture_id = material.pbrMetallicRoughness.baseColorTexture.index;
auto normal_texture_id = material.normalTexture.index;
if (base_color_texture_id != -1) {
auto const &base_color_texture = gltf.textures.at(base_color_texture_id);
load_texture(base_color_texture, gltf, document_path, Image::ColorFormat::SRGB, image_cache);
}
if (normal_texture_id != -1) {
auto const &normal_texture = gltf.textures.at(normal_texture_id);
load_texture(normal_texture, gltf, document_path, Image::ColorFormat::RGB, image_cache);
}
}
auto gltf_loader::operator()(std::filesystem::path const &document_path) -> result_type
{
fx::gltf::ReadQuotas const read_quotas{.MaxFileSize = MAX_SIZE, .MaxBufferByteLength = MAX_SIZE};
fx::gltf::Document gltf = [&]() {
if (document_path.extension() == ".gltf") {
return fx::gltf::LoadFromText(document_path, read_quotas);
}
return fx::gltf::LoadFromBinary(document_path, read_quotas);
}();
// Load here all the rest...
auto const base_directory = document_path.parent_path();
// Load textures
for (auto const &material : gltf.materials) {
load_material(material, gltf, document_path, image_cache);
}
// Load meshes
return std::make_shared<fx::gltf::Document>(std::move(gltf));
}

24
src/gltf_loader.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include "image.h"
#include "material.h"
#include <entt/entt.hpp>
#include <filesystem>
#include <fx/gltf.h>
static constexpr auto MAX_SIZE = 512 * 1024 * 1024;
struct Gltf
{
std::vector<entt::resource<Material>> materials;
};
struct gltf_loader final
{
using result_type = std::shared_ptr<fx::gltf::Document>;
auto operator()(std::filesystem::path const &document_path) -> result_type;
entt::resource_cache<Image> image_cache;
};

View File

@@ -0,0 +1,88 @@
#include "image.h"
#include "util/Log.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
Image::Image(std::span<uint8_t const> bytes, ColorFormat colorFormat) : colorFormat(colorFormat)
{
int width{};
int height{};
int components{};
uint8_t *stbi_image =
stbi_load_from_memory(bytes.data(), static_cast<int>(bytes.size()), &width, &height, &components, 0);
std::size_t const buffer_length = static_cast<unsigned>(width * height * components);
// Copy the image data into a vector as stbi currently does not support writing into user-defined buffers.
std::copy(stbi_image,
&stbi_image[buffer_length], // NOLINT (cppcoreguidelines-pro-bounds-pointer-arithmetic)
std::back_inserter(data));
dataFormat = [components]() {
switch (components) {
case 1:
return DataFormat::R8Uint;
case 3:
return DataFormat::RGB8Uint;
case 4:
return DataFormat::RGBA8Uint;
default:
Log::logger().warn("Unsupported data format for image.");
return DataFormat::RGBA8Uint;
}
}();
extent = Extent{.width = static_cast<unsigned>(width), .height = static_cast<unsigned>(height)};
stbi_image_free(stbi_image);
}
GpuImage::GpuImage(Image const &image)
{
GLenum internalFormat{};
GLenum dataFormat{};
switch (image.dataFormat) {
case Image::DataFormat::R8Uint:
internalFormat = GL_RED;
dataFormat = GL_RED;
break;
case Image::DataFormat::RGB8Uint:
internalFormat = (image.colorFormat == Image::ColorFormat::SRGB) ? GL_SRGB8 : GL_RGB8;
dataFormat = GL_RGB;
break;
case Image::DataFormat::RGBA8Uint:
internalFormat = (image.colorFormat == Image::ColorFormat::SRGB) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
dataFormat = GL_RGBA;
break;
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(image.sampler.magFilter));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(image.sampler.minFilter));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, LOD_BIAS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<GLint>(image.sampler.wrapS));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<GLint>(image.sampler.wrapT));
glTexImage2D(GL_TEXTURE_2D,
0,
static_cast<GLint>(internalFormat),
static_cast<GLsizei>(image.extent.width),
static_cast<GLsizei>(image.extent.height),
0,
dataFormat,
GL_UNSIGNED_BYTE,
image.data.data());
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}

View File

@@ -1,5 +1,73 @@
#pragma once
struct Image {
#include <filesystem>
#include <glad/gl.h>
#include <span>
#include <vector>
struct Sampler
{
enum class MagFilter : uint16_t
{
None,
Nearest = 9728,
Linear = 9729
};
enum class MinFilter : uint16_t
{
None,
Nearest = 9728,
Linear = 9729,
NearestMipMapNearest = 9984,
LinearMipMapNearest = 9985,
NearestMipMapLinear = 9986,
LinearMipMapLinear = 9987
};
enum class WrappingMode : uint16_t
{
ClampToEdge = 33071,
MirroredRepeat = 33648,
Repeat = 10497
};
MagFilter magFilter = MagFilter::Linear;
MinFilter minFilter = MinFilter::LinearMipMapLinear;
WrappingMode wrapS = WrappingMode::Repeat;
WrappingMode wrapT = WrappingMode::Repeat;
};
struct Image
{
std::vector<uint8_t> data;
Sampler sampler;
struct Extent {
unsigned int width;
unsigned int height;
} extent{};
enum class DataFormat
{
R8Uint,
RGB8Uint,
RGBA8Uint,
} dataFormat;
enum class ColorFormat {
SRGB,
RGB
} colorFormat;
Image(std::span<uint8_t const> bytes, ColorFormat colorFormat);
};
struct GpuImage
{
static constexpr float LOD_BIAS = -2.0;
GpuImage(Image const &image);
GLuint texture{};
};

11
src/material.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include "image.h"
#include <entt/entt.hpp>
struct Material
{
entt::resource<Image> base_color_texture;
entt::resource<Image> normal_map_texture;
};

View File

@@ -2,7 +2,7 @@
#include "../ShaderProgram.h"
#include "../util/Log.h"
#define STB_IMAGE_IMPLEMENTATION
// #define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
Texture::Texture(fx::gltf::Texture const &texture,
@@ -84,7 +84,7 @@ Texture::Texture(fx::gltf::Texture const &texture,
static_cast<GLsizei>(height),
0,
dataFormat,
GL_UNSIGNED_BYTE, // read from bufferview?
GL_UNSIGNED_BYTE,
stbi_image);
glGenerateMipmap(GL_TEXTURE_2D);