diff --git a/CMakeLists.txt b/CMakeLists.txt index d4aa351..c7a360c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ option(VERSION_STRING "Project version string" "0.0.0") project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX) + # Find dependency packages find_package(dr_wav REQUIRED CONFIG) find_package(stb REQUIRED CONFIG) diff --git a/src/game/bootloader.cpp b/src/game/bootloader.cpp index 28ee2bb..31a4a67 100644 --- a/src/game/bootloader.cpp +++ b/src/game/bootloader.cpp @@ -336,6 +336,7 @@ void setup_resources(game_context* ctx) // Include resource search paths in order of priority ctx->resource_manager->include("/shaders/"); ctx->resource_manager->include("/models/"); + ctx->resource_manager->include("/images/"); ctx->resource_manager->include("/textures/"); ctx->resource_manager->include("/materials/"); ctx->resource_manager->include("/entities/"); @@ -448,11 +449,11 @@ void setup_rendering(game_context* ctx) // Create HDR framebuffer (32F color, 32F depth) ctx->framebuffer_hdr_color = new gl::texture_2d(viewport_dimensions[0], viewport_dimensions[1], gl::pixel_type::float_32, gl::pixel_format::rgb); - ctx->framebuffer_hdr_color->set_wrapping(gl::texture_wrapping::clamp, gl::texture_wrapping::clamp); + ctx->framebuffer_hdr_color->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); ctx->framebuffer_hdr_color->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); ctx->framebuffer_hdr_color->set_max_anisotropy(0.0f); ctx->framebuffer_hdr_depth = new gl::texture_2d(viewport_dimensions[0], viewport_dimensions[1], gl::pixel_type::float_32, gl::pixel_format::ds); - ctx->framebuffer_hdr_depth->set_wrapping(gl::texture_wrapping::clamp, gl::texture_wrapping::clamp); + ctx->framebuffer_hdr_depth->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); ctx->framebuffer_hdr_depth->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); ctx->framebuffer_hdr_depth->set_max_anisotropy(0.0f); ctx->framebuffer_hdr = new gl::framebuffer(viewport_dimensions[0], viewport_dimensions[1]); @@ -467,7 +468,7 @@ void setup_rendering(game_context* ctx) shadow_map_resolution = ctx->config->get("shadow_map_resolution"); } ctx->shadow_map_depth_texture = new gl::texture_2d(shadow_map_resolution, shadow_map_resolution, gl::pixel_type::float_32, gl::pixel_format::d); - ctx->shadow_map_depth_texture->set_wrapping(gl::texture_wrapping::clamp, gl::texture_wrapping::clamp); + ctx->shadow_map_depth_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); ctx->shadow_map_depth_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); ctx->shadow_map_depth_texture->set_max_anisotropy(0.0f); ctx->shadow_map_framebuffer = new gl::framebuffer(shadow_map_resolution, shadow_map_resolution); @@ -477,18 +478,14 @@ void setup_rendering(game_context* ctx) int bloom_width = viewport_dimensions[0] >> 1; int bloom_height = viewport_dimensions[1] >> 1; ctx->bloom_texture = new gl::texture_2d(bloom_width, bloom_height, gl::pixel_type::float_16, gl::pixel_format::rgb); - ctx->bloom_texture->set_wrapping(gl::texture_wrapping::clamp, gl::texture_wrapping::clamp); + ctx->bloom_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); ctx->bloom_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); ctx->bloom_texture->set_max_anisotropy(0.0f); ctx->framebuffer_bloom = new gl::framebuffer(bloom_width, bloom_height); ctx->framebuffer_bloom->attach(gl::framebuffer_attachment_type::color, ctx->bloom_texture); // Load blue noise texture - gl::texture_2d* blue_noise_map = ctx->resource_manager->load("blue-noise.png"); - blue_noise_map->set_wrapping(gl::texture_wrapping::repeat, gl::texture_wrapping::repeat); - blue_noise_map->set_wrapping(gl::texture_wrapping::repeat, gl::texture_wrapping::repeat); - blue_noise_map->set_filters(gl::texture_min_filter::nearest, gl::texture_mag_filter::nearest); - blue_noise_map->set_filters(gl::texture_min_filter::nearest, gl::texture_mag_filter::nearest); + gl::texture_2d* blue_noise_map = ctx->resource_manager->load("blue-noise.tex"); // Load fallback material ctx->fallback_material = ctx->resource_manager->load("fallback.mtl"); @@ -583,21 +580,14 @@ void setup_rendering(game_context* ctx) // Load marker albedo textures ctx->marker_albedo_textures = new gl::texture_2d*[8]; - ctx->marker_albedo_textures[0] = ctx->resource_manager->load("marker-clear-albedo.png"); - ctx->marker_albedo_textures[1] = ctx->resource_manager->load("marker-yellow-albedo.png"); - ctx->marker_albedo_textures[2] = ctx->resource_manager->load("marker-green-albedo.png"); - ctx->marker_albedo_textures[3] = ctx->resource_manager->load("marker-blue-albedo.png"); - ctx->marker_albedo_textures[4] = ctx->resource_manager->load("marker-purple-albedo.png"); - ctx->marker_albedo_textures[5] = ctx->resource_manager->load("marker-pink-albedo.png"); - ctx->marker_albedo_textures[6] = ctx->resource_manager->load("marker-red-albedo.png"); - ctx->marker_albedo_textures[7] = ctx->resource_manager->load("marker-orange-albedo.png"); - for (int i = 0; i < 8; ++i) - { - gl::texture_2d* texture = ctx->marker_albedo_textures[i]; - texture->set_wrapping(gl::texture_wrapping::clamp, gl::texture_wrapping::clamp); - texture->set_filters(gl::texture_min_filter::nearest, gl::texture_mag_filter::nearest); - texture->set_max_anisotropy(0.0f); - } + ctx->marker_albedo_textures[0] = ctx->resource_manager->load("marker-clear-albedo.tex"); + ctx->marker_albedo_textures[1] = ctx->resource_manager->load("marker-yellow-albedo.tex"); + ctx->marker_albedo_textures[2] = ctx->resource_manager->load("marker-green-albedo.tex"); + ctx->marker_albedo_textures[3] = ctx->resource_manager->load("marker-blue-albedo.tex"); + ctx->marker_albedo_textures[4] = ctx->resource_manager->load("marker-purple-albedo.tex"); + ctx->marker_albedo_textures[5] = ctx->resource_manager->load("marker-pink-albedo.tex"); + ctx->marker_albedo_textures[6] = ctx->resource_manager->load("marker-red-albedo.tex"); + ctx->marker_albedo_textures[7] = ctx->resource_manager->load("marker-orange-albedo.tex"); // Create renderer ctx->renderer = new renderer(); @@ -668,7 +658,7 @@ void setup_scenes(game_context* ctx) - const gl::texture_2d* splash_texture = ctx->resource_manager->load("splash.png"); + const gl::texture_2d* splash_texture = ctx->resource_manager->load("splash.tex"); auto splash_dimensions = splash_texture->get_dimensions(); ctx->splash_billboard_material = new material(); ctx->splash_billboard_material->set_shader_program(ctx->resource_manager->load("ui-element-textured.glsl")); diff --git a/src/gl/texture-2d.cpp b/src/gl/texture-2d.cpp index 2979c69..4ab6e6f 100644 --- a/src/gl/texture-2d.cpp +++ b/src/gl/texture-2d.cpp @@ -66,14 +66,14 @@ static constexpr GLenum linear_internal_format_lut[][8] = static constexpr GLenum srgb_internal_format_lut[][8] = { - {GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8}, - {GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8}, - {GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8}, - {GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8}, - {GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8}, - {GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8}, - {GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8}, - {GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8} + {GL_NONE, GL_NONE, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32, GL_NONE, GL_DEPTH_COMPONENT32F}, + {GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH32F_STENCIL8}, + {GL_SRGB8, GL_SRGB8, GL_R16, GL_R16, GL_R32F, GL_R32F, GL_R16F, GL_R32F}, + {GL_SRGB8, GL_SRGB8, GL_RG16, GL_RG16, GL_RG32F, GL_RG32F, GL_RG16F, GL_RG32F}, + {GL_SRGB8, GL_SRGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F}, + {GL_SRGB8, GL_SRGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F}, + {GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F}, + {GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F} }; static constexpr GLint swizzle_mask_lut[][4] = @@ -90,6 +90,7 @@ static constexpr GLint swizzle_mask_lut[][4] = static constexpr GLenum wrapping_lut[] = { + GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT diff --git a/src/gl/texture-wrapping.hpp b/src/gl/texture-wrapping.hpp index f1e6e79..2190a25 100644 --- a/src/gl/texture-wrapping.hpp +++ b/src/gl/texture-wrapping.hpp @@ -24,7 +24,8 @@ namespace gl { enum class texture_wrapping { - clamp, + clip, + extend, repeat, mirrored_repeat }; diff --git a/src/renderer/passes/material-pass.cpp b/src/renderer/passes/material-pass.cpp index 5509dac..a87e1f6 100644 --- a/src/renderer/passes/material-pass.cpp +++ b/src/renderer/passes/material-pass.cpp @@ -62,9 +62,7 @@ material_pass::material_pass(gl::rasterizer* rasterizer, const gl::framebuffer* shadow_map(nullptr), shadow_strength(1.0f) { - soft_shadows_texture = resource_manager->load("tree-shadow.png"); - soft_shadows_texture->set_wrapping(gl::texture_wrapping::clamp, gl::texture_wrapping::clamp); - soft_shadows_texture->set_filters(gl::texture_min_filter::linear_mipmap_linear, gl::texture_mag_filter::linear); + soft_shadows_texture = resource_manager->load("forest-gobo.tex"); max_ambient_light_count = MATERIAL_PASS_MAX_AMBIENT_LIGHT_COUNT; max_point_light_count = MATERIAL_PASS_MAX_POINT_LIGHT_COUNT; diff --git a/src/resources/biome-loader.cpp b/src/resources/biome-loader.cpp index b8d6a1f..899223a 100644 --- a/src/resources/biome-loader.cpp +++ b/src/resources/biome-loader.cpp @@ -44,7 +44,7 @@ static bool load_array(T* value, std::size_t size, const nlohmann::json& json, c std::size_t i = 0; for (auto it = element.value().cbegin(); (it != element.value().cend()) && (i < size); ++it) { - *(value++) = it.value().get(); + *(value++) = it.value().get(); ++i; } diff --git a/src/resources/material-loader.cpp b/src/resources/material-loader.cpp index da68acf..16a816a 100644 --- a/src/resources/material-loader.cpp +++ b/src/resources/material-loader.cpp @@ -30,29 +30,6 @@ #include #include -static const std::map texture_wrapping_map = -{ - {"clamp", gl::texture_wrapping::clamp}, - {"repeat", gl::texture_wrapping::repeat}, - {"mirrored_repeat", gl::texture_wrapping::mirrored_repeat}, -}; - -static const std::map texture_min_filter_map = -{ - {"nearest", gl::texture_min_filter::nearest}, - {"linear", gl::texture_min_filter::linear}, - {"nearest_mipmap_nearest", gl::texture_min_filter::nearest_mipmap_nearest}, - {"linear_mipmap_nearest", gl::texture_min_filter::linear_mipmap_nearest}, - {"nearest_mipmap_linear", gl::texture_min_filter::nearest_mipmap_linear}, - {"linear_mipmap_linear", gl::texture_min_filter::linear_mipmap_linear} -}; - -static const std::map texture_mag_filter_map = -{ - {"nearest", gl::texture_mag_filter::nearest}, - {"linear", gl::texture_mag_filter::linear}, -}; - static bool load_bool_property(material* material, const string_table_row& row, int vector_size, int array_size) { if (row.size() - 4 != vector_size * array_size || vector_size < 1 || vector_size > 4) @@ -252,7 +229,7 @@ static bool load_float_matrix_property(material* material, const string_table_ro static bool load_texture_2d_property(material* material, const string_table_row& row, resource_manager* resource_manager, int array_size) { - if (row.size() - 4 != array_size * 6) + if (row.size() - 4 != array_size * 1) { return false; } @@ -260,37 +237,7 @@ static bool load_texture_2d_property(material* material, const string_table_row& const gl::texture_2d** values = new const gl::texture_2d*[array_size]; for (std::size_t i = 0; i < array_size; ++i) { - std::size_t offset = 4 + i; - - const std::string& filename = row[offset]; - gl::texture_wrapping wrap_s = gl::texture_wrapping::clamp; - gl::texture_wrapping wrap_t = gl::texture_wrapping::clamp; - gl::texture_min_filter min_filter = gl::texture_min_filter::linear_mipmap_linear; - gl::texture_mag_filter mag_filter = gl::texture_mag_filter::linear; - if (auto it = texture_wrapping_map.find(row[offset + 1]); it != texture_wrapping_map.end()) - { - wrap_s = it->second; - } - if (auto it = texture_wrapping_map.find(row[offset + 2]); it != texture_wrapping_map.end()) - { - wrap_t = it->second; - } - if (auto it = texture_min_filter_map.find(row[offset + 3]); it != texture_min_filter_map.end()) - { - min_filter = it->second; - } - if (auto it = texture_mag_filter_map.find(row[offset + 4]); it != texture_mag_filter_map.end()) - { - mag_filter = it->second; - } - float max_anisotropy = static_cast(std::stod(row[offset + 5])); - - gl::texture_2d* texture = resource_manager->load(row[4 + i]); - texture->set_wrapping(wrap_s, wrap_t); - texture->set_filters(min_filter, mag_filter); - texture->set_max_anisotropy(max_anisotropy); - - values[i] = texture; + values[i] = resource_manager->load(row[4 + i]); } material_property* property = material->add_property(row[1], array_size); diff --git a/src/resources/texture-2d-loader.cpp b/src/resources/texture-2d-loader.cpp deleted file mode 100644 index b331a7d..0000000 --- a/src/resources/texture-2d-loader.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2021 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Antkeeper source code. If not, see . - */ - -#include "resources/resource-loader.hpp" -#include "resources/image.hpp" -#include "gl/pixel-type.hpp" -#include "gl/pixel-format.hpp" -#include "gl/texture-2d.hpp" -#include - -template <> -gl::texture_2d* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file) -{ - // Load image - ::image* image = resource_loader<::image>::load(resource_manager, file); - - // Determine pixel type - gl::pixel_type type = (image->is_hdr()) ? gl::pixel_type::float_32 : gl::pixel_type::uint_8; - - // Determine pixel format - gl::pixel_format format; - if (image->get_channels() == 1) - { - format = gl::pixel_format::r; - } - else if (image->get_channels() == 2) - { - format = gl::pixel_format::rg; - } - else if (image->get_channels() == 3) - { - format = gl::pixel_format::rgb; - } - else if (image->get_channels() == 4) - { - format = gl::pixel_format::rgba; - } - else - { - std::stringstream stream; - stream << std::string("Texture cannot be created from an image with an unsupported number of color channels (") << image->get_channels() << std::string(")."); - delete image; - throw std::runtime_error(stream.str().c_str()); - } - - // Assume linear color space - gl::color_space color_space = gl::color_space::linear; - - // Create texture - gl::texture_2d* texture = new gl::texture_2d(image->get_width(), image->get_height(), type, format, color_space, image->get_pixels()); - - // Free loaded image - delete image; - - return texture; -} diff --git a/src/resources/texture-loader.cpp b/src/resources/texture-loader.cpp new file mode 100644 index 0000000..541262c --- /dev/null +++ b/src/resources/texture-loader.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2021 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#include "resources/resource-loader.hpp" +#include "resources/resource-manager.hpp" +#include "resources/image.hpp" +#include "gl/pixel-type.hpp" +#include "gl/pixel-format.hpp" +#include "gl/color-space.hpp" +#include "gl/texture-2d.hpp" +#include "gl/texture-wrapping.hpp" +#include "gl/texture-filter.hpp" +#include +#include +#include + +template <> +gl::texture_2d* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file) +{ + // Read file into buffer + std::size_t size = static_cast(PHYSFS_fileLength(file)); + std::string buffer; + buffer.resize(size); + PHYSFS_readBytes(file, &buffer[0], size); + + // Parse json from file buffer + nlohmann::json json = nlohmann::json::parse(buffer); + + // Read image filename + std::string image_filename; + if (auto element = json.find("image"); element != json.end()) + image_filename = element.value().get(); + + // Read color space + gl::color_space color_space = gl::color_space::linear; + if (auto element = json.find("color_space"); element != json.end()) + { + std::string value = element.value().get(); + if (value == "linear") + color_space = gl::color_space::linear; + else if (value == "srgb") + color_space = gl::color_space::srgb; + } + + // Read extension mode + gl::texture_wrapping wrapping = gl::texture_wrapping::repeat; + if (auto element = json.find("extension"); element != json.end()) + { + std::string value = element.value().get(); + if (value == "clip") + wrapping = gl::texture_wrapping::clip; + else if (value == "extend") + wrapping = gl::texture_wrapping::extend; + else if (value == "repeat") + wrapping = gl::texture_wrapping::repeat; + else if (value == "mirrored_repeat") + wrapping = gl::texture_wrapping::mirrored_repeat; + } + + // Read interpolation mode + gl::texture_min_filter min_filter = gl::texture_min_filter::linear_mipmap_linear; + gl::texture_mag_filter mag_filter = gl::texture_mag_filter::linear; + if (auto element = json.find("interpolation"); element != json.end()) + { + std::string value = element.value().get(); + if (value == "linear") + { + min_filter = gl::texture_min_filter::linear_mipmap_linear; + mag_filter = gl::texture_mag_filter::linear; + } + else if (value == "closest") + { + min_filter = gl::texture_min_filter::nearest_mipmap_nearest; + mag_filter = gl::texture_mag_filter::nearest; + } + } + + // Read max anisotropy + float max_anisotropy = 0.0f; + if (auto element = json.find("max_anisotropy"); element != json.end()) + max_anisotropy = element.value().get(); + + // Load image + ::image* image = resource_manager->load<::image>(image_filename); + + // Determine pixel type + gl::pixel_type type = (image->is_hdr()) ? gl::pixel_type::float_32 : gl::pixel_type::uint_8; + + // Determine pixel format + gl::pixel_format format; + if (image->get_channels() == 1) + { + format = gl::pixel_format::r; + } + else if (image->get_channels() == 2) + { + format = gl::pixel_format::rg; + } + else if (image->get_channels() == 3) + { + format = gl::pixel_format::rgb; + } + else if (image->get_channels() == 4) + { + format = gl::pixel_format::rgba; + } + else + { + std::stringstream stream; + stream << std::string("Texture cannot be created from an image with an unsupported number of color channels (") << image->get_channels() << std::string(")."); + delete image; + throw std::runtime_error(stream.str().c_str()); + } + + // Create texture + gl::texture_2d* texture = new gl::texture_2d(image->get_width(), image->get_height(), type, format, color_space, image->get_pixels()); + + // Set wrapping and filtering + texture->set_wrapping(wrapping, wrapping); + texture->set_filters(min_filter, mag_filter); + texture->set_max_anisotropy(max_anisotropy); + + // Free loaded image + resource_manager->unload(image_filename); + + return texture; +}