1171 lines
31 KiB
C++
1171 lines
31 KiB
C++
|
|
||
|
#include <algorithm>
|
||
|
#include <atomic> // C++11
|
||
|
#include <cassert>
|
||
|
#include <chrono> // C++11
|
||
|
#include <cmath>
|
||
|
#include <cstdio>
|
||
|
#include <cstdlib>
|
||
|
#include <iostream>
|
||
|
#include <mutex> // C++11
|
||
|
#include <thread> // C++11
|
||
|
|
||
|
#ifdef __EMSCRIPTEN__
|
||
|
#include <emscripten.h>
|
||
|
#include <emscripten/html5.h>
|
||
|
#endif
|
||
|
|
||
|
// ../common/SDL2
|
||
|
#include <SDL.h>
|
||
|
|
||
|
#if defined(SDL_VIDEO_DRIVER_X11)
|
||
|
#include <SDL_syswm.h>
|
||
|
#endif
|
||
|
|
||
|
#if defined(USDVIEW_USE_BULLET3)
|
||
|
#include <btBulletDynamicsCommon.h>
|
||
|
#endif
|
||
|
|
||
|
// common
|
||
|
#include "imgui.h"
|
||
|
#include "imgui_impl_sdl.h"
|
||
|
#include "imgui_impl_sdlrenderer.h"
|
||
|
#include "imnodes.h"
|
||
|
#include "roboto_mono_embed.inc.h"
|
||
|
#include "virtualGizmo3D/vGizmo.h"
|
||
|
|
||
|
//
|
||
|
#include "gui.hh"
|
||
|
#include "simple-render.hh"
|
||
|
#include "tinyusdz.hh"
|
||
|
#include "trackball.h"
|
||
|
|
||
|
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
|
||
|
#include "nfd.h"
|
||
|
#endif
|
||
|
|
||
|
//#define EMULATE_EMSCRIPTEN
|
||
|
|
||
|
#if defined(EMULATE_EMSCRIPTEN)
|
||
|
#define EM_BOOL int
|
||
|
#define EM_TRUE 1
|
||
|
#define EM_FALSE 0
|
||
|
#endif
|
||
|
|
||
|
struct GUIContext {
|
||
|
enum AOVMode {
|
||
|
AOV_COLOR = 0,
|
||
|
AOV_SHADING_NORMAL,
|
||
|
AOV_GEOMETRIC_NORMAL,
|
||
|
AOV_POSITION,
|
||
|
AOV_DEPTH,
|
||
|
AOV_TEXCOORD,
|
||
|
AOV_VARYCOORD,
|
||
|
AOV_VERTEXCOLOR
|
||
|
};
|
||
|
int aov_mode{AOV_COLOR};
|
||
|
|
||
|
example::AOV aov; // framebuffer
|
||
|
|
||
|
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 yaw = 90.0f; // for Z up scene
|
||
|
float pitch = 0.0f;
|
||
|
float roll = 0.0f;
|
||
|
|
||
|
// float curr_quat[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||
|
// std::array<float, 4> prev_quat[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||
|
|
||
|
// std::array<float, 3> eye = {0.0f, 0.0f, 5.0f};
|
||
|
// std::array<float, 3> lookat = {0.0f, 0.0f, 0.0f};
|
||
|
// std::array<float, 3> up = {0.0f, 1.0f, 0.0f};
|
||
|
|
||
|
example::RenderScene render_scene;
|
||
|
|
||
|
example::Camera camera;
|
||
|
|
||
|
std::atomic<bool> update_texture{false};
|
||
|
std::atomic<bool> redraw{true}; // require redraw
|
||
|
std::atomic<bool> quit{false};
|
||
|
|
||
|
SDL_Renderer* renderer;
|
||
|
SDL_Texture* texture; // Texture for rendered image
|
||
|
int render_width = 512;
|
||
|
int render_height = 512;
|
||
|
|
||
|
// scene reload
|
||
|
tinyusdz::Stage stage;
|
||
|
std::atomic<bool> request_reload{false};
|
||
|
std::string filename;
|
||
|
|
||
|
#if __EMSCRIPTEN__ || defined(EMULATE_EMSCRIPTEN)
|
||
|
bool render_finished{false};
|
||
|
int current_render_line = 0;
|
||
|
int render_line_size =
|
||
|
32; // render images with this lines per animation loop.
|
||
|
// for emscripten environment
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
GUIContext g_gui_ctx;
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
inline double radians(double degree) { return 3.141592653589 * degree / 180.0; }
|
||
|
|
||
|
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
|
||
|
std::array<double, 4> ToQuaternion(double yaw, double pitch,
|
||
|
double roll) // yaw (Z), pitch (Y), roll (X)
|
||
|
{
|
||
|
// Abbreviations for the various angular functions
|
||
|
double cy = std::cos(yaw * 0.5);
|
||
|
double sy = std::sin(yaw * 0.5);
|
||
|
double cp = std::cos(pitch * 0.5);
|
||
|
double sp = std::sin(pitch * 0.5);
|
||
|
double cr = std::cos(roll * 0.5);
|
||
|
double sr = std::sin(roll * 0.5);
|
||
|
|
||
|
std::array<double, 4> q;
|
||
|
q[0] = cr * cp * cy + sr * sp * sy;
|
||
|
q[1] = sr * cp * cy - cr * sp * sy;
|
||
|
q[2] = cr * sp * cy + sr * cp * sy;
|
||
|
q[3] = cr * cp * sy - sr * sp * cy;
|
||
|
|
||
|
return q;
|
||
|
}
|
||
|
|
||
|
#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);
|
||
|
}
|
||
|
|
||
|
for (const auto& child : node.children) {
|
||
|
// DrawNode(scene, scene.nodes.at(child));
|
||
|
}
|
||
|
|
||
|
if (node.type == tinyusdz::NODE_TYPE_XFORM) {
|
||
|
// glPopMatrix();
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void Proc(const tinyusdz::Stage& stage) {
|
||
|
(void)stage;
|
||
|
|
||
|
//std::cout << "num geom_meshes = " << scene.geom_meshes.size() << "\n";
|
||
|
//for (auto& mesh : scene.geom_meshes) {
|
||
|
//}
|
||
|
}
|
||
|
|
||
|
static std::string GetFileExtension(const std::string& filename) {
|
||
|
if (filename.find_last_of(".") != std::string::npos)
|
||
|
return filename.substr(filename.find_last_of(".") + 1);
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
static std::string str_tolower(std::string s) {
|
||
|
std::transform(s.begin(), s.end(), s.begin(),
|
||
|
// static_cast<int(*)(int)>(std::tolower) // wrong
|
||
|
// [](int c){ return std::tolower(c); } // wrong
|
||
|
// [](char c){ return std::tolower(c); } // wrong
|
||
|
[](unsigned char c) { return std::tolower(c); } // correct
|
||
|
);
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
// TODO: Use pow table for faster conversion.
|
||
|
inline float linearToSrgb(float x) {
|
||
|
if (x <= 0.0f)
|
||
|
return 0.0f;
|
||
|
else if (x >= 1.0f)
|
||
|
return 1.0f;
|
||
|
else if (x < 0.0031308f)
|
||
|
return x * 12.92f;
|
||
|
else
|
||
|
return std::pow(x, 1.0f / 2.4f) * 1.055f - 0.055f;
|
||
|
}
|
||
|
|
||
|
inline uint8_t ftouc(float f) {
|
||
|
int val = int(f * 255.0f);
|
||
|
val = (std::max)(0, (std::min)(255, val));
|
||
|
|
||
|
return static_cast<uint8_t>(val);
|
||
|
}
|
||
|
|
||
|
void UpdateTexutre(SDL_Texture* tex, const GUIContext& ctx,
|
||
|
const example::AOV& aov) {
|
||
|
int w, h;
|
||
|
SDL_QueryTexture(tex, nullptr, nullptr, &w, &h);
|
||
|
|
||
|
if ((aov.width != w) || (aov.height != h)) {
|
||
|
std::cerr << "texture size and AOV sized mismatch\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
std::vector<uint8_t> buf;
|
||
|
buf.resize(aov.width * aov.height * 4);
|
||
|
|
||
|
if (ctx.aov_mode == GUIContext::AOV_COLOR) {
|
||
|
for (size_t i = 0; i < aov.width * aov.height; i++) {
|
||
|
uint8_t r = ftouc(linearToSrgb(aov.rgb[3 * i + 0]));
|
||
|
uint8_t g = ftouc(linearToSrgb(aov.rgb[3 * i + 1]));
|
||
|
uint8_t b = ftouc(linearToSrgb(aov.rgb[3 * i + 2]));
|
||
|
|
||
|
buf[4 * i + 0] = r;
|
||
|
buf[4 * i + 1] = g;
|
||
|
buf[4 * i + 2] = b;
|
||
|
buf[4 * i + 3] = 255;
|
||
|
}
|
||
|
} else if (ctx.aov_mode == GUIContext::AOV_SHADING_NORMAL) {
|
||
|
for (size_t i = 0; i < aov.width * aov.height; i++) {
|
||
|
uint8_t r = ftouc(aov.shading_normal[3 * i + 0]);
|
||
|
uint8_t g = ftouc(aov.shading_normal[3 * i + 1]);
|
||
|
uint8_t b = ftouc(aov.shading_normal[3 * i + 2]);
|
||
|
|
||
|
buf[4 * i + 0] = r;
|
||
|
buf[4 * i + 1] = g;
|
||
|
buf[4 * i + 2] = b;
|
||
|
buf[4 * i + 3] = 255;
|
||
|
}
|
||
|
} else if (ctx.aov_mode == GUIContext::AOV_GEOMETRIC_NORMAL) {
|
||
|
for (size_t i = 0; i < aov.width * aov.height; i++) {
|
||
|
uint8_t r = ftouc(aov.geometric_normal[3 * i + 0]);
|
||
|
uint8_t g = ftouc(aov.geometric_normal[3 * i + 1]);
|
||
|
uint8_t b = ftouc(aov.geometric_normal[3 * i + 2]);
|
||
|
|
||
|
buf[4 * i + 0] = r;
|
||
|
buf[4 * i + 1] = g;
|
||
|
buf[4 * i + 2] = b;
|
||
|
buf[4 * i + 3] = 255;
|
||
|
}
|
||
|
} else if (ctx.aov_mode == GUIContext::AOV_TEXCOORD) {
|
||
|
for (size_t i = 0; i < aov.width * aov.height; i++) {
|
||
|
uint8_t r = ftouc(aov.texcoords[2 * i + 0]);
|
||
|
uint8_t g = ftouc(aov.texcoords[2 * i + 1]);
|
||
|
uint8_t b = 255;
|
||
|
|
||
|
buf[4 * i + 0] = r;
|
||
|
buf[4 * i + 1] = g;
|
||
|
buf[4 * i + 2] = b;
|
||
|
buf[4 * i + 3] = 255;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SDL_UpdateTexture(tex, nullptr, reinterpret_cast<const void*>(buf.data()),
|
||
|
aov.width * 4);
|
||
|
}
|
||
|
|
||
|
// https://discourse.libsdl.org/t/sdl-and-xserver/12610/4
|
||
|
static void ScreenActivate(SDL_Window* window) {
|
||
|
#if defined(SDL_VIDEO_DRIVER_X11)
|
||
|
SDL_SysWMinfo wm;
|
||
|
|
||
|
// Get window info.
|
||
|
SDL_VERSION(&wm.version);
|
||
|
SDL_GetWindowWMInfo(window, &wm);
|
||
|
|
||
|
// Lock to display access.
|
||
|
// wm.info.x11.lock_func();
|
||
|
|
||
|
// Show the window on top.
|
||
|
XMapRaised(wm.info.x11.display, wm.info.x11.window);
|
||
|
|
||
|
// Set the focus on it.
|
||
|
XSetInputFocus(wm.info.x11.display, wm.info.x11.window, RevertToParent,
|
||
|
CurrentTime);
|
||
|
#else
|
||
|
(void)window;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
bool LoadModel(const std::string& filename, tinyusdz::Stage* stage) {
|
||
|
std::string ext = str_tolower(GetFileExtension(filename));
|
||
|
|
||
|
std::string warn;
|
||
|
std::string err;
|
||
|
|
||
|
if (ext.compare("usdz") == 0) {
|
||
|
std::cout << "usdz\n";
|
||
|
bool ret = tinyusdz::LoadUSDZFromFile(filename, stage, &warn, &err);
|
||
|
if (!warn.empty()) {
|
||
|
std::cerr << "WARN : " << warn << "\n";
|
||
|
}
|
||
|
if (!err.empty()) {
|
||
|
std::cerr << "ERR : " << err << "\n";
|
||
|
}
|
||
|
|
||
|
if (!ret) {
|
||
|
std::cerr << "Failed to load USDZ file: " << filename << "\n";
|
||
|
return false;
|
||
|
}
|
||
|
} else if (ext.compare("usda") == 0) {
|
||
|
std::cout << "usda\n";
|
||
|
bool ret = tinyusdz::LoadUSDAFromFile(filename, stage, &warn, &err);
|
||
|
if (!warn.empty()) {
|
||
|
std::cerr << "WARN : " << warn << "\n";
|
||
|
}
|
||
|
if (!err.empty()) {
|
||
|
std::cerr << "ERR : " << err << "\n";
|
||
|
}
|
||
|
|
||
|
if (!ret) {
|
||
|
std::cerr << "Failed to load USDA file: " << filename << "\n";
|
||
|
return false;
|
||
|
}
|
||
|
} else { // assume usdc
|
||
|
bool ret = tinyusdz::LoadUSDCFromFile(filename, stage, &warn, &err);
|
||
|
if (!warn.empty()) {
|
||
|
std::cerr << "WARN : " << warn << "\n";
|
||
|
}
|
||
|
if (!err.empty()) {
|
||
|
std::cerr << "ERR : " << err << "\n";
|
||
|
}
|
||
|
|
||
|
if (!ret) {
|
||
|
std::cerr << "Failed to load USDC file: " << filename << "\n";
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void RenderThread(GUIContext* ctx) {
|
||
|
bool done = false;
|
||
|
|
||
|
while (!done) {
|
||
|
if (ctx->quit) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (ctx->request_reload) {
|
||
|
ctx->stage = tinyusdz::Stage(); // reset
|
||
|
|
||
|
if (LoadModel(ctx->filename, &ctx->stage)) {
|
||
|
Proc(ctx->stage);
|
||
|
#if 0
|
||
|
if (ctx->scene.geom_meshes.empty()) {
|
||
|
std::cerr << "The scene contains no GeomMesh\n";
|
||
|
} else {
|
||
|
ctx->render_scene.draw_meshes.clear();
|
||
|
|
||
|
for (size_t i = 0; i < ctx->scene.geom_meshes.size(); i++) {
|
||
|
example::DrawGeomMesh draw_mesh(&ctx->scene.geom_meshes[i]);
|
||
|
ctx->render_scene.draw_meshes.push_back(draw_mesh);
|
||
|
}
|
||
|
|
||
|
// Setup render mesh
|
||
|
if (!ctx->render_scene.Setup()) {
|
||
|
std::cerr << "Failed to setup render mesh.\n";
|
||
|
ctx->render_scene.draw_meshes.clear();
|
||
|
}
|
||
|
std::cout << "Setup render mesh\n";
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
ctx->request_reload = false;
|
||
|
|
||
|
ctx->redraw = true;
|
||
|
}
|
||
|
|
||
|
if (!ctx->redraw) {
|
||
|
// Give CPU some cycles.
|
||
|
std::this_thread::sleep_for(std::chrono::milliseconds(33));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
example::Render(ctx->render_scene, ctx->camera, &ctx->aov);
|
||
|
|
||
|
ctx->update_texture = true;
|
||
|
|
||
|
ctx->redraw = false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
|
||
|
// TODO: widechar(UTF-16) support for Windows
|
||
|
std::string OpenFileDialog() {
|
||
|
std::string path;
|
||
|
|
||
|
nfdchar_t* outPath;
|
||
|
nfdfilteritem_t filterItem[1] = {{"USD file", "usda,usdc,usdz"}};
|
||
|
|
||
|
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 1, NULL);
|
||
|
if (result == NFD_OKAY) {
|
||
|
puts("Success!");
|
||
|
path = outPath;
|
||
|
NFD_FreePath(outPath);
|
||
|
} else if (result == NFD_CANCEL) {
|
||
|
puts("User pressed cancel.");
|
||
|
} else {
|
||
|
printf("Error: %s\n", NFD_GetError());
|
||
|
}
|
||
|
|
||
|
return path;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Helper to display a little (?) mark which shows a tooltip when hovered.
|
||
|
// In your own code you may want to display an actual icon if you are using a
|
||
|
// merged icon fonts (see docs/FONTS.md)
|
||
|
static void HelpMarker(const char* desc) {
|
||
|
ImGui::TextDisabled("(?)");
|
||
|
if (ImGui::IsItemHovered()) {
|
||
|
ImGui::BeginTooltip();
|
||
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||
|
ImGui::TextUnformatted(desc);
|
||
|
ImGui::PopTextWrapPos();
|
||
|
ImGui::EndTooltip();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if defined(__EMSCRIPTEN__) || defined(EMULATE_EMSCRIPTEN)
|
||
|
|
||
|
EM_BOOL em_main_loop_frame(double tm, void* user) {
|
||
|
#if 1
|
||
|
// Render image fragment
|
||
|
if (g_gui_ctx.redraw) {
|
||
|
g_gui_ctx.render_finished = false;
|
||
|
g_gui_ctx.current_render_line = 0;
|
||
|
|
||
|
g_gui_ctx.redraw = false;
|
||
|
}
|
||
|
|
||
|
if (!g_gui_ctx.render_finished) {
|
||
|
std::cout << "RenderLines: " << g_gui_ctx.current_render_line << "\n";
|
||
|
RenderLines(g_gui_ctx.current_render_line,
|
||
|
g_gui_ctx.current_render_line + g_gui_ctx.render_line_size,
|
||
|
g_gui_ctx.render_scene, g_gui_ctx.camera, &g_gui_ctx.aov);
|
||
|
|
||
|
g_gui_ctx.current_render_line += g_gui_ctx.render_line_size;
|
||
|
if (g_gui_ctx.current_render_line >= g_gui_ctx.render_height) {
|
||
|
g_gui_ctx.current_render_line = 0;
|
||
|
g_gui_ctx.render_finished = true;
|
||
|
|
||
|
g_gui_ctx.update_texture = true;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
ImGuiIO& io = ImGui::GetIO();
|
||
|
|
||
|
#if 1
|
||
|
int wheel = 0;
|
||
|
|
||
|
SDL_Event e;
|
||
|
if (SDL_PollEvent(&e)) {
|
||
|
if (e.type == SDL_QUIT) {
|
||
|
return EM_FALSE;
|
||
|
} else if (e.type == SDL_DROPFILE) {
|
||
|
char* filepath = e.drop.file;
|
||
|
|
||
|
printf("File dropped: %s\n", filepath);
|
||
|
|
||
|
SDL_free(filepath);
|
||
|
|
||
|
} else if (e.type == SDL_WINDOWEVENT) {
|
||
|
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
||
|
io.DisplaySize.x = static_cast<float>(e.window.data1);
|
||
|
io.DisplaySize.y = static_cast<float>(e.window.data2);
|
||
|
}
|
||
|
} else if (e.type == SDL_KEYDOWN) {
|
||
|
if (e.key.keysym.sym == SDLK_ESCAPE) {
|
||
|
return EM_FALSE;
|
||
|
}
|
||
|
} else if (e.type == SDL_KEYUP) {
|
||
|
} else if (e.type == SDL_MOUSEWHEEL) {
|
||
|
wheel = e.wheel.y;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int mouseX, mouseY;
|
||
|
const int buttons = SDL_GetMouseState(&mouseX, &mouseY);
|
||
|
|
||
|
// Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or
|
||
|
// write to those fields from your Windows message loop handlers,
|
||
|
// etc.)
|
||
|
|
||
|
io.DeltaTime = 1.0f / 60.0f;
|
||
|
io.MousePos = ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
|
||
|
io.MouseDown[0] = buttons & SDL_BUTTON(SDL_BUTTON_LEFT);
|
||
|
io.MouseDown[1] = buttons & SDL_BUTTON(SDL_BUTTON_RIGHT);
|
||
|
io.MouseWheel = static_cast<float>(wheel);
|
||
|
#endif
|
||
|
|
||
|
#if 1
|
||
|
ImGui::NewFrame();
|
||
|
|
||
|
bool update = false;
|
||
|
bool update_display = false;
|
||
|
ImGui::Begin("Scene");
|
||
|
|
||
|
update |=
|
||
|
ImGui::SliderFloat("eye.z", &g_gui_ctx.camera.eye[2], -1000.0, 1000.0f);
|
||
|
update |= ImGui::SliderFloat("fov", &g_gui_ctx.camera.fov, 0.01f, 140.0f);
|
||
|
|
||
|
// TODO: Validate coordinate definition.
|
||
|
if (ImGui::SliderFloat("yaw", &g_gui_ctx.yaw, -360.0f, 360.0f)) {
|
||
|
auto q = ToQuaternion(radians(g_gui_ctx.yaw), radians(g_gui_ctx.pitch),
|
||
|
radians(g_gui_ctx.roll));
|
||
|
g_gui_ctx.camera.quat[0] = q[0];
|
||
|
g_gui_ctx.camera.quat[1] = q[1];
|
||
|
g_gui_ctx.camera.quat[2] = q[2];
|
||
|
g_gui_ctx.camera.quat[3] = q[3];
|
||
|
update = true;
|
||
|
}
|
||
|
if (ImGui::SliderFloat("pitch", &g_gui_ctx.pitch, -360.0f, 360.0f)) {
|
||
|
auto q = ToQuaternion(radians(g_gui_ctx.yaw), radians(g_gui_ctx.pitch),
|
||
|
radians(g_gui_ctx.roll));
|
||
|
g_gui_ctx.camera.quat[0] = q[0];
|
||
|
g_gui_ctx.camera.quat[1] = q[1];
|
||
|
g_gui_ctx.camera.quat[2] = q[2];
|
||
|
g_gui_ctx.camera.quat[3] = q[3];
|
||
|
update = true;
|
||
|
}
|
||
|
if (ImGui::SliderFloat("roll", &g_gui_ctx.roll, -360.0f, 360.0f)) {
|
||
|
auto q = ToQuaternion(radians(g_gui_ctx.yaw), radians(g_gui_ctx.pitch),
|
||
|
radians(g_gui_ctx.roll));
|
||
|
g_gui_ctx.camera.quat[0] = q[0];
|
||
|
g_gui_ctx.camera.quat[1] = q[1];
|
||
|
g_gui_ctx.camera.quat[2] = q[2];
|
||
|
g_gui_ctx.camera.quat[3] = q[3];
|
||
|
update = true;
|
||
|
}
|
||
|
|
||
|
ImGui::End();
|
||
|
|
||
|
ImGui::Begin("Image");
|
||
|
ImGui::Image(g_gui_ctx.texture,
|
||
|
ImVec2(g_gui_ctx.render_width, g_gui_ctx.render_height));
|
||
|
ImGui::End();
|
||
|
|
||
|
if (update) {
|
||
|
g_gui_ctx.redraw = true;
|
||
|
}
|
||
|
|
||
|
// Update texture
|
||
|
if (g_gui_ctx.update_texture || update_display) {
|
||
|
// Update texture for display
|
||
|
UpdateTexutre(g_gui_ctx.texture, g_gui_ctx, g_gui_ctx.aov);
|
||
|
|
||
|
g_gui_ctx.update_texture = false;
|
||
|
}
|
||
|
|
||
|
SDL_SetRenderDrawColor(g_gui_ctx.renderer, 114, 144, 154, 255);
|
||
|
SDL_RenderClear(g_gui_ctx.renderer);
|
||
|
|
||
|
// Imgui
|
||
|
|
||
|
ImGui::Render();
|
||
|
ImGuiSDL::Render(ImGui::GetDrawData());
|
||
|
|
||
|
// static int texUpdateCount = 0;
|
||
|
|
||
|
SDL_RenderPresent(g_gui_ctx.renderer);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return EM_TRUE;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if 0
|
||
|
void NodeTreeSubWindow(const tinyusdz::Node& node, uint32_t indent) {
|
||
|
if (node.name.empty()) {
|
||
|
// Do not traverse children of the node without name
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (ImGui::TreeNode(node.name.c_str())) {
|
||
|
for (const auto& c : node.children) {
|
||
|
NodeTreeSubWindow(c, indent + 1);
|
||
|
}
|
||
|
|
||
|
ImGui::TreePop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NodeTreeWindow(const tinyusdz::HighLevelScene& scene) {
|
||
|
ImGui::Begin("Node");
|
||
|
|
||
|
if (scene.nodes.size()) {
|
||
|
size_t root_node_id =
|
||
|
(scene.default_root_node >= 0) ? size_t(scene.default_root_node) : 0;
|
||
|
NodeTreeSubWindow(scene.nodes[root_node_id], /* indent */ 0);
|
||
|
}
|
||
|
|
||
|
ImGui::End();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if 0
|
||
|
void ShaderParamWindow(const tinyusdz::HighLevelScene& scene) {
|
||
|
ImGui::Begin("Shaders");
|
||
|
|
||
|
for (const auto& item : scene.shaders) {
|
||
|
if (item.name.empty()) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (ImGui::TreeNode(item.name.c_str())) {
|
||
|
if (item.value.is<tinyusdz::PreviewSurface>()) {
|
||
|
ImGui::Text("type:id UsdPreviewSurface");
|
||
|
|
||
|
} else if (item.value.is<tinyusdz::UVTexture>()) {
|
||
|
ImGui::Text("type:id UVTexture");
|
||
|
} else if (item.value.is<tinyusdz::PrimvarReader_float2>()) {
|
||
|
ImGui::Text("type:id PrimvarReader_float2");
|
||
|
} else if (item.value.is<tinyusdz::PrimvarReader_float3>()) {
|
||
|
ImGui::Text("type:id PrimvarReader_float3");
|
||
|
} else {
|
||
|
ImGui::Text("Unsupported Shader type");
|
||
|
}
|
||
|
ImGui::TreePop();
|
||
|
}
|
||
|
}
|
||
|
ImGui::End();
|
||
|
}
|
||
|
|
||
|
void MaterialsParamWindow(const tinyusdz::HighLevelScene& scene) {
|
||
|
ImGui::Begin("Materials");
|
||
|
|
||
|
for (const auto& item : scene.materials) {
|
||
|
if (!item.name.empty()) {
|
||
|
if (ImGui::TreeNode(item.name.c_str())) {
|
||
|
int nrow = 1;
|
||
|
|
||
|
ImGui::BeginTable("props", /* columns*/ 2);
|
||
|
|
||
|
ImGui::TableNextRow();
|
||
|
ImGui::TableSetColumnIndex(0);
|
||
|
ImGui::Text("output.surface");
|
||
|
ImGui::TableSetColumnIndex(1);
|
||
|
|
||
|
ImGui::Text("%s", item.outputs_surface.c_str());
|
||
|
|
||
|
ImGui::EndTable();
|
||
|
ImGui::TreePop();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ImGui::End();
|
||
|
}
|
||
|
|
||
|
void UVTextureNode(int node_id, const tinyusdz::UVTexture& texture) {
|
||
|
constexpr int kMaxSlots = 100;
|
||
|
constexpr int kOutputOffset = kMaxSlots / 2;
|
||
|
|
||
|
ImNodes::BeginNode(kMaxSlots * node_id);
|
||
|
|
||
|
ImNodes::BeginNodeTitleBar();
|
||
|
ImGui::TextUnformatted("UsdUVTexture");
|
||
|
ImNodes::EndNodeTitleBar();
|
||
|
|
||
|
ImNodes::BeginInputAttribute(kMaxSlots * node_id + 1);
|
||
|
ImGui::Text("inputs:file");
|
||
|
ImNodes::EndInputAttribute();
|
||
|
|
||
|
ImNodes::BeginInputAttribute(kMaxSlots * node_id + 2);
|
||
|
ImGui::Text("inputs:sourceColorSpace");
|
||
|
ImNodes::EndInputAttribute();
|
||
|
|
||
|
ImNodes::BeginInputAttribute(kMaxSlots * node_id + 3);
|
||
|
ImGui::Text("inputs:st");
|
||
|
ImNodes::EndInputAttribute();
|
||
|
|
||
|
ImNodes::BeginOutputAttribute(kMaxSlots * node_id + kOutputOffset + 1);
|
||
|
ImGui::Indent(40);
|
||
|
ImGui::Text("outputs:rgb");
|
||
|
ImNodes::EndOutputAttribute();
|
||
|
|
||
|
ImNodes::EndNode();
|
||
|
}
|
||
|
|
||
|
void ShaderGraphWindow(const tinyusdz::HighLevelScene& scene) {
|
||
|
ImGui::Begin("Shader graph");
|
||
|
|
||
|
ImNodes::BeginNodeEditor();
|
||
|
|
||
|
ImNodes::BeginNode(1);
|
||
|
|
||
|
ImNodes::BeginNodeTitleBar();
|
||
|
ImGui::TextUnformatted("File");
|
||
|
ImNodes::EndNodeTitleBar();
|
||
|
|
||
|
// ImNodes::BeginInputAttribute(2);
|
||
|
// ImGui::Text("file");
|
||
|
// ImNodes::EndInputAttribute();
|
||
|
|
||
|
ImNodes::BeginOutputAttribute(3);
|
||
|
ImGui::Indent(40);
|
||
|
ImGui::Text("checkerboard.png");
|
||
|
ImNodes::EndOutputAttribute();
|
||
|
|
||
|
ImNodes::EndNode();
|
||
|
|
||
|
tinyusdz::UVTexture texture;
|
||
|
int texture_node_id = 1;
|
||
|
UVTextureNode(texture_node_id, texture);
|
||
|
|
||
|
ImNodes::MiniMap();
|
||
|
|
||
|
ImNodes::EndNodeEditor();
|
||
|
|
||
|
ImGui::End();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
int main(int argc, char** argv) {
|
||
|
#if defined(USDVIEW_USE_BULLET3)
|
||
|
btDefaultCollisionConfiguration* collisionConfiguration =
|
||
|
new btDefaultCollisionConfiguration();
|
||
|
#endif
|
||
|
|
||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
|
||
|
std::cerr << "Failed to initialize SDL2\n";
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
std::cout << "SDL2 init OK\n";
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
std::string filename = "../../models/suzanne.usdc";
|
||
|
#elif __EMSCRIPTEN__
|
||
|
// assume filename is embeded with --embed-file in emcc compile flag.
|
||
|
std::string filename = "suzanne.usdc";
|
||
|
#else
|
||
|
std::string filename = "../../../models/suzanne.usdc";
|
||
|
#endif
|
||
|
|
||
|
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
|
||
|
NFD_Init();
|
||
|
|
||
|
#endif
|
||
|
|
||
|
if (argc > 1) {
|
||
|
filename = std::string(argv[1]);
|
||
|
}
|
||
|
|
||
|
std::cout << "Loading file " << filename << "\n";
|
||
|
|
||
|
bool init_with_empty = false;
|
||
|
|
||
|
if (!LoadModel(filename, &g_gui_ctx.stage)) {
|
||
|
init_with_empty = true;
|
||
|
}
|
||
|
|
||
|
if (!init_with_empty) {
|
||
|
std::cout << "Loaded USDC file\n";
|
||
|
|
||
|
Proc(g_gui_ctx.stage);
|
||
|
//if (g_gui_ctx.scene.geom_meshes.empty()) {
|
||
|
// std::cerr << "The scene contains no GeomMesh\n";
|
||
|
// exit(-1);
|
||
|
//}
|
||
|
}
|
||
|
|
||
|
// 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.
|
||
|
SDL_WindowFlags window_flags = static_cast<SDL_WindowFlags>(SDL_WINDOW_RESIZABLE);
|
||
|
#else
|
||
|
SDL_WindowFlags window_flags = static_cast<SDL_WindowFlags>(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,
|
||
|
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 "
|
||
|
"DISPLAY environment.\n";
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
std::cout << "SDL2 Window creation OK\n";
|
||
|
|
||
|
SDL_Renderer* renderer = SDL_CreateRenderer(
|
||
|
window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
|
||
|
|
||
|
if (!renderer) {
|
||
|
std::cerr << "Failed to create SDL2 renderer. If you are running on "
|
||
|
"Linux, "
|
||
|
"probably X11 Display is not setup correctly. Check your "
|
||
|
"DISPLAY environment.\n";
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
std::cout << "SDL2 Renderer creation OK\n";
|
||
|
|
||
|
|
||
|
GUIContext& gui_ctx = g_gui_ctx;
|
||
|
gui_ctx.renderer = renderer;
|
||
|
|
||
|
if (!init_with_empty) {
|
||
|
//for (size_t i = 0; i < g_gui_ctx.scene.geom_meshes.size(); i++) {
|
||
|
// example::DrawGeomMesh draw_mesh(&g_gui_ctx.scene.geom_meshes[i]);
|
||
|
// gui_ctx.render_scene.draw_meshes.push_back(draw_mesh);
|
||
|
//}
|
||
|
|
||
|
// Setup render mesh
|
||
|
if (!gui_ctx.render_scene.Setup()) {
|
||
|
std::cerr << "Failed to setup render mesh.\n";
|
||
|
exit(-1);
|
||
|
}
|
||
|
std::cout << "Setup render mesh\n";
|
||
|
}
|
||
|
|
||
|
bool done = false;
|
||
|
|
||
|
ImGui::CreateContext();
|
||
|
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.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);
|
||
|
}
|
||
|
|
||
|
ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
|
||
|
ImGui_ImplSDLRenderer_Init(renderer);
|
||
|
|
||
|
std::cout << "Imgui initialized\n";
|
||
|
|
||
|
gui_ctx.texture = SDL_CreateTexture(
|
||
|
renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET,
|
||
|
gui_ctx.render_width, gui_ctx.render_height);
|
||
|
{
|
||
|
SDL_SetRenderTarget(renderer, gui_ctx.texture);
|
||
|
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
|
||
|
SDL_RenderClear(renderer);
|
||
|
SDL_SetRenderTarget(renderer, nullptr);
|
||
|
|
||
|
// UpdateTexutre(texture, 0);
|
||
|
}
|
||
|
|
||
|
ScreenActivate(window);
|
||
|
|
||
|
gui_ctx.aov.Resize(gui_ctx.render_width, gui_ctx.render_height);
|
||
|
UpdateTexutre(gui_ctx.texture, gui_ctx, gui_ctx.aov);
|
||
|
|
||
|
int display_w, display_h;
|
||
|
ImVec4 clear_color = {0.1f, 0.18f, 0.3f, 1.0f};
|
||
|
|
||
|
// init camera matrix
|
||
|
{
|
||
|
auto q = ToQuaternion(radians(gui_ctx.yaw), radians(gui_ctx.pitch),
|
||
|
radians(gui_ctx.roll));
|
||
|
gui_ctx.camera.quat[0] = q[0];
|
||
|
gui_ctx.camera.quat[1] = q[1];
|
||
|
gui_ctx.camera.quat[2] = q[2];
|
||
|
gui_ctx.camera.quat[3] = q[3];
|
||
|
}
|
||
|
|
||
|
#if __EMSCRIPTEN__ || defined(EMULATE_EMSCRIPTEN)
|
||
|
// no thread
|
||
|
#else
|
||
|
std::thread render_thread(RenderThread, &gui_ctx);
|
||
|
#endif
|
||
|
|
||
|
// Initial rendering requiest
|
||
|
gui_ctx.redraw = true;
|
||
|
|
||
|
std::map<std::string, int> aov_list = {
|
||
|
{"color", GUIContext::AOV_COLOR},
|
||
|
{"shading normal", GUIContext::AOV_SHADING_NORMAL},
|
||
|
{"geometric normal", GUIContext::AOV_GEOMETRIC_NORMAL},
|
||
|
{"texcoord", GUIContext::AOV_TEXCOORD}};
|
||
|
|
||
|
std::string aov_name = "color";
|
||
|
|
||
|
#if __EMSCRIPTEN__ || defined(EMULATE_EMSCRIPTEN)
|
||
|
|
||
|
#if __EMSCRIPTEN__
|
||
|
std::cout << "enter loop\n";
|
||
|
emscripten_request_animation_frame_loop(em_main_loop_frame, /* fps */ 0);
|
||
|
|
||
|
// render_thread.join();
|
||
|
std::cout << "quit\n";
|
||
|
#else
|
||
|
|
||
|
while (!done) {
|
||
|
auto ret = em_main_loop_frame(0, nullptr);
|
||
|
if (ret == EM_FALSE) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#else
|
||
|
// Enable drop file
|
||
|
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||
|
|
||
|
#if 0
|
||
|
// Enable Docking;
|
||
|
{
|
||
|
ImGuiIO& io& io = ImGui::GetIO();
|
||
|
|
||
|
// Enable docking(available in imgui `docking` branch at the moment)
|
||
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
while (!done) {
|
||
|
ImGuiIO& io = ImGui::GetIO();
|
||
|
|
||
|
int wheel = 0;
|
||
|
|
||
|
SDL_Event e;
|
||
|
while (SDL_PollEvent(&e)) {
|
||
|
if (e.type == SDL_QUIT) {
|
||
|
done = true;
|
||
|
} else if (e.type == SDL_DROPFILE) {
|
||
|
char* filepath = e.drop.file;
|
||
|
|
||
|
printf("File dropped: %s\n", filepath);
|
||
|
|
||
|
std::string fname = filepath;
|
||
|
|
||
|
// Scene reloading is done in render thread.
|
||
|
g_gui_ctx.filename = fname;
|
||
|
g_gui_ctx.request_reload = true;
|
||
|
|
||
|
SDL_free(filepath);
|
||
|
|
||
|
} else if (e.type == SDL_WINDOWEVENT) {
|
||
|
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
||
|
io.DisplaySize.x = static_cast<float>(e.window.data1);
|
||
|
io.DisplaySize.y = static_cast<float>(e.window.data2);
|
||
|
}
|
||
|
} else if (e.type == SDL_KEYDOWN) {
|
||
|
if (e.key.keysym.sym == SDLK_ESCAPE) {
|
||
|
done = true;
|
||
|
}
|
||
|
} else if (e.type == SDL_KEYUP) {
|
||
|
} else if (e.type == SDL_MOUSEWHEEL) {
|
||
|
wheel = e.wheel.y;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int mouseX, mouseY;
|
||
|
const int buttons = SDL_GetMouseState(&mouseX, &mouseY);
|
||
|
|
||
|
// Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or
|
||
|
// write to those fields from your Windows message loop handlers,
|
||
|
// etc.)
|
||
|
|
||
|
io.DeltaTime = 1.0f / 60.0f;
|
||
|
io.MousePos =
|
||
|
ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
|
||
|
io.MouseDown[0] = buttons & SDL_BUTTON(SDL_BUTTON_LEFT);
|
||
|
io.MouseDown[1] = buttons & SDL_BUTTON(SDL_BUTTON_RIGHT);
|
||
|
io.MouseWheel = static_cast<float>(wheel);
|
||
|
|
||
|
ImGui_ImplSDLRenderer_NewFrame();
|
||
|
ImGui_ImplSDL2_NewFrame();
|
||
|
ImGui::NewFrame();
|
||
|
|
||
|
ImGui::Begin("Scene");
|
||
|
bool update = false;
|
||
|
|
||
|
bool update_display = false;
|
||
|
|
||
|
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
|
||
|
if (ImGui::Button("Open file ...")) {
|
||
|
std::string filename = OpenFileDialog();
|
||
|
std::cout << "TODO: Open file"
|
||
|
<< "\n";
|
||
|
}
|
||
|
|
||
|
ImGui::SameLine();
|
||
|
HelpMarker("You can also drop USDZ file to the window to open a file.");
|
||
|
#endif
|
||
|
|
||
|
if (example::ImGuiComboUI("aov", aov_name, aov_list)) {
|
||
|
gui_ctx.aov_mode = aov_list[aov_name];
|
||
|
update_display = true;
|
||
|
}
|
||
|
|
||
|
// update |= ImGui::InputFloat3("eye", gui_ctx.camera.eye);
|
||
|
// update |= ImGui::InputFloat3("look_at", gui_ctx.camera.look_at);
|
||
|
// update |= ImGui::InputFloat3("up", gui_ctx.camera.up);
|
||
|
update |=
|
||
|
ImGui::SliderFloat("eye.z", &gui_ctx.camera.eye[2], -1000.0, 1000.0f);
|
||
|
update |= ImGui::SliderFloat("fov", &gui_ctx.camera.fov, 0.01f, 140.0f);
|
||
|
|
||
|
// TODO: Validate coordinate definition.
|
||
|
if (ImGui::SliderFloat("yaw", &gui_ctx.yaw, -360.0f, 360.0f)) {
|
||
|
auto q = ToQuaternion(radians(gui_ctx.yaw), radians(gui_ctx.pitch),
|
||
|
radians(gui_ctx.roll));
|
||
|
gui_ctx.camera.quat[0] = q[0];
|
||
|
gui_ctx.camera.quat[1] = q[1];
|
||
|
gui_ctx.camera.quat[2] = q[2];
|
||
|
gui_ctx.camera.quat[3] = q[3];
|
||
|
update = true;
|
||
|
}
|
||
|
if (ImGui::SliderFloat("pitch", &gui_ctx.pitch, -360.0f, 360.0f)) {
|
||
|
auto q = ToQuaternion(radians(gui_ctx.yaw), radians(gui_ctx.pitch),
|
||
|
radians(gui_ctx.roll));
|
||
|
gui_ctx.camera.quat[0] = q[0];
|
||
|
gui_ctx.camera.quat[1] = q[1];
|
||
|
gui_ctx.camera.quat[2] = q[2];
|
||
|
gui_ctx.camera.quat[3] = q[3];
|
||
|
update = true;
|
||
|
}
|
||
|
if (ImGui::SliderFloat("roll", &gui_ctx.roll, -360.0f, 360.0f)) {
|
||
|
auto q = ToQuaternion(radians(gui_ctx.yaw), radians(gui_ctx.pitch),
|
||
|
radians(gui_ctx.roll));
|
||
|
gui_ctx.camera.quat[0] = q[0];
|
||
|
gui_ctx.camera.quat[1] = q[1];
|
||
|
gui_ctx.camera.quat[2] = q[2];
|
||
|
gui_ctx.camera.quat[3] = q[3];
|
||
|
update = true;
|
||
|
}
|
||
|
ImGui::End();
|
||
|
|
||
|
ImGui::Begin("Image");
|
||
|
ImGui::Image(gui_ctx.texture,
|
||
|
ImVec2(gui_ctx.render_width, gui_ctx.render_height));
|
||
|
ImGui::End();
|
||
|
|
||
|
//NodeTreeWindow(gui_ctx.scene);
|
||
|
//MaterialsParamWindow(gui_ctx.scene);
|
||
|
//ShaderParamWindow(gui_ctx.scene);
|
||
|
//ShaderGraphWindow(gui_ctx.scene);
|
||
|
|
||
|
if (update) {
|
||
|
gui_ctx.redraw = true;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// Draw scene
|
||
|
if ((scene.root_node >= 0) && (scene.root_node < scene.nodes.size())) {
|
||
|
DrawNode(scene, scene.nodes[scene.root_node]);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Update texture
|
||
|
if (gui_ctx.update_texture || update_display) {
|
||
|
// Update texture for display
|
||
|
UpdateTexutre(gui_ctx.texture, gui_ctx, gui_ctx.aov);
|
||
|
|
||
|
gui_ctx.update_texture = false;
|
||
|
}
|
||
|
|
||
|
SDL_SetRenderDrawColor(renderer, 114, 144, 154, 255);
|
||
|
SDL_RenderClear(renderer);
|
||
|
|
||
|
// Imgui
|
||
|
|
||
|
ImGui::Render();
|
||
|
|
||
|
// static int texUpdateCount = 0;
|
||
|
static int frameCount = 0;
|
||
|
static double currentTime =
|
||
|
SDL_GetTicks() / 1000.0; // GetTicks returns milliseconds
|
||
|
static double previousTime = currentTime;
|
||
|
static char title[256];
|
||
|
|
||
|
frameCount++;
|
||
|
currentTime = SDL_GetTicks() / 1000.0;
|
||
|
const auto deltaTime = currentTime - previousTime;
|
||
|
if (deltaTime >= 1.0) {
|
||
|
sprintf(title, "Simple USDZ viewer [%dFPS]", frameCount);
|
||
|
SDL_SetWindowTitle(window, title);
|
||
|
frameCount = 0;
|
||
|
previousTime = currentTime;
|
||
|
}
|
||
|
|
||
|
SDL_RenderClear(renderer);
|
||
|
ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData());
|
||
|
SDL_RenderPresent(renderer);
|
||
|
};
|
||
|
|
||
|
// Notify render thread to exit app
|
||
|
gui_ctx.quit = true;
|
||
|
|
||
|
render_thread.join();
|
||
|
|
||
|
ImGui_ImplSDLRenderer_Shutdown();
|
||
|
ImGui_ImplSDL2_Shutdown();
|
||
|
|
||
|
SDL_DestroyRenderer(renderer);
|
||
|
SDL_DestroyWindow(window);
|
||
|
|
||
|
SDL_Quit();
|
||
|
|
||
|
ImNodes::DestroyContext();
|
||
|
ImGui::DestroyContext();
|
||
|
|
||
|
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
|
||
|
NFD_Quit();
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|