Skip to content

Commit

Permalink
Fix #34: Support fallback buffers from EXT_meshopt_compression
Browse files Browse the repository at this point in the history
Also avoids parsing requiredExtensions twice, and fixes some warnings in gl_viewer
  • Loading branch information
spnda committed Nov 4, 2023
1 parent d2e8a52 commit 565c0a5
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 27 deletions.
36 changes: 20 additions & 16 deletions examples/gl_viewer/gl_viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
*/

#include <chrono>
#include <fstream>
#include <iostream>

#include <glad/gl.h>
Expand Down Expand Up @@ -91,9 +90,9 @@ constexpr std::string_view fragmentShaderSource = R"(

void glMessageCallback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam) {
if (severity == GL_DEBUG_SEVERITY_HIGH) {
std::cerr << message << std::endl;
std::cerr << message << '\n';
} else {
std::cout << message << std::endl;
std::cout << message << '\n';
}
}

Expand All @@ -106,7 +105,7 @@ bool checkGlCompileErrors(GLuint shader) {
if (success != GL_TRUE) {
glGetShaderInfoLog(shader, length, nullptr, log.data());
std::cout << "Shader compilation error: " << "\n"
<< log << "\n -- --------------------------------------------------- -- " << std::endl;
<< log << "\n -- --------------------------------------------------- -- " << '\n';
return false;
}
return true;
Expand All @@ -121,7 +120,7 @@ bool checkGlLinkErrors(GLuint target) {
if (success != GL_TRUE) {
glGetShaderInfoLog(target, length, nullptr, log.data());
std::cout << "Shader program linking error: " << "\n"
<< log << "\n -- --------------------------------------------------- -- " << std::endl;
<< log << "\n -- --------------------------------------------------- -- " << '\n';
return false;
}
return true;
Expand Down Expand Up @@ -282,7 +281,12 @@ glm::mat4 getTransformMatrix(const fastgltf::Node& node, glm::mat4x4& base) {
}

bool loadGltf(Viewer* viewer, std::string_view cPath) {
std::cout << "Loading " << cPath << std::endl;
if (!std::filesystem::exists(cPath)) {
std::cout << "Failed to find " << cPath << '\n';
return false;
}

std::cout << "Loading " << cPath << '\n';

// Parse the glTF file and get the constructed asset
{
Expand All @@ -308,12 +312,12 @@ bool loadGltf(Viewer* viewer, std::string_view cPath) {
} else if (type == fastgltf::GltfType::GLB) {
asset = parser.loadBinaryGLTF(&data, path.parent_path(), gltfOptions);
} else {
std::cerr << "Failed to determine glTF container" << std::endl;
std::cerr << "Failed to determine glTF container" << '\n';
return false;
}

if (asset.error() != fastgltf::Error::None) {
std::cerr << "Failed to load glTF: " << fastgltf::getErrorMessage(asset.error()) << std::endl;
std::cerr << "Failed to load glTF: " << fastgltf::getErrorMessage(asset.error()) << '\n';
return false;
}

Expand Down Expand Up @@ -565,14 +569,14 @@ void drawNode(Viewer* viewer, size_t nodeIndex, glm::mat4 matrix) {

int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "No gltf file specified." << std::endl;
std::cerr << "No gltf file specified." << '\n';
return -1;
}
auto gltfFile = std::string_view { argv[1] };
Viewer viewer;

if (glfwInit() != GLFW_TRUE) {
std::cerr << "Failed to initialize glfw." << std::endl;
std::cerr << "Failed to initialize glfw." << '\n';
return -1;
}

Expand All @@ -583,7 +587,7 @@ int main(int argc, char* argv[]) {

GLFWwindow* window = glfwCreateWindow(static_cast<int>(static_cast<float>(vidMode->width) * 0.9f), static_cast<int>(static_cast<float>(vidMode->height) * 0.9f), "gl_viewer", nullptr, nullptr);
if (window == nullptr) {
std::cerr << "Failed to create window" << std::endl;
std::cerr << "Failed to create window" << '\n';
return -1;
}
glfwSetWindowUserPointer(window, &viewer);
Expand All @@ -596,16 +600,16 @@ int main(int argc, char* argv[]) {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

if (!gladLoadGL(glfwGetProcAddress)) {
std::cerr << "Failed to initialize OpenGL context." << std::endl;
std::cerr << "Failed to initialize OpenGL context." << '\n';
return -1;
}

const auto *glRenderer = glGetString(GL_RENDERER);
const auto *glVersion = glGetString(GL_VERSION);
std::cout << "GL Renderer: " << glRenderer << "\nGL Version: " << glVersion << std::endl;
std::cout << "GL Renderer: " << glRenderer << "\nGL Version: " << glVersion << '\n';

if (GLAD_GL_VERSION_4_6 != 1) {
std::cerr << "Missing support for GL 4.6" << std::endl;
std::cerr << "Missing support for GL 4.6" << '\n';
return -1;
}

Expand Down Expand Up @@ -647,7 +651,7 @@ int main(int argc, char* argv[]) {
// Load the glTF file
auto start = std::chrono::high_resolution_clock::now();
if (!loadGltf(&viewer, gltfFile)) {
std::cerr << "Failed to parse glTF" << std::endl;
std::cerr << "Failed to parse glTF" << '\n';
return -1;
}

Expand All @@ -669,7 +673,7 @@ int main(int argc, char* argv[]) {
loadMesh(&viewer, mesh);
}
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
std::cout << "Loaded glTF file in " << diff.count() << "ms." << std::endl;
std::cout << "Loaded glTF file in " << diff.count() << "ms." << '\n';

// Create the material uniform buffer
viewer.materialBuffers.resize(viewer.materials.size(), GL_NONE);
Expand Down
4 changes: 3 additions & 1 deletion include/fastgltf/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,8 @@ namespace fastgltf {
span<const std::byte> bytes;
MimeType mimeType;
};

struct Fallback {};
} // namespace sources

/**
Expand All @@ -1247,7 +1249,7 @@ namespace fastgltf {
*
* @note For buffers, this variant will never hold a sources::BufferView, as only images are able to reference buffer views as a source.
*/
using DataSource = std::variant<std::monostate, sources::BufferView, sources::URI, sources::Vector, sources::CustomBuffer, sources::ByteView>;
using DataSource = std::variant<std::monostate, sources::BufferView, sources::URI, sources::Vector, sources::CustomBuffer, sources::ByteView, sources::Fallback>;

struct AnimationChannel {
std::size_t samplerIndex;
Expand Down
31 changes: 21 additions & 10 deletions src/fastgltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,9 @@ fg::Expected<fg::Asset> fg::Parser::parse(simdjson::dom::object root, Category c
if (!known) {
return Expected<Asset>(Error::UnknownRequiredExtension);
}

FASTGLTF_STD_PMR_NS::string FASTGLTF_CONSTRUCT_PMR_RESOURCE(requiredExtension, resourceAllocator.get(), string);
asset.extensionsRequired.emplace_back(std::move(requiredExtension));
}
}

Expand Down Expand Up @@ -1187,15 +1190,7 @@ fg::Expected<fg::Asset> fg::Parser::parse(simdjson::dom::object root, Category c
break;
}
case force_consteval<crc32c("extensionsRequired")>: {
for (auto requiredValue : array) {
std::string_view requiredString;
if (auto eError = requiredValue.get_string().get(requiredString); eError == SUCCESS) {
FASTGLTF_STD_PMR_NS::string FASTGLTF_CONSTRUCT_PMR_RESOURCE(string, resourceAllocator.get(), requiredString);
asset.extensionsRequired.emplace_back(std::move(string));
} else {
error = Error::InvalidGltf;
}
}
// These are already parsed before this section.
break;
}
default:
Expand Down Expand Up @@ -1558,6 +1553,19 @@ fg::Error fg::Parser::parseBuffers(simdjson::dom::array& buffers, Asset& asset)
}
buffer.byteLength = static_cast<std::size_t>(byteLength);

// The spec for EXT_meshopt_compression allows so-called 'fallback buffers' which only exist to
// act as a valid fallback for compressed buffer views, but actually do not contain any data.
// In these cases, there is either simply no URI, or a fallback boolean is added to the extensions'
// extension field.
// In these cases, fastgltf could just leave the std::monostate in the DataSource.
// However, to make the actual use of these buffers clear, we'll use an empty fallback type.
bool meshoptCompressionRequired = false;
for (const auto& extension : asset.extensionsRequired) {
if (extension == extensions::EXT_meshopt_compression) {
meshoptCompressionRequired = true;
}
}

// When parsing GLB, there's a buffer object that will point to the BUF chunk in the
// file. Otherwise, data must be specified in the "uri" field.
std::string_view uriString;
Expand Down Expand Up @@ -1590,7 +1598,10 @@ fg::Error fg::Parser::parseBuffers(simdjson::dom::array& buffers, Asset& asset)
}
} else if (bufferIndex == 0 && !std::holds_alternative<std::monostate>(glbBuffer)) {
buffer.data = std::move(glbBuffer);
} else {
} else if (meshoptCompressionRequired) {
// This buffer is not a GLB buffer and has no URI source and is therefore a fallback.
buffer.data = sources::Fallback();
} else {
// All other buffers have to contain an uri field.
return Error::InvalidGltf;
}
Expand Down

0 comments on commit 565c0a5

Please sign in to comment.