/* * 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. */ /* * JS BINDINGS DESIGN * ------------------ * * The purpose of filament-js is to offer a first-class JavaScript interface to the core Filament * classes: Engine, Renderer, Texture, etc. * * Emscripten offers two ways to binding JavaScript to C++: embind and WebIDL. We chose embind. * * With WebIDL, we would need to author WebIDL files and generate opaque C++ from the IDL, which * complicates the build process and ultimately results in the same amount of code. Using embind is * more direct and controllable. * * For nested classes, we use $ as the separator character because embind does not support nested * classes and it would transform dot separators into $ anyway. By using $, we at least make * this explicit rather than mysterious. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Avoid warnings for deprecated Filament APIs. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" using namespace emscripten; using namespace filament; using namespace filamesh; using namespace geometry; using namespace filament::gltfio; using namespace image; using namespace ktxreader; using namespace filament::viewer; namespace em = emscripten; #if __has_feature(cxx_rtti) #error Filament JS bindings require RTTI to be disabled. #endif // Many methods require a thin layer of C++ glue which is elegantly expressed with a lambda. // However, passing a bare lambda into embind's daisy chain requires a cast to a function pointer. #define EMBIND_LAMBDA(retval, arglist, impl) (retval (*) arglist) [] arglist impl // Builder functions that return "this" have verbose binding declarations, this macro reduces // the amount of boilerplate. #define BUILDER_FUNCTION(name, btype, arglist, impl) \ function(name, EMBIND_LAMBDA(btype*, arglist, impl), allow_raw_pointers()) // Explicit instantiation of emscripten::internal::raw_destructor is required for binding classes // that have non-public destructors. To prevent leaks, do not include pass-by-value types here. #define BIND(T) template<> void raw_destructor(T* ptr) {} namespace emscripten { namespace internal { BIND(Animator) BIND(AssetLoader) BIND(BufferObject) BIND(Camera) BIND(ColorGrading) BIND(Engine) BIND(FilamentAsset) BIND(FilamentInstance) BIND(IndexBuffer) BIND(IndirectLight) BIND(LightManager) BIND(Material) BIND(MaterialInstance) BIND(RenderableManager) BIND(Renderer) BIND(RenderTarget) BIND(Scene) BIND(Skybox) BIND(SwapChain) BIND(Texture) BIND(TransformManager) BIND(utils::EntityManager) BIND(VertexBuffer) BIND(View) } } #undef BIND namespace { // For convenience, declare terse private aliases to nested types. This lets us avoid extremely // verbose binding declarations. using ColorBuilder = ColorGrading::Builder; using IblBuilder = IndirectLight::Builder; using IndexBuilder = IndexBuffer::Builder; using LightBuilder = LightManager::Builder; using MatBuilder = Material::Builder; using RenderableBuilder = RenderableManager::Builder; using RenderTargetBuilder = RenderTarget::Builder; using SkyBuilder = Skybox::Builder; using SurfaceBuilder = SurfaceOrientation::Builder; using TexBuilder = Texture::Builder; using VertexBuilder = VertexBuffer::Builder; using BufferBuilder = BufferObject::Builder; // We avoid directly exposing backend::BufferDescriptor because embind does not support move // semantics and void* doesn't make sense to JavaScript anyway. This little wrapper class is exposed // to JavaScript as "driver$BufferDescriptor", but clients will normally use our "Filament.Buffer" // helper function (implemented in utilities.js) struct BufferDescriptor { BufferDescriptor() {} // This form is used when JavaScript sends a buffer into WASM. BufferDescriptor(uint32_t byteLength) { this->bd.reset(new backend::BufferDescriptor(malloc(byteLength), byteLength, [](void* buffer, size_t size, void* user) { free(buffer); })); } // This form is used when WASM needs to return a buffer to JavaScript. BufferDescriptor(uint8_t* data, uint32_t size) { this->bd.reset(new backend::BufferDescriptor(data, size)); } val getBytes() { unsigned char *byteBuffer = (unsigned char*) bd->buffer; size_t bufferLength = bd->size; return val(typed_memory_view(bufferLength, byteBuffer)); } // In order to match its JavaScript counterpart, the Buffer wrapper needs to use reference // counting, and the easiest way to achieve that is with shared_ptr. std::shared_ptr bd; }; // Exposed to JavaScript as "driver$PixelBufferDescriptor", but clients will normally use the // PixelBuffer or CompressedPixelBuffer helper functions (implemented in utilities.js) struct PixelBufferDescriptor { PixelBufferDescriptor(uint32_t byteLength, backend::PixelDataFormat fmt, backend::PixelDataType dtype) { this->pbd.reset(new backend::PixelBufferDescriptor(malloc(byteLength), byteLength, fmt, dtype, [](void* buffer, size_t size, void* user) { free(buffer); })); } // Note that embind allows overloading based on number of arguments, but not on types. // It's fine to have two constructors but they can't both have the same number of arguments. PixelBufferDescriptor(uint32_t byteLength, backend::CompressedPixelDataType cdtype, int imageSize, bool compressed) { assert(compressed == true); // For compressed cubemaps, the image size should be one-sixth the size of the entire blob. assert(imageSize == byteLength || imageSize == byteLength / 6); this->pbd.reset(new backend::PixelBufferDescriptor(malloc(byteLength), byteLength, cdtype, imageSize, [](void* buffer, size_t size, void* user) { free(buffer); })); } val getBytes() { unsigned char* byteBuffer = (unsigned char*) pbd->buffer; size_t bufferLength = pbd->size; return val(typed_memory_view(bufferLength, byteBuffer)); } // In order to match its JavaScript counterpart, the Buffer wrapper needs to use reference // counting, and the easiest way to achieve that is with shared_ptr. std::shared_ptr pbd; }; // Small structure whose sole purpose is to return decoded image data to JavaScript. struct DecodedImage { int width; int height; int encoded_ncomp; int decoded_ncomp; BufferDescriptor decoded_data; }; // JavaScript clients should call [createTextureFromPng] rather than calling this directly. DecodedImage decodeImage(BufferDescriptor encoded_data, int requested_ncomp) { DecodedImage result; stbi_uc* decoded_data = stbi_load_from_memory( (stbi_uc const *) encoded_data.bd->buffer, encoded_data.bd->size, &result.width, &result.height, &result.encoded_ncomp, requested_ncomp); const uint32_t decoded_size = result.width * result.height * requested_ncomp; result.decoded_data = BufferDescriptor(decoded_data, decoded_size); result.decoded_data.bd->setCallback([](void* buffer, size_t size, void* user) { stbi_image_free(buffer); }); result.decoded_ncomp = requested_ncomp; return result; } } // anonymous namespace EMSCRIPTEN_BINDINGS(jsbindings) { // MATH TYPES // ---------- // Individual JavaScript objects for math types would be too heavy, so instead we simply accept // array-like data using embind's "value_array" feature. We do not expose all our math functions // under the assumption that JS clients will use glMatrix or something similar for math. value_array("float2") .element(&filament::math::float2::x) .element(&filament::math::float2::y); value_array("float3") .element(&filament::math::float3::x) .element(&filament::math::float3::y) .element(&filament::math::float3::z); value_array("float4") .element(&filament::math::float4::x) .element(&filament::math::float4::y) .element(&filament::math::float4::z) .element(&filament::math::float4::w); value_array("double2") .element(&filament::math::double2::x) .element(&filament::math::double2::y); value_array("double3") .element(&filament::math::double3::x) .element(&filament::math::double3::y) .element(&filament::math::double3::z); value_array("double4") .element(&filament::math::double4::x) .element(&filament::math::double4::y) .element(&filament::math::double4::z) .element(&filament::math::double4::w); value_array("quat") .element(&filament::math::quat::x) .element(&filament::math::quat::y) .element(&filament::math::quat::z) .element(&filament::math::quat::w); value_array("Viewport") .element(&Viewport::left) .element(&Viewport::bottom) .element(&Viewport::width) .element(&Viewport::height); value_array("KtxBlobIndex") .element(&KtxBlobIndex::mipLevel) .element(&KtxBlobIndex::arrayIndex) .element(&KtxBlobIndex::cubeFace); value_object("Box") .field("center", &Box::center) .field("halfExtent", &Box::halfExtent); value_object("Aabb") .field("min", &filament::Aabb::min) .field("max", &filament::Aabb::max); value_object("Renderer$ClearOptions") .field("clearColor", &filament::Renderer::ClearOptions::clearColor) .field("clear", &filament::Renderer::ClearOptions::clear) .field("discard", &filament::Renderer::ClearOptions::discard); value_object("LightManager$ShadowOptions") .field("mapSize", &LightManager::ShadowOptions::mapSize) .field("shadowCascades", &LightManager::ShadowOptions::shadowCascades) .field("constantBias", &LightManager::ShadowOptions::constantBias) .field("normalBias", &LightManager::ShadowOptions::normalBias) .field("shadowFar", &LightManager::ShadowOptions::shadowFar) .field("shadowNearHint", &LightManager::ShadowOptions::shadowNearHint) .field("shadowFarHint", &LightManager::ShadowOptions::shadowFarHint) .field("stable", &LightManager::ShadowOptions::stable) .field("lispsm", &LightManager::ShadowOptions::lispsm) .field("polygonOffsetConstant", &LightManager::ShadowOptions::polygonOffsetConstant) .field("polygonOffsetSlope", &LightManager::ShadowOptions::polygonOffsetSlope) .field("screenSpaceContactShadows", &LightManager::ShadowOptions::screenSpaceContactShadows) .field("stepCount", &LightManager::ShadowOptions::stepCount) .field("maxShadowDistance", &LightManager::ShadowOptions::maxShadowDistance) .field("shadowBulbRadius", &LightManager::ShadowOptions::shadowBulbRadius) .field("transform", &LightManager::ShadowOptions::transform); // In JavaScript, a flat contiguous representation is best for matrices (see gl-matrix) so we // need to define a small wrapper here. struct flatmat4 { filament::math::mat4f m; float& operator[](int i) { return m[i / 4][i % 4]; } }; value_array("mat4") .element(em::index< 0>()).element(em::index< 1>()).element(em::index< 2>()).element(em::index< 3>()) .element(em::index< 4>()).element(em::index< 5>()).element(em::index< 6>()).element(em::index< 7>()) .element(em::index< 8>()).element(em::index< 9>()).element(em::index<10>()).element(em::index<11>()) .element(em::index<12>()).element(em::index<13>()).element(em::index<14>()).element(em::index<15>()); struct flatmat3 { filament::math::mat3f m; float& operator[](int i) { return m[i / 3][i % 3]; } }; value_array("mat3") .element(em::index<0>()).element(em::index<1>()).element(em::index<2>()) .element(em::index<3>()).element(em::index<4>()).element(em::index<5>()) .element(em::index<6>()).element(em::index<7>()).element(em::index<8>()); value_object("RenderableManager$Bone") .field("unitQuaternion", &RenderableManager::Bone::unitQuaternion) .field("translation", &RenderableManager::Bone::translation); // VECTOR TYPES // ------------ using EntityVector = std::vector; register_vector("RegistryKeys"); register_vector("EntityVector"); register_vector>("AssetInstanceVector"); register_vector>("MaterialInstanceVector"); // CORE FILAMENT CLASSES // --------------------- /// Engine ::core class:: Central manager and resource owner. class_("Engine") .class_function("_create", (Engine* (*)()) [] { EM_ASM_INT({ const options = window.filament_glOptions; const context = window.filament_glContext; const handle = GL.registerContext(context, options); window.filament_contextHandle = handle; GL.makeContextCurrent(handle); }); return Engine::create(); }, allow_raw_pointers()) .class_function("getSteadyClockTimeNano", &Engine::getSteadyClockTimeNano) .function("unprotected", &Engine::unprotected) .function("enableAccurateTranslations", &Engine::enableAccurateTranslations) .function("setAutomaticInstancingEnabled", &Engine::setAutomaticInstancingEnabled) .function("isAutomaticInstancingEnabled", &Engine::isAutomaticInstancingEnabled) .function("getSupportedFeatureLevel", &Engine::getSupportedFeatureLevel) .function("setActiveFeatureLevel", &Engine::setActiveFeatureLevel) .function("getActiveFeatureLevel", &Engine::getActiveFeatureLevel) .class_function("getMaxStereoscopicEyes", &Engine::getMaxStereoscopicEyes) .function("_execute", EMBIND_LAMBDA(void, (Engine* engine), { EM_ASM_INT({ const handle = window.filament_contextHandle; GL.makeContextCurrent(handle); }); engine->execute(); }), allow_raw_pointers()) /// destroy ::static method:: Destroys an engine instance and cleans up resources. /// engine ::argument:: the instance to destroy .class_function("destroy", (void (*)(Engine*)) [] (Engine* engine) { Engine::destroy(&engine); }, allow_raw_pointers()) /// getTransformManager ::method:: /// ::retval:: an instance of [TransformManager] .function("getTransformManager", EMBIND_LAMBDA(TransformManager*, (Engine* engine), { return &engine->getTransformManager(); }), allow_raw_pointers()) /// getLightManager ::method:: /// ::retval:: an instance of [LightManager] .function("getLightManager", EMBIND_LAMBDA(LightManager*, (Engine* engine), { return &engine->getLightManager(); }), allow_raw_pointers()) /// getRenderableManager ::method:: /// ::retval:: an instance of [RenderableManager] .function("getRenderableManager", EMBIND_LAMBDA(RenderableManager*, (Engine* engine), { return &engine->getRenderableManager(); }), allow_raw_pointers()) /// getEntityManager ::method:: /// ::retval:: an instance of [utils::EntityManager] .function("getEntityManager", EMBIND_LAMBDA(utils::EntityManager*, (Engine* engine), { return &engine->getEntityManager(); }), allow_raw_pointers()) /// createSwapChain ::method:: /// ::retval:: an instance of [SwapChain] .function("createSwapChain", (SwapChain* (*)(Engine*)) [] (Engine* engine) { return engine->createSwapChain(nullptr); }, allow_raw_pointers()) /// destroySwapChain ::method:: /// swapChain ::argument:: an instance of [SwapChain] .function("destroySwapChain", (void (*)(Engine*, SwapChain*)) [] (Engine* engine, SwapChain* swapChain) { engine->destroy(swapChain); }, allow_raw_pointers()) /// createRenderer ::method:: /// ::retval:: an instance of [Renderer] .function("createRenderer", &Engine::createRenderer, allow_raw_pointers()) /// destroyRenderer ::method:: /// renderer ::argument:: an instance of [Renderer] .function("destroyRenderer", (void (*)(Engine*, Renderer*)) [] (Engine* engine, Renderer* renderer) { engine->destroy(renderer); }, allow_raw_pointers()) /// createView ::method:: /// ::retval:: an instance of [View] .function("createView", &Engine::createView, allow_raw_pointers()) /// destroyView ::method:: /// view ::argument:: an instance of [View] .function("destroyView", (void (*)(Engine*, View*)) [] (Engine* engine, View* view) { engine->destroy(view); }, allow_raw_pointers()) /// createScene ::method:: /// ::retval:: an instance of [Scene] .function("createScene", &Engine::createScene, allow_raw_pointers()) /// destroyScene ::method:: /// scene ::argument:: an instance of [Scene] .function("destroyScene", (void (*)(Engine*, Scene*)) [] (Engine* engine, Scene* scene) { engine->destroy(scene); }, allow_raw_pointers()) /// createCamera ::method:: /// entity ::argument:: the [Entity] to add the camera component to /// ::retval:: an instance of [Camera] .function("createCamera", select_overload(&Engine::createCamera), allow_raw_pointers()) /// getCameraComponent ::method:: /// ::retval:: an instance of [Camera] .function("getCameraComponent", &Engine::getCameraComponent, allow_raw_pointers()) /// destroyCameraComponent ::method:: /// camera ::argument:: an [Entity] with a camera component .function("destroyCameraComponent", (void (*)(Engine*, utils::Entity)) [] (Engine* engine, utils::Entity camera) { engine->destroyCameraComponent(camera); }, allow_raw_pointers()) .function("_createMaterial", EMBIND_LAMBDA(Material*, (Engine* engine, BufferDescriptor mbd), { return Material::Builder().package(mbd.bd->buffer, mbd.bd->size).build(*engine); }), allow_raw_pointers()) /// destroyMaterial ::method:: /// material ::argument:: an instance of [Material] .function("destroyMaterial", (void (*)(Engine*, Material*)) [] (Engine* engine, Material* mat) { engine->destroy(mat); }, allow_raw_pointers()) /// destroyEntity ::method:: /// entity ::argument:: an [Entity] .function("destroyEntity", (void (*)(Engine*, utils::Entity)) [] (Engine* engine, utils::Entity entity) { engine->destroy(entity); }, allow_raw_pointers()) /// destroyColorGrading ::method:: /// entity ::argument:: an [ColorGrading] .function("destroyColorGrading", (void (*)(Engine*, ColorGrading*)) [] (Engine* engine, ColorGrading* colorGrading) { engine->destroy(colorGrading); }, allow_raw_pointers()) /// destroyIndexBuffer ::method:: /// ib ::argument:: the [IndexBuffer] to destroy .function("destroyIndexBuffer", (void (*)(Engine*, IndexBuffer*)) [] (Engine* engine, IndexBuffer* ib) { engine->destroy(ib); }, allow_raw_pointers()) /// destroyIndirectLight ::method:: /// light ::argument:: the [IndirectLight] to destroy .function("destroyIndirectLight", (void (*)(Engine*, IndirectLight*)) [] (Engine* engine, IndirectLight* light) { engine->destroy(light); }, allow_raw_pointers()) /// destroyMaterial ::method:: /// instance ::argument:: the [MaterialInstance] to destroy .function("destroyMaterialInstance", (void (*)(Engine*, MaterialInstance*)) [] (Engine* engine, MaterialInstance* mi) { engine->destroy(mi); }, allow_raw_pointers()) /// destroyRenderTarget ::method:: /// rt ::argument:: the [RenderTarget] to destroy .function("destroyRenderTarget", (void (*)(Engine*, RenderTarget*)) [] (Engine* engine, RenderTarget* rt) { engine->destroy(rt); }, allow_raw_pointers()) /// destroySkybox ::method:: /// skybox ::argument:: the [Skybox] to destroy .function("destroySkybox", (void (*)(Engine*, Skybox*)) [] (Engine* engine, Skybox* sky) { engine->destroy(sky); }, allow_raw_pointers()) /// destroyTexture ::method:: /// texture ::argument:: the [Texture] to destroy .function("destroyTexture", (void (*)(Engine*, Texture*)) [] (Engine* engine, Texture* tex) { engine->destroy(tex); }, allow_raw_pointers()) /// destroyVertexBuffer ::method:: /// vb ::argument:: the [VertexBuffer] to destroy .function("destroyVertexBuffer", (void (*)(Engine*, VertexBuffer*)) [] (Engine* engine, VertexBuffer* vb) { engine->destroy(vb); }, allow_raw_pointers()) .function("isValidRenderer", EMBIND_LAMBDA(bool, (Engine* engine, Renderer* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidView", EMBIND_LAMBDA(bool, (Engine* engine, View* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidScene", EMBIND_LAMBDA(bool, (Engine* engine, Scene* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidFence", EMBIND_LAMBDA(bool, (Engine* engine, Fence* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidStream", EMBIND_LAMBDA(bool, (Engine* engine, Stream* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidIndexBuffer", EMBIND_LAMBDA(bool, (Engine* engine, IndexBuffer* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidVertexBuffer", EMBIND_LAMBDA(bool, (Engine* engine, VertexBuffer* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidSkinningBuffer", EMBIND_LAMBDA(bool, (Engine* engine, SkinningBuffer* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidIndirectLight", EMBIND_LAMBDA(bool, (Engine* engine, IndirectLight* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidMaterial", EMBIND_LAMBDA(bool, (Engine* engine, Material* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidMaterialInstance", EMBIND_LAMBDA(bool, (Engine* engine, Material* ma, MaterialInstance* mi), { return engine->isValid(ma, mi); }), allow_raw_pointers()) .function("isValidExpensiveMaterialInstance", EMBIND_LAMBDA(bool, (Engine* engine, MaterialInstance* object), { return engine->isValidExpensive(object); }), allow_raw_pointers()) .function("isValidSkybox", EMBIND_LAMBDA(bool, (Engine* engine, Skybox* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidColorGrading", EMBIND_LAMBDA(bool, (Engine* engine, ColorGrading* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidTexture", EMBIND_LAMBDA(bool, (Engine* engine, Texture* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidRenderTarget", EMBIND_LAMBDA(bool, (Engine* engine, RenderTarget* object), { return engine->isValid(object); }), allow_raw_pointers()) .function("isValidSwapChain", EMBIND_LAMBDA(bool, (Engine* engine, SwapChain* object), { return engine->isValid(object); }), allow_raw_pointers()); /// SwapChain ::core class:: Represents the platform's native rendering surface. /// See also the [Engine] methods `createSwapChain` and `destroySwapChain`. class_("SwapChain") .class_function("isSRGBSwapChainSupported", &SwapChain::isSRGBSwapChainSupported); /// Renderer ::core class:: Represents the platform's native window. /// See also the [Engine] methods `createRenderer` and `destroyRenderer`. class_("Renderer") .function("renderView", &Renderer::render, allow_raw_pointers()) .function("renderStandaloneView", &Renderer::renderStandaloneView, allow_raw_pointers()) /// render ::method:: requests rendering for a single frame on the given [View] /// swapChain ::argument:: the [SwapChain] corresponding to the canvas /// view ::argument:: the [View] corresponding to the canvas .function("render", EMBIND_LAMBDA(void, (Renderer* self, SwapChain* swapChain, View* view), { auto engine = self->getEngine(); if (self->beginFrame(swapChain)) { self->render(view); self->endFrame(); } engine->execute(); }), allow_raw_pointers()) .function("getUserTime", &Renderer::getUserTime) .function("resetUserTime", &Renderer::resetUserTime) .function("skipNextFrames", &Renderer::skipNextFrames) .function("getFrameToSkipCount", &Renderer::getFrameToSkipCount) .function("_setClearOptions", &Renderer::setClearOptions, allow_raw_pointers()) .function("getClearOptions", &Renderer::getClearOptions) .function("setPresentationTime", &Renderer::setPresentationTime) .function("setVsyncTime", &Renderer::setVsyncTime) .function("skipFrame", &Renderer::skipFrame) .function("shouldRenderFrame", &Renderer::shouldRenderFrame) .function("beginFrame", EMBIND_LAMBDA(bool, (Renderer* self, SwapChain* swapChain), { return self->beginFrame(swapChain); }), allow_raw_pointers()) .function("endFrame", &Renderer::endFrame, allow_raw_pointers()); /// View ::core class:: Encompasses all the state needed for rendering a Scene. /// A view is associated with a particular [Scene], [Camera], and viewport. /// See also the [Engine] methods `createView` and `destroyView`. class_("View") .function("pick", EMBIND_LAMBDA(void, (View* self, uint32_t x, uint32_t y, val cb), { self->pick(x, y, [cb](const View::PickingQueryResult& result) { EM_ASM_ARGS({ const fn = Emval.toValue($0); fn({ "renderable": Emval.toValue($1), "depth": $2, "fragCoords": [$3, $4, $5], }); }, cb.as_handle(), val(result.renderable).as_handle(), result.depth, result.fragCoords.x, result.fragCoords.y, result.fragCoords.z); }); }), allow_raw_pointers()) .function("setScene", &View::setScene, allow_raw_pointers()) .function("setCamera", &View::setCamera, allow_raw_pointers()) .function("hasCamera", &View::hasCamera) .function("setColorGrading", &View::setColorGrading, allow_raw_pointers()) .function("setChannelDepthClearEnabled", &View::setChannelDepthClearEnabled) .function("isChannelDepthClearEnabled", &View::isChannelDepthClearEnabled) .function("setBlendMode", &View::setBlendMode) .function("getBlendMode", &View::getBlendMode) .function("setViewport", &View::setViewport) .function("getViewport", &View::getViewport) .function("setVisibleLayers", &View::setVisibleLayers) .function("setPostProcessingEnabled", &View::setPostProcessingEnabled) .function("setDithering", &View::setDithering) .function("_setAmbientOcclusionOptions", &View::setAmbientOcclusionOptions) .function("_setDepthOfFieldOptions", &View::setDepthOfFieldOptions) .function("_setMultiSampleAntiAliasingOptions", &View::setMultiSampleAntiAliasingOptions) .function("_setTemporalAntiAliasingOptions", &View::setTemporalAntiAliasingOptions) .function("_setScreenSpaceReflectionsOptions", &View::setScreenSpaceReflectionsOptions) .function("_setBloomOptions", &View::setBloomOptions) .function("_setFogOptions", &View::setFogOptions) .function("_setVignetteOptions", &View::setVignetteOptions) .function("_setGuardBandOptions", &View::setGuardBandOptions) .function("_setStereoscopicOptions", &View::setStereoscopicOptions) .function("setAmbientOcclusion", &View::setAmbientOcclusion) .function("getAmbientOcclusion", &View::getAmbientOcclusion) .function("setAntiAliasing", &View::setAntiAliasing) .function("getAntiAliasing", &View::getAntiAliasing) .function("setSampleCount", &View::setSampleCount) .function("getSampleCount", &View::getSampleCount) .function("setRenderTarget", EMBIND_LAMBDA(void, (View* self, RenderTarget* renderTarget), { self->setRenderTarget(renderTarget); }), allow_raw_pointers()) .function("setTransparentPickingEnabled", &View::setTransparentPickingEnabled) .function("isTransparentPickingEnabled", &View::isTransparentPickingEnabled) .function("setStencilBufferEnabled", &View::setStencilBufferEnabled) .function("isStencilBufferEnabled", &View::isStencilBufferEnabled) .function("setMaterialGlobal", &View::setMaterialGlobal) .function("getMaterialGlobal", &View::getMaterialGlobal) .function("getLastDynamicResolutionScale", &View::getLastDynamicResolutionScale) .function("getFogEntity", &View::getFogEntity) .function("clearFrameHistory", &View::clearFrameHistory); /// Scene ::core class:: Flat container of renderables and lights. /// See also the [Engine] methods `createScene` and `destroyScene`. class_("Scene") .function("addEntity", &Scene::addEntity) .function("_addEntities", EMBIND_LAMBDA(void, (Scene* self, EntityVector entities), { self->addEntities(entities.data(), entities.size()); }), allow_raw_pointers()) .function("_removeEntities", EMBIND_LAMBDA(void, (Scene* self, EntityVector entities), { self->removeEntities(entities.data(), entities.size()); }), allow_raw_pointers()) .function("hasEntity", &Scene::hasEntity) .function("remove", &Scene::remove) .function("setSkybox", &Scene::setSkybox, allow_raw_pointers()) .function("getSkybox", &Scene::getSkybox, allow_raw_pointers()) .function("setIndirectLight", &Scene::setIndirectLight, allow_raw_pointers()) .function("getIndirectLight", &Scene::getIndirectLight, allow_raw_pointers()) .function("getEntityCount", &Scene::getEntityCount) .function("getRenderableCount", &Scene::getRenderableCount) .function("getLightCount", &Scene::getLightCount); /// Frustum ::core class:: Represents the six planes of a truncated viewing pyramid class_("Frustum") .constructor(EMBIND_LAMBDA(Frustum*, (flatmat4 m), { return new Frustum(m.m); }), allow_raw_pointers()) .function("setProjection", EMBIND_LAMBDA(void, (Frustum* self, flatmat4 m), { self->setProjection(m.m); }), allow_raw_pointers()) .function("getNormalizedPlane", &Frustum::getNormalizedPlane) .function("intersectsBox", EMBIND_LAMBDA(bool, (Frustum* self, const Box& box), { return self->intersects(box); }), allow_raw_pointers()) .function("intersectsSphere", EMBIND_LAMBDA(bool, (Frustum* self, const filament::math::float4& sphere), { return self->intersects(sphere); }), allow_raw_pointers()); /// Camera ::core class:: Represents the eye through which the scene is viewed. /// See also the [Engine] methods `createCamera` and `destroyCamera`. class_("Camera") .function("setProjection", EMBIND_LAMBDA(void, (Camera* self, Camera::Projection projection, double left, double right, double bottom, double top, double near, double far), { self->setProjection(projection, left, right, bottom, top, near, far); }), allow_raw_pointers()) .function("setProjectionFov", EMBIND_LAMBDA(void, (Camera* self, double fovInDegrees, double aspect, double near, double far, Camera::Fov direction), { self->setProjection(fovInDegrees, aspect, near, far, direction); }), allow_raw_pointers()) .function("setLensProjection", &Camera::setLensProjection) .function("setCustomProjection", EMBIND_LAMBDA(void, (Camera* self, flatmat4 m, double near, double far), { self->setCustomProjection(filament::math::mat4(m.m), near, far); }), allow_raw_pointers()) .function("setScaling", EMBIND_LAMBDA(void, (Camera* self, math::double2 scaling), { self->setScaling(scaling); }), allow_raw_pointers()) .function("getProjectionMatrix", EMBIND_LAMBDA(flatmat4, (Camera* self), { return flatmat4 { filament::math::mat4f(self->getProjectionMatrix()) }; }), allow_raw_pointers()) .function("getCullingProjectionMatrix", EMBIND_LAMBDA(flatmat4, (Camera* self), { return flatmat4 { filament::math::mat4f(self->getCullingProjectionMatrix()) }; }), allow_raw_pointers()) .function("getScaling", &Camera::getScaling) .function("getNear", &Camera::getNear) .function("getCullingFar", &Camera::getCullingFar) .function("setModelMatrix", EMBIND_LAMBDA(void, (Camera* self, flatmat4 m), { self->setModelMatrix(m.m); }), allow_raw_pointers()) .function("lookAt", EMBIND_LAMBDA(void, (Camera* self, const math::float3& eye, const math::float3& center, const math::float3& up), { self->lookAt(eye, center, up); }), allow_raw_pointers()) .function("getModelMatrix", EMBIND_LAMBDA(flatmat4, (Camera* self), { return flatmat4 { (filament::math::mat4f)self->getModelMatrix() }; }), allow_raw_pointers()) .function("getViewMatrix", EMBIND_LAMBDA(flatmat4, (Camera* self), { return flatmat4 { (filament::math::mat4f)self->getViewMatrix() }; }), allow_raw_pointers()) .function("getPosition", &Camera::getPosition) .function("getLeftVector", &Camera::getLeftVector) .function("getUpVector", &Camera::getUpVector) .function("getForwardVector", &Camera::getForwardVector) .function("getFrustum", &Camera::getFrustum) .function("setExposure", (void(Camera::*)(float, float, float)) &Camera::setExposure) .function("setExposureDirect", (void(Camera::*)(float)) &Camera::setExposure) .function("getAperture", &Camera::getAperture) .function("getShutterSpeed", &Camera::getShutterSpeed) .function("getSensitivity", &Camera::getSensitivity) .function("setFocusDistance", &Camera::setFocusDistance) .function("getFocusDistance", &Camera::getFocusDistance) .function("getFocalLength", &Camera::getFocalLength) .class_function("computeEffectiveFocalLength", &Camera::computeEffectiveFocalLength) .class_function("computeEffectiveFov", &Camera::computeEffectiveFov) .class_function("inverseProjection", (flatmat4 (*)(flatmat4)) [] (flatmat4 m) { return flatmat4 { filament::math::mat4f(Camera::inverseProjection(m.m)) }; }, allow_raw_pointers()); class_("ColorGrading") .class_function("Builder", (ColorBuilder (*)()) [] { return ColorBuilder(); }); class_("ColorGrading$Builder") .function("_build", EMBIND_LAMBDA(ColorGrading*, (ColorBuilder* builder, Engine* engine), { return builder->build(*engine); }), allow_raw_pointers()) .BUILDER_FUNCTION("quality", ColorBuilder, (ColorBuilder* builder, ColorGrading::QualityLevel ql), { return &builder->quality(ql); }) .BUILDER_FUNCTION("format", ColorBuilder, (ColorBuilder* builder, ColorGrading::LutFormat format), { return &builder->format(format); }) .BUILDER_FUNCTION("dimensions", ColorBuilder, (ColorBuilder* builder, uint8_t dim), { return &builder->dimensions(dim); }) .BUILDER_FUNCTION("toneMapping", ColorBuilder, (ColorBuilder* builder, ColorGrading::ToneMapping tm), { return &builder->toneMapping(tm); }) .BUILDER_FUNCTION("luminanceScaling", ColorBuilder, (ColorBuilder* builder, bool luminanceScaling), { return &builder->luminanceScaling(luminanceScaling); }) .BUILDER_FUNCTION("gamutMapping", ColorBuilder, (ColorBuilder* builder, bool gamutMapping), { return &builder->gamutMapping(gamutMapping); }) .BUILDER_FUNCTION("exposure", ColorBuilder, (ColorBuilder* builder, float exposure), { return &builder->exposure(exposure); }) .BUILDER_FUNCTION("nightAdaptation", ColorBuilder, (ColorBuilder* builder, float adaptation), { return &builder->nightAdaptation(adaptation); }) .BUILDER_FUNCTION("whiteBalance", ColorBuilder, (ColorBuilder* builder, float temp, float tint), { return &builder->whiteBalance(temp, tint); }) .BUILDER_FUNCTION("channelMixer", ColorBuilder, (ColorBuilder* builder, filament::math::float3 red, filament::math::float3 green, filament::math::float3 blue), { return &builder->channelMixer(red, green, blue); }) .BUILDER_FUNCTION("shadowsMidtonesHighlights", ColorBuilder, (ColorBuilder* builder, filament::math::float4 shadows, filament::math::float4 midtones, filament::math::float4 highlights, filament::math::float4 ranges), { return &builder->shadowsMidtonesHighlights(shadows, midtones, highlights, ranges); }) .BUILDER_FUNCTION("slopeOffsetPower", ColorBuilder, (ColorBuilder* builder, math::float3 slope, math::float3 offset, math::float3 power), { return &builder->slopeOffsetPower(slope, offset, power); }) .BUILDER_FUNCTION("contrast", ColorBuilder, (ColorBuilder* builder, float contrast), { return &builder->contrast(contrast); }) .BUILDER_FUNCTION("vibrance", ColorBuilder, (ColorBuilder* builder, float vibrance), { return &builder->vibrance(vibrance); }) .BUILDER_FUNCTION("saturation", ColorBuilder, (ColorBuilder* builder, float saturation), { return &builder->saturation(saturation); }) .BUILDER_FUNCTION("curves", ColorBuilder, (ColorBuilder* builder, math::float3 shadowGamma, math::float3 midPoint, math::float3 highlightScale), { return &builder->curves(shadowGamma, midPoint, highlightScale); }); class_("RenderTarget$Builder") .BUILDER_FUNCTION("texture", RenderTargetBuilder, (RenderTargetBuilder* builder, RenderTarget::AttachmentPoint attachment, Texture* tex), { return &builder->texture(attachment, tex); }) .BUILDER_FUNCTION("mipLevel", RenderTargetBuilder, (RenderTargetBuilder* builder, RenderTarget::AttachmentPoint attachment, uint8_t level), { return &builder->mipLevel(attachment, level); }) .BUILDER_FUNCTION("face", RenderTargetBuilder, (RenderTargetBuilder* builder, RenderTarget::AttachmentPoint attachment, Texture::CubemapFace face), { return &builder->face(attachment, face); }) .BUILDER_FUNCTION("layer", RenderTargetBuilder, (RenderTargetBuilder* builder, RenderTarget::AttachmentPoint attachment, uint32_t layer), { return &builder->layer(attachment, layer); }) .function("_build", EMBIND_LAMBDA(RenderTarget*, (RenderTargetBuilder* builder, Engine* engine), { return builder->build(*engine); }), allow_raw_pointers()); class_("RenderTarget") .class_function("Builder", (RenderTargetBuilder (*)()) [] () { return RenderTarget::Builder(); }) .function("getMipLevel", &RenderTarget::getMipLevel) .function("getFace", &RenderTarget::getFace) .function("getLayer", &RenderTarget::getLayer); class_("RenderableManager$Builder") .BUILDER_FUNCTION("geometry", RenderableBuilder, (RenderableBuilder* builder, size_t index, RenderableManager::PrimitiveType type, VertexBuffer* vertices, IndexBuffer* indices), { return &builder->geometry(index, type, vertices, indices); }) .BUILDER_FUNCTION("geometryOffset", RenderableBuilder, (RenderableBuilder* builder, size_t index, RenderableManager::PrimitiveType type, VertexBuffer* vertices, IndexBuffer* indices, size_t offset, size_t count), { return &builder->geometry(index, type, vertices, indices, offset, count); }) .BUILDER_FUNCTION("geometryMinMax", RenderableBuilder, (RenderableBuilder* builder, size_t index, RenderableManager::PrimitiveType type, VertexBuffer* vertices, IndexBuffer* indices, size_t offset, size_t minIndex, size_t maxIndex, size_t count), { return &builder->geometry(index, type, vertices, indices, offset, minIndex, maxIndex, count); }) .BUILDER_FUNCTION("geometryType", RenderableBuilder, (RenderableBuilder* builder, RenderableManager::Builder::GeometryType type), { return &builder->geometryType(type); }) .BUILDER_FUNCTION("material", RenderableBuilder, (RenderableBuilder* builder, size_t index, MaterialInstance* mi), { return &builder->material(index, mi); }) .BUILDER_FUNCTION("boundingBox", RenderableBuilder, (RenderableBuilder* builder, Box box), { return &builder->boundingBox(box); }) .BUILDER_FUNCTION("layerMask", RenderableBuilder, (RenderableBuilder* builder, uint8_t select, uint8_t values), { return &builder->layerMask(select, values); }) .BUILDER_FUNCTION("priority", RenderableBuilder, (RenderableBuilder* builder, uint8_t value), { return &builder->priority(value); }) .BUILDER_FUNCTION("channel", RenderableBuilder, (RenderableBuilder* builder, uint8_t value), { return &builder->channel(value); }) .BUILDER_FUNCTION("culling", RenderableBuilder, (RenderableBuilder* builder, bool enable), { return &builder->culling(enable); }) .BUILDER_FUNCTION("lightChannel", RenderableBuilder, (RenderableBuilder* builder, unsigned int channel, bool enable), { return &builder->lightChannel(channel, enable); }) .BUILDER_FUNCTION("castShadows", RenderableBuilder, (RenderableBuilder* builder, bool enable), { return &builder->castShadows(enable); }) .BUILDER_FUNCTION("receiveShadows", RenderableBuilder, (RenderableBuilder* builder, bool enable), { return &builder->receiveShadows(enable); }) .BUILDER_FUNCTION("screenSpaceContactShadows", RenderableBuilder, (RenderableBuilder* builder, bool enable), { return &builder->screenSpaceContactShadows(enable); }) .BUILDER_FUNCTION("fog", RenderableBuilder, (RenderableBuilder* builder, bool enable), { return &builder->fog(enable); }) .BUILDER_FUNCTION("skinning", RenderableBuilder, (RenderableBuilder* builder, size_t boneCount), { return &builder->skinning(boneCount); }) .BUILDER_FUNCTION("skinningBones", RenderableBuilder, (RenderableBuilder* builder, emscripten::val transforms), { auto nbones = transforms["length"].as(); std::vector bones(nbones); for (size_t i = 0; i < nbones; i++) { bones[i] = transforms[i].as(); } return &builder->skinning(bones.size(), bones.data()); }) .BUILDER_FUNCTION("skinningMatrices", RenderableBuilder, (RenderableBuilder* builder, emscripten::val transforms), { auto nbones = transforms["length"].as(); std::vector matrices(nbones); for (size_t i = 0; i < nbones; i++) { matrices[i] = transforms[i].as().m; } return &builder->skinning(matrices.size(), matrices.data()); }) .BUILDER_FUNCTION("morphing", RenderableBuilder, (RenderableBuilder* builder, bool enable), { return &builder->morphing(enable); }) .BUILDER_FUNCTION("blendOrder", RenderableBuilder, (RenderableBuilder* builder, size_t index, uint16_t order), { return &builder->blendOrder(index, order); }) .BUILDER_FUNCTION("globalBlendOrderEnabled", RenderableBuilder, (RenderableBuilder* builder, size_t index, bool enabled), { return &builder->globalBlendOrderEnabled(index, enabled); }) .BUILDER_FUNCTION("instances", RenderableBuilder, (RenderableBuilder* builder, size_t instanceCount), { return &builder->instances(instanceCount); }) .function("_build", EMBIND_LAMBDA(int, (RenderableBuilder* builder, Engine* engine, utils::Entity entity), { return (int) builder->build(*engine, entity); }), allow_raw_pointers()); /// RenderableManager ::core class:: Allows access to properties of drawable objects. class_("RenderableManager") .function("hasComponent", &RenderableManager::hasComponent) /// getInstance ::method:: Gets an instance of the renderable component for an entity. /// entity ::argument:: an [Entity] /// ::retval:: a renderable component .function("getInstance", &RenderableManager::getInstance) .class_function("Builder", (RenderableBuilder (*)(int)) [] (int n) { return RenderableBuilder(n); }, return_value_policy::take_ownership()) .function("destroy", &RenderableManager::destroy) .function("setAxisAlignedBoundingBox", &RenderableManager::setAxisAlignedBoundingBox) .function("setLayerMask", &RenderableManager::setLayerMask) .function("setPriority", &RenderableManager::setPriority) .function("setChannel", &RenderableManager::setChannel) .function("setCastShadows", &RenderableManager::setCastShadows) .function("setReceiveShadows", &RenderableManager::setReceiveShadows) .function("isShadowCaster", &RenderableManager::isShadowCaster) .function("isShadowReceiver", &RenderableManager::isShadowReceiver) .function("setLightChannel", &RenderableManager::setLightChannel) .function("getLightChannel", &RenderableManager::getLightChannel) .function("setFogEnabled", &RenderableManager::setFogEnabled) .function("getFogEnabled", &RenderableManager::getFogEnabled) .function("setBones", EMBIND_LAMBDA(void, (RenderableManager* self, RenderableManager::Instance instance, emscripten::val transforms, size_t offset), { auto nbones = transforms["length"].as(); std::vector bones(nbones); for (size_t i = 0; i < nbones; i++) { bones[i] = transforms[i].as(); } self->setBones(instance, bones.data(), bones.size(), offset); }), allow_raw_pointers()) .function("setBonesFromMatrices", EMBIND_LAMBDA(void, (RenderableManager* self, RenderableManager::Instance instance, emscripten::val transforms, size_t offset), { auto nbones = transforms["length"].as(); std::vector bones(nbones); for (size_t i = 0; i < nbones; i++) { bones[i] = transforms[i].as().m; } self->setBones(instance, bones.data(), bones.size(), offset); }), allow_raw_pointers()) .function("setMorphWeights", EMBIND_LAMBDA(void, (RenderableManager* self, RenderableManager::Instance instance, emscripten::val weights), { auto nfloats = weights["length"].as(); std::vector floats(nfloats); for (size_t i = 0; i < nfloats; i++) { floats[i] = weights[i].as(); } self->setMorphWeights(instance, floats.data(), nfloats); }), allow_raw_pointers()) .function("getAxisAlignedBoundingBox", &RenderableManager::getAxisAlignedBoundingBox) .function("getPrimitiveCount", &RenderableManager::getPrimitiveCount) .function("getInstanceCount", &RenderableManager::getInstanceCount) .function("setMaterialInstanceAt", &RenderableManager::setMaterialInstanceAt, allow_raw_pointers()) .function("clearMaterialInstanceAt", &RenderableManager::clearMaterialInstanceAt) .function("getMaterialInstanceAt", &RenderableManager::getMaterialInstanceAt, allow_raw_pointers()) .function("setGeometryAt", EMBIND_LAMBDA(void, (RenderableManager* self, RenderableManager::Instance instance, size_t primitiveIndex, RenderableManager::PrimitiveType type, VertexBuffer* vertices, IndexBuffer* indices, size_t offset, size_t count), { self->setGeometryAt(instance, primitiveIndex, type, vertices, indices, offset, count); }), allow_raw_pointers()) .function("setBlendOrderAt", &RenderableManager::setBlendOrderAt) .function("setGlobalBlendOrderEnabledAt", &RenderableManager::setGlobalBlendOrderEnabledAt) .function("getEnabledAttributesAt", EMBIND_LAMBDA(uint32_t, (RenderableManager* self, RenderableManager::Instance instance, size_t primitiveIndex), { return self->getEnabledAttributesAt(instance, primitiveIndex).getValue(); }), allow_raw_pointers()); /// RenderableManager$Instance ::class:: Component instance returned by [RenderableManager] /// Be sure to call the instance's `delete` method when you're done with it. class_("RenderableManager$Instance"); /// delete ::method:: Frees an instance obtained via `getInstance` /// TransformManager ::core class:: Adds transform components to entities. class_("TransformManager") .function("hasComponent", &TransformManager::hasComponent) /// getInstance ::method:: Gets an instance representing the transform component for an entity. /// entity ::argument:: an [Entity] /// ::retval:: a transform component that can be passed to `setTransform`. .function("getInstance", &TransformManager::getInstance) .function("create", EMBIND_LAMBDA(void, (TransformManager* self, utils::Entity entity), { self->create(entity); }), allow_raw_pointers()) .function("destroy", &TransformManager::destroy) .function("setParent", &TransformManager::setParent) .function("getParent", &TransformManager::getParent) .function("getChildren", EMBIND_LAMBDA(EntityVector, (TransformManager* self, TransformManager::Instance instance), { EntityVector result(self->getChildCount(instance)); self->getChildren(instance, result.data(), result.size()); return result; }), allow_raw_pointers()) /// setTransform ::method:: Sets the mat4 value of a transform component. /// instance ::argument:: The transform instance of entity, obtained via `getInstance`. /// matrix ::argument:: Array of 16 numbers (mat4) .function("setTransform", EMBIND_LAMBDA(void, (TransformManager* self, TransformManager::Instance instance, flatmat4 m), { self->setTransform(instance, m.m); }), allow_raw_pointers()) .function("getTransform", EMBIND_LAMBDA(flatmat4, (TransformManager* self, TransformManager::Instance instance), { return flatmat4 { self->getTransform(instance) } ; }), allow_raw_pointers()) .function("getWorldTransform", EMBIND_LAMBDA(flatmat4, (TransformManager* self, TransformManager::Instance instance), { return flatmat4 { self->getWorldTransform(instance) } ; }), allow_raw_pointers()) .function("openLocalTransformTransaction", &TransformManager::openLocalTransformTransaction) .function("commitLocalTransformTransaction", &TransformManager::commitLocalTransformTransaction); /// TransformManager$Instance ::class:: Component instance returned by [TransformManager] /// Be sure to call the instance's `delete` method when you're done with it. class_("TransformManager$Instance"); /// delete ::method:: Frees an instance obtained via `getInstance` class_("LightManager$Builder") .function("_build", EMBIND_LAMBDA(int, (LightBuilder* builder, Engine* engine, utils::Entity entity), { return (int) builder->build(*engine, entity); }), allow_raw_pointers()) .BUILDER_FUNCTION("castShadows", LightBuilder, (LightBuilder* builder, bool enable), { return &builder->castShadows(enable); }) .BUILDER_FUNCTION("_shadowOptions", LightBuilder, (LightBuilder* builder, LightManager::ShadowOptions options), { return &builder->shadowOptions(options); }) .BUILDER_FUNCTION("castLight", LightBuilder, (LightBuilder* builder, bool enable), { return &builder->castLight(enable); }) .BUILDER_FUNCTION("position", LightBuilder, (LightBuilder* builder, filament::math::float3 value), { return &builder->position(value); }) .BUILDER_FUNCTION("direction", LightBuilder, (LightBuilder* builder, filament::math::float3 value), { return &builder->direction(value); }) .BUILDER_FUNCTION("color", LightBuilder, (LightBuilder* builder, filament::math::float3 value), { return &builder->color(value); }) .BUILDER_FUNCTION("intensity", LightBuilder, (LightBuilder* builder, float value), { return &builder->intensity(value); }) .BUILDER_FUNCTION("falloff", LightBuilder, (LightBuilder* builder, float value), { return &builder->falloff(value); }) .BUILDER_FUNCTION("spotLightCone", LightBuilder, (LightBuilder* builder, float inner, float outer), { return &builder->spotLightCone(inner, outer); }) .BUILDER_FUNCTION("sunAngularRadius", LightBuilder, (LightBuilder* builder, float value), { return &builder->sunAngularRadius(value); }) .BUILDER_FUNCTION("sunHaloSize", LightBuilder, (LightBuilder* builder, float value), { return &builder->sunHaloSize(value); }) .BUILDER_FUNCTION("sunHaloFalloff", LightBuilder, (LightBuilder* builder, float value), { return &builder->sunHaloFalloff(value); }) .BUILDER_FUNCTION("lightChannel", LightBuilder, (LightBuilder* builder, unsigned int channel, bool enable), { return &builder->lightChannel(channel, enable); }); class_("LightManager") .function("hasComponent", &LightManager::hasComponent) /// getInstance ::method:: Gets an instance of the light component for an entity. /// entity ::argument:: an [Entity] /// ::retval:: a light source component .function("getInstance", &LightManager::getInstance) .class_function("Builder", (LightBuilder (*)(LightManager::Type)) [] (LightManager::Type lt) { return LightBuilder(lt); }) .function("getType", &LightManager::getType) .function("isDirectional", &LightManager::isDirectional) .function("isPointLight", &LightManager::isPointLight) .function("isSpotLight", &LightManager::isSpotLight) .function("setPosition", &LightManager::setPosition) .function("getPosition", &LightManager::getPosition) .function("setDirection", &LightManager::setDirection) .function("getDirection", &LightManager::getDirection) .function("setColor", &LightManager::setColor) .function("getColor", &LightManager::getColor) .function("setIntensity", EMBIND_LAMBDA(void, (LightManager* self, LightManager::Instance instance, float intensity), { self->setIntensity(instance, intensity); }), allow_raw_pointers()) .function("setIntensityEnergy", EMBIND_LAMBDA(void, (LightManager* self, LightManager::Instance instance, float watts, float efficiency), { self->setIntensity(instance, watts, efficiency); }), allow_raw_pointers()) .function("getIntensity", &LightManager::getIntensity) .function("setFalloff", &LightManager::setFalloff) .function("getFalloff", &LightManager::getFalloff) .function("_setShadowOptions", &LightManager::setShadowOptions) .function("setSpotLightCone", &LightManager::setSpotLightCone) .function("setSunAngularRadius", &LightManager::setSunAngularRadius) .function("getSunAngularRadius", &LightManager::getSunAngularRadius) .function("setSunHaloSize", &LightManager::setSunHaloSize) .function("getSunHaloSize", &LightManager::getSunHaloSize) .function("setSunHaloFalloff", &LightManager::setSunHaloFalloff) .function("getSunHaloFalloff", &LightManager::getSunHaloFalloff) .function("setShadowCaster", &LightManager::setShadowCaster) .function("isShadowCaster", &LightManager::isShadowCaster) .function("setLightChannel", &LightManager::setLightChannel) .function("getLightChannel", &LightManager::getLightChannel) ; /// LightManager$Instance ::class:: Component instance returned by [LightManager] /// Be sure to call the instance's `delete` method when you're done with it. class_("LightManager$Instance"); /// delete ::method:: Frees an instance obtained via `getInstance` class_("BufferObject$Builder") .function("_build", EMBIND_LAMBDA(BufferObject*, (BufferBuilder* builder, Engine* engine), { return builder->build(*engine); }), allow_raw_pointers()) .BUILDER_FUNCTION("bindingType", BufferBuilder, (BufferBuilder* builder, BufferObject::BindingType bt), { return &builder->bindingType(bt); }) .BUILDER_FUNCTION("size", BufferBuilder, (BufferBuilder* builder, int byteCount), { return &builder->size(byteCount); }); /// BufferObject ::core class:: Represents a single GPU buffer. class_("BufferObject") .class_function("Builder", (BufferBuilder (*)()) [] { return BufferBuilder(); }) .function("getByteCount", &BufferObject::getByteCount) .function("_setBuffer", EMBIND_LAMBDA(void, (BufferObject* self, Engine* engine, BufferDescriptor bd, uint32_t byteOffset), { self->setBuffer(*engine, std::move(*bd.bd), byteOffset); }), allow_raw_pointers()); class_("VertexBuffer$Builder") .function("_build", EMBIND_LAMBDA(VertexBuffer*, (VertexBuilder* builder, Engine* engine), { return builder->build(*engine); }), allow_raw_pointers()) .BUILDER_FUNCTION("attribute", VertexBuilder, (VertexBuilder* builder, VertexAttribute attr, uint8_t bufferIndex, VertexBuffer::AttributeType attrType, uint32_t byteOffset, uint8_t byteStride), { return &builder->attribute(attr, bufferIndex, attrType, byteOffset, byteStride); }) .BUILDER_FUNCTION("vertexCount", VertexBuilder, (VertexBuilder* builder, int count), { return &builder->vertexCount(count); }) .BUILDER_FUNCTION("enableBufferObjects", VertexBuilder, (VertexBuilder* builder, bool enable), { return &builder->enableBufferObjects(enable); }) .BUILDER_FUNCTION("normalized", VertexBuilder, (VertexBuilder* builder, VertexAttribute attrib), { return &builder->normalized(attrib); }) .BUILDER_FUNCTION("normalizedIf", VertexBuilder, (VertexBuilder* builder, VertexAttribute attrib, bool normalized), { return &builder->normalized(attrib, normalized); }) .BUILDER_FUNCTION("bufferCount", VertexBuilder, (VertexBuilder* builder, int count), { return &builder->bufferCount(count); }); /// VertexBuffer ::core class:: Bundle of buffers and associated vertex attributes. class_("VertexBuffer") .class_function("Builder", (VertexBuilder (*)()) [] { return VertexBuilder(); }) .function("setBufferObjectAt", &VertexBuffer::setBufferObjectAt, allow_raw_pointers()) .function("_setBufferAt", EMBIND_LAMBDA(void, (VertexBuffer* self, Engine* engine, uint8_t bufferIndex, BufferDescriptor vbd, uint32_t byteOffset), { self->setBufferAt(*engine, bufferIndex, std::move(*vbd.bd), byteOffset); }), allow_raw_pointers()); class_("IndexBuffer$Builder") .function("_build", EMBIND_LAMBDA(IndexBuffer*, (IndexBuilder* builder, Engine* engine), { return builder->build(*engine); }), allow_raw_pointers()) .BUILDER_FUNCTION("indexCount", IndexBuilder, (IndexBuilder* builder, int count), { return &builder->indexCount(count); }) .BUILDER_FUNCTION("bufferType", IndexBuilder, (IndexBuilder* builder, IndexBuffer::IndexType indexType), { return &builder->bufferType(indexType); }); /// IndexBuffer ::core class:: Array of 16-bit or 32-bit unsigned integers consumed by the GPU. class_("IndexBuffer") .class_function("Builder", (IndexBuilder (*)()) [] { return IndexBuilder(); }) .function("_setBuffer", EMBIND_LAMBDA(void, (IndexBuffer* self, Engine* engine, BufferDescriptor ibd, uint32_t byteOffset), { self->setBuffer(*engine, std::move(*ibd.bd), byteOffset); }), allow_raw_pointers()); class_("Material") .function("getDefaultInstance", select_overload(&Material::getDefaultInstance), allow_raw_pointers()) .function("createInstance", EMBIND_LAMBDA(MaterialInstance*, (Material* self), { return self->createInstance(); }), allow_raw_pointers()) .function("createNamedInstance", EMBIND_LAMBDA(MaterialInstance*, (Material* self, std::string name), { return self->createInstance(name.c_str()); }), allow_raw_pointers()) .function("getName", EMBIND_LAMBDA(std::string, (Material* self), { return std::string(self->getName()); }), allow_raw_pointers()) .function("getParameterTransformName", EMBIND_LAMBDA(std::string, (Material* self, std::string samplerName), { const char* transformName = self->getParameterTransformName(samplerName.c_str()); return transformName ? std::string(transformName) : std::string(); }), allow_raw_pointers()); class_("MaterialInstance") .function("getName", EMBIND_LAMBDA(std::string, (MaterialInstance* self), { return std::string(self->getName()); }), allow_raw_pointers()) .function("setBoolParameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, bool value), { self->setParameter(name.c_str(), value); }), allow_raw_pointers()) .function("setFloatParameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, float value), { self->setParameter(name.c_str(), value); }), allow_raw_pointers()) .function("setFloat2Parameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, filament::math::float2 value), { self->setParameter(name.c_str(), value); }), allow_raw_pointers()) .function("setFloat3Parameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, filament::math::float3 value), { self->setParameter(name.c_str(), value); }), allow_raw_pointers()) .function("setFloat4Parameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, filament::math::float4 value), { self->setParameter(name.c_str(), value); }), allow_raw_pointers()) .function("setMat3Parameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, flatmat3 value), { self->setParameter(name.c_str(), value.m); }), allow_raw_pointers()) .function("setMat4Parameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, flatmat4 value), { self->setParameter(name.c_str(), value.m); }), allow_raw_pointers()) .function("setTextureParameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, Texture* value, TextureSampler sampler), { self->setParameter(name.c_str(), value, sampler); }), allow_raw_pointers()) .function("setColor3Parameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, RgbType type, filament::math::float3 value), { self->setParameter(name.c_str(), type, value); }), allow_raw_pointers()) .function("setColor4Parameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, RgbaType type, filament::math::float4 value), { self->setParameter(name.c_str(), type, value); }), allow_raw_pointers()) .function("setPolygonOffset", &MaterialInstance::setPolygonOffset) .function("setMaskThreshold", &MaterialInstance::setMaskThreshold) .function("getMaskThreshold", &MaterialInstance::getMaskThreshold) .function("setSpecularAntiAliasingVariance", &MaterialInstance::setSpecularAntiAliasingVariance) .function("getSpecularAntiAliasingVariance", &MaterialInstance::getSpecularAntiAliasingVariance) .function("setSpecularAntiAliasingThreshold", &MaterialInstance::setSpecularAntiAliasingThreshold) .function("getSpecularAntiAliasingThreshold", &MaterialInstance::getSpecularAntiAliasingThreshold) .function("setDoubleSided", &MaterialInstance::setDoubleSided) .function("isDoubleSided", &MaterialInstance::isDoubleSided) .function("setTransparencyMode", &MaterialInstance::setTransparencyMode) .function("getTransparencyMode", &MaterialInstance::getTransparencyMode) .function("setCullingMode", EMBIND_LAMBDA(void, (MaterialInstance* self, MaterialInstance::CullingMode mode), { self->setCullingMode(mode); }), allow_raw_pointers()) .function("setCullingModeSeparate", EMBIND_LAMBDA(void, (MaterialInstance* self, MaterialInstance::CullingMode color, MaterialInstance::CullingMode shadows), { self->setCullingMode(color, shadows); }), allow_raw_pointers()) .function("getCullingMode", &MaterialInstance::getCullingMode) .function("getShadowCullingMode", &MaterialInstance::getShadowCullingMode) .function("setColorWrite", &MaterialInstance::setColorWrite) .function("isColorWriteEnabled", &MaterialInstance::isColorWriteEnabled) .function("setDepthWrite", &MaterialInstance::setDepthWrite) .function("isDepthWriteEnabled", &MaterialInstance::isDepthWriteEnabled) .function("setStencilWrite", &MaterialInstance::setStencilWrite) .function("setDepthCulling", &MaterialInstance::setDepthCulling) .function("isDepthCullingEnabled", &MaterialInstance::isDepthCullingEnabled) .function("setDepthFunc", &MaterialInstance::setDepthFunc) .function("getDepthFunc", &MaterialInstance::getDepthFunc) .function("setStencilCompareFunction", &MaterialInstance::setStencilCompareFunction) .function("setStencilCompareFunction", EMBIND_LAMBDA(void, (MaterialInstance* self, MaterialInstance::StencilCompareFunc func), { self->setStencilCompareFunction(func, backend::StencilFace::FRONT_AND_BACK); }), allow_raw_pointers()) .function("setStencilOpStencilFail", &MaterialInstance::setStencilOpStencilFail) .function("setStencilOpStencilFail", EMBIND_LAMBDA(void, (MaterialInstance* self, MaterialInstance::StencilOperation op), { self->setStencilOpStencilFail(op, backend::StencilFace::FRONT_AND_BACK); }), allow_raw_pointers()) .function("setStencilOpDepthFail", &MaterialInstance::setStencilOpDepthFail) .function("setStencilOpDepthFail", EMBIND_LAMBDA(void, (MaterialInstance* self, MaterialInstance::StencilOperation op), { self->setStencilOpDepthFail(op, backend::StencilFace::FRONT_AND_BACK); }), allow_raw_pointers()) .function("setStencilOpDepthStencilPass", &MaterialInstance::setStencilOpDepthStencilPass) .function("setStencilOpDepthStencilPass", EMBIND_LAMBDA(void, (MaterialInstance* self, MaterialInstance::StencilOperation op), { self->setStencilOpDepthStencilPass(op, backend::StencilFace::FRONT_AND_BACK); }), allow_raw_pointers()) .function("setStencilReferenceValue", &MaterialInstance::setStencilReferenceValue) .function("setStencilReferenceValue", EMBIND_LAMBDA(void, (MaterialInstance* self, uint8_t value), { self->setStencilReferenceValue(value, backend::StencilFace::FRONT_AND_BACK); }), allow_raw_pointers()) .function("setStencilReadMask", &MaterialInstance::setStencilReadMask) .function("setStencilReadMask", EMBIND_LAMBDA(void, (MaterialInstance* self, uint8_t readMask), { self->setStencilReadMask(readMask, backend::StencilFace::FRONT_AND_BACK); }), allow_raw_pointers()) .function("setStencilWriteMask", &MaterialInstance::setStencilWriteMask) .function("setStencilWriteMask", EMBIND_LAMBDA(void, (MaterialInstance* self, uint8_t writeMask), { self->setStencilWriteMask(writeMask, backend::StencilFace::FRONT_AND_BACK); }), allow_raw_pointers()); class_("TextureSampler") .constructor() .function("setAnisotropy", &TextureSampler::setAnisotropy) .function("setCompareMode", &TextureSampler::setCompareMode); /// Texture ::core class:: 2D image or cubemap that can be sampled by the GPU, possibly mipmapped. class_("Texture") .class_function("Builder", (TexBuilder (*)()) [] { return TexBuilder(); }) .class_function("isTextureFormatMipmappable", &Texture::isTextureFormatMipmappable) .class_function("validatePixelFormatAndType", &Texture::validatePixelFormatAndType) .function("generateMipmaps", &Texture::generateMipmaps) .function("_setImage", EMBIND_LAMBDA(void, (Texture* self, Engine* engine, uint8_t level, PixelBufferDescriptor pbd), { self->setImage(*engine, level, std::move(*pbd.pbd)); }), allow_raw_pointers()) .function("_setImageCube", EMBIND_LAMBDA(void, (Texture* self, Engine* engine, uint8_t level, PixelBufferDescriptor pbd), { uint32_t faceSize = pbd.pbd->size / 6; Texture::FaceOffsets offsets(faceSize); self->setImage(*engine, level, std::move(*pbd.pbd), offsets); }), allow_raw_pointers()) .function("_getWidth", EMBIND_LAMBDA(size_t, (Texture* self, Engine* engine, uint8_t level), { return self->getWidth(level); }), allow_raw_pointers()) .function("_getHeight", EMBIND_LAMBDA(size_t, (Texture* self, Engine* engine, uint8_t level), { return self->getHeight(level); }), allow_raw_pointers()) .function("_getDepth", EMBIND_LAMBDA(size_t, (Texture* self, Engine* engine, uint8_t level), { return self->getDepth(level); }), allow_raw_pointers()) .function("_getLevels", EMBIND_LAMBDA(size_t, (Texture* self, Engine* engine), { return self->getLevels(); }), allow_raw_pointers()); class_("Texture$Builder") .function("_build", EMBIND_LAMBDA(Texture*, (TexBuilder* builder, Engine* engine), { return builder->build(*engine); }), allow_raw_pointers()) .BUILDER_FUNCTION("width", TexBuilder, (TexBuilder* builder, uint32_t width), { return &builder->width(width); }) .BUILDER_FUNCTION("height", TexBuilder, (TexBuilder* builder, uint32_t height), { return &builder->height(height); }) .BUILDER_FUNCTION("depth", TexBuilder, (TexBuilder* builder, uint32_t depth), { return &builder->depth(depth); }) .BUILDER_FUNCTION("levels", TexBuilder, (TexBuilder* builder, uint8_t levels), { return &builder->levels(levels); }) .BUILDER_FUNCTION("sampler", TexBuilder, (TexBuilder* builder, Texture::Sampler target), { return &builder->sampler(target); }) .BUILDER_FUNCTION("format", TexBuilder, (TexBuilder* builder, Texture::InternalFormat fmt), { return &builder->format(fmt); }) .BUILDER_FUNCTION("external", TexBuilder, (TexBuilder* builder), { return &builder->external(); }) // This takes a bitfield that can be composed by or'ing constants. // - JS clients should use the value member, as in: "Texture$Usage.SAMPLEABLE.value". // - TypeScript clients can simply say "TextureUsage.SAMPLEABLE" (note the lack of $) .BUILDER_FUNCTION("usage", TexBuilder, (TexBuilder* builder, uint8_t usage), { return &builder->usage((Texture::Usage)usage); }); class_("IndirectLight") .class_function("Builder", (IblBuilder (*)()) [] { return IblBuilder(); }) .function("setIntensity", &IndirectLight::setIntensity) .function("getIntensity", &IndirectLight::getIntensity) .function("setRotation", EMBIND_LAMBDA(void, (IndirectLight* self, flatmat3 value), { return self->setRotation(value.m); }), allow_raw_pointers()) .function("getRotation", EMBIND_LAMBDA(flatmat3, (IndirectLight* self), { return flatmat3 { self->getRotation() }; }), allow_raw_pointers()) .function("getReflectionsTexture", EMBIND_LAMBDA(Texture*, (IndirectLight* self), { return (Texture*) self->getReflectionsTexture(); // cast away const to appease embind }), allow_raw_pointers()) .function("getIrradianceTexture", EMBIND_LAMBDA(Texture*, (IndirectLight* self), { return (Texture*) self->getIrradianceTexture(); // cast away const to appease embind }), allow_raw_pointers()) .class_function("getDirectionEstimate", EMBIND_LAMBDA(filament::math::float3, (val ta), { size_t nfloats = ta["length"].as(); std::vector floats(nfloats); for (size_t i = 0; i < nfloats; i++) { floats[i] = ta[i].as(); } return IndirectLight::getDirectionEstimate((filament::math::float3*) floats.data()); }), allow_raw_pointers()) .class_function("getColorEstimate", EMBIND_LAMBDA(filament::math::float4, (val ta, filament::math::float3 dir), { size_t nfloats = ta["length"].as(); std::vector floats(nfloats); for (size_t i = 0; i < nfloats; i++) { floats[i] = ta[i].as(); } return IndirectLight::getColorEstimate((filament::math::float3*) floats.data(), dir); }), allow_raw_pointers()); class_("IndirectLight$Builder") .function("_build", EMBIND_LAMBDA(IndirectLight*, (IblBuilder* builder, Engine* engine), { return builder->build(*engine); }), allow_raw_pointers()) .BUILDER_FUNCTION("reflections", IblBuilder, (IblBuilder* builder, Texture const* cubemap), { return &builder->reflections(cubemap); }) .BUILDER_FUNCTION("irradianceTex", IblBuilder, (IblBuilder* builder, Texture const* cubemap), { return &builder->irradiance(cubemap); }) .BUILDER_FUNCTION("irradianceSh", IblBuilder, (IblBuilder* builder, uint8_t nbands, val ta), { // This is not efficient but consuming a BufferDescriptor would be overkill. size_t nfloats = ta["length"].as(); if (nfloats != nbands * nbands * 3) { printf("Received %zu floats for spherical harmonics, expected %d.", nfloats, nbands); return builder; } std::vector floats(nfloats); for (size_t i = 0; i < nfloats; i++) { floats[i] = ta[i].as(); } return &builder->irradiance(nbands, (filament::math::float3 const*) floats.data()); }) .BUILDER_FUNCTION("intensity", IblBuilder, (IblBuilder* builder, float value), { return &builder->intensity(value); }) .BUILDER_FUNCTION("rotation", IblBuilder, (IblBuilder* builder, flatmat3 value), { return &builder->rotation(value.m); }); class_("Skybox") .class_function("Builder", (SkyBuilder (*)()) [] { return SkyBuilder(); }) .function("setColor", &Skybox::setColor) .function("getTexture", EMBIND_LAMBDA(Texture*, (Skybox* skybox), { return (Texture*) skybox->getTexture(); // cast away const to appease embind }), allow_raw_pointers()); class_("Skybox$Builder") .function("_build", EMBIND_LAMBDA(Skybox*, (SkyBuilder* builder, Engine* engine), { return builder->build(*engine); }), allow_raw_pointers()) .BUILDER_FUNCTION("color", SkyBuilder, (SkyBuilder* builder, filament::math::float4 color), { return &builder->color(color); }) .BUILDER_FUNCTION("environment", SkyBuilder, (SkyBuilder* builder, Texture* cubemap), { return &builder->environment(cubemap); }) .BUILDER_FUNCTION("showSun", SkyBuilder, (SkyBuilder* builder, bool show), { return &builder->showSun(show); }); // UTILS TYPES // ----------- /// Entity ::core class:: Handle to an object consisting of a set of components. /// To create an entity with no components, use [EntityManager]. /// TODO: It would be better to expose these as JS numbers rather than as JS objects. /// This would also be more consistent with Filament's Java bindings. class_("Entity") .function("getId", &utils::Entity::getId); /// delete ::method:: Frees an entity. /// EntityManager ::core class:: Singleton used for constructing entities in Filament's ECS. class_("EntityManager") /// get ::static method:: Gets the singleton entity manager instance. /// ::retval:: the one and only entity manager .class_function("get", (utils::EntityManager* (*)()) [] { return &utils::EntityManager::get(); }, allow_raw_pointers()) #if FILAMENT_UTILS_TRACK_ENTITIES .function("getActiveEntityCount", EMBIND_LAMBDA(size_t, (utils::EntityManager* self), { return self->getActiveEntities().size(); }), allow_raw_pointers()) #endif /// create ::method:: /// ::retval:: an [Entity] without any components .function("create", select_overload(&utils::EntityManager::create)) .function("destroy", select_overload(&utils::EntityManager::destroy)); // DRIVER TYPES // ------------ /// BufferDescriptor ::class:: Low level buffer wrapper. /// Clients should use the [Buffer] helper function to contruct BufferDescriptor objects. class_("driver$BufferDescriptor") .constructor() /// getBytes ::method:: Gets a view of the WASM heap referenced by the buffer descriptor. /// ::retval:: Uint8Array .function("getBytes", &BufferDescriptor::getBytes); /// PixelBufferDescriptor ::class:: Low level pixel buffer wrapper. /// Clients should use the [PixelBuffer] helper function to contruct PixelBufferDescriptor objects. class_("driver$PixelBufferDescriptor") .constructor() .constructor() /// getBytes ::method:: Gets a view of the WASM heap referenced by the buffer descriptor. /// ::retval:: Uint8Array .function("getBytes", &PixelBufferDescriptor::getBytes); // HELPER TYPES // ------------ /// Ktx1Bundle ::class:: In-memory representation of a KTX file. /// Most clients should use one of the `create*FromKtx` utility methods in the JavaScript [Engine] /// wrapper rather than interacting with `Ktx1Bundle` directly. class_("Ktx1Bundle") .constructor(EMBIND_LAMBDA(Ktx1Bundle*, (BufferDescriptor kbd), { return new Ktx1Bundle((uint8_t*) kbd.bd->buffer, (uint32_t) kbd.bd->size); })) /// info ::method:: Obtains properties of the KTX header. /// ::retval:: The [KtxInfo] property accessor object. .function("getNumMipLevels", &Ktx1Bundle::getNumMipLevels) /// getArrayLength ::method:: Obtains length of the texture array. /// ::retval:: The number of elements in the texture array .function("getArrayLength", &Ktx1Bundle::getArrayLength) /// getInternalFormat ::method:: /// srgb ::argument:: boolean that forces the resulting format to SRGB if possible. /// ::retval:: [Texture$InternalFormat] /// Returns "undefined" if no valid Filament enumerant exists. .function("getInternalFormat", EMBIND_LAMBDA(Texture::InternalFormat, (Ktx1Bundle* self, bool srgb), { auto result = Ktx1Reader::toTextureFormat(self->info()); if (srgb) { if (result == Texture::InternalFormat::RGB8) { result = Texture::InternalFormat::SRGB8; } if (result == Texture::InternalFormat::RGBA8) { result = Texture::InternalFormat::SRGB8_A8; } } return result; }), allow_raw_pointers()) /// getPixelDataFormat ::method:: /// ::retval:: [PixelDataFormat] /// Returns "undefined" if no valid Filament enumerant exists. .function("getPixelDataFormat", EMBIND_LAMBDA(backend::PixelDataFormat, (Ktx1Bundle* self), { return Ktx1Reader::toPixelDataFormat(self->getInfo()); }), allow_raw_pointers()) /// getPixelDataType ::method:: /// ::retval:: [PixelDataType] /// Returns "undefined" if no valid Filament enumerant exists. .function("getPixelDataType", EMBIND_LAMBDA(backend::PixelDataType, (Ktx1Bundle* self), { return Ktx1Reader::toPixelDataType(self->getInfo()); }), allow_raw_pointers()) /// getCompressedPixelDataType ::method:: /// ::retval:: [CompressedPixelDataType] /// Returns "undefined" if no valid Filament enumerant exists. .function("getCompressedPixelDataType", EMBIND_LAMBDA(backend::CompressedPixelDataType, (Ktx1Bundle* self), { return Ktx1Reader::toCompressedPixelDataType(self->getInfo()); }), allow_raw_pointers()) /// isCompressed ::method:: /// Per spec, compressed textures in KTX always have their glFormat field set to 0. /// ::retval:: boolean .function("isCompressed", EMBIND_LAMBDA(bool, (Ktx1Bundle* self), { return Ktx1Reader::isCompressed(self->getInfo()); }), allow_raw_pointers()) .function("isCubemap", &Ktx1Bundle::isCubemap) .function("_getBlob", EMBIND_LAMBDA(BufferDescriptor, (Ktx1Bundle* self, KtxBlobIndex index), { uint8_t* data; uint32_t size; self->getBlob(index, &data, &size); return BufferDescriptor(data, size); }), allow_raw_pointers()) .function("_getCubeBlob", EMBIND_LAMBDA(BufferDescriptor, (Ktx1Bundle* self, uint32_t miplevel), { uint8_t* data; uint32_t size; self->getBlob({miplevel}, &data, &size); return BufferDescriptor(data, size * 6); }), allow_raw_pointers()) /// info ::method:: Obtains properties of the KTX header. /// ::retval:: The [KtxInfo] property accessor object. .function("info", &Ktx1Bundle::info) /// getMetadata ::method:: Obtains arbitrary metadata from the KTX file. /// key ::argument:: string /// ::retval:: string .function("getMetadata", EMBIND_LAMBDA(std::string, (Ktx1Bundle* self, std::string key), { return std::string(self->getMetadata(key.c_str())); }), allow_raw_pointers()); function("ktx1reader$createTexture", EMBIND_LAMBDA(Texture*, (Engine* engine, const Ktx1Bundle& ktx, bool srgb), { return Ktx1Reader::createTexture(engine, ktx, srgb, nullptr, nullptr); }), allow_raw_pointers()); class_("Ktx2Reader") .constructor() .function("requestFormat", &Ktx2Reader::requestFormat) .function("unrequestFormat", &Ktx2Reader::unrequestFormat) .function("load", EMBIND_LAMBDA(Texture*, (Ktx2Reader* self, BufferDescriptor bd, Ktx2Reader::TransferFunction transfer), { return self->load((uint8_t*) bd.bd->buffer, (uint32_t) bd.bd->size, transfer); }), allow_raw_pointers()); /// KtxInfo ::class:: Property accessor for KTX1 header. /// For example, `Ktx1Bundle.info().pixelWidth`. See the /// [KTX spec](https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/) for the list of /// properties. class_("KtxInfo") .property("endianness", &KtxInfo::endianness) .property("glType", &KtxInfo::glType) .property("glTypeSize", &KtxInfo::glTypeSize) .property("glFormat", &KtxInfo::glFormat) .property("glInternalFormat", &KtxInfo::glInternalFormat) .property("glBaseInternalFormat", &KtxInfo::glBaseInternalFormat) .property("pixelWidth", &KtxInfo::pixelWidth) .property("pixelHeight", &KtxInfo::pixelHeight) .property("pixelDepth", &KtxInfo::pixelDepth); class_("MeshReader$MaterialRegistry") .constructor<>() .function("size", &MeshReader::MaterialRegistry::numRegistered) .function("get", EMBIND_LAMBDA(val, (MeshReader::MaterialRegistry* self, std::string k), { const utils::CString name(k.c_str(), k.size()); auto i = self->getMaterialInstance(name); if (i == nullptr) { return val::undefined(); } else { return val(i); } }), allow_raw_pointers()) .function("set", EMBIND_LAMBDA(void, (MeshReader::MaterialRegistry* self, std::string k, filament::MaterialInstance* v), { const utils::CString name(k.c_str(), k.size()); self->registerMaterialInstance(name, v); }), allow_raw_pointers()) .function("keys", EMBIND_LAMBDA(std::vector, (MeshReader::MaterialRegistry* self), { std::vector names(self->numRegistered()); self->getRegisteredMaterialNames(names.data()); std::vector result(self->numRegistered()); for (const auto& name : names) { result.emplace_back(name.c_str()); } return result; }), allow_raw_pointers()); // MeshReader ::class:: Simple parser for filamesh files. // JavaScript clients are encouraged to use the [loadFilamesh] helper function instead of using // this class directly. class_("MeshReader") // loadMeshFromBuffer ::static method:: Parses a filamesh buffer. // engine ::argument:: [Engine] // buffer ::argument:: [Buffer] // materials ::argument:: [MeshReader$MaterialRegistry] // ::retval:: the [MeshReader$Mesh] object .class_function("loadMeshFromBuffer", EMBIND_LAMBDA(MeshReader::Mesh, (Engine* engine, BufferDescriptor buffer, MeshReader::MaterialRegistry& matreg), { // 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. struct Bundle { int count; BufferDescriptor buffer; }; Bundle* bundle = new Bundle({ .count = 0, .buffer = buffer }); const auto destructor = [](void* buffer, size_t size, void* user) { Bundle* bundle = (Bundle*) user; if (++bundle->count == 2) { delete bundle; } }; // Parse the filamesh buffer. This creates the VB, IB, and renderable. return MeshReader::loadMeshFromBuffer( engine, buffer.bd->buffer, destructor, bundle, matreg); }), allow_raw_pointers()); // MeshReader$Mesh ::class:: Property accessor for objects created by [MeshReader]. // This exposes three getter methods: `renderable()`, `vertexBuffer()`, and `indexBuffer()`. These // are of type [Entity], [VertexBuffer], and [IndexBuffer]. JavaScript clients are encouraged to // use the [loadFilamesh] helper function instead of using this class directly. class_("MeshReader$Mesh") .function("renderable", EMBIND_LAMBDA(utils::Entity, (MeshReader::Mesh mesh), { return mesh.renderable; }), allow_raw_pointers()) .function("vertexBuffer", EMBIND_LAMBDA(VertexBuffer*, (MeshReader::Mesh mesh), { return mesh.vertexBuffer; }), allow_raw_pointers()) .function("indexBuffer", EMBIND_LAMBDA(IndexBuffer*, (MeshReader::Mesh mesh), { return mesh.indexBuffer; }), allow_raw_pointers()); // Clients should call [createTextureFromPng] (et al) rather than using decodeImage directly. function("decodeImage", &decodeImage); class_("DecodedImage") .property("width", &DecodedImage::width) .property("height", &DecodedImage::height) .property("data", &DecodedImage::decoded_data); class_("SurfaceOrientation$Builder") .constructor<>() .BUILDER_FUNCTION("vertexCount", SurfaceBuilder, (SurfaceBuilder* builder, size_t nverts), { return &builder->vertexCount(nverts); }) .BUILDER_FUNCTION("_normals", SurfaceBuilder, (SurfaceBuilder* builder, intptr_t data, int stride), { return &builder->normals((const filament::math::float3*) data, stride); }) .BUILDER_FUNCTION("_tangents", SurfaceBuilder, (SurfaceBuilder* builder, intptr_t data, int stride), { return &builder->tangents((const filament::math::float4*) data, stride); }) .BUILDER_FUNCTION("_uvs", SurfaceBuilder, (SurfaceBuilder* builder, intptr_t data, int stride), { return &builder->uvs((const filament::math::float2*) data, stride); }) .BUILDER_FUNCTION("_positions", SurfaceBuilder, (SurfaceBuilder* builder, intptr_t data, int stride), { return &builder->positions((const filament::math::float3*) data, stride); }) .BUILDER_FUNCTION("triangleCount", SurfaceBuilder, (SurfaceBuilder* builder, size_t n), { return &builder->triangleCount(n); }) .BUILDER_FUNCTION("_triangles16", SurfaceBuilder, (SurfaceBuilder* builder, intptr_t data), { return &builder->triangles((filament::math::ushort3*) data); }) .BUILDER_FUNCTION("_triangles32", SurfaceBuilder, (SurfaceBuilder* builder, intptr_t data), { return &builder->triangles((filament::math::uint3*) data); }) .function("_build", EMBIND_LAMBDA(SurfaceOrientation*, (SurfaceBuilder* builder), { return builder->build(); }), allow_raw_pointers()); class_("SurfaceOrientation") .function("_getQuats", EMBIND_LAMBDA(void, (SurfaceOrientation* self, intptr_t out, size_t quatCount, VertexBuffer::AttributeType attrtype), { switch (attrtype) { case VertexBuffer::AttributeType::FLOAT4: { self->getQuats((filament::math::quatf*) out, quatCount); break; } case VertexBuffer::AttributeType::HALF4: { self->getQuats((filament::math::quath*) out, quatCount); break; } case VertexBuffer::AttributeType::SHORT4: { self->getQuats((filament::math::short4*) out, quatCount); break; } default: utils::slog.e << "Unsupported quaternion type." << utils::io::endl; } }), allow_raw_pointers()); class_("gltfio$Animator") .function("applyAnimation", &Animator::applyAnimation) .function("updateBoneMatrices", &Animator::updateBoneMatrices) .function("applyCrossFade", &Animator::applyCrossFade) .function("resetBoneMatrices", &Animator::resetBoneMatrices) .function("getAnimationCount", &Animator::getAnimationCount) .function("getAnimationDuration", &Animator::getAnimationDuration) .function("getAnimationName", EMBIND_LAMBDA(std::string, (Animator* self, size_t index), { return std::string(self->getAnimationName(index)); }), allow_raw_pointers()); class_("gltfio$FilamentAsset") .function("_getEntities", EMBIND_LAMBDA(EntityVector, (FilamentAsset* self), { const utils::Entity* ptr = self->getEntities(); return EntityVector(ptr, ptr + self->getEntityCount()); }), allow_raw_pointers()) .function("_getEntitiesByName", EMBIND_LAMBDA(EntityVector, (FilamentAsset* self, std::string name), { EntityVector result(self->getEntitiesByName(name.c_str(), nullptr, 0)); self->getEntitiesByName(name.c_str(), result.data(), result.size()); return result; }), allow_raw_pointers()) .function("_getEntitiesByPrefix", EMBIND_LAMBDA(EntityVector, (FilamentAsset* self, std::string prefix), { EntityVector result(self->getEntitiesByPrefix(prefix.c_str(), nullptr, 0)); self->getEntitiesByPrefix(prefix.c_str(), result.data(), result.size()); return result; }), allow_raw_pointers()) .function("getFirstEntityByName", EMBIND_LAMBDA(utils::Entity, (FilamentAsset* self, std::string name), { return self->getFirstEntityByName(name.c_str()); }), allow_raw_pointers()) .function("_getLightEntities", EMBIND_LAMBDA(EntityVector, (FilamentAsset* self), { const utils::Entity* ptr = self->getLightEntities(); return EntityVector(ptr, ptr + self->getLightEntityCount()); }), allow_raw_pointers()) .function("_getRenderableEntities", EMBIND_LAMBDA(EntityVector, (FilamentAsset* self), { const utils::Entity* ptr = self->getRenderableEntities(); return EntityVector(ptr, ptr + self->getRenderableEntityCount()); }), allow_raw_pointers()) .function("_getCameraEntities", EMBIND_LAMBDA(EntityVector, (FilamentAsset* self), { const utils::Entity* ptr = self->getCameraEntities(); return EntityVector(ptr, ptr + self->getCameraEntityCount()); }), allow_raw_pointers()) .function("getRoot", &FilamentAsset::getRoot) .function("popRenderable", &FilamentAsset::popRenderable) .function("getInstance", &FilamentAsset::getInstance, allow_raw_pointers()) .function("_getAssetInstances", EMBIND_LAMBDA(std::vector, (FilamentAsset* self), { FilamentInstance** ptr = self->getAssetInstances(); return std::vector(ptr, ptr + self->getAssetInstanceCount()); }), allow_raw_pointers()) .function("_getResourceUris", EMBIND_LAMBDA(std::vector, (FilamentAsset* self), { std::vector retval; auto uris = self->getResourceUris(); for (size_t i = 0, len = self->getResourceUriCount(); i < len; ++i) { retval.push_back(uris[i]); } return retval; }), allow_raw_pointers()) .function("getBoundingBox", &FilamentAsset::getBoundingBox) .function("getName", EMBIND_LAMBDA(std::string, (FilamentAsset* self, utils::Entity entity), { return std::string(self->getName(entity)); }), allow_raw_pointers()) .function("getExtras", EMBIND_LAMBDA(std::string, (FilamentAsset* self, utils::Entity entity), { return std::string(self->getExtras(entity)); }), allow_raw_pointers()) .function("getWireframe", &FilamentAsset::getWireframe) .function("getEngine", &FilamentAsset::getEngine, allow_raw_pointers()) .function("releaseSourceData", &FilamentAsset::releaseSourceData); class_("gltfio$FilamentInstance") .function("getAsset", &FilamentInstance::getAsset, allow_raw_pointers()) .function("getEntities", EMBIND_LAMBDA(EntityVector, (FilamentInstance* self), { const utils::Entity* ptr = self->getEntities(); return EntityVector(ptr, ptr + self->getEntityCount()); }), allow_raw_pointers()) .function("getRoot", &FilamentInstance::getRoot) .function("getAnimator", &FilamentInstance::getAnimator, allow_raw_pointers()) .function("getSkinNames", EMBIND_LAMBDA(std::vector, (FilamentInstance* self), { std::vector names(self->getSkinCount()); for (size_t i = 0; i < names.size(); ++i) { names[i] = self->getSkinNameAt(i); } return names; }), allow_raw_pointers()) .function("attachSkin", &FilamentInstance::attachSkin) .function("detachSkin", &FilamentInstance::detachSkin) .function("applyMaterialVariant", &FilamentInstance::applyMaterialVariant) .function("getMaterialInstances", EMBIND_LAMBDA(std::vector, (FilamentInstance* self), { MaterialInstance* const* ptr = self->getMaterialInstances(); return std::vector(ptr, ptr + self->getMaterialInstanceCount()); }), allow_raw_pointers()) .function("_getMaterialVariantNames", EMBIND_LAMBDA(std::vector, (FilamentInstance* self), { std::vector retval(self->getMaterialVariantCount()); for (size_t i = 0, len = retval.size(); i < len; ++i) { retval[i] = self->getMaterialVariantName(i); } return retval; }), allow_raw_pointers()); // These little wrappers exist to get around RTTI requirements in embind. struct UbershaderProvider { MaterialProvider* provider; void destroyMaterials() { provider->destroyMaterials(); } }; struct StbProvider { TextureProvider* provider; }; struct Ktx2Provider { TextureProvider* provider; }; class_("gltfio$UbershaderProvider") .constructor(EMBIND_LAMBDA(UbershaderProvider, (Engine* engine), { return UbershaderProvider { createUbershaderProvider(engine, UBERARCHIVE_DEFAULT_DATA, UBERARCHIVE_DEFAULT_SIZE) }; })) .function("destroyMaterials", &UbershaderProvider::destroyMaterials); class_("gltfio$StbProvider") .constructor(EMBIND_LAMBDA(StbProvider, (Engine* engine), { return StbProvider { createStbProvider(engine) }; })); class_("gltfio$Ktx2Provider") .constructor(EMBIND_LAMBDA(Ktx2Provider, (Engine* engine), { return Ktx2Provider { createKtx2Provider(engine) }; })); class_("gltfio$AssetLoader") .constructor(EMBIND_LAMBDA(AssetLoader*, (Engine* engine, UbershaderProvider materials), { auto names = new utils::NameComponentManager(utils::EntityManager::get()); return AssetLoader::create({ engine, materials.provider, names }); }), allow_raw_pointers()) /// createAsset ::method:: /// buffer ::argument:: asset string, or Uint8Array, or [Buffer] /// ::retval:: an instance of [FilamentAsset] .function("_createAsset", EMBIND_LAMBDA(FilamentAsset*, (AssetLoader* self, BufferDescriptor buffer), { return self->createAsset((const uint8_t*) buffer.bd->buffer, buffer.bd->size); }), allow_raw_pointers()) /// createInstancedAsset ::method:: /// buffer ::argument:: asset string, or Uint8Array, or [Buffer] /// ::retval:: an instance of [FilamentAsset] .function("_createInstancedAsset", EMBIND_LAMBDA(FilamentAsset*, (AssetLoader* self, BufferDescriptor buffer, int numInstances), { // Ignore the returned instances, they can be extracted from the asset. std::vector instances; return self->createInstancedAsset((const uint8_t*) buffer.bd->buffer, buffer.bd->size, instances.data(), numInstances); }), allow_raw_pointers()) // createInstance ::method:: // Adds a new instance to an instanced asset. .function("createInstance", &AssetLoader::createInstance, allow_raw_pointers()) // destroyAsset ::method:: // Destroys the given asset and all of its associated Filament objects. This includes // components, material instances, vertex buffers, index buffers, and textures. // asset ::argument:: the Filament asset created using AssetLoader .function("destroyAsset", &AssetLoader::destroyAsset, allow_raw_pointers()); class_("gltfio$ResourceLoader") .constructor(EMBIND_LAMBDA(ResourceLoader*, (Engine* engine, bool normalizeSkinningWeights), { return new ResourceLoader({ .engine = engine, .gltfPath = nullptr, .normalizeSkinningWeights = normalizeSkinningWeights }); }), allow_raw_pointers()) .function("addResourceData", EMBIND_LAMBDA(void, (ResourceLoader* self, std::string url, BufferDescriptor buffer), { self->addResourceData(url.c_str(), std::move(*buffer.bd)); }), allow_raw_pointers()) .function("addStbProvider", EMBIND_LAMBDA(void, (ResourceLoader* self, std::string mime, StbProvider provider), { self->addTextureProvider(mime.c_str(), provider.provider); }), allow_raw_pointers()) .function("addKtx2Provider", EMBIND_LAMBDA(void, (ResourceLoader* self, std::string mime, Ktx2Provider provider), { self->addTextureProvider(mime.c_str(), provider.provider); }), allow_raw_pointers()) .function("hasResourceData", EMBIND_LAMBDA(bool, (ResourceLoader* self, std::string url), { return self->hasResourceData(url.c_str()); }), allow_raw_pointers()) .function("loadResources", EMBIND_LAMBDA(bool, (ResourceLoader* self, FilamentAsset* asset), { return self->loadResources(asset); }), allow_raw_pointers()) .function("asyncBeginLoad", EMBIND_LAMBDA(bool, (ResourceLoader* self, FilamentAsset* asset), { return self->asyncBeginLoad(asset); }), allow_raw_pointers()) .function("asyncGetLoadProgress", &ResourceLoader::asyncGetLoadProgress) .function("asyncUpdateLoad", &ResourceLoader::asyncUpdateLoad); class_("Settings"); class_("JsonSerializer") .constructor<>() .function("writeJson", &JsonSerializer::writeJson); class_("ViewerGui") .constructor() .function("renderUserInterface", &ViewerGui::renderUserInterface, allow_raw_pointers()) .function("getSettings", &ViewerGui::getSettings) .function("mouseEvent", &ViewerGui::mouseEvent) .function("keyDownEvent", &ViewerGui::keyDownEvent) .function("keyUpEvent", &ViewerGui::keyUpEvent) .function("keyPressEvent", &ViewerGui::keyPressEvent); function("fitIntoUnitCube", EMBIND_LAMBDA(flatmat4, (Aabb box, float zoffset), { return flatmat4 { fitIntoUnitCube(box, zoffset) }; })); function("multiplyMatrices", EMBIND_LAMBDA(flatmat4, (flatmat4 a, flatmat4 b), { return flatmat4 { a.m * b.m }; })); } // EMSCRIPTEN_BINDINGS #pragma clang diagnostic pop