From a42dcd2291150a78ee57fcfa75fcce5cb2a1f992 Mon Sep 17 00:00:00 2001 From: Philip Rideout Date: Thu, 1 Nov 2018 11:56:15 -0700 Subject: [PATCH] JavaScript code re-org (#443) This removes the old CPP-based web samples in favor of the new JS API. The `web/samples` folder will be added in a subsequent commit. --- CMakeLists.txt | 3 +- build.sh | 11 +- {samples/web => docs}/favicon.png | Bin samples/web/CMakeLists.txt | 204 ----------- samples/web/filaweb.cpp | 346 ------------------ samples/web/filaweb.h | 107 ------ samples/web/filaweb.js | 141 ------- samples/web/sandbox.cpp | 193 ---------- samples/web/sandbox.html | 31 -- samples/web/suzanne.cpp | 268 -------------- samples/web/suzanne.html | 43 --- samples/web/triangle.cpp | 120 ------ samples/web/triangle.html | 28 -- {libs/filamentjs => web}/docs/build.py | 20 +- .../docs/demo_template.html | 0 {libs/filamentjs => web}/docs/main.css | 0 {libs/filamentjs => web}/docs/plastic.mat | 0 .../filamentjs => web}/docs/ref_template.html | 0 .../filamentjs => web}/docs/requirements.txt | 0 {libs/filamentjs => web}/docs/triangle.mat | 0 .../docs/tutorial_redball.md | 0 .../docs/tutorial_template.html | 0 .../docs/tutorial_triangle.md | 0 {libs => web}/filamentjs/CMakeLists.txt | 0 {libs => web}/filamentjs/extensions.js | 0 {libs => web}/filamentjs/jsbindings.cpp | 0 {libs => web}/filamentjs/jsenums.cpp | 0 {libs => web}/filamentjs/utilities.js | 0 {libs => web}/filamentjs/wasmloader.js | 0 .../filamentjs => web}/tests/requirements.txt | 0 {libs/filamentjs => web}/tests/test.py | 0 .../filamentjs => web}/tests/test_leaks.html | 0 {libs/filamentjs => web}/tests/test_leaks.js | 0 .../tests/test_parquet.html | 0 .../filamentjs => web}/tests/test_parquet.js | 0 .../tests/test_redball.html | 0 .../filamentjs => web}/tests/test_redball.js | 0 37 files changed, 15 insertions(+), 1500 deletions(-) rename {samples/web => docs}/favicon.png (100%) delete mode 100644 samples/web/CMakeLists.txt delete mode 100644 samples/web/filaweb.cpp delete mode 100644 samples/web/filaweb.h delete mode 100644 samples/web/filaweb.js delete mode 100644 samples/web/sandbox.cpp delete mode 100644 samples/web/sandbox.html delete mode 100644 samples/web/suzanne.cpp delete mode 100644 samples/web/suzanne.html delete mode 100644 samples/web/triangle.cpp delete mode 100644 samples/web/triangle.html rename {libs/filamentjs => web}/docs/build.py (96%) rename {libs/filamentjs => web}/docs/demo_template.html (100%) rename {libs/filamentjs => web}/docs/main.css (100%) rename {libs/filamentjs => web}/docs/plastic.mat (100%) rename {libs/filamentjs => web}/docs/ref_template.html (100%) rename {libs/filamentjs => web}/docs/requirements.txt (100%) rename {libs/filamentjs => web}/docs/triangle.mat (100%) rename {libs/filamentjs => web}/docs/tutorial_redball.md (100%) rename {libs/filamentjs => web}/docs/tutorial_template.html (100%) rename {libs/filamentjs => web}/docs/tutorial_triangle.md (100%) rename {libs => web}/filamentjs/CMakeLists.txt (100%) rename {libs => web}/filamentjs/extensions.js (100%) rename {libs => web}/filamentjs/jsbindings.cpp (100%) rename {libs => web}/filamentjs/jsenums.cpp (100%) rename {libs => web}/filamentjs/utilities.js (100%) rename {libs => web}/filamentjs/wasmloader.js (100%) rename {libs/filamentjs => web}/tests/requirements.txt (100%) rename {libs/filamentjs => web}/tests/test.py (100%) rename {libs/filamentjs => web}/tests/test_leaks.html (100%) rename {libs/filamentjs => web}/tests/test_leaks.js (100%) rename {libs/filamentjs => web}/tests/test_parquet.html (100%) rename {libs/filamentjs => web}/tests/test_parquet.js (100%) rename {libs/filamentjs => web}/tests/test_redball.html (100%) rename {libs/filamentjs => web}/tests/test_redball.js (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5178722248..ad8d9e3eb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -290,10 +290,9 @@ endif() set (FILAMENT_SAMPLES_BINARY_DIR ${PROJECT_BINARY_DIR}/samples) if (WEBGL) - add_subdirectory(${FILAMENT}/samples/web) + add_subdirectory(web/filamentjs) add_subdirectory(${LIBRARIES}/filagui) - add_subdirectory(${LIBRARIES}/filamentjs) add_subdirectory(${EXTERNAL}/imgui/tnt) add_subdirectory(${EXTERNAL}/stb/tnt) diff --git a/build.sh b/build.sh index 2d118f3b4f..82c07f2d08 100755 --- a/build.sh +++ b/build.sh @@ -219,14 +219,14 @@ function build_webgl_with_target { ${BUILD_COMMAND} ${BUILD_TARGETS} fi - if [ -d "samples/web/public" ]; then + if [ -d "web/filamentjs" ]; then if [ "$ISSUE_ARCHIVES" == "true" ]; then which -s python3 if [ $? == 0 ]; then echo "Generating JavaScript documentation..." - local DOCS_FOLDER="libs/filamentjs/jsdocs" - local DOCS_SCRIPT="../../libs/filamentjs/docs/build.py" + local DOCS_FOLDER="web/docs" + local DOCS_SCRIPT="../../web/docs/build.py" python3 ${DOCS_SCRIPT} --disable-demo \ --output-folder ${DOCS_FOLDER} \ --build-folder ${PWD} @@ -236,13 +236,12 @@ function build_webgl_with_target { # The web archive has the following subfolders: # dist...core WASM module and accompanying JS file. # docs...HTML tutorials for the JS API, accompanying demos, and a reference page. - cd libs + cd web tar -cvf ../../filament-${LC_TARGET}-web.tar -s /^filamentjs/dist/ \ filamentjs/filament.js tar -rvf ../../filament-${LC_TARGET}-web.tar -s /^filamentjs/dist/ \ filamentjs/filament.wasm - tar -rvf ../../filament-${LC_TARGET}-web.tar -s /^filamentjs.jsdocs/docs/ \ - filamentjs/jsdocs + tar -rvf ../../filament-${LC_TARGET}-web.tar docs cd - gzip -c ../filament-${LC_TARGET}-web.tar > ../filament-${LC_TARGET}-web.tgz rm ../filament-${LC_TARGET}-web.tar diff --git a/samples/web/favicon.png b/docs/favicon.png similarity index 100% rename from samples/web/favicon.png rename to docs/favicon.png diff --git a/samples/web/CMakeLists.txt b/samples/web/CMakeLists.txt deleted file mode 100644 index 987a51fec9..0000000000 --- a/samples/web/CMakeLists.txt +++ /dev/null @@ -1,204 +0,0 @@ -cmake_minimum_required(VERSION 3.1) -project(web-samples) - -# ================================================================================================== -# To fetch materials, the web samples can either: (1) use #include or (2) download filamat files. -# For simplicity, we generate both types of files for each material. -# ================================================================================================== - -set(MATERIAL_NAMES - sandboxCloth - sandboxLit - sandboxLitFade - sandboxLitTransparent - sandboxSubsurface - sandboxUnlit - texturedLit - bakedColor) - -if (CMAKE_CROSSCOMPILING) - include(${IMPORT_EXECUTABLES}) -endif() - -set(MATC_FLAGS -a opengl -m material -p mobile) -if (CMAKE_BUILD_TYPE MATCHES Release) - set(MATC_FLAGS -O ${MATC_FLAGS}) -endif() - -set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR}) -file(MAKE_DIRECTORY "${GENERATION_ROOT}/generated/material/") -file(MAKE_DIRECTORY "public/material/") - -set(MATERIAL_BINS) -foreach (NAME ${MATERIAL_NAMES}) - set(mat_src "../materials/${NAME}.mat") - get_filename_component(localname "${mat_src}" NAME_WE) - get_filename_component(fullname "${mat_src}" ABSOLUTE) - set(output_inc "${GENERATION_ROOT}/generated/material/${localname}.inc") - set(output_bin "public/material/${localname}.filamat") - add_custom_command( - OUTPUT ${output_inc} ${output_bin} - COMMAND matc ${MATC_FLAGS} -f header -o ${output_inc} ${fullname} - COMMAND matc ${MATC_FLAGS} -o ${output_bin} ${fullname} - MAIN_DEPENDENCY ${mat_src} - DEPENDS matc - COMMENT "Compiling material ${mat_src} to ${output_path}") - list(APPEND MATERIAL_BINS ${output_inc} ${output_bin}) -endforeach() - -add_custom_target(sample_materials DEPENDS ${MATERIAL_BINS}) - -# ================================================================================================== -# Build Assets. -# -# The goal is to create a "public" folder that can be the root of a simple file server: -# -# /suzanne.js built by em++ -# /suzanne.wasm built by em++ -# /suzanne.html copied from REPO/samples/web -# /filaweb.js copied from REPO/samples/web -# /favicon.png copied from REPO/samples/web -# /monkey/*.ktx generated by mipgen from REPO/assets/models -# /monkey/*.filamesh built by filamesh -# /syferfontein_18d_clear_2k/* built by cmgen -# -# ================================================================================================== - -function(copy_assets PATH NAME) - file(COPY ${PATH}/${NAME} DESTINATION ${PROJECT_BINARY_DIR}/public) - add_custom_target(${NAME} ALL DEPENDS ${NAME}) - add_dependencies(filament ${NAME}) -endfunction() - -copy_assets("." filaweb.js) -copy_assets("." favicon.png) - -# Generate mipmapped KTX files from various PNG files using mipgen. -function(add_ktxfiles SOURCE TARGET EXTRA_ARGS) - set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/../../${SOURCE}") - set(target_path "public/${TARGET}") - set(target_ktxfiles ${target_ktxfiles} ${target_path} PARENT_SCOPE) - add_custom_command( - OUTPUT ${target_path} - COMMAND mipgen --strip-alpha ${EXTRA_ARGS} ${source_path} ${target_path} - MAIN_DEPENDENCY ${source_path} - DEPENDS mipgen) -endfunction() - -set(ETC_R11_ARGS "--grayscale;--compression=etc_r11_numeric_40") - -# TODO: Instead of "rgb8" we should be using "rg11", but that causes an assertion in etc2comp. -set(ETC_NORMALS_ARGS "--kernel=NORMALS;--linear;--compression=etc_rgb8_normalxyz_40") - -add_ktxfiles("assets/models/monkey/albedo.png" "monkey/albedo.ktx" "") -add_ktxfiles("assets/models/monkey/albedo.png" "monkey/albedo_astc.ktx" "--compression=astc_fast_ldr_4x4") -add_ktxfiles("assets/models/monkey/albedo.png" "monkey/albedo_s3tc.ktx" "--compression=s3tc_rgb_dxt1") -add_ktxfiles("assets/models/monkey/normal.png" "monkey/normal.ktx" "--kernel=NORMALS;--linear") -add_ktxfiles("assets/models/monkey/normal.png" "monkey/normal_etc.ktx" "${ETC_NORMALS_ARGS}") -add_ktxfiles("assets/models/monkey/roughness.png" "monkey/roughness.ktx" "--grayscale") -add_ktxfiles("assets/models/monkey/roughness.png" "monkey/roughness_etc.ktx" "${ETC_R11_ARGS}") -add_ktxfiles("assets/models/monkey/metallic.png" "monkey/metallic.ktx" "--grayscale") -add_ktxfiles("assets/models/monkey/metallic.png" "monkey/metallic_etc.ktx" "${ETC_R11_ARGS}") -add_ktxfiles("assets/models/monkey/ao.png" "monkey/ao.ktx" "--grayscale") -add_ktxfiles("assets/models/monkey/ao.png" "monkey/ao_etc.ktx" "${ETC_R11_ARGS}") - -# Convert OBJ files into filamesh files. -function(add_mesh SOURCE TARGET) - set(source_mesh "${CMAKE_CURRENT_SOURCE_DIR}/../../${SOURCE}") - set(target_mesh "public/${TARGET}") - set(target_meshes ${target_meshes} ${target_mesh} PARENT_SCOPE) - add_custom_command( - OUTPUT ${target_mesh} - COMMAND filamesh ${source_mesh} ${target_mesh} - MAIN_DEPENDENCY ${source_mesh} - DEPENDS filamesh) -endfunction() - -add_mesh("assets/models/monkey/monkey.obj" "monkey/mesh.filamesh") -add_mesh("third_party/shader_ball/shader_ball.obj" "shaderball/mesh.filamesh") - -# Generate IBL and skybox images using cmgen. -set(CMGEN_ARGS -x public --format=ktx --size=256 --extract-blur=0.1) -set(CMGEN_ARGS_S3TC ${CMGEN_ARGS} --compression=s3tc_rgba_dxt5) -set(CMGEN_ARGS_ETC ${CMGEN_ARGS} --compression=etc_rgba8_rgba_40) -function(add_envmap SOURCE TARGET) - set(source_envmap "${CMAKE_CURRENT_SOURCE_DIR}/../../${SOURCE}") - - file(MAKE_DIRECTORY "public/${TARGET}") - - set(target_skybox "public/${TARGET}/${TARGET}_skybox.ktx") - set(target_envmap "public/${TARGET}/${TARGET}_ibl.ktx") - - set(target_envmap_etc "public/${TARGET}/${TARGET}_ibl_etc.ktx") - set(target_envmap_s3tc "public/${TARGET}/${TARGET}_ibl_s3tc.ktx") - - set(target_skyboxes ${target_skyboxes} ${target_skybox} PARENT_SCOPE) - - set(target_envmaps ${target_envmaps} - ${target_envmap} ${target_envmap_etc} ${target_envmap_s3tc} PARENT_SCOPE) - - add_custom_command(OUTPUT ${target_skybox} - ${target_envmap} ${target_envmap_etc} ${target_envmap_s3tc} - - # First create an S3TC-encoded envmap, then rename it. - COMMAND cmgen ${CMGEN_ARGS_S3TC} ${source_envmap} - COMMAND mv ${target_envmap} ${target_envmap_s3tc} - - # Now create an ETC-encoded envmap, then rename it. - COMMAND cmgen ${CMGEN_ARGS_ETC} ${source_envmap} - COMMAND mv ${target_envmap} ${target_envmap_etc} - - # Finally, create KTX files for the uncompressed envmap. - COMMAND cmgen ${CMGEN_ARGS} ${source_envmap} - - MAIN_DEPENDENCY ${source_envmap} - DEPENDS cmgen) -endfunction() - -add_envmap("third_party/environments/syferfontein_18d_clear_2k.hdr" "syferfontein_18d_clear_2k") -add_envmap("third_party/environments/pillars_2k.hdr" "pillars_2k") - -add_custom_target(sample_assets DEPENDS - ${target_ktxfiles} - ${target_meshes} - ${target_envmaps} - ${target_skyboxes}) - -# ================================================================================================== -# For each demo, build a pair of wasm/js files and copy over an HTML file. -# ================================================================================================== - -set(EXPORTS "'_launch','_main','_render','_resize','_mouse'") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORTED_FUNCTIONS=[${EXPORTS}]") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1") -if (CMAKE_BUILD_TYPE MATCHES Debug) - # Note that emcc offers a SAFE_HEAP=1 option to perform extra memory checks. Ideally we would - # enable it for debug builds, but currently it triggers an abort due to the custom memory - # alignments that Filament uses for various objects. This merits further investigation. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s ASSERTIONS=2") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s DEMANGLE_SUPPORT=1") -endif() - -function(add_demo NAME) - include_directories(${GENERATION_ROOT}) - add_executable(${NAME} ${NAME}.cpp - ../app/CameraManipulator.cpp - filaweb.h - filaweb.cpp) - add_dependencies(${NAME} sample_materials sample_assets) - target_link_libraries(${NAME} PRIVATE filament filagui filameshio image math utils) - - # Copy the generated js and wasm files into the public folder, as well as the app-specific - # manually-written HTML file. - add_custom_command( - OUTPUT ${PROJECT_BINARY_DIR}/public/${NAME}.js - DEPENDS ${NAME} ${PROJECT_BINARY_DIR}/${NAME}.js ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.html - COMMAND cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.html ${PROJECT_BINARY_DIR}/public - COMMAND cmake -E copy ${PROJECT_BINARY_DIR}/${NAME}.* ${PROJECT_BINARY_DIR}/public) - add_custom_target(${NAME}_public ALL DEPENDS ${PROJECT_BINARY_DIR}/public/${NAME}.js) - -endfunction() - -add_demo(suzanne) -add_demo(triangle) -add_demo(sandbox) diff --git a/samples/web/filaweb.cpp b/samples/web/filaweb.cpp deleted file mode 100644 index bc4ff7a7f5..0000000000 --- a/samples/web/filaweb.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "filaweb.h" - -#include - -#include - -#include - -#include - -#include -#include - -using namespace filament; -using namespace image; -using namespace std; -using namespace utils; - -extern "C" void render() { - filaweb::Application::get()->render(); -} - -extern "C" void resize(uint32_t width, uint32_t height, double pixelRatio) { - filaweb::Application::get()->resize(width, height, pixelRatio); -} - -extern "C" void mouse(int x, int y, int wx, int wy, int buttons) { - // We are careful not to pass down negative numbers, doing so would cause a numeric - // representation exception in WebAssembly. - x = std::max(0, x); - y = std::max(0, y); - filaweb::Application::get()->mouse(x, y, wx, wy, buttons); -} - -namespace filaweb { - -void Application::run(SetupCallback setup, AnimCallback animation, ImGuiCallback imgui) { - mAnimation = animation; - mGuiCallback = imgui; - mEngine = Engine::create(Engine::Backend::OPENGL); - mSwapChain = mEngine->createSwapChain(nullptr); - mScene = mEngine->createScene(); - mRenderer = mEngine->createRenderer(); - mView = mEngine->createView(); - mView->setScene(mScene); - mGuiCam = mEngine->createCamera(); - mGuiView = mEngine->createView(); - mGuiView->setClearTargets(false, false, false); - mGuiView->setRenderTarget(View::TargetBufferFlags::DEPTH_AND_STENCIL); - mGuiView->setPostProcessingEnabled(false); - mGuiView->setShadowsEnabled(false); - mGuiView->setCamera(mGuiCam); - mGuiHelper = new filagui::ImGuiHelper(mEngine, mGuiView, ""); - setup(mEngine, mView, mScene); - - // File I/O in WebAssembly does not exist, so tell ImGui to not bother with the ini file. - ImGui::GetIO().IniFilename = nullptr; -} - -void Application::resize(uint32_t width, uint32_t height, double pixelRatio) { - mPixelRatio = pixelRatio; - mView->setViewport({0, 0, width, height}); - mGuiView->setViewport({0, 0, width, height}); - mManipulator.setViewport(width, height); - mGuiCam->setProjection(filament::Camera::Projection::ORTHO, - 0.0, width / pixelRatio, - height / pixelRatio, 0.0, - 0.0, 1.0); - mGuiHelper->setDisplaySize(width / pixelRatio, height / pixelRatio, pixelRatio, pixelRatio); -} - -void Application::mouse(uint32_t x, uint32_t y, int32_t wx, int32_t wy, uint16_t buttons) { - // First, pass the current pointer state to ImGui. - auto& io = ImGui::GetIO(); - if (wx > 0) io.MouseWheelH += 1; - if (wx < 0) io.MouseWheelH -= 1; - if (wy > 0) io.MouseWheel += 1; - if (wy < 0) io.MouseWheel -= 1; - io.MousePos.x = x; - io.MousePos.y = y; - io.MouseDown[0] = buttons & 1; - io.MouseDown[1] = buttons & 2; - io.MouseDown[2] = buttons & 4; - - // Negate Y before pushing values to the manipulator. - y = -y; - wy = -wy; - - // Pass values to the camera manipulator to enable dolly and rotate. - // We do not call call track() because two-button mouse usage is less useful on web. - using namespace math; - static double2 previousMousePosition = double2(x, y); - static uint16_t previousMouseButtons = buttons; - double2 delta = double2(x, y) - previousMousePosition; - previousMousePosition = double2(x, y); - mManipulator.dolly(wy); - if (!io.WantCaptureMouse && buttons == 1 && buttons == previousMouseButtons) { - mManipulator.rotate(delta); - } - previousMouseButtons = buttons; -} - -void Application::render() { - using namespace std::chrono; - - mManipulator.updateCameraTransform(); - - auto milliseconds_since_epoch = system_clock::now().time_since_epoch() / milliseconds(1); - mAnimation(mEngine, mView, milliseconds_since_epoch / 1000.0); - - double now = milliseconds_since_epoch / 1000.0; - static double previous = now; - mGuiHelper->render(now - previous, mGuiCallback); - previous = now; - - if (mRenderer->beginFrame(mSwapChain)) { - mRenderer->render(mView); - mRenderer->render(mGuiView); - mRenderer->endFrame(); - } - mEngine->execute(); -} - -Asset getRawFile(const char* name) { - // Obtain size and URL from JavaScript. - Asset result = {}; - EM_ASM({ - var nbytes = $0 >> 2; - var name = UTF8ToString($1); - HEAP32[nbytes] = assets[name].data.byteLength; - stringToUTF8(assets[name].url, $2, $3); - }, &result.rawSize, name, &result.rawUrl[0], sizeof(result.rawUrl)); - - // Move the data from JavaScript. - uint8_t* data = new uint8_t[result.rawSize]; - EM_ASM({ - var data = $0; - var name = UTF8ToString($1); - HEAPU8.set(assets[name].data, data); - assets[name].data = null; - }, data, name); - result.rawData = decltype(Asset::rawData)(data); - return result; -} - -static Asset getKtxTexture(const Asset& rawfile) { - Asset result = {}; - result.texture.reset(new KtxBundle(rawfile.rawData.get(), rawfile.rawSize)); - return result; -} - -Asset getTexture(const char* name) { - Asset rawfile = getRawFile(name); - return getKtxTexture(rawfile); -} - -Asset getCubemap(const char* name) { - string prefix = string(name) + "/"; - - // Deserialize the KtxBundle for the IBL. - Asset* envFaces = new Asset; - string key = prefix + "ibl"; - *envFaces = getKtxTexture(getRawFile(key.c_str())); - - // Ditto but for the blurry sky. - Asset* skyFaces = new Asset; - key = prefix + "skybox"; - *skyFaces = getKtxTexture(getRawFile(key.c_str())); - - Asset result = {}; - result.envIBL.reset(envFaces); - result.envSky.reset(skyFaces); - return result; -} - -static Texture* createCubemapTexture(filament::Engine& engine, image::KtxBundle* ktxbundle) { - auto info = ktxbundle->getInfo(); - uint32_t nmips = ktxbundle->getNumMipLevels(); - auto builder = Texture::Builder() - .width(info.pixelWidth) - .height(info.pixelHeight) - .levels(nmips) - .rgbm(true) - .sampler(Texture::Sampler::SAMPLER_CUBEMAP); - - // Compressed textures in KTX always have a glFormat of 0. - if (info.glFormat == 0) { - builder.format(filaweb::toTextureFormat(info.glInternalFormat)); - } else { - builder.format(Texture::InternalFormat::RGBA8); - } - Texture* texture = builder.build(engine); - size_t size = info.pixelWidth; - uint32_t i = 0; - for (uint32_t mip = 0; mip < nmips; ++mip, size >>= 1) { - - uint8_t* ktxPixels; - uint32_t faceSize; - ktxbundle->getBlob({mip}, &ktxPixels, &faceSize); - - Texture::FaceOffsets offsets; - offsets.px = faceSize * 0; - offsets.nx = faceSize * 1; - offsets.py = faceSize * 2; - offsets.ny = faceSize * 3; - offsets.pz = faceSize * 4; - offsets.nz = faceSize * 5; - - // If this is a compressed texture, use a special PixelBufferDescriptor constructor. - Texture::PixelBufferDescriptor* buffer; - if (info.glFormat == 0) { - auto datatype = filaweb::toPixelDataType(info.glInternalFormat); - buffer = new Texture::PixelBufferDescriptor( - malloc(faceSize * 6), faceSize * 6, - datatype, faceSize, - [](void* buffer, size_t size, void* user) { - free(buffer); - }, /* user = */ nullptr); - } else { - buffer = new Texture::PixelBufferDescriptor( - malloc(faceSize * 6), faceSize * 6, - Texture::Format::RGBM, Texture::Type::UBYTE, - [](void* buffer, size_t size, void* user) { - free(buffer); - }, /* user = */ nullptr); - } - - // Copy 6 faces from the KTX bundle into the Filament pixel buffer. - uint8_t* pbdPixels = static_cast(buffer->buffer); - memcpy(pbdPixels, ktxPixels, faceSize * 6); - texture->setImage(engine, mip, std::move(*buffer), offsets); - delete buffer; - } - return texture; -} - -SkyLight getSkyLight(Engine& engine, const char* name) { - SkyLight result; - using size_t = std::size_t; - - // Pull the data out of JavaScript. - static auto asset = filaweb::getCubemap(name); - - // Parse the coefficients. - const char* shtext = asset.envIBL->texture->getMetadata("sh"); - if (!shtext) { - cerr << name << " is missing spherical harmonics coefficients." << endl; - abort(); - } - std::istringstream shReader(shtext); - shReader >> std::skipws; - for (size_t i = 0; i < 9; i++) { - shReader >> result.bands[i].r >> result.bands[i].g >> result.bands[i].b; - } - - // Copy over the miplevels for the indirect light. - Texture* texture = createCubemapTexture(engine, asset.envIBL->texture.get()); - asset.envIBL->texture.reset(); - - result.indirectLight = IndirectLight::Builder() - .reflections(texture) - .irradiance(3, result.bands) - .intensity(30000.0f) - .build(engine); - - // Copy a single miplevel for the blurry skybox - Texture* skybox = createCubemapTexture(engine, asset.envSky->texture.get()); - asset.envSky->texture.reset(); - result.skybox = Skybox::Builder().environment(skybox).build(engine); - return result; -} - -template -T toFilamentEnum(uint32_t format) { - switch (format) { - case KtxBundle::RGB_S3TC_DXT1: return T::DXT1_RGB; - case KtxBundle::RGBA_S3TC_DXT1: return T::DXT1_RGBA; - case KtxBundle::RGBA_S3TC_DXT3: return T::DXT3_RGBA; - case KtxBundle::RGBA_S3TC_DXT5: return T::DXT5_RGBA; - case KtxBundle::RGBA_ASTC_4x4: return T::RGBA_ASTC_4x4; - case KtxBundle::RGBA_ASTC_5x4: return T::RGBA_ASTC_5x4; - case KtxBundle::RGBA_ASTC_5x5: return T::RGBA_ASTC_5x5; - case KtxBundle::RGBA_ASTC_6x5: return T::RGBA_ASTC_6x5; - case KtxBundle::RGBA_ASTC_6x6: return T::RGBA_ASTC_6x6; - case KtxBundle::RGBA_ASTC_8x5: return T::RGBA_ASTC_8x5; - case KtxBundle::RGBA_ASTC_8x6: return T::RGBA_ASTC_8x6; - case KtxBundle::RGBA_ASTC_8x8: return T::RGBA_ASTC_8x8; - case KtxBundle::RGBA_ASTC_10x5: return T::RGBA_ASTC_10x5; - case KtxBundle::RGBA_ASTC_10x6: return T::RGBA_ASTC_10x6; - case KtxBundle::RGBA_ASTC_10x8: return T::RGBA_ASTC_10x8; - case KtxBundle::RGBA_ASTC_10x10: return T::RGBA_ASTC_10x10; - case KtxBundle::RGBA_ASTC_12x10: return T::RGBA_ASTC_12x10; - case KtxBundle::RGBA_ASTC_12x12: return T::RGBA_ASTC_12x12; - case KtxBundle::SRGB8_ALPHA8_ASTC_4x4: return T::SRGB8_ALPHA8_ASTC_4x4; - case KtxBundle::SRGB8_ALPHA8_ASTC_5x4: return T::SRGB8_ALPHA8_ASTC_5x4; - case KtxBundle::SRGB8_ALPHA8_ASTC_5x5: return T::SRGB8_ALPHA8_ASTC_5x5; - case KtxBundle::SRGB8_ALPHA8_ASTC_6x5: return T::SRGB8_ALPHA8_ASTC_6x5; - case KtxBundle::SRGB8_ALPHA8_ASTC_6x6: return T::SRGB8_ALPHA8_ASTC_6x6; - case KtxBundle::SRGB8_ALPHA8_ASTC_8x5: return T::SRGB8_ALPHA8_ASTC_8x5; - case KtxBundle::SRGB8_ALPHA8_ASTC_8x6: return T::SRGB8_ALPHA8_ASTC_8x6; - case KtxBundle::SRGB8_ALPHA8_ASTC_8x8: return T::SRGB8_ALPHA8_ASTC_8x8; - case KtxBundle::SRGB8_ALPHA8_ASTC_10x5: return T::SRGB8_ALPHA8_ASTC_10x5; - case KtxBundle::SRGB8_ALPHA8_ASTC_10x6: return T::SRGB8_ALPHA8_ASTC_10x6; - case KtxBundle::SRGB8_ALPHA8_ASTC_10x8: return T::SRGB8_ALPHA8_ASTC_10x8; - case KtxBundle::SRGB8_ALPHA8_ASTC_10x10: return T::SRGB8_ALPHA8_ASTC_10x10; - case KtxBundle::SRGB8_ALPHA8_ASTC_12x10: return T::SRGB8_ALPHA8_ASTC_12x10; - case KtxBundle::SRGB8_ALPHA8_ASTC_12x12: return T::SRGB8_ALPHA8_ASTC_12x12; - case KtxBundle::R11_EAC: return T::EAC_R11; - case KtxBundle::SIGNED_R11_EAC: return T::EAC_R11_SIGNED; - case KtxBundle::RG11_EAC: return T::EAC_RG11; - case KtxBundle::SIGNED_RG11_EAC: return T::EAC_RG11_SIGNED; - case KtxBundle::RGB8_ETC2: return T::ETC2_RGB8; - case KtxBundle::SRGB8_ETC2: return T::ETC2_SRGB8; - case KtxBundle::RGB8_ALPHA1_ETC2: return T::ETC2_RGB8_A1; - case KtxBundle::SRGB8_ALPHA1_ETC: return T::ETC2_SRGB8_A1; - case KtxBundle::RGBA8_ETC2_EAC: return T::ETC2_EAC_RGBA8; - case KtxBundle::SRGB8_ALPHA8_ETC2_EAC: return T::ETC2_EAC_SRGBA8; - } - return (T) 0xffff; -} - -filament::driver::CompressedPixelDataType toPixelDataType(uint32_t format) { - return toFilamentEnum(format); -} - -filament::driver::TextureFormat toTextureFormat(uint32_t format) { - return toFilamentEnum(format); -} - -} // namespace filaweb diff --git a/samples/web/filaweb.h b/samples/web/filaweb.h deleted file mode 100644 index 21dc616fc7..0000000000 --- a/samples/web/filaweb.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef TNT_FILAMENT_SAMPLES_FILAWEB_H -#define TNT_FILAMENT_SAMPLES_FILAWEB_H - -#include "../app/CameraManipulator.h" - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace filaweb { - -// Filaweb defines three kinds of assets: textures, environments, and raw files. -// For simplicity all three kinds are represented with a single struct. -struct Asset { - std::unique_ptr texture; - std::unique_ptr envIBL; - std::unique_ptr envSky; - std::unique_ptr rawData; - uint32_t rawSize; - char rawUrl[256]; -}; - -Asset getRawFile(const char* name); -Asset getTexture(const char* name); -Asset getCubemap(const char* name); - -struct SkyLight { - math::float3 bands[9]; - filament::IndirectLight* indirectLight; - filament::Skybox* skybox; -}; - -SkyLight getSkyLight(filament::Engine& engine, const char* name); - -filament::driver::CompressedPixelDataType toPixelDataType(uint32_t format); -filament::driver::TextureFormat toTextureFormat(uint32_t format); - -static const auto NoopCallback = [](filament::Engine*, filament::View*) {}; - -class Application { -public: - using Engine = filament::Engine; - using View = filament::View; - using Scene = filament::Scene; - using SetupCallback = std::function; - using ImGuiCallback = std::function; - using AnimCallback = std::function; - - static Application* get() { - static Application app; - return &app; - } - - void run(SetupCallback setup, AnimCallback animation, ImGuiCallback imgui = NoopCallback); - void resize(uint32_t width, uint32_t height, double pixelRatio); - void mouse(uint32_t x, uint32_t y, int32_t wx, int32_t wy, uint16_t buttons); - void render(); - - CameraManipulator& getManipulator() { return mManipulator; } - -private: - Application() { } - filagui::ImGuiHelper* mGuiHelper = nullptr; - Engine* mEngine = nullptr; - Scene* mScene = nullptr; - View* mView = nullptr; - View* mGuiView = nullptr; - filament::Camera* mGuiCam = nullptr; - filament::Renderer* mRenderer = nullptr; - filament::SwapChain* mSwapChain = nullptr; - CameraManipulator mManipulator; - AnimCallback mAnimation; - ImGuiCallback mGuiCallback; - double mPixelRatio = 1.0; -}; - -} // namespace filaweb - -#endif // TNT_FILAMENT_SAMPLES_FILAWEB_H diff --git a/samples/web/filaweb.js b/samples/web/filaweb.js deleted file mode 100644 index 587b4b5717..0000000000 --- a/samples/web/filaweb.js +++ /dev/null @@ -1,141 +0,0 @@ -let assets = {}; -let assets_ready = false; -let context_ready = false; -let previous_mouse_buttons = 0; -let queued_mouse_events = []; - -let use_astc = false; -let use_s3tc = false; -let use_etc = false; - -let canvas = document.getElementById('filament-canvas'); -let ctx = GL.createContext(canvas, { - majorVersion: 2, - minorVersion: 0, - antialias: false, - depth: false, - alpha: false -}); -GL.makeContextCurrent(ctx); -for (let ext of Module.ctx.getSupportedExtensions()) { - if (ext == "WEBGL_compressed_texture_s3tc") { - Module.ctx.getExtension('WEBGL_compressed_texture_s3tc'); - use_s3tc = true; - } else if (ext == "WEBGL_compressed_texture_astc") { - Module.ctx.getExtension('WEBGL_compressed_texture_astc'); - use_astc = true; - } else if (ext == "WEBGL_compressed_texture_etc") { - Module.ctx.getExtension('WEBGL_compressed_texture_etc'); - use_etc = true; - } -} - -// This is usually (not always) called before the wasm has finished JIT compiling. -async function load(promises) { - for (let name in promises) { - assets[name] = await promises[name]; - } - assets_ready = true; - maybe_launch(); -} - -// This is called as soon as the wasm has finished JIT compilation. -Module.postRun = function() { - context_ready = true; - maybe_launch(); -} - -// This is called twice: once after assets have loaded, and once after WASM compilation. We try to -// be robust with either order, launching the C++ code only after both requirements are fulfilled. -function maybe_launch() { - if (assets_ready && context_ready) { - _launch(); - canvas_resize(); - window.addEventListener("resize", canvas_resize); - let canvas = document.getElementById('filament-canvas'); - canvas.addEventListener("wheel", canvas_mouse); - canvas.addEventListener("pointermove", canvas_mouse); - canvas.addEventListener("pointerdown", canvas_mouse); - canvas.addEventListener("pointerup", canvas_mouse); - canvas_render(); - } -} - -// Update a tiny queue of pointer events. We don't send them to WASM immediately because ImGui -// detects click events by looking for three consecutive frames of down-up-down. -function canvas_mouse(evt) { - if (evt.pointerType == 'touch' && !evt.isPrimary) { - return; - } - let args = [evt.clientX, evt.clientY, evt.deltaX || 0, evt.deltaY || 0, evt.buttons]; - if (evt.buttons != previous_mouse_buttons || queued_mouse_events.length == 0) { - queued_mouse_events.push(args); - } else { - // Clobber the previous event if the button state doesn't change, there's no point in - // creating latency. - queued_mouse_events[queued_mouse_events.length - 1] = args; - } - previous_mouse_buttons = evt.buttons; -} - -function canvas_render() { - if (queued_mouse_events.length > 0) { - let args = queued_mouse_events.splice(0, 1)[0]; - _mouse(args[0], args[1], args[2], args[3], args[4]); - } - _render(); - window.requestAnimationFrame(canvas_render); -} - -function canvas_resize() { - let canvas = document.getElementById('filament-canvas'); - let pr = window.devicePixelRatio; - let w = window.innerWidth; - let h = window.innerHeight; - canvas.width = (w * pr) | 0; - canvas.height = (h * pr) | 0; - _resize((w * pr) | 0, (h * pr) | 0, pr); -} - -function load_rawfile(url) { - let promise = new Promise((success, failure) => { - fetch(url).then(resp => { - resp.arrayBuffer().then(filedata => success({ - kind: 'rawfile', - url: url, - data: new Uint8Array(filedata) - })); - }); - }); - return promise; -} - -let load_texture = load_rawfile; - -function load_cubemap(name, suffix) { - let compressed_suffix = suffix; - if (use_etc) { - compressed_suffix = '_etc' + suffix; - } else if (use_s3tc) { - compressed_suffix = '_s3tc' + suffix; - } - let urlprefix = name + '/'; - let promises = {}; - promises['ibl'] = load_rawfile(urlprefix + name + '_ibl' + compressed_suffix); - promises['skybox'] = load_rawfile(urlprefix + name + '_skybox' + suffix); - let numberRemaining = Object.keys(promises).length; - var promise = new Promise((success) => { - for (let key in promises) { - promises[key].then((result) => { - assets[urlprefix + key] = result; - if (--numberRemaining == 0) { - success({ - kind: 'cubemap', - name: urlprefix, - }); - } - }); - } - }); - return promise; -} diff --git a/samples/web/sandbox.cpp b/samples/web/sandbox.cpp deleted file mode 100644 index e8238713f6..0000000000 --- a/samples/web/sandbox.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "../material_sandbox.h" - -#include "filaweb.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -#include - -#include - -using namespace filament; -using namespace filagui; -using namespace math; -using namespace utils; - -using MagFilter = TextureSampler::MagFilter; -using WrapMode = TextureSampler::WrapMode; -using Format = Texture::InternalFormat; - -struct SandboxApp { - MeshIO::Mesh filamesh; - Camera* cam; - SandboxParameters params; - filaweb::SkyLight skylight; - Scene* scene; -}; - -static SandboxApp app; - -void setup(Engine* engine, View* view, Scene* scene) { - app.scene = scene; - - // These initial values seem reasonable with the "pillars_2k" envmap. - app.params.iblIntensity = 10000.0f; - app.params.lightDirection.x = 1; - app.params.lightDirection.y = -1; - app.params.lightDirection.z = -0.4; - app.params.iblRotation = 289 * M_PI / 180; - - // These initial values look pretty nice with the shaderball. - app.params.clearCoat = 0.7f; - app.params.metallic = 0.0f; - app.params.reflectance = 0.5f; - app.params.color.x = 158 / 255.0f; - app.params.color.y = 118 / 255.0f; - app.params.color.z = 74 / 255.0f; - - // Create material. - createInstances(app.params, *engine); - - // Move raw asset data from JavaScript to C++ static storage. Their held data will be freed via - // BufferDescriptor callbacks after Filament creates the corresponding GPU objects. - static auto mesh = filaweb::getRawFile("mesh"); - - // Create mesh. - const uint8_t* mdata = mesh.rawData.get(); - const auto destructor = [](void* buffer, size_t size, void* user) { - // This destruction lambda is called for the vertex buffer AND index buffer, so release CPU - // memory only after both have been uploaded to the GPU. The static count trick here works - // only because we create a single mesh in this demo. - static int count = 0; - if (++count == 2) { - auto asset = (filaweb::Asset*) user; - asset->rawData.reset(); - } - }; - MaterialInstance* materialInstance = app.params.materialInstance[MATERIAL_LIT]; - app.filamesh = MeshIO::loadMeshFromBuffer(engine, mdata, destructor, &mesh, materialInstance); - scene->addEntity(app.filamesh.renderable); - - // Create the sun. - scene->addEntity(app.params.light); - - // Create skybox and image-based light source. - app.skylight = filaweb::getSkyLight(*engine, "pillars_2k"); - scene->setIndirectLight(app.skylight.indirectLight); - scene->setSkybox(app.skylight.skybox); - - app.cam = engine->createCamera(); - app.cam->setExposure(16.0f, 1 / 125.0f, 100.0f); - view->setCamera(app.cam); - - // Set up an interesting orientation for the shader ball. - auto& manip = filaweb::Application::get()->getManipulator(); - manip.setCamera(app.cam); - manip.lookAt(math::double3({0, 1, 6}), math::double3({0, 1, 0})); -}; - -void animate(Engine* engine, View* view, double now) { - static double previous = now; - - // Adjust camera on every frame in case window size changes. - using Fov = Camera::Fov; - const uint32_t width = view->getViewport().width; - const uint32_t height = view->getViewport().height; - double ratio = double(width) / height; - app.cam->setProjection(45.0, ratio, 0.1, 50.0, ratio < 1 ? Fov::HORIZONTAL : Fov::VERTICAL); -}; - -void ui(Engine* engine, View* view) { - auto& params = app.params; - // Initial window size and position are somewhat optimized for a Pixel 2 portrait screen. - ImGui::SetNextWindowSize(ImVec2(300.0f, 150.0f), ImGuiCond_Always); - ImGui::SetNextWindowPos(ImVec2(8, 6), ImGuiCond_Once); - ImGui::Begin("Material", nullptr, ImGuiWindowFlags_NoResize); - { - ImGui::ColorEdit3("baseColor", ¶ms.color.r); - if (params.currentMaterialModel > MATERIAL_MODEL_UNLIT) { - if (params.currentBlending == BLENDING_TRANSPARENT || - params.currentBlending == BLENDING_FADE) { - ImGui::SliderFloat("alpha", ¶ms.alpha, 0.0f, 1.0f); - } - ImGui::SliderFloat("roughness", ¶ms.roughness, 0.0f, 1.0f); - if (params.currentMaterialModel != MATERIAL_MODEL_CLOTH) { - ImGui::SliderFloat("metallic", ¶ms.metallic, 0.0f, 1.0f); - ImGui::SliderFloat("reflectance", ¶ms.reflectance, 0.0f, 1.0f); - } - if (params.currentMaterialModel != MATERIAL_MODEL_CLOTH && - params.currentMaterialModel != MATERIAL_MODEL_SUBSURFACE) { - ImGui::SliderFloat("clearCoat", ¶ms.clearCoat, 0.0f, 1.0f); - } - if (params.currentMaterialModel == MATERIAL_MODEL_SUBSURFACE) { - ImGui::SliderFloat("thickness", ¶ms.thickness, 0.0f, 1.0f); - ImGui::SliderFloat("subsurfacePower", ¶ms.subsurfacePower, 1.0f, 24.0f); - ImGui::ColorEdit3("subsurfaceColor", ¶ms.subsurfaceColor.r); - } - if (params.currentMaterialModel == MATERIAL_MODEL_CLOTH) { - ImGui::ColorEdit3("sheenColor", ¶ms.sheenColor.r); - ImGui::ColorEdit3("subsurfaceColor", ¶ms.subsurfaceColor.r); - } - } - } - ImGui::End(); - - MaterialInstance* materialInstance = updateInstances(params, *engine); - - auto& rcm = engine->getRenderableManager(); - auto instance = rcm.getInstance(app.filamesh.renderable); - for (size_t i = 0; i < rcm.getPrimitiveCount(instance); i++) { - rcm.setMaterialInstanceAt(instance, i, materialInstance); - } - rcm.setCastShadows(instance, params.castShadows); - - if (params.directionalLightEnabled && !params.hasDirectionalLight) { - app.scene->addEntity(params.light); - params.hasDirectionalLight = true; - } else if (!params.directionalLightEnabled && params.hasDirectionalLight) { - app.scene->remove(params.light); - params.hasDirectionalLight = false; - } - - app.skylight.indirectLight->setIntensity(params.iblIntensity); - app.skylight.indirectLight->setRotation( - mat3f::rotate(params.iblRotation, float3{ 0, 1, 0 })); -} - -// This is called only after the JavaScript layer has created a WebGL 2.0 context and all assets -// have been downloaded. -extern "C" void launch() { - filaweb::Application::get()->run(setup, animate, ui); -} - -// The main() entry point is implicitly called after JIT compilation, but potentially before the -// WebGL context has been created or assets have finished loading. -int main() { } - diff --git a/samples/web/sandbox.html b/samples/web/sandbox.html deleted file mode 100644 index cf18fc58ee..0000000000 --- a/samples/web/sandbox.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - Sandbox - - - - - - - - - - - diff --git a/samples/web/suzanne.cpp b/samples/web/suzanne.cpp deleted file mode 100644 index 9be6542b11..0000000000 --- a/samples/web/suzanne.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "filaweb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -using namespace filament; -using namespace math; -using namespace std; -using namespace utils; - -using MagFilter = TextureSampler::MagFilter; -using WrapMode = TextureSampler::WrapMode; -using Format = Texture::InternalFormat; - -struct SuzanneApp { - MeshIO::Mesh filamesh; - Material* mat; - MaterialInstance* mi; - Camera* cam; - Entity sun; - Entity ptlight[4]; -}; - -static constexpr uint8_t MATERIAL_LIT_PACKAGE[] = { - #include "generated/material/texturedLit.inc" -}; - -static SuzanneApp app; - -static Texture* setTextureParameter(Engine& engine, filaweb::Asset& asset, string name, bool linear, - TextureSampler const &sampler) { - const auto& info = asset.texture->getInfo(); - const uint32_t nmips = asset.texture->getNumMipLevels(); - - // This little structure tracks how many miplevels have been uploaded to the GPU so that we can - // free the CPU memory at the right time. - struct Uploader { - filaweb::Asset* asset; - uint32_t refcount; - }; - - Uploader* uploader = new Uploader {&asset, nmips}; - - const auto destroy = [](void* buffer, size_t size, void* user) { - auto uploader = (Uploader*) user; - if (--uploader->refcount == 0) { - uploader->asset->texture.reset(); - delete uploader; - } - }; - - uint8_t* data; - uint32_t nbytes; - - // Compressed textures in KTX always have a glFormat of 0. - if (info.glFormat == 0) { - assert(info.pixelWidth == info.pixelHeight); - driver::CompressedPixelDataType datatype = filaweb::toPixelDataType(info.glInternalFormat); - driver::TextureFormat texformat = filaweb::toTextureFormat(info.glInternalFormat); - - auto texture = Texture::Builder() - .width(info.pixelWidth) - .height(info.pixelHeight) - .levels(nmips) - .sampler(Texture::Sampler::SAMPLER_2D) - .format(texformat) - .build(engine); - - for (uint32_t level = 0; level < nmips; ++level) { - asset.texture->getBlob({level}, &data, &nbytes); - Texture::PixelBufferDescriptor pb(data, nbytes, datatype, nbytes, destroy, uploader); - texture->setImage(engine, level, std::move(pb)); - } - app.mi->setParameter(name.c_str(), texture, sampler); - return texture; - } - - Texture::Format format; - switch (info.glTypeSize) { - case 1: format = Texture::Format::R; break; - case 2: format = Texture::Format::RG; break; - case 3: format = Texture::Format::RGB; break; - case 4: format = Texture::Format::RGBA; break; - } - - Format internalFormat; - switch (info.glTypeSize) { - case 1: internalFormat = Format::R8; break; - case 2: internalFormat = Format::RG8; break; - case 3: internalFormat = linear ? Format::RGB8 : Format::SRGB8; break; - case 4: internalFormat = linear ? Format::RGBA8 : Format::SRGB8_A8; break; - } - - auto texture = Texture::Builder() - .width(info.pixelWidth) - .height(info.pixelHeight) - .levels(nmips) - .sampler(Texture::Sampler::SAMPLER_2D) - .format(internalFormat) - .build(engine); - - for (uint32_t level = 0; level < nmips; ++level) { - asset.texture->getBlob({level}, &data, &nbytes); - Texture::PixelBufferDescriptor pb(data, nbytes, format, Texture::Type::UBYTE, - destroy, uploader); - texture->setImage(engine, level, std::move(pb)); - } - - app.mi->setParameter(name.c_str(), texture, sampler); - return texture; -} - -void setup(Engine* engine, View* view, Scene* scene) { - - // Create material. - app.mat = Material::Builder() - .package((void*) MATERIAL_LIT_PACKAGE, sizeof(MATERIAL_LIT_PACKAGE)) - .build(*engine); - app.mi = app.mat->createInstance(); - app.mi->setParameter("clearCoat", 0.0f); - - // Move raw asset data from JavaScript to C++ static storage. Their held data will be freed via - // BufferDescriptor callbacks after Filament creates the corresponding GPU objects. - static auto mesh = filaweb::getRawFile("mesh"); - static auto albedo = filaweb::getTexture("albedo"); - static auto metallic = filaweb::getTexture("metallic"); - static auto roughness = filaweb::getTexture("roughness"); - static auto normal = filaweb::getTexture("normal"); - static auto ao = filaweb::getTexture("ao"); - - // Create mesh. - printf("%s: %d bytes\n", "mesh", mesh.rawSize); - const uint8_t* mdata = mesh.rawData.get(); - const auto destructor = [](void* buffer, size_t size, void* user) { - // This destruction lambda is called for the vertex buffer AND index buffer, so release CPU - // memory only after both have been uploaded to the GPU. The static count trick here works - // only because we create a single mesh in this demo. - static int count = 0; - if (++count == 2) { - auto asset = (filaweb::Asset*) user; - asset->rawData.reset(); - } - }; - - app.filamesh = MeshIO::loadMeshFromBuffer(engine, mdata, destructor, &mesh, app.mi); - scene->addEntity(app.filamesh.renderable); - - // Create textures. - TextureSampler sampler(TextureSampler::MinFilter::LINEAR_MIPMAP_LINEAR, MagFilter::LINEAR, - WrapMode::REPEAT); - auto setTexture = [engine, sampler] (filaweb::Asset& asset, const char* name, bool linear) { - setTextureParameter(*engine, asset, name, linear, sampler); - }; - setTexture(albedo, "albedo", false); - setTexture(metallic, "metallic", false); - setTexture(roughness, "roughness", false); - setTexture(normal, "normal", true); - setTexture(ao, "ao", false); - - // Create the sun. - auto& em = EntityManager::get(); - app.sun = em.create(); - LightManager::Builder(LightManager::Type::SUN) - .color(Color::toLinear({ 0.98f, 0.92f, 0.89f })) - .intensity(110000) - .direction({ 0.7, -1, -0.8 }) - .sunAngularRadius(1.2f) - .castShadows(true) - .build(*engine, app.sun); - scene->addEntity(app.sun); - - // Create point lights. - em.create(4, app.ptlight); - LightManager::Builder(LightManager::Type::POINT) - .color(Color::toLinear({0.98f, 0.92f, 0.89f})) - .intensity(LightManager::EFFICIENCY_LED, 300.0f) - .position({0.0f, -0.2f, -3.0f}) - .falloff(4.0f) - .build(*engine, app.ptlight[0]); - LightManager::Builder(LightManager::Type::POINT) - .color(Color::toLinear({0.98f, 0.12f, 0.19f})) - .intensity(LightManager::EFFICIENCY_LED, 200.0f) - .position({0.6f, 0.6f, -3.2f}) - .falloff(2.0f) - .build(*engine, app.ptlight[1]); - LightManager::Builder(LightManager::Type::POINT) - .color(Color::toLinear({0.18f, 0.12f, 0.89f})) - .intensity(LightManager::EFFICIENCY_LED, 200.0f) - .position({-0.6f, 0.6f, -3.2f}) - .falloff(2.0f) - .build(*engine, app.ptlight[2]); - LightManager::Builder(LightManager::Type::POINT) - .color(Color::toLinear({0.88f, 0.82f, 0.29f})) - .intensity(LightManager::EFFICIENCY_LED, 200.0f) - .position({0.0f, 1.5f, -3.5f}) - .falloff(2.0f) - .build(*engine, app.ptlight[3]); - scene->addEntity(app.ptlight[0]); - scene->addEntity(app.ptlight[1]); - scene->addEntity(app.ptlight[2]); - scene->addEntity(app.ptlight[3]); - - // Create skybox and image-based light source. - auto skylight = filaweb::getSkyLight(*engine, "syferfontein_18d_clear_2k"); - scene->setIndirectLight(skylight.indirectLight); - scene->setSkybox(skylight.skybox); - skylight.indirectLight->setIntensity(100000); - - app.cam = engine->createCamera(); - app.cam->setExposure(16.0f, 1 / 125.0f, 100.0f); - app.cam->lookAt(float3{0}, float3{0, 0, -4}); - view->setCamera(app.cam); - view->setClearColor({0.1, 0.125, 0.25, 1.0}); -}; - -void animate(Engine* engine, View* view, double now) { - using Fov = Camera::Fov; - const uint32_t width = view->getViewport().width; - const uint32_t height = view->getViewport().height; - double ratio = double(width) / height; - app.cam->setProjection(45.0, ratio, 0.1, 50.0, ratio < 1 ? Fov::HORIZONTAL : Fov::VERTICAL); - auto& tcm = engine->getTransformManager(); - tcm.setTransform(tcm.getInstance(app.filamesh.renderable), - mat4f{mat3f{1.0}, float3{0.0f, 0.0f, -4.0f}} * - mat4f::rotate(now, math::float3{0, 1, 0})); -}; - -// This is called only after the JavaScript layer has created a WebGL 2.0 context and all assets -// have been downloaded. -extern "C" void launch() { - filaweb::Application::get()->run(setup, animate); -} - -// The main() entry point is implicitly called after JIT compilation, but potentially before the -// WebGL context has been created or assets have finished loading. -int main() { } - diff --git a/samples/web/suzanne.html b/samples/web/suzanne.html deleted file mode 100644 index 4c79a1b427..0000000000 --- a/samples/web/suzanne.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Suzanne - - - - - - - - - - - diff --git a/samples/web/triangle.cpp b/samples/web/triangle.cpp deleted file mode 100644 index aa31eb89df..0000000000 --- a/samples/web/triangle.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "filaweb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -using namespace filament; - -using utils::Entity; -using utils::EntityManager; - -struct TriangleApp { - VertexBuffer* vb; - IndexBuffer* ib; - Material* mat; - Camera* cam; - Entity renderable; -}; - -struct Vertex { - math::float2 position; - uint32_t color; -}; - -static const Vertex TRIANGLE_VERTICES[3] = { - {{1, 0}, 0xffff0000u}, - {{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u}, - {{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu}, -}; - -static constexpr uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 }; - -static TriangleApp app; - -void setup(Engine* engine, View* view, Scene* scene) { - view->setClearColor({0.1, 0.125, 0.25, 1.0}); - view->setPostProcessingEnabled(false); - view->setDepthPrepass(filament::View::DepthPrepass::DISABLED); - static_assert(sizeof(Vertex) == 12, "Strange vertex size."); - app.vb = VertexBuffer::Builder() - .vertexCount(3) - .bufferCount(1) - .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12) - .attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12) - .normalized(VertexAttribute::COLOR) - .build(*engine); - app.vb->setBufferAt(*engine, 0, - VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr)); - app.ib = IndexBuffer::Builder() - .indexCount(3) - .bufferType(IndexBuffer::IndexType::USHORT) - .build(*engine); - app.ib->setBuffer(*engine, - IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr)); - - auto bakedColor = filaweb::getRawFile("bakedColor"); - app.mat = Material::Builder() - .package(bakedColor.rawData.get(), bakedColor.rawSize) - .build(*engine); - - app.renderable = EntityManager::get().create(); - RenderableManager::Builder(1) - .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) - .material(0, app.mat->getDefaultInstance()) - .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.vb, app.ib, 0, 3) - .culling(false) - .receiveShadows(false) - .castShadows(false) - .build(*engine, app.renderable); - scene->addEntity(app.renderable); - app.cam = engine->createCamera(); - view->setCamera(app.cam); -}; - -void animate(Engine* engine, View* view, double now) { - constexpr float ZOOM = 1.5f; - const uint32_t w = view->getViewport().width; - const uint32_t h = view->getViewport().height; - const float aspect = (float) w / h; - app.cam->setProjection(Camera::Projection::ORTHO, - -aspect * ZOOM, aspect * ZOOM, - -ZOOM, ZOOM, 0, 1); - auto& tcm = engine->getTransformManager(); - tcm.setTransform(tcm.getInstance(app.renderable), - math::mat4f::rotate(now, math::float3{0, 0, 1})); -}; - -// This is called only after the JavaScript layer has created a WebGL 2.0 context and all assets -// have been downloaded. -extern "C" void launch() { - filaweb::Application::get()->run(setup, animate); -} - -// The main() entry point is implicitly called after JIT compilation, but potentially before the -// WebGL context has been created or assets have finished loading. -int main() { } diff --git a/samples/web/triangle.html b/samples/web/triangle.html deleted file mode 100644 index d692250eec..0000000000 --- a/samples/web/triangle.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Triangle - - - - - - - - - - - diff --git a/libs/filamentjs/docs/build.py b/web/docs/build.py similarity index 96% rename from libs/filamentjs/docs/build.py rename to web/docs/build.py index ec53b55871..84b8489da3 100755 --- a/libs/filamentjs/docs/build.py +++ b/web/docs/build.py @@ -32,7 +32,7 @@ generate a markdown string, which then produces HTML. import os SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) + '/' -ROOT_DIR = SCRIPT_DIR + '../../../' +ROOT_DIR = SCRIPT_DIR + '../../' OUTPUT_DIR = ROOT_DIR + 'docs/webgl/' ENABLE_EMBEDDED_DEMO = True BUILD_DIR = ROOT_DIR + 'out/cmake-webgl-release/' @@ -442,11 +442,11 @@ def build_reference_markdown(doctree): def build_reference(): doctree = gather_docstrings([ - ROOT_DIR + 'libs/filamentjs/jsbindings.cpp', - ROOT_DIR + 'libs/filamentjs/jsenums.cpp', - ROOT_DIR + 'libs/filamentjs/utilities.js', - ROOT_DIR + 'libs/filamentjs/wasmloader.js', - ROOT_DIR + 'libs/filamentjs/extensions.js', + ROOT_DIR + 'web/filamentjs/jsbindings.cpp', + ROOT_DIR + 'web/filamentjs/jsenums.cpp', + ROOT_DIR + 'web/filamentjs/utilities.js', + ROOT_DIR + 'web/filamentjs/wasmloader.js', + ROOT_DIR + 'web/filamentjs/extensions.js', ]) markdown = build_reference_markdown(doctree) rendered = mistletoe.markdown(markdown, PygmentsRenderer) @@ -487,12 +487,10 @@ if __name__ == "__main__": tangle(name) generate_demo_html(name) - copy_src_file(ROOT_DIR + 'libs/filamentjs/docs/main.css') + copy_src_file(ROOT_DIR + 'web/docs/main.css') copy_src_file(ROOT_DIR + 'third_party/gl-matrix/gl-matrix-min.js') - copy_built_file('libs/filamentjs/filament.js') - copy_built_file('libs/filamentjs/filament.wasm') - copy_built_file('samples/web/public/pillars_2k/pillars_2k_skybox.ktx') - copy_built_file('samples/web/public/pillars_2k/pillars_2k_ibl.ktx') + copy_built_file('web/filamentjs/filament.js') + copy_built_file('web/filamentjs/filament.wasm') build_filamat('triangle') build_filamat('plastic') build_reference() diff --git a/libs/filamentjs/docs/demo_template.html b/web/docs/demo_template.html similarity index 100% rename from libs/filamentjs/docs/demo_template.html rename to web/docs/demo_template.html diff --git a/libs/filamentjs/docs/main.css b/web/docs/main.css similarity index 100% rename from libs/filamentjs/docs/main.css rename to web/docs/main.css diff --git a/libs/filamentjs/docs/plastic.mat b/web/docs/plastic.mat similarity index 100% rename from libs/filamentjs/docs/plastic.mat rename to web/docs/plastic.mat diff --git a/libs/filamentjs/docs/ref_template.html b/web/docs/ref_template.html similarity index 100% rename from libs/filamentjs/docs/ref_template.html rename to web/docs/ref_template.html diff --git a/libs/filamentjs/docs/requirements.txt b/web/docs/requirements.txt similarity index 100% rename from libs/filamentjs/docs/requirements.txt rename to web/docs/requirements.txt diff --git a/libs/filamentjs/docs/triangle.mat b/web/docs/triangle.mat similarity index 100% rename from libs/filamentjs/docs/triangle.mat rename to web/docs/triangle.mat diff --git a/libs/filamentjs/docs/tutorial_redball.md b/web/docs/tutorial_redball.md similarity index 100% rename from libs/filamentjs/docs/tutorial_redball.md rename to web/docs/tutorial_redball.md diff --git a/libs/filamentjs/docs/tutorial_template.html b/web/docs/tutorial_template.html similarity index 100% rename from libs/filamentjs/docs/tutorial_template.html rename to web/docs/tutorial_template.html diff --git a/libs/filamentjs/docs/tutorial_triangle.md b/web/docs/tutorial_triangle.md similarity index 100% rename from libs/filamentjs/docs/tutorial_triangle.md rename to web/docs/tutorial_triangle.md diff --git a/libs/filamentjs/CMakeLists.txt b/web/filamentjs/CMakeLists.txt similarity index 100% rename from libs/filamentjs/CMakeLists.txt rename to web/filamentjs/CMakeLists.txt diff --git a/libs/filamentjs/extensions.js b/web/filamentjs/extensions.js similarity index 100% rename from libs/filamentjs/extensions.js rename to web/filamentjs/extensions.js diff --git a/libs/filamentjs/jsbindings.cpp b/web/filamentjs/jsbindings.cpp similarity index 100% rename from libs/filamentjs/jsbindings.cpp rename to web/filamentjs/jsbindings.cpp diff --git a/libs/filamentjs/jsenums.cpp b/web/filamentjs/jsenums.cpp similarity index 100% rename from libs/filamentjs/jsenums.cpp rename to web/filamentjs/jsenums.cpp diff --git a/libs/filamentjs/utilities.js b/web/filamentjs/utilities.js similarity index 100% rename from libs/filamentjs/utilities.js rename to web/filamentjs/utilities.js diff --git a/libs/filamentjs/wasmloader.js b/web/filamentjs/wasmloader.js similarity index 100% rename from libs/filamentjs/wasmloader.js rename to web/filamentjs/wasmloader.js diff --git a/libs/filamentjs/tests/requirements.txt b/web/tests/requirements.txt similarity index 100% rename from libs/filamentjs/tests/requirements.txt rename to web/tests/requirements.txt diff --git a/libs/filamentjs/tests/test.py b/web/tests/test.py similarity index 100% rename from libs/filamentjs/tests/test.py rename to web/tests/test.py diff --git a/libs/filamentjs/tests/test_leaks.html b/web/tests/test_leaks.html similarity index 100% rename from libs/filamentjs/tests/test_leaks.html rename to web/tests/test_leaks.html diff --git a/libs/filamentjs/tests/test_leaks.js b/web/tests/test_leaks.js similarity index 100% rename from libs/filamentjs/tests/test_leaks.js rename to web/tests/test_leaks.js diff --git a/libs/filamentjs/tests/test_parquet.html b/web/tests/test_parquet.html similarity index 100% rename from libs/filamentjs/tests/test_parquet.html rename to web/tests/test_parquet.html diff --git a/libs/filamentjs/tests/test_parquet.js b/web/tests/test_parquet.js similarity index 100% rename from libs/filamentjs/tests/test_parquet.js rename to web/tests/test_parquet.js diff --git a/libs/filamentjs/tests/test_redball.html b/web/tests/test_redball.html similarity index 100% rename from libs/filamentjs/tests/test_redball.html rename to web/tests/test_redball.html diff --git a/libs/filamentjs/tests/test_redball.js b/web/tests/test_redball.js similarity index 100% rename from libs/filamentjs/tests/test_redball.js rename to web/tests/test_redball.js