diff --git a/examples/basic/main.cpp b/examples/basic/main.cpp index 03fb67c..d3b7b4a 100644 --- a/examples/basic/main.cpp +++ b/examples/basic/main.cpp @@ -14,6 +14,7 @@ #endif // Inlude tinyktx.h before tiny_gltf.h +// to get TKTX_*** definitions #define TINYKTX_IMPLEMENTATION #include "../../tinyktx.h" @@ -27,6 +28,8 @@ #define TINYGLTF_NOEXCEPTION #define JSON_NOEXCEPTION #define TINYGLTF_ENABLE_KTX +// tinyktx.h is already included above, +// so let tiny_gltf.h know do not include tinyktx.h anymore #define TINYGLTF_NO_INCLUDE_TINY_KTX #include "../../tiny_gltf.h" @@ -56,6 +59,30 @@ bool loadModel(tinygltf::Model &model, const char *filename) { return res; } +static bool GetOpenGLFormatFromKTX(int ktx_fmt, GLint *internal_format, GLenum *format, GLenum *type) { +#if defined(TINYGLTF_ENABLE_KTX) + bool ret = true; + + std::cout << "fmt = " << ktx_fmt << ", rgb8 fmt = " << TKTX_R8G8B8_UNORM << "\n"; + + if (ktx_fmt == TKTX_R8G8B8_UNORM) { + (*internal_format) = GL_RGB; + (*format) = GL_RGB; + (*type) = GL_UNSIGNED_BYTE; + } else { + // TODO(syoyo): Support more KTX formats. + ret = false; + } + + return ret; +#else + (void)fmt; + (void)internal_format; + (void)internal_format; + return false; +#endif +} + std::map bindMesh(std::map vbos, tinygltf::Model &model, tinygltf::Mesh &mesh) { for (size_t i = 0; i < model.bufferViews.size(); ++i) { @@ -114,7 +141,7 @@ std::map bindMesh(std::map vbos, accessor.normalized ? GL_TRUE : GL_FALSE, byteStride, BUFFER_OFFSET(accessor.byteOffset)); } else - std::cout << "vaa missing: " << attrib.first << std::endl; + std::cout << "Unsupported vertex attribute: " << attrib.first << std::endl; } GLuint texid; @@ -130,29 +157,52 @@ std::map bindMesh(std::map vbos, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + GLint internal_format = GL_RGBA; GLenum format = GL_RGBA; - - if (image.component == 1) { - format = GL_RED; - } else if (image.component == 2) { - format = GL_RG; - } else if (image.component == 3) { - format = GL_RGB; - } else { - // ??? - } - GLenum type = GL_UNSIGNED_BYTE; - if (image.bits == 8) { - // ok - } else if (image.bits == 16) { - type = GL_UNSIGNED_SHORT; + + bool valid = false; + + // KTX extension + if (image.extras.Has("ktx_format")) { + + valid = GetOpenGLFormatFromKTX(image.extras.Get("ktx_format").Get(), &internal_format, &format, &type); + + if (valid) { + + std::cout << "ktx_format: " << image.extras.Get("ktx_format").Get() << std::endl; + std::cout << "ktx image size: " << image.width << ", " << image.height << std::endl; + } + } else { - // ??? + + if (image.component == 1) { + format = GL_RED; + } else if (image.component == 2) { + format = GL_RG; + } else if (image.component == 3) { + format = GL_RGB; + } else if (image.component == 4) { + format = GL_RGBA; + } else { + valid = false; + } + + if (image.bits == 8) { + // ok + } else if (image.bits == 16) { + type = GL_UNSIGNED_SHORT; + } else { + valid = false; + } + } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, - format, type, &image.image.at(0)); + if (valid) { + + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, image.width, image.height, 0, + format, type, &image.image.at(0)); + } } return vbos; diff --git a/models/Cube-KTX/Cube.bin b/models/Cube-KTX/Cube.bin new file mode 100644 index 0000000..7dae4b0 Binary files /dev/null and b/models/Cube-KTX/Cube.bin differ diff --git a/models/Cube-KTX/Cube.gltf b/models/Cube-KTX/Cube.gltf new file mode 100644 index 0000000..fc8aca0 --- /dev/null +++ b/models/Cube-KTX/Cube.gltf @@ -0,0 +1,193 @@ +{ + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 36, + "max" : [ + 35 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000001 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 2, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 3, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + -0.000000, + -0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -0.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC4" + }, + { + "bufferView" : 4, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000 + ], + "type" : "VEC2" + } + ], + "asset" : { + "generator" : "VKTS glTF 2.0 exporter", + "version" : "2.0" + }, + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 72, + "byteOffset" : 0, + "target" : 34963 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 72, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 504, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 576, + "byteOffset" : 936, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 1512, + "target" : 34962 + } + ], + "buffers" : [ + { + "byteLength" : 1800, + "uri" : "Cube.bin" + } + ], + "images" : [ + { + "uri" : "Cube_BaseColor.ktx" + }, + { + "uri" : "Cube_MetallicRoughness.ktx" + } + ], + "materials" : [ + { + "name" : "Cube", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicRoughnessTexture" : { + "index" : 1 + } + } + } + ], + "meshes" : [ + { + "name" : "Cube", + "primitives" : [ + { + "attributes" : { + "NORMAL" : 2, + "POSITION" : 1, + "TANGENT" : 3, + "TEXCOORD_0" : 4 + }, + "indices" : 0, + "material" : 0, + "mode" : 4 + } + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Cube" + } + ], + "samplers" : [ + {} + ], + "scene" : 0, + "scenes" : [ + { + "nodes" : [ + 0 + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + }, + { + "sampler" : 0, + "source" : 1 + } + ] +} diff --git a/models/Cube-KTX/Cube_BaseColor.ktx b/models/Cube-KTX/Cube_BaseColor.ktx new file mode 100644 index 0000000..888c9e7 Binary files /dev/null and b/models/Cube-KTX/Cube_BaseColor.ktx differ diff --git a/models/Cube-KTX/Cube_MetallicRoughness.ktx b/models/Cube-KTX/Cube_MetallicRoughness.ktx new file mode 100644 index 0000000..4df13a7 Binary files /dev/null and b/models/Cube-KTX/Cube_MetallicRoughness.ktx differ diff --git a/models/Cube-KTX/README.md b/models/Cube-KTX/README.md new file mode 100644 index 0000000..f9f032c --- /dev/null +++ b/models/Cube-KTX/README.md @@ -0,0 +1,12 @@ +License: Donated by Norbert Nopper for glTF testing. + +https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Cube + + +---- + +Converted .png to .ktx image by Syoyo Fujita. + +.png -> .ppm using image magic(resize with 25% to reduce file size) +.ppm -> .ktx using `toktx` in KTX-Software https://github.com/KhronosGroup/KTX-Software + diff --git a/tiny_gltf.h b/tiny_gltf.h index 888053e..883fd52 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -1808,6 +1808,7 @@ static void tinyktxCallbackError(void *user, char const *msg) { static void *tinyktxCallbackAlloc(void *user, size_t size) { (void)user; + //std::cerr << "Alloc : " << std::to_string(size) << "\n"; return malloc(size); }; @@ -1819,7 +1820,7 @@ static void tinyktxCallbackFree(void *user, void *data) { static size_t tinyktxCallbackRead(void *user, void* data, size_t size) { SimpleVFile *ss = reinterpret_cast(user); - if ((ss->pos + size) >= ss->len) { + if ((ss->pos + size) > ss->len) { if (ss->err) { std::stringstream msg; msg << "KTX read: Invalid data length. pos = " << ss->pos << ", len = " << ss->len << ", requested size to read = " << size << "\n"; @@ -1830,6 +1831,9 @@ static size_t tinyktxCallbackRead(void *user, void* data, size_t size) { memcpy(data, ss->data + ss->pos, size); + // Advance pos + ss->pos += size; + return size; }; @@ -1871,7 +1875,7 @@ bool LoadImageDataKTX(Image *image, const int image_idx, std::string *err, &tinyktxCallbackError, &tinyktxCallbackAlloc, &tinyktxCallbackFree, - tinyktxCallbackRead, + &tinyktxCallbackRead, &tinyktxCallbackSeek, &tinyktxCallbackTell }; @@ -1920,6 +1924,12 @@ bool LoadImageDataKTX(Image *image, const int image_idx, std::string *err, return false; } + const void *src_ptr = TinyKtx_ImageRawData(ctx, miplevel); + if (src_ptr == nullptr) { + TinyKtx_DestroyContext(ctx); + return false; + } + image->image.resize(byte_count); memcpy(image->image.data(), TinyKtx_ImageRawData(ctx, miplevel), byte_count); @@ -1952,34 +1962,49 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, bool ret = false; + std::string stb_err; + std::string stb_warn; + +#if !defined(TINYGLTF_NO_STB_IMAGE) + // Try to load images using stb_image(png, gif, bmp, tga, ...) + + ret = tinygltf::LoadImageDataSTB(image, image_idx, &stb_err, &stb_warn, req_width, req_height, + bytes, size, user_data); + + if (ret) { + return true; + } + +#endif + + std::string ktx_err; + std::string ktx_warn; + #if defined(TINYGLTF_ENABLE_KTX) // Try KTX image - ret = tinygltf::LoadImageDataKTX(image, image_idx, err, warn, req_width, req_height, + ret = tinygltf::LoadImageDataKTX(image, image_idx, &ktx_err, &ktx_warn, req_width, req_height, bytes, size, user_data); if (ret) { + if (warn) { + (*warn) = ktx_warn; + } return true; } #endif -#if defined(TINYGLTF_NO_STB_IMAGE) - // Try to load images using stb_image(png, gif, bmp, tga, ...) - - ret = tinygltf::LoadImageDataSTB(image, image_idx, err, warn, req_width, req_height, - bytes, size, user_data); - - if (ret) { - return true; + if (err) { + (*err) = stb_err + ktx_err; } -#endif + if (warn) { + (*warn) = stb_warn + ktx_warn; + } (void)image; (void)image_idx; - (void)err; - (void)warn; (void)req_width; (void)req_height; (void)bytes;