Skip to content

Commit

Permalink
Bring tinygltf in as a dependency
Browse files Browse the repository at this point in the history
It vendors the header and does a minimal smoke test in RenderEngineGl's
unit tests.

In addition to vendoring:
  - we redirect tinygltf to use Drake's vendored  json library.
  - We change the callback declaration from a C-style function pointer
    to a std::function to allow a callback with captures.
  • Loading branch information
SeanCurtis-TRI committed Jun 6, 2024
1 parent dbc6210 commit a2b8df8
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 0 deletions.
1 change: 1 addition & 0 deletions geometry/render_gl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ drake_cc_googletest_linux_only(
"//common/test_utilities:expect_throws_message",
"//geometry/render:render_label",
"@gflags",
"@tinygltf_internal//:tinygltf",
"@vtk_internal//:vtkCommonCore",
"@vtk_internal//:vtkCommonDataModel",
"@vtk_internal//:vtkIOImage",
Expand Down
24 changes: 24 additions & 0 deletions geometry/render_gl/test/internal_render_engine_gl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <tiny_gltf.h>

// To ease build system upkeep, we annotate VTK includes with their deps.
#include <vtkImageData.h> // vtkCommonDataModel
Expand Down Expand Up @@ -204,6 +205,29 @@ ::testing::AssertionResult CompareColor(
<< "\n Found: " << tested << "\n with tolerance: " << tolerance;
}

// Because we haven't bothered with tinygltf's stb_image dependency we're
// obliged to provide our own load image callback. In this case, we provide a
// no-op callback just to show that things work.
bool LocalGltfLoadImage(tinygltf::Image*, const int, std::string*, std::string*,
int, int, const unsigned char*, int, void*) {
return true;
}

// Simply confirm that we can use tinygltf to load a gltf file.
GTEST_TEST(TinyGltf, SmokeTest) {
tinygltf::Model model;
tinygltf::TinyGLTF loader;
loader.SetImageLoader(LocalGltfLoadImage, nullptr);

const std::string path = FindResourceOrThrow(
"drake/geometry/render/test/meshes/fully_textured_pyramid.gltf");
const bool ret = loader.LoadASCIIFromFile(&model, nullptr /* err */,
nullptr /* warn */, path);

ASSERT_TRUE(ret);
ASSERT_EQ(model.nodes.size(), 1);
}

class RenderEngineGlTest : public ::testing::Test {
public:
RenderEngineGlTest()
Expand Down
2 changes: 2 additions & 0 deletions tools/workspace/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ drake_py_binary(
"@nlopt_internal//:__subpackages__",
"@qhull_internal//:__subpackages__",
"@sdformat_internal//:__subpackages__",
"@tinygltf_internal//:__subpackages__",
"@tinyobjloader_internal//:__subpackages__",
"@yaml_cpp_internal//:__subpackages__",
],
Expand Down Expand Up @@ -108,6 +109,7 @@ _DRAKE_EXTERNAL_PACKAGE_INSTALLS = ["@%s//:install" % p for p in [
"statsjs",
"stduuid_internal",
"suitesparse_internal",
"tinygltf_internal",
"tinyobjloader_internal",
"tinyxml2_internal",
"usockets_internal",
Expand Down
3 changes: 3 additions & 0 deletions tools/workspace/default.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ load("//tools/workspace/stduuid_internal:repository.bzl", "stduuid_internal_repo
load("//tools/workspace/styleguide:repository.bzl", "styleguide_repository")
load("//tools/workspace/suitesparse_internal:repository.bzl", "suitesparse_internal_repository") # noqa
load("//tools/workspace/sympy_py_internal:repository.bzl", "sympy_py_internal_repository") # noqa
load("//tools/workspace/tinygltf_internal:repository.bzl", "tinygltf_internal_repository") # noqa
load("//tools/workspace/tinyobjloader_internal:repository.bzl", "tinyobjloader_internal_repository") # noqa
load("//tools/workspace/tinyxml2_internal:repository.bzl", "tinyxml2_internal_repository") # noqa
load("//tools/workspace/tomli_internal:repository.bzl", "tomli_internal_repository") # noqa
Expand Down Expand Up @@ -292,6 +293,8 @@ def add_default_repositories(excludes = [], mirrors = DEFAULT_MIRRORS):
suitesparse_internal_repository(name = "suitesparse_internal", mirrors = mirrors) # noqa
if "sympy_py_internal" not in excludes:
sympy_py_internal_repository(name = "sympy_py_internal", mirrors = mirrors) # noqa
if "tinygltf_internal" not in excludes:
tinygltf_internal_repository(name = "tinygltf_internal", mirrors = mirrors) # noqa
if "tinyobjloader_internal" not in excludes:
tinyobjloader_internal_repository(name = "tinyobjloader_internal", mirrors = mirrors) # noqa
if "tinyxml2_internal" not in excludes:
Expand Down
6 changes: 6 additions & 0 deletions tools/workspace/tinygltf_internal/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This file exists to make our directory into a Bazel package, so that our
# neighboring *.bzl file can be loaded elsewhere.

load("//tools/lint:lint.bzl", "add_lint_tests")

add_lint_tests()
37 changes: 37 additions & 0 deletions tools/workspace/tinygltf_internal/package.BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# -*- bazel -*-

load("@drake//tools/install:install.bzl", "install")
load("@drake//tools/workspace:vendor_cxx.bzl", "cc_library_vendored")

licenses(["notice"]) # MIT

package(
default_visibility = ["//visibility:public"],
)

cc_library_vendored(
name = "tinygltf",
srcs = ["tiny_gltf.cc"],
srcs_vendored = ["drake_vendor/tiny_gltf.cc"],
hdrs = ["tiny_gltf.h"],
hdrs_vendored = ["drake_vendor/tiny_gltf.h"],
defines = [
# Don't bother reading external images during glTF parsing; we'll
# handle while processing the resulting RenderMaterial.
"TINYGLTF_NO_EXTERNAL_IMAGE",
# We also won't use tinygltf to decode embedded images; we'll process
# the bytes in Drake.
"TINYGLTF_NO_STB_IMAGE",
"TINYGLTF_NO_STB_IMAGE_WRITE",
],
includes = ["drake_vendor"],
linkstatic = 1,
deps = [
"@nlohmann_internal//:nlohmann",
],
)

install(
name = "install",
docs = ["LICENSE"],
)
77 changes: 77 additions & 0 deletions tools/workspace/tinygltf_internal/patches/function_pointer.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
Replaces the typedef of a function pointer (for the image loading callback)
with the equivalent std::function alias.

This doesn't bind *all* function pointer typedefs, just the ones that Drake
cares about right now. We've submitted a PR to tinygltf upgrading all such
callbacks and can eliminate this patch when our upstream version adopts it and
releases a new version. See https://github.com/syoyo/tinygltf/pull/489.

--- tiny_gltf.h
+++ tiny_gltf.h
@@ -43,6 +43,7 @@
#include <cstdint>
#include <cstdlib>
#include <cstring>
+#include <functional>
#include <limits>
#include <map>
#include <string>
@@ -1292,10 +1293,9 @@ struct URICallbacks {
///
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
///
-typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
- std::string *, int, int,
- const unsigned char *, int,
- void *user_pointer);
+using LoadImageDataFunction =
+ std::function<bool(Image *, const int, std::string *, std::string *, int,
+ int, const unsigned char *, int, void *)>;

///
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
@@ -4218,7 +4218,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
bool store_original_json_for_extras_and_extensions,
const std::string &basedir, const size_t max_file_size,
FsCallbacks *fs, const URICallbacks *uri_cb,
- LoadImageDataFunction *LoadImageData = nullptr,
+ LoadImageDataFunction LoadImageData = nullptr,
void *load_image_user_data = nullptr) {
// A glTF image must either reference a bufferView or an image uri

@@ -4349,14 +4349,14 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
#endif
}

- if (*LoadImageData == nullptr) {
+ if (LoadImageData == nullptr) {
if (err) {
(*err) += "No LoadImageData callback specified.\n";
}
return false;
}
- return (*LoadImageData)(image, image_idx, err, warn, 0, 0, &img.at(0),
- static_cast<int>(img.size()), load_image_user_data);
+ return LoadImageData(image, image_idx, err, warn, 0, 0, &img.at(0),
+ static_cast<int>(img.size()), load_image_user_data);
}

static bool ParseTexture(Texture *texture, std::string *err,
@@ -6307,7 +6307,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
if (!ParseImage(&image, idx, err, warn, o,
store_original_json_for_extras_and_extensions_, base_dir,
max_external_file_size_, &fs, &uri_cb,
- &this->LoadImageData, load_image_user_data)) {
+ this->LoadImageData, load_image_user_data)) {
return false;
}

@@ -6336,7 +6336,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
}
const Buffer &buffer = model->buffers[size_t(bufferView.buffer)];

- if (*LoadImageData == nullptr) {
+ if (LoadImageData == nullptr) {
if (err) {
(*err) += "No LoadImageData callback specified.\n";
}
13 changes: 13 additions & 0 deletions tools/workspace/tinygltf_internal/patches/json.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Redirects tinygltf to use Drake's vendored nlohmann json.

--- tiny_gltf.h
+++ tiny_gltf.h
@@ -1705,7 +1705,7 @@ class TinyGLTF {

#ifndef TINYGLTF_NO_INCLUDE_JSON
#ifndef TINYGLTF_USE_RAPIDJSON
-#include "json.hpp"
+#include <nlohmann/json.hpp>
#else
#ifndef TINYGLTF_NO_INCLUDE_RAPIDJSON
#include "document.h"
17 changes: 17 additions & 0 deletions tools/workspace/tinygltf_internal/repository.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
load("@drake//tools/workspace:github.bzl", "github_archive")

def tinygltf_internal_repository(
name,
mirrors = None):
github_archive(
name = name,
repository = "syoyo/tinygltf",
commit = "v2.8.22",
sha256 = "97c3eb1080c1657cd749d0b49af189c6a867d5af30689c48d5e19521e7b5a070", # noqa
build_file = ":package.BUILD.bazel",
patches = [
":patches/function_pointer.patch",
":patches/json.patch",
],
mirrors = mirrors,
)

0 comments on commit a2b8df8

Please sign in to comment.