From 29f91edf0645928a5e92c4577951c2c10febd831 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sun, 8 Oct 2023 19:24:36 +0900 Subject: [PATCH 1/9] Initial support of __AnyType__ Prim typeName. --- src/usda-reader.cc | 8 +++++++- src/usdc-reader.cc | 25 +++++++++++++++++++++++-- tests/usda/anytype-001.usda | 6 ++++++ tests/usdc/anytype-001.usdc | Bin 0 -> 591 bytes 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/usda/anytype-001.usda create mode 100644 tests/usdc/anytype-001.usdc diff --git a/src/usda-reader.cc b/src/usda-reader.cc index 4d5d22c0b..7f5b9cc5d 100644 --- a/src/usda-reader.cc +++ b/src/usda-reader.cc @@ -359,12 +359,18 @@ class USDAReader::Impl { bool RegisterReconstructCallback() { _parser.RegisterPrimConstructFunction( PrimTypeTraits::prim_type_name, - [&](const Path &full_path, const Specifier spec, const std::string &primTypeName, const Path &prim_name, const int64_t primIdx, + [&](const Path &full_path, const Specifier spec, const std::string &_primTypeName, const Path &prim_name, const int64_t primIdx, const int64_t parentPrimIdx, const prim::PropertyMap &properties, const ascii::AsciiParser::PrimMetaMap &in_meta, const ascii::AsciiParser::VariantSetList &in_variants) -> nonstd::expected { + + std::string primTypeName = _primTypeName; + if (primTypeName == "__AnyType__") { + primTypeName = ""; // Make empty + } + if (!prim_name.is_valid()) { return nonstd::make_unexpected("Invalid Prim name: " + prim_name.full_path_name()); diff --git a/src/usdc-reader.cc b/src/usdc-reader.cc index a035124b5..a74232b5b 100644 --- a/src/usdc-reader.cc +++ b/src/usdc-reader.cc @@ -1678,7 +1678,7 @@ nonstd::optional USDCReader::Impl::ReconstructPrimFromTypeName( return std::move(prim); \ } else - if (typeName == "Model") { + if (typeName == "Model" || typeName == "__AnyType__") { // Code is mostly identical to RECONSTRUCT_PRIM. // Difference is store primTypeName to Model class itself. Model typed_prim; @@ -1688,7 +1688,11 @@ nonstd::optional USDCReader::Impl::ReconstructPrimFromTypeName( } typed_prim.meta = meta; typed_prim.name = prim_name; - typed_prim.prim_type_name = primTypeName; + if (typeName == "__AnyType__") { + typed_prim.prim_type_name = ""; + } else { + typed_prim.prim_type_name = primTypeName; + } typed_prim.spec = spec; typed_prim.propertyNames() = properties; typed_prim.primChildrenNames() = primChildren; @@ -2345,6 +2349,11 @@ bool USDCReader::Impl::ReconstructPrimNode(int parent, int current, int level, std::string prim_name = elemPath.prim_part(); std::string primTypeName = typeName.has_value() ? typeName.value() : ""; + // __AnyType__ + if (typeName.has_value() && typeName.value() == "__AnyType__") { + primTypeName = ""; + } + // Validation check should be already done in crate-reader, so no // further validation required. if (!ValidatePrimElementName(prim_name)) { @@ -2507,6 +2516,10 @@ bool USDCReader::Impl::ReconstructPrimNode(int parent, int current, int level, DCOUT("prim_name = " << prim_name); std::string primTypeName = typeName.has_value() ? typeName.value() : ""; + // __AnyType__ + if (typeName.has_value() && typeName.value() == "__AnyType__") { + primTypeName = ""; + } // Something like '{shapeVariant=Capsule}' @@ -2796,6 +2809,10 @@ bool USDCReader::Impl::ReconstructPrimSpecNode(int parent, int current, int leve DCOUT("elemPath.prim_name = " << elemPath.prim_part()); std::string prim_name = elemPath.prim_part(); std::string primTypeName = typeName.has_value() ? typeName.value() : ""; + // __AnyType__ + if (typeName.has_value() && typeName.value() == "__AnyType__") { + primTypeName = ""; + } // Validation check should be already done in crate-reader, so no // further validation required. @@ -2973,6 +2990,10 @@ bool USDCReader::Impl::ReconstructPrimSpecNode(int parent, int current, int leve DCOUT("prim_name = " << prim_name); std::string primTypeName = typeName.has_value() ? typeName.value() : ""; + // __AnyType__ + if (typeName.has_value() && typeName.value() == "__AnyType__") { + primTypeName = ""; + } // Something like '{shapeVariant=Capsule}' diff --git a/tests/usda/anytype-001.usda b/tests/usda/anytype-001.usda new file mode 100644 index 000000000..9803818c6 --- /dev/null +++ b/tests/usda/anytype-001.usda @@ -0,0 +1,6 @@ +#usda 1.0 + +# __AnyType__ = Old syntax for 'generic' Prim type. +def __AnyType__ "bora" { + +} diff --git a/tests/usdc/anytype-001.usdc b/tests/usdc/anytype-001.usdc new file mode 100644 index 0000000000000000000000000000000000000000..5b5e70b4fbac2330aa02a49383c3c17fe3e2136e GIT binary patch literal 591 zcmWHD2+|D=c5!ClU;u-5MhHzQ2{Q&nvqKFtgVL5T!#}87>uNG20#HQDffX#y4W$_vcwp)lfV8ft*02+_>Q2F2hS7&5-f2h0#R2~3y CIy9RA literal 0 HcmV?d00001 From 3b6c98e471f3931279200b346e77b39913b0edee Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sun, 8 Oct 2023 20:12:04 +0900 Subject: [PATCH 2/9] Support unregistered Prim meta with token type. --- src/pprinter.cc | 1 + src/prim-types.hh | 1 + src/usda-reader.cc | 2 ++ src/usdc-reader.cc | 3 +++ 4 files changed, 7 insertions(+) diff --git a/src/pprinter.cc b/src/pprinter.cc index 8b73053a9..2a37525b7 100644 --- a/src/pprinter.cc +++ b/src/pprinter.cc @@ -1649,6 +1649,7 @@ std::string to_string(const APISchemas::APIName &name) { switch (name) { case APISchemas::APIName::SkelBindingAPI: { s = "SkelBindingAPI"; break; } case APISchemas::APIName::MaterialBindingAPI: { s = "MaterialBindingAPI"; break; } + case APISchemas::APIName::ShapingAPI: { s = "ShapingAPI"; break; } case APISchemas::APIName::Preliminary_AnchoringAPI: { s = "Preliminary_AnchoringAPI"; break; } case APISchemas::APIName::Preliminary_PhysicsColliderAPI: { s = "Preliminary_PhysicsColliderAPI"; break; } case APISchemas::APIName::Preliminary_PhysicsRigidBodyAPI: { s = "Preliminary_PhysicsRigidBodyAPI"; break; } diff --git a/src/prim-types.hh b/src/prim-types.hh index 727c903f3..4cf70fbc4 100644 --- a/src/prim-types.hh +++ b/src/prim-types.hh @@ -753,6 +753,7 @@ struct APISchemas { enum class APIName { MaterialBindingAPI, // "MaterialBindingAPI" SkelBindingAPI, // "SkelBindingAPI" + ShapingAPI, // "ShapingAPI"(usdLux) // USDZ AR extensions Preliminary_AnchoringAPI, Preliminary_PhysicsColliderAPI, diff --git a/src/usda-reader.cc b/src/usda-reader.cc index 7f5b9cc5d..08b73e211 100644 --- a/src/usda-reader.cc +++ b/src/usda-reader.cc @@ -720,6 +720,8 @@ class USDAReader::Impl { std::make_pair(APISchemas::APIName::SkelBindingAPI, "SkelBindingAPI"), std::make_pair(APISchemas::APIName::MaterialBindingAPI, "MaterialBindingAPI"), + std::make_pair(APISchemas::APIName::ShapingAPI, + "ShapingAPI"), std::make_pair(APISchemas::APIName::Preliminary_PhysicsMaterialAPI, "Preliminary_PhysicsMaterialAPI"), std::make_pair(APISchemas::APIName::Preliminary_PhysicsRigidBodyAPI, diff --git a/src/usdc-reader.cc b/src/usdc-reader.cc index a74232b5b..57db9df8a 100644 --- a/src/usdc-reader.cc +++ b/src/usdc-reader.cc @@ -2144,6 +2144,9 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs, if (auto pv = fv.second.as()) { // Assume unregistered Prim metadatum primMeta.unregisteredMetas[fv.first] = (*pv); + } else if (auto ptv = fv.second.as()) { + // store value as string type. + primMeta.unregisteredMetas[fv.first] = quote((*ptv).str()); } else { DCOUT("PrimProp TODO: " << fv.first); PUSH_WARN("PrimProp TODO: " << fv.first); From 9d7999b738a6315278483d5f61aec24defa8d1cc Mon Sep 17 00:00:00 2001 From: Adrian Perez Date: Wed, 11 Oct 2023 16:08:44 -0700 Subject: [PATCH 3/9] Elide unaligned reads in stream reader --- src/stream-reader.hh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/stream-reader.hh b/src/stream-reader.hh index 84990d0ee..578366f86 100644 --- a/src/stream-reader.hh +++ b/src/stream-reader.hh @@ -203,8 +203,8 @@ class StreamReader { return false; } - unsigned short val = - *(reinterpret_cast(&binary_[idx_])); + unsigned short val; + memcpy(&val, &binary_[idx_], sizeof(val)); if (swap_endian_) { swap2(&val); @@ -221,7 +221,8 @@ class StreamReader { return false; } - uint32_t val = *(reinterpret_cast(&binary_[idx_])); + uint32_t val; + memcpy(&val, &binary_[idx_], sizeof(val)); if (swap_endian_) { swap4(&val); @@ -238,7 +239,8 @@ class StreamReader { return false; } - int val = *(reinterpret_cast(&binary_[idx_])); + int val; + memcpy(&val, &binary_[idx_], sizeof(val)); if (swap_endian_) { swap4(&val); @@ -255,7 +257,8 @@ class StreamReader { return false; } - uint64_t val = *(reinterpret_cast(&binary_[idx_])); + uint64_t val; + memcpy(&val, &binary_[idx_], sizeof(val)); if (swap_endian_) { swap8(&val); @@ -272,7 +275,8 @@ class StreamReader { return false; } - int64_t val = *(reinterpret_cast(&binary_[idx_])); + int64_t val; + memcpy(&val, &binary_[idx_], sizeof(val)); if (swap_endian_) { swap8(&val); From 865d44abe3877eadaec056b9c85b386ffed743ae Mon Sep 17 00:00:00 2001 From: Adrian Perez Date: Wed, 11 Oct 2023 16:11:12 -0700 Subject: [PATCH 4/9] Elide unaligned reads in header parse --- src/tinyusdz.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tinyusdz.cc b/src/tinyusdz.cc index c34f23fdf..fdc3fd480 100644 --- a/src/tinyusdz.cc +++ b/src/tinyusdz.cc @@ -341,8 +341,8 @@ bool ParseUSDZHeader(const uint8_t *addr, const size_t length, uint16_t compr_method = *reinterpret_cast(&local_header[0] + 8); // uint32_t compr_bytes = *reinterpret_cast(&local_header[0]+18); - uint32_t uncompr_bytes = - *reinterpret_cast(&local_header[0] + 22); + uint32_t uncompr_bytes; + memcpy(&uncompr_bytes, &local_header[22], sizeof(uncompr_bytes)); // USDZ only supports uncompressed ZIP if (compr_method != 0) { From fd82ac85c6096950d6f757428c5825563f99b26c Mon Sep 17 00:00:00 2001 From: Adrian Perez Date: Wed, 11 Oct 2023 16:17:00 -0700 Subject: [PATCH 5/9] add missing seek to animation loading --- src/crate-reader.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crate-reader.cc b/src/crate-reader.cc index 6e4d98412..8a882e890 100644 --- a/src/crate-reader.cc +++ b/src/crate-reader.cc @@ -889,6 +889,7 @@ bool CrateReader::ReadTimeSamples(value::TimeSamples *d) { // Move to next location. // sizeof(uint64) = sizeof(ValueRep) + _sr->seek_set(values_offset); if (!_sr->seek_from_current(int64_t(sizeof(uint64_t) * num_values))) { PUSH_ERROR_AND_RETURN_TAG(kTag, "Failed to seek over TimeSamples's values."); } From 3d8362dcf3ffb4f2b43d88f100db4c2ed2586983 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Thu, 12 Oct 2023 22:45:52 +0900 Subject: [PATCH 6/9] Add some missing files to Android cmake project. Bump gradle version. --- android/app/src/main/cpp/CMakeLists.txt | 7 ++++++- android/build.gradle | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/cpp/CMakeLists.txt b/android/app/src/main/cpp/CMakeLists.txt index 479c16ef3..352de1af6 100644 --- a/android/app/src/main/cpp/CMakeLists.txt +++ b/android/app/src/main/cpp/CMakeLists.txt @@ -7,6 +7,7 @@ option(TINYUSDZ_USE_USDOBJ "Build with built-in .obj support" On) set(TINYUSDZ_SOURCES ${PROJECT_SOURCE_DIR}/../../../../../src/tinyusdz.cc ${PROJECT_SOURCE_DIR}/../../../../../src/asset-resolution.cc + ${PROJECT_SOURCE_DIR}/../../../../../src/composition.cc ${PROJECT_SOURCE_DIR}/../../../../../src/prim-types.cc ${PROJECT_SOURCE_DIR}/../../../../../src/ascii-parser.cc ${PROJECT_SOURCE_DIR}/../../../../../src/ascii-parser-basetype.cc @@ -29,6 +30,10 @@ set(TINYUSDZ_SOURCES ${PROJECT_SOURCE_DIR}/../../../../../src/image-loader.cc ${PROJECT_SOURCE_DIR}/../../../../../src/usda-writer.cc ${PROJECT_SOURCE_DIR}/../../../../../src/usdGeom.cc + ${PROJECT_SOURCE_DIR}/../../../../../src/usdSkel.cc + ${PROJECT_SOURCE_DIR}/../../../../../src/usdShade.cc + ${PROJECT_SOURCE_DIR}/../../../../../src/usdMtlx.cc + ${PROJECT_SOURCE_DIR}/../../../../../src/usdLux.cc ${PROJECT_SOURCE_DIR}/../../../../../src/xform.cc ${PROJECT_SOURCE_DIR}/../../../../../src/stage.cc ${PROJECT_SOURCE_DIR}/../../../../../src/str-util.cc @@ -36,12 +41,12 @@ set(TINYUSDZ_SOURCES ${PROJECT_SOURCE_DIR}/../../../../../src/image-util.cc ${PROJECT_SOURCE_DIR}/../../../../../src/image-writer.cc ${PROJECT_SOURCE_DIR}/../../../../../src/linear-algebra.cc + ${PROJECT_SOURCE_DIR}/../../../../../src/tydra/facial.cc ${PROJECT_SOURCE_DIR}/../../../../../src/tydra/scene-access.cc ${PROJECT_SOURCE_DIR}/../../../../../src/tydra/render-data.cc ${PROJECT_SOURCE_DIR}/../../../../../src/tydra/prim-apply.cc ${PROJECT_SOURCE_DIR}/../../../../../src/tydra/shader-network.cc ) - if (TINYUSDZ_USE_USDOBJ) list(APPEND TINYUSDZ_SOURCES ${PROJECT_SOURCE_DIR}/../../../../../src/usdObj.cc) diff --git a/android/build.gradle b/android/build.gradle index aec1b12d7..8b5b2c3a7 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:8.0.1' + classpath 'com.android.tools.build:gradle:8.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files From bd9ab32f805f2bd112f722d8f2c9652f971453f1 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Fri, 13 Oct 2023 22:21:29 +0900 Subject: [PATCH 7/9] Possible highDPI support in linux. --- examples/openglviewer/CMakeLists.txt | 2 +- examples/openglviewer/main.cc | 41 +++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/examples/openglviewer/CMakeLists.txt b/examples/openglviewer/CMakeLists.txt index 70dfbbac0..6d7108712 100644 --- a/examples/openglviewer/CMakeLists.txt +++ b/examples/openglviewer/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16) set(BUILD_TARGET "usdz_glview") -project(${BUILD_TARGET} CXX) +project(${BUILD_TARGET} CXX C) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED On) diff --git a/examples/openglviewer/main.cc b/examples/openglviewer/main.cc index 747544402..857ad8262 100644 --- a/examples/openglviewer/main.cc +++ b/examples/openglviewer/main.cc @@ -79,7 +79,7 @@ struct GLTexState { struct GLVertexUniformState { GLint u_modelview{-1}; - GLint u_normal{-1}; + GLint u_normal{-1}; GLint u_perspective{-1}; std::array modelviewMatrix[16]; @@ -98,7 +98,7 @@ struct GLMeshState { struct GLNodeState { GLVertexUniformState gl_v_uniform_state; - GLMeshState gl_mesh_state; + GLMeshState gl_mesh_state; }; @@ -533,7 +533,7 @@ static bool SetupMesh( facevaryingVertices.push_back(mesh.points[vi1]); facevaryingVertices.push_back(mesh.points[vi2]); } - + GLuint vb; glGenBuffers(1, &vb); glBindBuffer(GL_ARRAY_BUFFER, vb); @@ -637,7 +637,7 @@ static bool SetupMesh( } } -#if 0 +#if 0 // Build index buffer. GLuint elementbuffer; glGenBuffers(1, &elementbuffer); @@ -727,6 +727,25 @@ int main(int argc, char** argv) { //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only #endif + float highDPIscaleFactor = 1.0f; + +#if defined(_WIN32) || defined(__linux__) + // if it's a HighDPI monitor, try to scale everything + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + float xscale, yscale; + glfwGetMonitorContentScale(monitor, &xscale, &yscale); + std::cout << "monitor xscale, yscale = " << xscale << ", " << yscale << "\n"; + if (xscale > 1 || yscale > 1) + { + highDPIscaleFactor = xscale; + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); + + } +#elif __APPLE__ + glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); +#endif + + #ifdef _DEBUG_OPENGL glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); #endif @@ -802,6 +821,20 @@ int main(int argc, char** argv) { int display_w, display_h; ImVec4 clear_color = {0.1f, 0.18f, 0.3f, 1.0f}; + { + float cxscale, cyscale; + glfwGetWindowContentScale(window, &cxscale, &cyscale); + std::cout << "xscale, yscale = " << cxscale << ", " << cyscale << "\n"; + + ImGuiIO& io = ImGui::GetIO(); + + io.DisplayFramebufferScale = {2.0f, 2.0f}; // HACK + + ImFontConfig font_config; + font_config.SizePixels = 16.0f * xscale; + io.Fonts->AddFontDefault(&font_config); + } + while (!done) { glfwPollEvents(); ImGui_ImplOpenGL3_NewFrame(); From f0fe6f3f86e11913040c20375b151a33bdbd6603 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Fri, 13 Oct 2023 22:54:15 +0900 Subject: [PATCH 8/9] experimental highdpi support in linux. --- examples/sdlviewer/main.cc | 45 ++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/examples/sdlviewer/main.cc b/examples/sdlviewer/main.cc index d493dec05..9ab31d063 100644 --- a/examples/sdlviewer/main.cc +++ b/examples/sdlviewer/main.cc @@ -765,8 +765,6 @@ int main(int argc, char** argv) { std::cout << "Loading file " << filename << "\n"; - // tinyusdz::HighLevelScene scene; - bool init_with_empty = false; if (!LoadModel(filename, &g_gui_ctx.stage)) { @@ -783,6 +781,22 @@ int main(int argc, char** argv) { //} } + // Assume single monitor + SDL_DisplayMode DM; + SDL_GetCurrentDisplayMode(0, &DM); + std::cout << "Current monitor: " << DM.w << " x " << DM.h << "\n"; + + int default_win_x = 1600; + int default_win_y = 800; + + if (DM.w > 2560) { + default_win_x = 2560; + } + + if (DM.h > 1600) { + default_win_y = 1600; + } + #if defined(__APPLE__) // For some reason, HIGHDPI does not work well on Retina Display for SDLRenderer backend. // Disable it for a while. @@ -791,9 +805,10 @@ int main(int argc, char** argv) { SDL_WindowFlags window_flags = static_cast(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); #endif + std::cout << "default window size: " << default_win_x << " x " << default_win_y << "\n"; SDL_Window* window = SDL_CreateWindow( "Simple USDZ viewer", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - 1600, 800, window_flags); + default_win_x, default_win_y, window_flags); if (!window) { std::cerr << "Failed to create SDL2 window. If you are running on Linux, " "probably X11 Display is not setup correctly. Check your " @@ -840,12 +855,34 @@ int main(int argc, char** argv) { ImNodes::CreateContext(); { + + float ddpi, hdpi, vdpi; + if (SDL_GetDisplayDPI(0, &ddpi, &hdpi, &vdpi) != 0) { + fprintf(stderr, "Failed to obtain DPI information for display 0: %s\n", SDL_GetError()); + exit(1); + } + std::cout << "ddpi " << ddpi << ", hdpi " << hdpi << ", vdpi " << vdpi << "\n"; + + float dpi_scaling = ddpi / 72.0f; + ImGuiIO& io = ImGui::GetIO(); + if (dpi_scaling >= 144.0f) { + // https://github.com/ocornut/imgui/issues/1786 + // nx DisplayFrameBufferScale + nx font_size + FontGlobalScale 0.5 may give nicer visual on High DPI monitor + io.FontGlobalScale = 0.5f; + } + + io.DisplayFramebufferScale = {dpi_scaling , dpi_scaling}; // HACK + ImFontConfig roboto_config; strcpy(roboto_config.Name, "Roboto"); - float font_size = 18.0f; + float font_size = 18.0 * dpi_scaling; + + //ImFontConfig font_config; + //font_config.SizePixels = 18.0f * xscale; + //io.Fonts->AddFontDefault(&font_config); io.Fonts->AddFontFromMemoryCompressedTTF(roboto_mono_compressed_data, roboto_mono_compressed_size, font_size, &roboto_config); From 4992dd1c0070c7d910df7dd4e8a5652ce64ae598 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sat, 14 Oct 2023 23:37:52 +0900 Subject: [PATCH 9/9] Implement some GL stuff. --- examples/openglviewer/main.cc | 429 ++++++++++++++++++++++------------ 1 file changed, 286 insertions(+), 143 deletions(-) diff --git a/examples/openglviewer/main.cc b/examples/openglviewer/main.cc index 857ad8262..b99e156e9 100644 --- a/examples/openglviewer/main.cc +++ b/examples/openglviewer/main.cc @@ -38,7 +38,7 @@ constexpr auto kAttribPoints = "points"; constexpr auto kAttribNormals = "normals"; constexpr auto kAttribTexCoordBase = "texcoord_"; constexpr auto kAttribTexCoord0 = "texcoord_0"; -constexpr auto kMaxTexCoords = 1; // TODO: multi texcoords +constexpr auto kMaxTexCoords = 1; // TODO: multi texcoords constexpr auto kUniformModelviewMatrix = "modelviewMatrix"; constexpr auto kUniformNormalMatrix = "normalMatrix"; @@ -46,31 +46,36 @@ constexpr auto kUniformProjectionMatrix = "projectionMatrix"; constexpr auto kUniformDiffuseTex = "diffuseTex"; constexpr auto kUniformDiffuseTexTransform = "diffuseTexTransform"; -constexpr auto kUniformDiffuseTexScaleAndBias = "diffuseTexScaleAndBias"; // (sx, sy, bx, by) +constexpr auto kUniformDiffuseTexScaleAndBias = + "diffuseTexScaleAndBias"; // (sx, sy, bx, by) constexpr auto kUniformNormaTex = "normalTex"; constexpr auto kUniformNormaTexTransform = "normalTexTransform"; -constexpr auto kUniformNormalTexScaleAndBias = "normalTexScaleAndBias"; // (sx, sy, bx, by) +constexpr auto kUniformNormalTexScaleAndBias = + "normalTexScaleAndBias"; // (sx, sy, bx, by) constexpr auto kUniformOcclusionTex = "occlusionlTex"; constexpr auto kUniformOcclusionTexTransform = "occlusionlTexTransform"; -constexpr auto kUniformOcclusionTexScaleAndBias = "occlusionTexScaleAndBias"; // (sx, sy, bx, by) +constexpr auto kUniformOcclusionTexScaleAndBias = + "occlusionTexScaleAndBias"; // (sx, sy, bx, by) // Embedded shaders #include "shaders/no_skinning.vert_inc.hh" -#define CHECK_GL(tag) do { \ - GLenum err = glGetError(); \ - if (err != GL_NO_ERROR) { \ - std::cerr << "[" << tag << "] " << __FILE__ << ":" << __LINE__ << ":" << __func__ << " code " << std::to_string(int(err)) << "\n"; \ - } \ -} while(0) +#define CHECK_GL(tag) \ + do { \ + GLenum err = glGetError(); \ + if (err != GL_NO_ERROR) { \ + std::cerr << "[" << tag << "] " << __FILE__ << ":" << __LINE__ << ":" \ + << __func__ << " code " << std::to_string(int(err)) << "\n"; \ + } \ + } while (0) struct GLTexParams { std::map uniforms; GLenum wrapS{GL_REPEAT}; GLenum wrapT{GL_REPEAT}; - std::array borderCol{0.0f, 0.0f, 0.0f, 0.0f}; // transparent black + std::array borderCol{0.0f, 0.0f, 0.0f, 0.0f}; // transparent black }; struct GLTexState { @@ -83,17 +88,16 @@ struct GLVertexUniformState { GLint u_perspective{-1}; std::array modelviewMatrix[16]; - std::array normalMatrix[16]; // transpose(inverse(modelview)) + std::array normalMatrix[16]; // transpose(inverse(modelview)) std::array perspectiveMatrix[16]; - }; // TODO: Use handle_id for key struct GLMeshState { std::map attribs; std::vector diffuseTexHandles; - GLuint vertex_array_object{0}; // vertex array object - GLuint num_triangles{0}; // up to 4GB triangles + GLuint vertex_array_object{0}; // vertex array object + GLuint num_triangles{0}; // up to 4GB triangles }; struct GLNodeState { @@ -101,14 +105,12 @@ struct GLNodeState { GLMeshState gl_mesh_state; }; - struct GLProgramState { - //std::map uniforms; + // std::map uniforms; std::map shaders; }; - struct GUIContext { enum AOV { AOV_COLOR = 0, @@ -135,6 +137,9 @@ struct GUIContext { float curr_quat[4] = {0.0f, 0.0f, 0.0f, 1.0f}; float prev_quat[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + float xrotate = 0.0f; // in degree + float yrotate = 0.0f; // in degree + std::array eye = {0.0f, 0.0f, 5.0f}; std::array lookat = {0.0f, 0.0f, 0.0f}; std::array up = {0.0f, 1.0f, 0.0f}; @@ -211,6 +216,7 @@ static void mouse_move_callback(GLFWwindow* window, double x, double y) { trans_scale * (param->mouse_y - static_cast(y)); } else { +#if 0 // Adjust y. trackball(param->prev_quat, (2.f * (param->mouse_x - x_offset) - w) / static_cast(w), @@ -220,6 +226,20 @@ static void mouse_move_callback(GLFWwindow* window, double x, double y) { (h - 2.f * (static_cast(y) - y_offset)) / static_cast(h)); add_quats(param->prev_quat, param->curr_quat, param->curr_quat); +#else + const float rotation_amp = 1.0f; + param->xrotate += rotation_amp * (param->mouse_y - static_cast(y)); + param->yrotate += rotation_amp * (param->mouse_x - static_cast(x)); + + // limit rotation around X axis. + if (param->xrotate < -89) { + param->xrotate = -89; + } + if (param->xrotate > 89) { + param->xrotate = 89; + } + +#endif } } @@ -260,49 +280,50 @@ static void resize_callback(GLFWwindow* window, int width, int height) { namespace { -void SetupVertexUniforms(GLVertexUniformState &gl_state, - tinyusdz::tydra::XformNode &xform_node) -{ +void SetupVertexUniforms(GLVertexUniformState& gl_state, + tinyusdz::tydra::XformNode& xform_node) { using namespace tinyusdz::value; // implicitly casts matrix4d to matrix4f; matrix4f worldmat = xform_node.get_world_matrix(); - matrix4d invtransmatd = tinyusdz::inverse(tinyusdz::upper_left_3x3_only(xform_node.get_world_matrix())); + matrix4d invtransmatd = tinyusdz::inverse( + tinyusdz::upper_left_3x3_only(xform_node.get_world_matrix())); matrix4f invtransmat = invtransmatd; memcpy(gl_state.modelviewMatrix, &worldmat.m[0][0], sizeof(float) * 16); memcpy(gl_state.normalMatrix, &invtransmat.m[0][0], sizeof(float) * 16); - //memcpy(gl_state.perspectiveMatrix, &perspective.m[0][0], sizeof(float) * 16); + // memcpy(gl_state.perspectiveMatrix, &perspective.m[0][0], sizeof(float) * + // 16); } -void SetVertexUniforms( - const GLVertexUniformState &gl_state) { - +void SetVertexUniforms(const GLVertexUniformState& gl_state) { if (gl_state.u_modelview > -1) { - glUniformMatrix4fv(gl_state.u_modelview, 1, GL_FALSE, gl_state.modelviewMatrix->data()); + glUniformMatrix4fv(gl_state.u_modelview, 1, GL_FALSE, + gl_state.modelviewMatrix->data()); CHECK_GL("UniformMatrix u_modelview"); } if (gl_state.u_modelview > -1) { - glUniformMatrix4fv(gl_state.u_normal, 1, GL_FALSE, gl_state.normalMatrix->data()); + glUniformMatrix4fv(gl_state.u_normal, 1, GL_FALSE, + gl_state.normalMatrix->data()); CHECK_GL("UniformMatrix u_normal"); } - } bool LoadShaders() { - std::string s(reinterpret_cast(shaders_no_skinning_vert), shaders_no_skinning_vert_len); + std::string s(reinterpret_cast(shaders_no_skinning_vert), + shaders_no_skinning_vert_len); return true; } bool SetupShader() { - GLuint prog_id; GLint modelv_loc = glGetUniformLocation(prog_id, kUniformModelviewMatrix); if (modelv_loc < 0) { - std::cerr << kUniformModelviewMatrix << " not found in the vertex shader.\n"; + std::cerr << kUniformModelviewMatrix + << " not found in the vertex shader.\n"; return false; } @@ -314,7 +335,8 @@ bool SetupShader() { GLint proj_loc = glGetUniformLocation(prog_id, kUniformProjectionMatrix); if (proj_loc < 0) { - std::cerr << kUniformProjectionMatrix << " not found in the vertex shader.\n"; + std::cerr << kUniformProjectionMatrix + << " not found in the vertex shader.\n"; return false; } @@ -358,8 +380,10 @@ bool SetupTexture(const tinyusdz::tydra::RenderScene& scene, // There are two possibilities: opaque black or transparent black. // We use fully transparent(0.0) for a while. texParams.borderCol = {0.0f, 0.0f, 0.0f, 0.0f}; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, &texParams.borderCol[0]); - CHECK_GL("texture_id[" << std::to_string(tex.texture_image_id) << "] glTexParameters"); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, + &texParams.borderCol[0]); + CHECK_GL("texture_id[" << std::to_string(tex.texture_image_id) + << "] glTexParameters"); texState.texParams = std::move(texParams); @@ -434,8 +458,9 @@ bool SetupTexture(const tinyusdz::tydra::RenderScene& scene, // continue anyway } else { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, - format, type, buffer.data.data()); - CHECK_GL("texture_id[" << std::to_string(image_id) << "] glTexImage2D"); + format, type, buffer.data.data()); + CHECK_GL("texture_id[" << std::to_string(image_id) + << "] glTexImage2D"); } } } @@ -448,21 +473,21 @@ bool SetupTexture(const tinyusdz::tydra::RenderScene& scene, return true; } -static bool SetupMesh( - tinyusdz::tydra::RenderMesh &mesh, - GLuint program_id, - GLMeshState &gl_state) // [out] +static bool SetupMesh(tinyusdz::tydra::RenderMesh& mesh, GLuint program_id, + GLMeshState& gl_state) // [out] { std::vector indices; if (mesh.faceVertexCounts.empty()) { // assume all triangulaged faces. if ((mesh.faceVertexIndices.size() % 3) != 0) { - std::cerr << "mesh <" << mesh.abs_name << "> faceVertexIndices.size " << std::to_string(mesh.faceVertexIndices.size()) << " must be multiple of 3\n"; + std::cerr << "mesh <" << mesh.abs_name << "> faceVertexIndices.size " + << std::to_string(mesh.faceVertexIndices.size()) + << " must be multiple of 3\n"; } for (size_t f = 0; f < mesh.faceVertexIndices.size() / 3; f++) { - for (size_t c = 0; c < 3; c++ ) { + for (size_t c = 0; c < 3; c++) { indices.push_back(mesh.faceVertexIndices[3 * f + c]); } } @@ -472,15 +497,17 @@ static bool SetupMesh( // Currently all faces must be triangle. for (size_t f = 0; f < mesh.faceVertexCounts.size(); f++) { if (mesh.faceVertexCounts[f] != 3) { - std::cerr << "mesh <" << mesh.abs_name << "> Non triangle face found at faceVertexCounts[" << f << "] (" << mesh.faceVertexCounts[f] << ")\n"; + std::cerr << "mesh <" << mesh.abs_name + << "> Non triangle face found at faceVertexCounts[" << f + << "] (" << mesh.faceVertexCounts[f] << ")\n"; return false; } - for (size_t c = 0; c < mesh.faceVertexCounts[f]; c++ ) { + for (size_t c = 0; c < mesh.faceVertexCounts[f]; c++) { indices.push_back(mesh.faceVertexIndices[faceOffset + c]); } - faceOffset += f; + faceOffset += f; } } @@ -500,7 +527,7 @@ static bool SetupMesh( // // - Static mesh(STATIC_DRAW) only - { // position + { // position // expand position to facevarying data. // assume faces are all triangle. @@ -509,23 +536,28 @@ static bool SetupMesh( gl_state.num_triangles = indices.size() / 3; for (size_t i = 0; i < indices.size() / 3; i++) { - size_t vi0 = indices[3 * i + 0]; size_t vi1 = indices[3 * i + 1]; size_t vi2 = indices[3 * i + 2]; if (vi0 >= mesh.points.size()) { - std::cerr << "indices[" << (3 * i + 0) << "(" << vi0 << ") exceeds mesh.points.size()(" << mesh.points.size() << ")\n"; + std::cerr << "indices[" << (3 * i + 0) << "(" << vi0 + << ") exceeds mesh.points.size()(" << mesh.points.size() + << ")\n"; return false; } if (vi1 >= mesh.points.size()) { - std::cerr << "indices[" << (3 * i + 1) << "(" << vi1 << ") exceeds mesh.points.size()(" << mesh.points.size() << ")\n"; + std::cerr << "indices[" << (3 * i + 1) << "(" << vi1 + << ") exceeds mesh.points.size()(" << mesh.points.size() + << ")\n"; return false; } if (vi2 >= mesh.points.size()) { - std::cerr << "indices[" << (3 * i + 2) << "(" << vi2 << ") exceeds mesh.points.size()(" << mesh.points.size() << ")\n"; + std::cerr << "indices[" << (3 * i + 2) << "(" << vi2 + << ") exceeds mesh.points.size()(" << mesh.points.size() + << ")\n"; return false; } @@ -537,26 +569,17 @@ static bool SetupMesh( GLuint vb; glGenBuffers(1, &vb); glBindBuffer(GL_ARRAY_BUFFER, vb); - glBufferData( - GL_ARRAY_BUFFER, - facevaryingVertices.size() * sizeof(tinyusdz::tydra::vec3), - facevaryingVertices.data(), - GL_STATIC_DRAW - ); + glBufferData(GL_ARRAY_BUFFER, + facevaryingVertices.size() * sizeof(tinyusdz::tydra::vec3), + facevaryingVertices.data(), GL_STATIC_DRAW); CHECK_GL("Set facevaryingVertices buffer data"); GLint loc = glGetAttribLocation(program_id, kAttribPoints); if (loc > -1) { glEnableVertexAttribArray(loc); - glVertexAttribPointer( - loc, - 3, - GL_FLOAT, - GL_FALSE, - /* stride */sizeof(GLfloat) * 3, - 0 - ); + glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, + /* stride */ sizeof(GLfloat) * 3, 0); CHECK_GL("VertexAttribPointer"); } else { std::cerr << kAttribPoints << " attribute not found in vertex shader.\n"; @@ -564,30 +587,21 @@ static bool SetupMesh( } } - if (mesh.facevaryingNormals.size()) { // normals + if (mesh.facevaryingNormals.size()) { // normals GLuint vb; glGenBuffers(1, &vb); glBindBuffer(GL_ARRAY_BUFFER, vb); - glBufferData( - GL_ARRAY_BUFFER, - mesh.facevaryingNormals.size() * sizeof(tinyusdz::tydra::vec3), - mesh.facevaryingNormals.data(), - GL_STATIC_DRAW - ); + glBufferData(GL_ARRAY_BUFFER, + mesh.facevaryingNormals.size() * sizeof(tinyusdz::tydra::vec3), + mesh.facevaryingNormals.data(), GL_STATIC_DRAW); CHECK_GL("Set facevaryingNormals buffer data"); GLint loc = glGetAttribLocation(program_id, kAttribNormals); if (loc > -1) { glEnableVertexAttribArray(loc); - glVertexAttribPointer( - loc, - 3, - GL_FLOAT, - GL_FALSE, - /* stride */sizeof(GLfloat) * 3, - 0 - ); + glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, + /* stride */ sizeof(GLfloat) * 3, 0); CHECK_GL("VertexAttribPointer"); } else { std::cerr << kAttribNormals << " attribute not found in vertex shader.\n"; @@ -601,19 +615,18 @@ static bool SetupMesh( for (const auto it : mesh.facevaryingTexcoords) { uint32_t slot_id = it.first; if (slot_id >= kMaxTexCoords) { - std::cerr << "Texcoord slot id " << slot_id << " must be less than kMaxTexCoords " << kMaxTexCoords << "\n"; + std::cerr << "Texcoord slot id " << slot_id + << " must be less than kMaxTexCoords " << kMaxTexCoords + << "\n"; return false; } GLuint vb; glGenBuffers(1, &vb); glBindBuffer(GL_ARRAY_BUFFER, vb); - glBufferData( - GL_ARRAY_BUFFER, - it.second.size() * sizeof(tinyusdz::tydra::vec2), - it.second.data(), - GL_STATIC_DRAW - ); + glBufferData(GL_ARRAY_BUFFER, + it.second.size() * sizeof(tinyusdz::tydra::vec2), + it.second.data(), GL_STATIC_DRAW); CHECK_GL("Set facevaryingTexcoord0 buffer data"); std::string texattr = kAttribTexCoordBase + std::to_string(slot_id); @@ -621,14 +634,8 @@ static bool SetupMesh( if (loc > -1) { glEnableVertexAttribArray(loc); - glVertexAttribPointer( - loc, - 2, - GL_FLOAT, - GL_FALSE, - /* stride */sizeof(GLfloat) * 2, - 0 - ); + glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, + /* stride */ sizeof(GLfloat) * 2, 0); CHECK_GL("VertexAttribPointer"); } else { std::cerr << texattr << " attribute not found in vertex shader.\n"; @@ -652,19 +659,16 @@ static bool SetupMesh( return true; } -static void DrawMesh(const GLMeshState &gl_state) { - +static void DrawMesh(const GLMeshState& gl_state) { // Simply bind vertex array object and call glDrawArrays. glBindVertexArray(gl_state.vertex_array_object); glDrawArrays(GL_TRIANGLES, 0, gl_state.num_triangles * 3); CHECK_GL("DrawArrays"); glBindVertexArray(0); - } -static void DrawScene( - const example::shader shader, - const tinyusdz::tydra::RenderScene &scene) { +static void DrawScene(const example::shader shader, + const tinyusdz::tydra::RenderScene& scene) { // // Use single shader for the scene // @@ -673,79 +677,187 @@ static void DrawScene( shader.use(); CHECK_GL("shader.use"); - glUseProgram(0); CHECK_GL("glUseProgram(0)"); } -static void DrawNode(const GLNodeState &gl_node) { +static void DrawNode(const GLNodeState& gl_node) { SetVertexUniforms(gl_node.gl_v_uniform_state); // TODO DrawMesh(gl_node.gl_mesh_state); } +static void ComputeBoundingBox( + const tinyusdz::tydra::RenderMesh &mesh, + std::array &bmin, + std::array &bmax +) +{ + bmin = { std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity() }; + + bmax = { -std::numeric_limits::infinity(), + -std::numeric_limits::infinity(), + -std::numeric_limits::infinity() }; + + for (const auto &p : mesh.points) { + bmin[0] = (std::min)(bmin[0], p[0]); + bmin[1] = (std::min)(bmin[1], p[1]); + bmin[2] = (std::min)(bmin[2], p[2]); + + bmax[0] = (std::max)(bmax[0], p[0]); + bmax[1] = (std::max)(bmax[1], p[1]); + bmax[2] = (std::max)(bmax[2], p[2]); + } +} -static void ProcScene(const tinyusdz::Stage& stage) { +static bool ProcScene(const tinyusdz::Stage& stage) { // // Stage to Renderable Scene tinyusdz::tydra::RenderSceneConverter converter; + tinyusdz::tydra::RenderScene renderScene; + bool ret = converter.ConvertToRenderScene(stage, &renderScene); + if (converter.GetWarning().size()) { + std::cout << "ConvertToRenderScene WARN: " << converter.GetWarning() << "\n"; + } + + if (!ret) { + std::cerr << "Failed to convert USD Stage to OpenGL-like data structure: " << converter.GetError() << "\n"; + exit(-1); + } + + std::cout << "# of meshes: " << renderScene.meshes.size() << "\n"; + + for (size_t i = 0; i < renderScene.meshes.size(); i++) { + std::array bmin; + std::array bmax; + + ComputeBoundingBox(renderScene.meshes[i], bmin, bmax); + + std::cout << "mesh[" << i << "].bmin " << bmin[0] << ", " << bmin[1] << ", " << bmin[2] << "\n"; + std::cout << "mesh[" << i << "].bmax " << bmax[0] << ", " << bmax[1] << ", " << bmax[2] << "\n"; + + GLMeshState gl_mesh; + if (!SetupMesh(renderScene.meshes[i], program_id, gl_mesh)) { + std::cerr << "SetupMesh for mesh[" << i << "] failed.\n"; + exit(-1); + } + } + + // TODO + return true; +} + +static void vnormalize(float v[3]) { + float r; + + r = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + if (r == 0.0) return; + + v[0] /= r; + v[1] /= r; + v[2] /= r; +} + +static void vcross(float v1[3], float v2[3], float result[3]) { + result[0] = v1[1] * v2[2] - v1[2] * v2[1]; + result[1] = v1[2] * v2[0] - v1[0] * v2[2]; + result[2] = v1[0] * v2[1] - v1[1] * v2[0]; +} + +// based on mesa. +static void MygluLookAt(float eye[3], float center[3], float up[3]) { + float forward[3], side[3]; + GLfloat m[4][4]; + + forward[0] = center[0] - eye[0]; + forward[1] = center[1] - eye[1]; + forward[2] = center[2] - eye[2]; + + vnormalize(forward); + + /* Side = forward x up */ + vcross(forward, up, side); + vnormalize(side); + + /* Recompute up as: up = side x forward */ + vcross(side, forward, up); + + memset(m, 0, sizeof(GLfloat) * 16); + m[0][0] = 1.0f; + m[1][1] = 1.0f; + m[2][2] = 1.0f; + m[3][3] = 1.0f; + + m[0][0] = side[0]; + m[1][0] = side[1]; + m[2][0] = side[2]; + + m[0][1] = up[0]; + m[1][1] = up[1]; + m[2][1] = up[2]; + + m[0][2] = -forward[0]; + m[1][2] = -forward[1]; + m[2][2] = -forward[2]; + + glMultMatrixf(&m[0][0]); + // TODO: Use glTranslated? + glTranslatef(-eye[0], -eye[1], -eye[2]); } } // namespace int main(int argc, char** argv) { - // Setup window glfwSetErrorCallback(error_callback); if (!glfwInit()) { exit(EXIT_FAILURE); } - // Decide GL+GLSL versions - #if defined(IMGUI_IMPL_OPENGL_ES2) - // GL ES 2.0 + GLSL 100 - const char* glsl_version = "#version 100"; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); - #elif defined(__APPLE__) - // GL 3.2 + GLSL 150 - const char* glsl_version = "#version 150"; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac - #else - // GL 3.0 + GLSL 130 - const char* glsl_version = "#version 130"; - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only - //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only - #endif +// Decide GL+GLSL versions +#if defined(IMGUI_IMPL_OPENGL_ES2) + // GL ES 2.0 + GLSL 100 + const char* glsl_version = "#version 100"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); +#elif defined(__APPLE__) + // GL 3.2 + GLSL 150 + const char* glsl_version = "#version 150"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac +#else + // GL 3.0 + GLSL 130 + const char* glsl_version = "#version 130"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + // glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ + // only glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only +#endif float highDPIscaleFactor = 1.0f; #if defined(_WIN32) || defined(__linux__) - // if it's a HighDPI monitor, try to scale everything - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - float xscale, yscale; - glfwGetMonitorContentScale(monitor, &xscale, &yscale); - std::cout << "monitor xscale, yscale = " << xscale << ", " << yscale << "\n"; - if (xscale > 1 || yscale > 1) - { - highDPIscaleFactor = xscale; - glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); - - } + // if it's a HighDPI monitor, try to scale everything + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + float xscale, yscale; + glfwGetMonitorContentScale(monitor, &xscale, &yscale); + std::cout << "monitor xscale, yscale = " << xscale << ", " << yscale << "\n"; + if (xscale > 1 || yscale > 1) { + highDPIscaleFactor = xscale; + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); + } #elif __APPLE__ - glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); + glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); #endif - #ifdef _DEBUG_OPENGL glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); #endif @@ -774,12 +886,11 @@ int main(int argc, char** argv) { ProcScene(stage); - GLFWwindow* window{nullptr}; window = glfwCreateWindow(gCtx.width, gCtx.height, "Simple USDZ GL viewer", nullptr, nullptr); glfwMakeContextCurrent(window); - glfwSwapInterval(1); // vsync on + glfwSwapInterval(1); // vsync on if (!gladLoadGLLoader(reinterpret_cast(glfwGetProcAddress))) { std::cerr << "Failed to load OpenGL functions with gladLoadGL\n"; @@ -828,13 +939,30 @@ int main(int argc, char** argv) { ImGuiIO& io = ImGui::GetIO(); - io.DisplayFramebufferScale = {2.0f, 2.0f}; // HACK + io.DisplayFramebufferScale = {2.0f, 2.0f}; // HACK ImFontConfig font_config; font_config.SizePixels = 16.0f * xscale; io.Fonts->AddFontDefault(&font_config); } + std::array bmin = {-100.0f, -100.0f, -100.0f}; + std::array bmax = {100.0f, 100.0f, 100.0f}; + + float maxExtent = 0.5f * (bmax[0] - bmin[0]); + if (maxExtent < 0.5f * (bmax[1] - bmin[1])) { + maxExtent = 0.5f * (bmax[1] - bmin[1]); + } + if (maxExtent < 0.5f * (bmax[2] - bmin[2])) { + maxExtent = 0.5f * (bmax[2] - bmin[2]); + } + + float eye[3], lookat[3], up[3]; + + up[0] = 0.0f; + up[1] = 1.0f; + up[2] = 0.0f; + while (!done) { glfwPollEvents(); ImGui_ImplOpenGL3_NewFrame(); @@ -854,6 +982,21 @@ int main(int argc, char** argv) { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // camera & rotate + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + MygluLookAt(eye, lookat, up); + // GLfloat mat[4][4]; + // build_rotmatrix(mat, curr_quat); + // glMultMatrixf(&mat[0][0]); + + // Fit model to [-1, 1] + glScalef(1.0f / maxExtent, 1.0f / maxExtent, 1.0f / maxExtent); + + // Centerize object. + glTranslatef(-0.5 * (bmax[0] + bmin[0]), -0.5 * (bmax[1] + bmin[1]), + -0.5 * (bmax[2] + bmin[2])); + #if 0 // Draw scene if ((scene.default_root_node >= 0) && (scene.default_root_node < scene.nodes.size())) {