Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ set_packages(
flecs

tinyobjloader
fastgltf
${SHADERC_PACKAGE}
watcher
vulkan-cpp
Expand All @@ -108,6 +109,7 @@ set_packages(
stb::stb
flecs::flecs_static
tinyobjloader::tinyobjloader
fastgltf::fastgltf
${SHADERC_LINK_PACKAGE}
watcher::watcher
vulkan-cpp
Expand Down Expand Up @@ -208,9 +210,10 @@ target_sources(${PROJECT_NAME} PUBLIC
atlas/drivers/vulkan/hash.cppm


# 3D Model Importers
# 3D Model File Format Importers
atlas/drivers/importer/importer.cppm
atlas/drivers/importer/obj_loader.cppm
atlas/drivers/importer/gltf_importer.cppm
)

target_sources(${PROJECT_NAME} PUBLIC
Expand Down
8 changes: 4 additions & 4 deletions atlas/core/application.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ module;

#include <cstdint>
#include <string>
#include <print>
#include <chrono>
#include <utility>

Expand Down Expand Up @@ -150,7 +149,6 @@ export namespace atlas {
m_color_format,
m_depth_format,
m_window_params);
std::println("images.size() = {}", images.size());

m_window->center_window();

Expand Down Expand Up @@ -418,14 +416,15 @@ export namespace atlas {

invoke_post_update(m_current_scene.get());
invoke_post_update(m_world.get());

m_next_image_frame_idx =
(m_next_image_frame_idx + 1) % m_frames_in_flight;
}

// Experimental: Will look into later once we dive into scene
// transitioning void on_scene_transition(event::scene_transition&
// p_scene_transition) {
// m_world->current(p_scene_transition.next_scene);
// std::println("Attempting to switch to the scene: {}",
// p_scene_transition.next_scene);

// // We only want to set the current scene if that specific scene
// is valid if(m_world->current() != nullptr) {
Expand Down Expand Up @@ -484,6 +483,7 @@ export namespace atlas {
std::vector<vk::command_buffer> m_command_buffers;
float m_delta_time = 0.f;
window_params m_window_params{};
uint32_t m_frames_in_flight = 2;
static application* s_instance;
};

Expand Down
19 changes: 10 additions & 9 deletions atlas/core/entry_point/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#include <GLFW/glfw3.h>
#include <memory_resource>
#include <memory>
#include <print>
#include <vector>
#include <expected>

Expand Down Expand Up @@ -30,12 +29,11 @@ import vk;
atlas::event::bus& p_bus);

static VKAPI_ATTR VkBool32 VKAPI_CALL
debug_callback(
[[maybe_unused]] VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity,
[[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT p_message_type,
const VkDebugUtilsMessengerCallbackDataEXT* p_callback_data,
[[maybe_unused]] void* p_user_data) {
std::print("validation layer:\t\t{}\n\n", p_callback_data->pMessage);
debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT,
VkDebugUtilsMessageTypeFlagsEXT,
const VkDebugUtilsMessengerCallbackDataEXT* p_callback_data,
void*) {
console_log_info_tagged("vk::validation", "{}", p_callback_data->pMessage);
return false;
}

Expand All @@ -47,7 +45,7 @@ get_instance_extensions() {
glfwGetRequiredInstanceExtensions(&extension_count);

for (uint32_t i = 0; i < extension_count; i++) {
std::println("Required Extension = {}", required_extensions[i]);
console_log_info("Required Extension = {}", required_extensions[i]);
extension_names.emplace_back(required_extensions[i]);
}

Expand All @@ -73,7 +71,7 @@ main() {
}

if (!glfwVulkanSupported()) {
std::println("GLFW: Vulkan is not supported!");
console_log_error("GLFW: Vulkan is not supported!");
return -1;
}

Expand Down Expand Up @@ -114,6 +112,9 @@ main() {
vk::physical_device physical_device = physical_device_expected.value();

std::array<float, 1> priorities = { 0.f };

// VK_KHR_dynamic_rendering is required to be explicitly specified in the
// extensions to prevent imgui from crashing.
#if defined(__APPLE__)
std::array<const char*, 3> extensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
Expand Down
7 changes: 5 additions & 2 deletions atlas/core/logger.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ module;
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <memory>
#include <print>

export module atlas.core.utilities:logger;
import :common;
Expand All @@ -24,13 +23,14 @@ export namespace atlas {
public:
console_log_manager(
const std::string& p_pattern = "%^[%n] [%T]: %v%$") {
std::println("Constructing console_log_manager!");

//! @note Setting up logs for different log stdout's
//! @note Logs for p_tag is logs specific to the game.
m_loggers.insert({ "atlas", spdlog::stdout_color_mt("atlas") });
m_loggers.insert({ "physics", spdlog::stdout_color_mt("physics") });
m_loggers.insert({ "vulkan", spdlog::stdout_color_mt("vulkan") });
m_loggers.insert(
{ "vk::validation", spdlog::stdout_color_mt("vk::validation") });
m_loggers.insert(
{ "assert", spdlog::stdout_color_mt("core assertion") });

Expand All @@ -45,6 +45,9 @@ export namespace atlas {

m_loggers["assert"]->set_level(spdlog::level::trace);
m_loggers["assert"]->set_pattern(p_pattern);

m_loggers["vk::validation"]->set_level(spdlog::level::trace);
m_loggers["vk::validation"]->set_pattern(p_pattern);
s_instance = this;
}

Expand Down
4 changes: 2 additions & 2 deletions atlas/core/serialize/serializer.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ module;
#include <sstream>
#include <glm/glm.hpp>
#include <fstream>
#include <print>

export module atlas.core.serialize;

Expand Down Expand Up @@ -208,7 +207,8 @@ namespace atlas {
.build();

q.each([&output](flecs::entity p_entity) {
std::println("Serialize Entity: {}", p_entity.name().c_str());
console_log_error("Serialize Entity: {}",
p_entity.name().c_str());
serialize_entity(output, p_entity);
});

Expand Down
213 changes: 213 additions & 0 deletions atlas/drivers/importer/gltf_importer.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
module;

#include <string>
#include <format>

#include <glm/glm.hpp>

#include <fastgltf/core.hpp>
#include <fastgltf/math.hpp>
#include <fastgltf/tools.hpp>
#include <fastgltf/types.hpp>
#include <fastgltf/glm_element_traits.hpp>

export module atlas.drivers.importer:gltf_importer;

import atlas.core.utilities;
import vk;

namespace atlas {
export class gltf_importer {
public:
gltf_importer(const std::string& p_path, bool p_flip)
: m_flip(p_flip) {
m_load_successful = load(p_path);
}

bool load(const std::string& p_path) {
if (!std::filesystem::exists(p_path)) {
console_log_error("GLTF Error: Path does not exist: {}",
p_path);
return false;
}

size_t base_color_uv_index = 0;

// Create the Parser configuration (enable SIMD parsing if
// available)
fastgltf::Parser parser(fastgltf::Extensions::None);

// 2. Map buffers directly without copying them into memory
// prematurely
constexpr auto gltf_options =
fastgltf::Options::DontRequireValidAssetMember |
fastgltf::Options::LoadExternalBuffers;

std::filesystem::path filepath = std::filesystem::path(p_path);

auto data = fastgltf::GltfDataBuffer::FromPath(filepath);
if (data.error() != fastgltf::Error::None) {
console_log_error("GLTF Error: Failed to load data buffer.");
console_log_info("GLTF Error Message: {}",
fastgltf::getErrorMessage(data.error()));
m_load_successful = false;
return m_load_successful;
}

auto asset =
parser.loadGltf(data.get(), filepath.parent_path(), gltf_options);
if (asset.error() != fastgltf::Error::None) {
console_log_error("GLTF Error: Parsing failed with code {}",
static_cast<size_t>(asset.error()));
console_log_info("GLTF Error Message: {}",
fastgltf::getErrorMessage(asset.error()));
m_load_successful = false;
return m_load_successful;
}

fastgltf::Asset& model = asset.get();

// Position
for (const auto& mesh : model.meshes) {
for (const auto& primitive : mesh.primitives) {

// Get output primitive mesh texture color index
// (base_color_uv_index)
auto* primitive_mesh = primitive.findAttribute("POSITION");

if (primitive.materialIndex.has_value()) {
auto& material =
model.materials[primitive.materialIndex.value()];

auto& base_color_texture =
material.pbrData.baseColorTexture;

if (base_color_texture.has_value()) {
auto& texture =
model.textures[base_color_texture->textureIndex];

if (!texture.imageIndex.has_value()) {
return false;
}

if (base_color_texture->transform and
base_color_texture->transform->texCoordIndex
.has_value()) {
base_color_uv_index =
base_color_texture->transform->texCoordIndex
.value();
}
else {
base_color_uv_index =
material.pbrData.baseColorTexture
->texCoordIndex;
}
}
}

// Required to have a primitive that contains the meshes
// position
if (primitive_mesh == primitive.attributes.end()) {
m_load_successful = false;
return m_load_successful;
}

// Required to have indices associated with the mesh
if (!primitive.indicesAccessor.value()) {
m_load_successful = false;
return m_load_successful;
}

auto& position_accessor =
model.accessors[primitive_mesh->accessorIndex];

if (!position_accessor.bufferViewIndex.value()) {
m_load_successful = false;
return m_load_successful;
}

const auto& pos_accessor =
model.accessors[primitive_mesh->accessorIndex];
uint32_t base_vertex =
static_cast<uint32_t>(m_vertices.size());
m_vertices.reserve(base_vertex + pos_accessor.count);

// Check if this 3D model as texture coordinates or normals
auto uv_attribute = primitive.findAttribute(
std::format("TEXCOORD_{}", base_color_uv_index));
bool has_uv = (uv_attribute != primitive.attributes.end());

auto normal_attribute = primitive.findAttribute("NORMAL");
bool has_normals =
(normal_attribute != primitive.attributes.end());

fastgltf::iterateAccessorWithIndex<fastgltf::math::fvec3>(
model,
position_accessor,
[&](fastgltf::math::fvec3 pos, size_t index) {
vk::vertex_input vertex{};
vertex.position = { pos.x(), pos.y(), pos.z() };

if (has_normals) {
const auto& normal_accessor =
model
.accessors[normal_attribute->accessorIndex];

fastgltf::math::fvec3 norm =
fastgltf::getAccessorElement<
fastgltf::math::fvec3>(
model, normal_accessor, index);
vertex.normals = { norm.x(), norm.y(), norm.z() };
}

if (has_uv) {
const auto& uv_accessor =
model.accessors[uv_attribute->accessorIndex];

// Extract 2D texture coordinate element matching
// based from the current primitive index
glm::vec2 uv =
fastgltf::getAccessorElement<glm::vec2>(
model, uv_accessor, index);

glm::vec2 flipped_uv = { uv.x, 1.0f - uv.y };
vertex.uv = m_flip ? flipped_uv : uv;
}

m_vertices.push_back(vertex);
});

// Indices
if (primitive.indicesAccessor.has_value()) {
const auto& index_accessor =
model.accessors[primitive.indicesAccessor.value()];
m_indices.reserve(m_indices.size() +
index_accessor.count);

fastgltf::iterateAccessor<uint32_t>(
model, index_accessor, [&](uint32_t index) {
m_indices.push_back(base_vertex + index);
});
}
}
}

m_load_successful = true;
return m_load_successful;
}

[[nodiscard]] bool load() const { return m_load_successful; }

//! @return the geometry vertices
std::span<vk::vertex_input> vertices() { return m_vertices; }

//! @return the geometry indices
std::span<uint32_t> indices() { return m_indices; }

private:
std::vector<vk::vertex_input> m_vertices;
std::vector<uint32_t> m_indices;
bool m_load_successful = false;
bool m_flip = false;
};
};
3 changes: 2 additions & 1 deletion atlas/drivers/importer/importer.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ module;
export module atlas.drivers.importer;

// Importers to load .obj 3D models
export import :obj_loader;
export import :obj_loader;
export import :gltf_importer;
Loading
Loading