mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Initial WebAssembly support.
This commit is contained in:
@@ -52,6 +52,9 @@ TinyUSDZ does not support Reality Composer file format(`.reality`) since it uses
|
||||
* [x] macOS
|
||||
* [x] Windows 10 64bit or later
|
||||
* [ ] Windows ARM(should work)
|
||||
* [x] WebAssembly(through Emscripten)
|
||||
* See `examples/sdlviewer/` example.
|
||||
* Multithreading is not available due to Browser's restriction.
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||
@@ -9,6 +9,11 @@ option(TINYUSDZ_USE_CCACHE "Use ccache for faster recompile." ON)
|
||||
option(TINYUSDZ_WITH_OPENSUBDIV "Build with OpenSubdiv(osdCPU. if required, set `osd_DIR` to specify the path to your own OpenSubdiv)" ON)
|
||||
option(USDVIEW_USE_NATIVEFILEDIALOG "Use nativefiledialog. Requires gtk+-3 libs on linux to build" ON)
|
||||
|
||||
if (EMSCRIPTEN)
|
||||
# Disable nfd
|
||||
set(USDVIEW_USE_NATIVEFILEDIALOG OFF CACHE INTERNAL "" FORCE)
|
||||
endif ()
|
||||
|
||||
# Use embedded version of OpenSubdiv code by default
|
||||
set(osd_DIR ${PROJECT_SOURCE_DIR}/../../src/osd)
|
||||
|
||||
@@ -68,13 +73,33 @@ function ( ADD_SDL2_LIB )
|
||||
set(SDL_STATIC ON CACHE INTERNAL "" FORCE)
|
||||
add_subdirectory(../common/SDL2-2.0.14/ SDL2)
|
||||
endfunction ()
|
||||
ADD_SDL2_LIB()
|
||||
|
||||
if (EMSCRIPTEN)
|
||||
# Use emcc ported SDL2
|
||||
# https://stackoverflow.com/questions/61590519/how-to-use-emscripten-ports-sdl2-and-freetype-with-cmake
|
||||
|
||||
# Assume `suzanne.usdc` is coped to build directory with PRE_BUILD custom command
|
||||
# TODO: Read USD file from JS world
|
||||
# TODO: Use max memory size.
|
||||
set(USE_FLAGS "-s ASSERTIONS=1 -s USE_SDL=2 -s USE_FREETYPE=1 --embed-file suzanne.usdc")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${USE_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${USE_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${USE_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
|
||||
set(CMAKE_EXECUTABLE_SUFFIX .html)
|
||||
|
||||
set(USDVIEW_SDL2_LIBRARIES ${SDL2_LIBRARIES})
|
||||
else()
|
||||
ADD_SDL2_LIB()
|
||||
set(USDVIEW_SDL2_LIBRARIES SDL2-static SDL2main)
|
||||
endif()
|
||||
|
||||
|
||||
if(WIN32)
|
||||
# nothing.
|
||||
# do nothing.
|
||||
elseif(APPLE)
|
||||
find_library(COCOA Cocoa REQUIRED)
|
||||
elseif(EMSCRIPTEN)
|
||||
# do nothing
|
||||
else()
|
||||
find_package(X11 REQUIRED)
|
||||
endif()
|
||||
@@ -194,6 +219,7 @@ set(GUI_SOURCES
|
||||
|
||||
add_executable(${BUILD_TARGET} ${SOURCES} ${GUI_SOURCES})
|
||||
add_sanitizers(${BUILD_TARGET})
|
||||
target_compile_options(${BUILD_TARGET} PRIVATE ${EXT_COMPILE_OPTIONS})
|
||||
|
||||
if (UNIX)
|
||||
target_include_directories(${BUILD_TARGET} PUBLIC ${X11_INCLUDE_DIR})
|
||||
@@ -212,29 +238,31 @@ if (USDVIEW_USE_NATIVEFILEDIALOG)
|
||||
list(APPEND EXT_LIBRARIES nfd)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# nothing.
|
||||
elseif(APPLE)
|
||||
list(APPEND EXT_LIBRARIES ${COCOA})
|
||||
else()
|
||||
list(APPEND EXT_LIBRARIES ${X11_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(
|
||||
${BUILD_TARGET}
|
||||
PRIVATE
|
||||
SDL2-static
|
||||
SDL2main
|
||||
${USDVIEW_SDL2_LIBRARIES}
|
||||
${EXT_LIBRARIES}
|
||||
${CMAKE_DL_LIBS}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
# nothing.
|
||||
elseif(APPLE)
|
||||
target_link_libraries(
|
||||
${BUILD_TARGET}
|
||||
${COCOA}
|
||||
)
|
||||
else()
|
||||
target_link_libraries(
|
||||
${BUILD_TARGET}
|
||||
${X11_LIBRARIES}
|
||||
)
|
||||
if (EMSCRIPTEN)
|
||||
add_custom_command(TARGET ${BUILD_TARGET} PRE_BUILD # Adds a post-build event to MyTest
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
|
||||
"${PROJECT_SOURCE_DIR}/../../models/suzanne.usdc" # src
|
||||
$<TARGET_FILE_DIR:${BUILD_TARGET}>) # dest
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
source_group("Source Files" FILES ${SOURCES})
|
||||
|
||||
# [VisualStudio]
|
||||
|
||||
7
examples/sdlviewer/bootstrap-emscripten-linux.sh
Executable file
7
examples/sdlviewer/bootstrap-emscripten-linux.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
rm -rf build_emcc
|
||||
mkdir build_emcc
|
||||
|
||||
cd build_emcc
|
||||
|
||||
# Assume emsdk env has been setup
|
||||
emcmake cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
@@ -10,6 +10,11 @@
|
||||
#include <mutex> // C++11
|
||||
#include <thread> // C++11
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
#endif
|
||||
|
||||
// ../common/SDL2
|
||||
#include <SDL.h>
|
||||
|
||||
@@ -20,12 +25,11 @@
|
||||
// common
|
||||
#include "imgui.h"
|
||||
#include "imgui_sdl/imgui_sdl.h"
|
||||
#include "roboto_mono_embed.inc.h"
|
||||
#include "simple-render.hh"
|
||||
#include "tinyusdz.hh"
|
||||
#include "trackball.h"
|
||||
|
||||
#include "roboto_mono_embed.inc.h"
|
||||
|
||||
// sdlviewer
|
||||
#include "gui.hh"
|
||||
|
||||
@@ -33,6 +37,14 @@
|
||||
#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,
|
||||
@@ -59,7 +71,7 @@ struct GUIContext {
|
||||
bool ctrl_pressed = false;
|
||||
bool tab_pressed = false;
|
||||
|
||||
float yaw = 90.0f; // for Z up scene
|
||||
float yaw = 90.0f; // for Z up scene
|
||||
float pitch = 0.0f;
|
||||
float roll = 0.0f;
|
||||
|
||||
@@ -77,9 +89,21 @@ struct GUIContext {
|
||||
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;
|
||||
|
||||
#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 gCtx;
|
||||
GUIContext g_gui_ctx;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -114,7 +138,7 @@ static void DrawNode(const tinyusdz::Scene& scene, const tinyusdz::Node& node) {
|
||||
}
|
||||
|
||||
for (const auto& child : node.children) {
|
||||
//DrawNode(scene, scene.nodes.at(child));
|
||||
// DrawNode(scene, scene.nodes.at(child));
|
||||
}
|
||||
|
||||
if (node.type == tinyusdz::NODE_TYPE_XFORM) {
|
||||
@@ -272,38 +296,193 @@ void RenderThread(GUIContext* ctx) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#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"} };
|
||||
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;
|
||||
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
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -333,6 +512,9 @@ int main(int argc, char** argv) {
|
||||
|
||||
#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
|
||||
@@ -345,7 +527,6 @@ int main(int argc, char** argv) {
|
||||
if (argc > 1) {
|
||||
filename = std::string(argv[1]);
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
std::cout << "Loading file " << filename << "\n";
|
||||
@@ -393,7 +574,8 @@ int main(int argc, char** argv) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
GUIContext gui_ctx;
|
||||
GUIContext& gui_ctx = g_gui_ctx;
|
||||
gui_ctx.renderer = renderer;
|
||||
|
||||
for (size_t i = 0; i < scene.geom_meshes.size(); i++) {
|
||||
example::DrawGeomMesh draw_mesh(&scene.geom_meshes[i]);
|
||||
@@ -405,6 +587,7 @@ int main(int argc, char** argv) {
|
||||
std::cerr << "Failed to setup render mesh.\n";
|
||||
exit(-1);
|
||||
}
|
||||
std::cout << "Setup render mesh\n";
|
||||
|
||||
bool done = false;
|
||||
|
||||
@@ -422,19 +605,17 @@ int main(int argc, char** argv) {
|
||||
font_size, &roboto_config);
|
||||
}
|
||||
|
||||
|
||||
ImGuiSDL::Initialize(renderer, 1600, 800);
|
||||
// ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||
// ImGui_ImplOpenGL2_Init();
|
||||
|
||||
int render_width = 512;
|
||||
int render_height = 512;
|
||||
std::cout << "Imgui initialized\n";
|
||||
|
||||
SDL_Texture* texture =
|
||||
SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32,
|
||||
SDL_TEXTUREACCESS_TARGET, render_width, render_height);
|
||||
gui_ctx.texture = SDL_CreateTexture(
|
||||
renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET,
|
||||
gui_ctx.render_width, gui_ctx.render_height);
|
||||
{
|
||||
SDL_SetRenderTarget(renderer, texture);
|
||||
SDL_SetRenderTarget(renderer, gui_ctx.texture);
|
||||
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
@@ -444,8 +625,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
ScreenActivate(window);
|
||||
|
||||
gui_ctx.aov.Resize(render_width, render_height);
|
||||
UpdateTexutre(texture, gui_ctx, gui_ctx.aov);
|
||||
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};
|
||||
@@ -460,20 +641,45 @@ int main(int argc, char** argv) {
|
||||
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 }
|
||||
};
|
||||
{"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);
|
||||
|
||||
while (!done) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
@@ -482,9 +688,16 @@ int main(int argc, char** argv) {
|
||||
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
if (e.type == SDL_QUIT)
|
||||
if (e.type == SDL_QUIT) {
|
||||
done = true;
|
||||
else if (e.type == SDL_WINDOWEVENT) {
|
||||
} 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);
|
||||
@@ -523,8 +736,12 @@ int main(int argc, char** argv) {
|
||||
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
|
||||
if (ImGui::Button("Open file ...")) {
|
||||
std::string filename = OpenFileDialog();
|
||||
std::cout << "TODO: Open file" << "\n";
|
||||
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)) {
|
||||
@@ -532,10 +749,11 @@ int main(int argc, char** argv) {
|
||||
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::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.
|
||||
@@ -569,7 +787,8 @@ int main(int argc, char** argv) {
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Begin("Image");
|
||||
ImGui::Image(texture, ImVec2(render_width, render_height));
|
||||
ImGui::Image(gui_ctx.texture,
|
||||
ImVec2(gui_ctx.render_width, gui_ctx.render_height));
|
||||
ImGui::End();
|
||||
|
||||
if (update) {
|
||||
@@ -586,7 +805,7 @@ int main(int argc, char** argv) {
|
||||
// Update texture
|
||||
if (gui_ctx.update_texture || update_display) {
|
||||
// Update texture for display
|
||||
UpdateTexutre(texture, gui_ctx, gui_ctx.aov);
|
||||
UpdateTexutre(gui_ctx.texture, gui_ctx, gui_ctx.aov);
|
||||
|
||||
gui_ctx.update_texture = false;
|
||||
}
|
||||
@@ -633,6 +852,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
|
||||
NFD_Quit();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#include "nanosg.h"
|
||||
|
||||
// common
|
||||
#include "mapbox/earcut.hpp" // For polygon triangulation
|
||||
#include "matrix.h"
|
||||
#include "trackball.h"
|
||||
#include "mapbox/earcut.hpp" // For polygon triangulation
|
||||
|
||||
const float kPI = 3.141592f;
|
||||
|
||||
@@ -53,8 +53,10 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
|
||||
std::cout << "# of facevarying normals = " << facevarying_normals.size() / 3
|
||||
<< "\n";
|
||||
|
||||
std::cout << "# of faceVertexCounts: " << mesh.faceVertexCounts.size() << "\n";
|
||||
std::cout << "# of faceVertexIndices: " << mesh.faceVertexIndices.size() << "\n";
|
||||
std::cout << "# of faceVertexCounts: " << mesh.faceVertexCounts.size()
|
||||
<< "\n";
|
||||
std::cout << "# of faceVertexIndices: " << mesh.faceVertexIndices.size()
|
||||
<< "\n";
|
||||
|
||||
// for (size_t i = 0; i < facevarying_normals.size() / 3; i++) {
|
||||
// std::cout << "fid[" << i << "] = " << facevarying_normals[3 * i + 0] << ",
|
||||
@@ -183,7 +185,7 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
|
||||
dst->int_primvars.clear();
|
||||
dst->int_primvars_map.clear();
|
||||
|
||||
for (const auto &attrib : mesh.attribs) {
|
||||
for (const auto& attrib : mesh.attribs) {
|
||||
if (!attrib.second.facevarying) {
|
||||
continue;
|
||||
}
|
||||
@@ -192,8 +194,8 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attrib.second.buffer.GetDataType() == tinyusdz::BufferData::BUFFER_DATA_TYPE_FLOAT) {
|
||||
|
||||
if (attrib.second.buffer.GetDataType() ==
|
||||
tinyusdz::BufferData::BUFFER_DATA_TYPE_FLOAT) {
|
||||
Buffer<float> buf;
|
||||
buf.num_coords = attrib.second.buffer.GetNumCoords();
|
||||
buf.data = attrib.second.buffer.GetAsFloatArray();
|
||||
@@ -203,8 +205,8 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
|
||||
|
||||
std::cout << "Added [" << attrib.first << "] to float_primvars\n";
|
||||
|
||||
} else if (attrib.second.buffer.GetDataType() == tinyusdz::BufferData::BUFFER_DATA_TYPE_INT) {
|
||||
|
||||
} else if (attrib.second.buffer.GetDataType() ==
|
||||
tinyusdz::BufferData::BUFFER_DATA_TYPE_INT) {
|
||||
Buffer<int32_t> buf;
|
||||
buf.num_coords = attrib.second.buffer.GetNumCoords();
|
||||
buf.data = attrib.second.buffer.GetAsInt32Array();
|
||||
@@ -217,8 +219,6 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
std::cout << "num points = " << dst->vertices.size() / 3 << "\n";
|
||||
@@ -497,17 +497,172 @@ bool Render(const RenderScene& scene, const Camera& cam, AOV* output) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderScene::Setup() {
|
||||
bool RenderLines(int start_y, int end_y, const RenderScene& scene,
|
||||
const Camera& cam, AOV* output) {
|
||||
int width = output->width;
|
||||
int height = output->height;
|
||||
|
||||
float eye[3] = {cam.eye[0], cam.eye[1], cam.eye[2]};
|
||||
float look_at[3] = {cam.look_at[0], cam.look_at[1], cam.look_at[2]};
|
||||
float up[3] = {cam.up[0], cam.up[1], cam.up[2]};
|
||||
float fov = cam.fov;
|
||||
float3 origin, corner, u, v;
|
||||
BuildCameraFrame(&origin, &corner, &u, &v, cam.quat, eye, look_at, up, fov,
|
||||
width, height);
|
||||
|
||||
// Single threaded
|
||||
for (int y = start_y; y < std::min(end_y, height); y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
nanort::Ray<float> ray;
|
||||
ray.org[0] = origin[0];
|
||||
ray.org[1] = origin[1];
|
||||
ray.org[2] = origin[2];
|
||||
|
||||
float3 dir;
|
||||
|
||||
float u0 = 0.5f;
|
||||
float u1 = 0.5f;
|
||||
|
||||
dir = corner + (float(x) + u0) * u + (float(y) + u1) * v;
|
||||
|
||||
dir = vnormalize(dir);
|
||||
ray.dir[0] = dir[0];
|
||||
ray.dir[1] = dir[1];
|
||||
ray.dir[2] = dir[2];
|
||||
|
||||
size_t pixel_idx = y * width + x;
|
||||
|
||||
// HACK. Use the first mesh
|
||||
const DrawGeomMesh& mesh = scene.draw_meshes[0];
|
||||
|
||||
// Intersector functor.
|
||||
nanort::TriangleIntersector<> triangle_intersector(
|
||||
mesh.vertices.data(), mesh.facevarying_indices.data(),
|
||||
sizeof(float) * 3);
|
||||
nanort::TriangleIntersection<> isect; // stores isect info
|
||||
|
||||
bool hit = mesh.accel.Traverse(ray, triangle_intersector, &isect);
|
||||
|
||||
if (hit) {
|
||||
float3 Ng;
|
||||
{
|
||||
// geometric normal.
|
||||
float3 v0;
|
||||
float3 v1;
|
||||
float3 v2;
|
||||
|
||||
size_t vid0 = mesh.facevarying_indices[3 * isect.prim_id + 0];
|
||||
size_t vid1 = mesh.facevarying_indices[3 * isect.prim_id + 1];
|
||||
size_t vid2 = mesh.facevarying_indices[3 * isect.prim_id + 2];
|
||||
|
||||
v0[0] = mesh.vertices[3 * vid0 + 0];
|
||||
v0[1] = mesh.vertices[3 * vid0 + 1];
|
||||
v0[2] = mesh.vertices[3 * vid0 + 2];
|
||||
|
||||
v1[0] = mesh.vertices[3 * vid1 + 0];
|
||||
v1[1] = mesh.vertices[3 * vid1 + 1];
|
||||
v1[2] = mesh.vertices[3 * vid1 + 2];
|
||||
|
||||
v2[0] = mesh.vertices[3 * vid2 + 0];
|
||||
v2[1] = mesh.vertices[3 * vid2 + 1];
|
||||
v2[2] = mesh.vertices[3 * vid2 + 2];
|
||||
|
||||
CalcNormal(Ng, v0, v1, v2);
|
||||
}
|
||||
|
||||
float3 Ns;
|
||||
if (mesh.facevarying_normals.size()) {
|
||||
float3 n0;
|
||||
float3 n1;
|
||||
float3 n2;
|
||||
|
||||
n0[0] = mesh.facevarying_normals[9 * isect.prim_id + 0];
|
||||
n0[1] = mesh.facevarying_normals[9 * isect.prim_id + 1];
|
||||
n0[2] = mesh.facevarying_normals[9 * isect.prim_id + 2];
|
||||
|
||||
n1[0] = mesh.facevarying_normals[9 * isect.prim_id + 3];
|
||||
n1[1] = mesh.facevarying_normals[9 * isect.prim_id + 4];
|
||||
n1[2] = mesh.facevarying_normals[9 * isect.prim_id + 5];
|
||||
|
||||
n2[0] = mesh.facevarying_normals[9 * isect.prim_id + 6];
|
||||
n2[1] = mesh.facevarying_normals[9 * isect.prim_id + 7];
|
||||
n2[2] = mesh.facevarying_normals[9 * isect.prim_id + 8];
|
||||
|
||||
// lerp normal.
|
||||
Ns = vnormalize(Lerp3(n0, n1, n2, isect.u, isect.v));
|
||||
} else {
|
||||
Ns = Ng;
|
||||
}
|
||||
|
||||
float3 texcoord = {0.0f, 0.0f, 0.0f};
|
||||
if (mesh.facevarying_texcoords.size()) {
|
||||
float3 t0;
|
||||
float3 t1;
|
||||
float3 t2;
|
||||
|
||||
t0[0] = mesh.facevarying_texcoords[6 * isect.prim_id + 0];
|
||||
t0[1] = mesh.facevarying_texcoords[6 * isect.prim_id + 1];
|
||||
t0[2] = 0.0f;
|
||||
|
||||
t1[0] = mesh.facevarying_texcoords[6 * isect.prim_id + 2];
|
||||
t1[1] = mesh.facevarying_texcoords[6 * isect.prim_id + 3];
|
||||
t1[2] = 0.0f;
|
||||
|
||||
t2[0] = mesh.facevarying_texcoords[6 * isect.prim_id + 4];
|
||||
t2[1] = mesh.facevarying_texcoords[6 * isect.prim_id + 5];
|
||||
t2[2] = 0.0f;
|
||||
|
||||
texcoord = Lerp3(t0, t1, t2, isect.u, isect.v);
|
||||
}
|
||||
|
||||
output->rgb[3 * pixel_idx + 0] = 0.5f * Ns[0] + 0.5f;
|
||||
output->rgb[3 * pixel_idx + 1] = 0.5f * Ns[1] + 0.5f;
|
||||
output->rgb[3 * pixel_idx + 2] = 0.5f * Ns[2] + 0.5f;
|
||||
|
||||
output->geometric_normal[3 * pixel_idx + 0] = 0.5f * Ns[0] + 0.5f;
|
||||
output->geometric_normal[3 * pixel_idx + 1] = 0.5f * Ns[1] + 0.5f;
|
||||
output->geometric_normal[3 * pixel_idx + 2] = 0.5f * Ns[2] + 0.5f;
|
||||
|
||||
output->shading_normal[3 * pixel_idx + 0] = 0.5f * Ns[0] + 0.5f;
|
||||
output->shading_normal[3 * pixel_idx + 1] = 0.5f * Ns[1] + 0.5f;
|
||||
output->shading_normal[3 * pixel_idx + 2] = 0.5f * Ns[2] + 0.5f;
|
||||
|
||||
output->texcoords[2 * pixel_idx + 0] = texcoord[0];
|
||||
output->texcoords[2 * pixel_idx + 1] = texcoord[1];
|
||||
|
||||
} else {
|
||||
output->rgb[3 * pixel_idx + 0] = 0.0f;
|
||||
output->rgb[3 * pixel_idx + 1] = 0.0f;
|
||||
output->rgb[3 * pixel_idx + 2] = 0.0f;
|
||||
|
||||
output->geometric_normal[3 * pixel_idx + 0] = 0.0f;
|
||||
output->geometric_normal[3 * pixel_idx + 1] = 0.0f;
|
||||
output->geometric_normal[3 * pixel_idx + 2] = 0.0f;
|
||||
|
||||
output->shading_normal[3 * pixel_idx + 0] = 0.0f;
|
||||
output->shading_normal[3 * pixel_idx + 1] = 0.0f;
|
||||
output->shading_normal[3 * pixel_idx + 2] = 0.0f;
|
||||
|
||||
output->texcoords[2 * pixel_idx + 0] = 0.0f;
|
||||
output->texcoords[2 * pixel_idx + 1] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderScene::Setup() {
|
||||
//
|
||||
// Construct scene
|
||||
//
|
||||
{
|
||||
float local_xform[4][4]; // TODO
|
||||
float local_xform[4][4]; // TODO
|
||||
|
||||
for (size_t i = 0; i < draw_meshes.size(); i++) {
|
||||
// Construct Node by passing the pointer to draw_meshes[i]
|
||||
// Pointer address of draw_meshes[i] must be identical during app's lifetime.
|
||||
// Pointer address of draw_meshes[i] must be identical during app's
|
||||
// lifetime.
|
||||
nanosg::Node<float, example::DrawGeomMesh> node(&draw_meshes[i]);
|
||||
|
||||
std::cout << "SetName: " << draw_meshes[i].ref_mesh->name << "\n";
|
||||
@@ -518,7 +673,6 @@ bool RenderScene::Setup() {
|
||||
this->nodes.push_back(node);
|
||||
this->scene.AddNode(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < draw_meshes.size(); i++) {
|
||||
|
||||
@@ -176,4 +176,13 @@ bool Render(
|
||||
const Camera &cam,
|
||||
AOV *output);
|
||||
|
||||
// Render images for lines [start_y, end_y]
|
||||
// single-threaded. for webassembly.
|
||||
bool RenderLines(
|
||||
int start_y,
|
||||
int end_y,
|
||||
const RenderScene &scene,
|
||||
const Camera &cam,
|
||||
AOV *output);
|
||||
|
||||
} // namespace example
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
/* work around of DEPRECATE macro */
|
||||
#define LZ4_DISABLE_DEPRECATE_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "lz4-compression.hh"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -83,6 +83,10 @@
|
||||
# define LZ4_FORCE_SW_BITCOUNT
|
||||
#endif
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
/* work around of DEPRECATE macro */
|
||||
#define LZ4_DISABLE_DEPRECATE_WARNINGS
|
||||
#endif
|
||||
|
||||
/*-************************************
|
||||
* Dependency
|
||||
|
||||
Reference in New Issue
Block a user