// glad must be included before glfw3.h #include // #include #include // C++11 #include #include // C++11 #include #include #include #include // C++11 #include // C++11 #include // common #include "imgui.h" #include "imgui_impl_glfw.h" #include "imgui_impl_opengl2.h" #include "tinyusdz.hh" #include "trackball.h" #include "cuew/cuew.h" #define OPTIX_DONT_INCLUDE_CUDA #include #define CU_CHECK(cond) \ do { \ CUresult ret = cond; \ if (ret != CUDA_SUCCESS) { \ std::cerr << __FILE__ << ":" << __LINE__ \ << " CUDA Device API failed. retcode " << ret << "\n"; \ exit(-1); \ } \ } while (0) #define CU_SYNC_CHECK() \ do { \ /* assume cuCtxSynchronize() ~= cudaDeviceSynchronize() */ \ CUresult ret = cuCtxSynchronize(); \ if (ret != CUDA_SUCCESS) { \ std::cerr << __FILE__ << ":" << __LINE__ \ << " cuCtxSynchronize() failed. retcode " << ret << "\n"; \ exit(-1); \ } \ } while (0) #define OPTIX_CHECK(callfun) \ do { \ OptixResult ret = callfun; \ if (ret != OPTIX_SUCCESS) { \ std::cerr << __FILE__ << ":" << __LINE__ << " Optix call" << #callfun \ << " failed. retcode " << ret << "\n"; \ exit(-1); \ } \ } while (0) struct GUIContext { enum AOV { AOV_COLOR = 0, AOV_NORMAL, AOV_POSITION, AOV_DEPTH, AOV_TEXCOORD, AOV_VARYCOORD, AOV_VERTEXCOLOR }; AOV aov{AOV_COLOR}; int width = 1024; int height = 768; int mouse_x = -1; int mouse_y = -1; bool mouse_left_down = false; bool shift_pressed = false; bool ctrl_pressed = false; bool tab_pressed = false; float curr_quat[4] = {0.0f, 0.0f, 0.0f, 1.0f}; float prev_quat[4] = {0.0f, 0.0f, 0.0f, 1.0f}; 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}; }; GUIContext gCtx; // --- glfw ---------------------------------------------------- static void error_callback(int error, const char* description) { std::cerr << "GLFW Error : " << error << ", " << description << std::endl; } static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { (void)scancode; ImGuiIO& io = ImGui::GetIO(); if (io.WantCaptureKeyboard) { return; } if ((key == GLFW_KEY_LEFT_SHIFT) || (key == GLFW_KEY_RIGHT_SHIFT)) { auto* param = reinterpret_cast(glfwGetWindowUserPointer(window)); param->shift_pressed = (action == GLFW_PRESS); } if ((key == GLFW_KEY_LEFT_CONTROL) || (key == GLFW_KEY_RIGHT_CONTROL)) { auto* param = reinterpret_cast(glfwGetWindowUserPointer(window)); param->ctrl_pressed = (action == GLFW_PRESS); } if (key == GLFW_KEY_Q && action == GLFW_PRESS && (mods & GLFW_MOD_CONTROL)) { glfwSetWindowShouldClose(window, GLFW_TRUE); } } static void mouse_move_callback(GLFWwindow* window, double x, double y) { auto param = reinterpret_cast(glfwGetWindowUserPointer(window)); assert(param); if (param->mouse_left_down) { float w = static_cast(param->width); float h = static_cast(param->height); float x_offset = param->width - w; float y_offset = param->height - h; if (param->ctrl_pressed) { const float dolly_scale = 0.1f; param->eye[2] += dolly_scale * (param->mouse_y - static_cast(y)); param->lookat[2] += dolly_scale * (param->mouse_y - static_cast(y)); } else if (param->shift_pressed) { const float trans_scale = 0.02f; param->eye[0] += trans_scale * (param->mouse_x - static_cast(x)); param->eye[1] -= trans_scale * (param->mouse_y - static_cast(y)); param->lookat[0] += trans_scale * (param->mouse_x - static_cast(x)); param->lookat[1] -= trans_scale * (param->mouse_y - static_cast(y)); } else { // Adjust y. trackball(param->prev_quat, (2.f * (param->mouse_x - x_offset) - w) / static_cast(w), (h - 2.f * (param->mouse_y - y_offset)) / static_cast(h), (2.f * (static_cast(x) - x_offset) - w) / static_cast(w), (h - 2.f * (static_cast(y) - y_offset)) / static_cast(h)); add_quats(param->prev_quat, param->curr_quat, param->curr_quat); } } param->mouse_x = static_cast(x); param->mouse_y = static_cast(y); } static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { ImGuiIO& io = ImGui::GetIO(); if (io.WantCaptureMouse || io.WantCaptureKeyboard) { return; } auto param = reinterpret_cast(glfwGetWindowUserPointer(window)); assert(param); // left button if (button == 0) { if (action) { param->mouse_left_down = true; trackball(param->prev_quat, 0.0f, 0.0f, 0.0f, 0.0f); } else { param->mouse_left_down = false; } } } static void resize_callback(GLFWwindow* window, int width, int height) { auto param = reinterpret_cast(glfwGetWindowUserPointer(window)); assert(param); param->width = width; param->height = height; } // ------------------------------------------------ namespace { #if 0 static void DrawGeomMesh(tinyusdz::GeomMesh& mesh) {} static void DrawNode(const tinyusdz::Scene& scene, const tinyusdz::Node& node) { if (node.type == tinyusdz::NODE_TYPE_XFORM) { const tinyusdz::Xform& xform = scene.xforms.at(node.index); glPushMatrix(); tinyusdz::Matrix4d matrix = xform.GetMatrix(); glMultMatrixd(reinterpret_cast(&(matrix.m))); } for (const auto& child : node.children) { if ((child.index >= 0) && (child.index < scene.nodes.size())) { DrawNode(scene, scene.nodes.at(size_t(child.index))); } } if (node.type == tinyusdz::NODE_TYPE_XFORM) { glPopMatrix(); } } static void Proc(const tinyusdz::Scene &scene) { std::cout << "num geom_meshes = " << scene.geom_meshes.size(); for (auto &mesh : scene.geom_meshes) { } } #endif } // namespace int main(int argc, char** argv) { if (cuewInit(CUEW_INIT_CUDA) != CUEW_SUCCESS) { std::cerr << "Failed to initialize CUDA\n"; return -1; } printf("CUDA compiler path: %s, compiler version: %d\n", cuewCompilerPath(), cuewCompilerVersion()); // Currently we require NVRTC to be available for runtime .cu compilation. if (cuewInit(CUEW_INIT_NVRTC) != CUEW_SUCCESS) { std::cerr << "Failed to initialize NVRTC. NVRTC library is not available " "or not found in the system search path\n"; return -1; } else { int major, minor; nvrtcVersion(&major, &minor); std::cout << "Found NVRTC runtime compilation library version " << major << "." << minor << "\n"; } // // Initialize CUDA and create OptiX context // if (cuInit(0) != CUDA_SUCCESS) { std::cerr << "Failed to init CUDA\n"; return -1; } OptixDeviceContext context = nullptr; CUcontext cuCtx{}; { int counts{0}; CU_CHECK(cuDeviceGetCount(&counts)); std::cout << "# of CUDA devices: " << counts << "\n"; if (counts < 1) { std::cerr << "No CUDA device found\n"; return -1; } CUdevice device{}; if (CUDA_SUCCESS != cuDeviceGet(&device, /* devid */ 0)) { std::cerr << "Failed to get CUDA device.\n"; return -1; } { int major, minor; CU_CHECK(cuDeviceComputeCapability(&major, &minor, device)); std::cerr << "compute capability: " << major << "." << minor << "\n"; } if (CUDA_SUCCESS != cuCtxCreate(&cuCtx, /* flags */ 0, device)) { std::cerr << "Failed to get Create CUDA context.\n"; return -1; } } // ====================================== // Setup window glfwSetErrorCallback(error_callback); if (!glfwInit()) { exit(EXIT_FAILURE); } std::string filename = "../../../models/suzanne.usdc"; if (argc > 1) { filename = std::string(argv[1]); } std::cout << "Loading file " << filename << "\n"; std::string warn; std::string err; tinyusdz::Stage stage; bool ret = tinyusdz::LoadUSDFromFile(filename, &stage, &warn, &err); if (!warn.empty()) { std::cerr << "WARN : " << warn << "\n"; return EXIT_FAILURE; } if (!err.empty()) { std::cerr << "ERR : " << err << "\n"; return EXIT_FAILURE; } if (!ret) { std::cerr << "Failed to load USD file: " << filename << "\n"; return EXIT_FAILURE; } //Proc(scene); #ifdef _DEBUG_OPENGL glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); #endif //// Create a GLES 3.0 context // glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); // glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // glfwWindowHint(GLFW_SAMPLES, 16); // glfwWindowHint(GLFW_DOUBLEBUFFER, GL_TRUE); #ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // It looks this is important on macOS. #endif GLFWwindow* window{nullptr}; window = glfwCreateWindow(gCtx.width, gCtx.height, "Simple USDZ GL viewer", nullptr, nullptr); glfwMakeContextCurrent(window); if (!gladLoadGLLoader(reinterpret_cast(glfwGetProcAddress))) { std::cerr << "Failed to load OpenGL functions with gladLoadGL\n"; exit(EXIT_FAILURE); } std::cout << "OpenGL " << GLVersion.major << '.' << GLVersion.minor << '\n'; if (GLVersion.major < 2) { std::cerr << "OpenGL 2. or later should be available." << std::endl; exit(EXIT_FAILURE); } #ifdef _DEBUG_OPENGL glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(reinterpret_cast(glDebugOutput), nullptr); glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); #endif glfwSwapInterval(1); // Enable vsync GUIContext gui_ctx; glfwSetWindowUserPointer(window, &gui_ctx); glfwSetKeyCallback(window, key_callback); glfwSetCursorPosCallback(window, mouse_move_callback); glfwSetMouseButtonCallback(window, mouse_button_callback); glfwSetFramebufferSizeCallback(window, resize_callback); bool done = false; ImGui::CreateContext(); ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL2_Init(); int display_w, display_h; ImVec4 clear_color = {0.1f, 0.18f, 0.3f, 1.0f}; while (!done) { glfwPollEvents(); ImGui_ImplOpenGL2_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); ImGui::Begin("Bora"); ImGui::Button("muda"); ImGui::End(); glfwGetFramebufferSize(window, &display_w, &display_h); glViewport(0, 0, display_w, display_h); glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); #if 0 // Draw scene if ((scene.default_root_node >= 0) && (scene.default_root_node < scene.nodes.size())) { DrawNode(scene, scene.nodes[scene.default_root_node]); } else { static bool printed = false; if (!printed) { std::cerr << "USD scene does not contain root node. or has invalid root node ID\n"; std::cerr << " # of nodes in the scene: " << scene.nodes.size() << "\n"; std::cerr << " scene.default_root_node: " << scene.default_root_node << "\n"; printed = true; } } #endif // Imgui ImGui::Render(); ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(window); glFlush(); static int frameCount = 0; static double currentTime = glfwGetTime(); static double previousTime = currentTime; static char title[256]; frameCount++; currentTime = glfwGetTime(); const auto deltaTime = currentTime - previousTime; if (deltaTime >= 1.0) { sprintf(title, "Simple GL USDZ viewer [%dFPS]", frameCount); glfwSetWindowTitle(window, title); frameCount = 0; previousTime = currentTime; } glfwSwapBuffers(window); done = glfwWindowShouldClose(window); }; ImGui_ImplOpenGL2_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); glfwDestroyWindow(window); glfwTerminate(); return EXIT_SUCCESS; }