jsbindings: add JS utilities, enhance testwasm.

This commit is contained in:
Philip Rideout
2018-10-16 13:23:42 -07:00
parent d15e275de0
commit e00ba80561
7 changed files with 356 additions and 94 deletions

View File

@@ -2,20 +2,34 @@ cmake_minimum_required(VERSION 3.1)
project(filamentjs)
set(JAVASCRIPT_SRC
${CMAKE_CURRENT_SOURCE_DIR}/wasmloader.js
${CMAKE_CURRENT_SOURCE_DIR}/utilities.js)
set(CPP_SRC
jsenums.cpp
jsbindings.cpp)
# The emcc options are not documented well, the best place to find them is the source:
# https://github.com/kripken/emscripten/blob/master/src/settings.js
set(COPTS "${COPTS} -DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0")
set(LOPTS "${LOPTS} --bind")
set(LOPTS "${LOPTS} --post-js ${CMAKE_CURRENT_SOURCE_DIR}/wasmloader.js")
set(LOPTS "${LOPTS} -s ALLOW_MEMORY_GROWTH=1")
set(LOPTS "${LOPTS} -s MODULARIZE_INSTANCE=1")
set(LOPTS "${LOPTS} -s EXPORT_NAME=Filament")
foreach (JS_FILENAME ${JAVASCRIPT_SRC})
set(LOPTS "${LOPTS} --post-js ${JS_FILENAME}")
endforeach()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LOPTS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COPTS}")
add_executable(filamentjs jsenums.cpp jsbindings.cpp)
set_target_properties(filamentjs PROPERTIES OUTPUT_NAME filament)
add_executable(filamentjs ${CPP_SRC})
set_target_properties(filamentjs PROPERTIES
LINK_DEPENDS "${JAVASCRIPT_SRC}"
OUTPUT_NAME filament)
target_link_libraries(filamentjs PRIVATE filament math utils image filameshio)

View File

@@ -35,6 +35,7 @@
#include <filament/Camera.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/LightManager.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
@@ -82,6 +83,7 @@ namespace emscripten {
BIND(View)
BIND(Scene)
BIND(Camera)
BIND(LightManager)
BIND(RenderableManager)
BIND(TransformManager)
BIND(VertexBuffer)
@@ -104,11 +106,12 @@ using VertexBuilder = VertexBuffer::Builder;
using IndexBuilder = IndexBuffer::Builder;
using MatBuilder = Material::Builder;
using TexBuilder = Texture::Builder;
using LightBuilder = LightManager::Builder;
// We avoid directly exposing driver::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, which is implemented in wasmloader.
// helper function (implemented in utilities.js)
struct BufferDescriptor {
// This form is used when JavaScript sends a buffer into WASM.
BufferDescriptor(val arrdata) {
@@ -132,7 +135,7 @@ struct BufferDescriptor {
};
// Exposed to JavaScript as "driver$PixelBufferDescriptor", but clients will normally use the
// "Filament.PixelBuffer" helper function, which is implemented in wasmloader.
// "Filament.PixelBuffer" helper function (implemented in utilities.js)
struct PixelBufferDescriptor {
PixelBufferDescriptor(val arrdata, driver::PixelDataFormat fmt, driver::PixelDataType dtype) {
auto byteLength = arrdata["byteLength"].as<uint32_t>();
@@ -286,7 +289,13 @@ class_<Camera>("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());
}), 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("setExposure", &Camera::setExposure)
.function("lookAt", &Camera::lookAt);
class_<RenderBuilder>("RenderableManager$Builder")
.function("build", EMBIND_LAMBDA(void, (RenderBuilder* builder,
@@ -322,6 +331,39 @@ class_<TransformManager>("TransformManager")
class_<TransformManager::Instance>("TransformManager$Instance");
class_<LightBuilder>("LightManager$Builder")
.function("build", EMBIND_LAMBDA(void, (LightBuilder* builder,
Engine* engine, utils::Entity entity), {
builder->build(*engine, entity);
}), allow_raw_pointers())
.BUILDER_FUNCTION("castShadows", LightBuilder, (LightBuilder* builder, bool enable), {
return &builder->castShadows(enable); })
.BUILDER_FUNCTION("castLight", LightBuilder, (LightBuilder* builder, bool enable), {
return &builder->castLight(enable); })
.BUILDER_FUNCTION("position", LightBuilder, (LightBuilder* builder, math::float3 value), {
return &builder->position(value); })
.BUILDER_FUNCTION("direction", LightBuilder, (LightBuilder* builder, math::float3 value), {
return &builder->direction(value); })
.BUILDER_FUNCTION("color", LightBuilder, (LightBuilder* builder, 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); });
class_<LightManager>("LightManager")
.class_function("Builder", (LightBuilder (*)(LightManager::Type)) [] (LightManager::Type lt) {
return LightBuilder(lt); });
class_<VertexBuilder>("VertexBuffer$Builder")
.function("build", EMBIND_LAMBDA(VertexBuffer*, (VertexBuilder* builder, Engine* engine), {
return builder->build(*engine);
@@ -386,7 +428,10 @@ class_<MaterialInstance>("MaterialInstance")
self->setParameter(name.c_str(), value); }), 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());
self->setParameter(name.c_str(), value, sampler); }), allow_raw_pointers())
.function("setColorParameter", EMBIND_LAMBDA(void,
(MaterialInstance* self, std::string name, RgbType type, math::float3 value), {
self->setParameter(name.c_str(), type, value); }), allow_raw_pointers());
class_<TextureSampler>("TextureSampler")
.constructor<driver::SamplerMinFilter, driver::SamplerMagFilter, driver::SamplerWrapMode>();

View File

@@ -15,8 +15,10 @@
*/
#include <filament/Camera.h>
#include <filament/Color.h>
#include <filament/IndexBuffer.h>
#include <filament/RenderableManager.h>
#include <filament/LightManager.h>
#include <filament/Texture.h>
#include <filament/VertexBuffer.h>
#include <filament/View.h>
@@ -29,6 +31,16 @@ using namespace filament;
EMSCRIPTEN_BINDINGS(jsenums) {
enum_<RgbType>("RgbType")
.value("sRGB", RgbType::sRGB)
.value("LINEAR", RgbType::LINEAR);
enum_<RgbaType>("RgbaType")
.value("sRGB", RgbaType::sRGB)
.value("LINEAR", RgbaType::LINEAR)
.value("PREMULTIPLIED_sRGB", RgbaType::PREMULTIPLIED_sRGB)
.value("PREMULTIPLIED_LINEAR", RgbaType::PREMULTIPLIED_LINEAR);
enum_<VertexAttribute>("VertexAttribute")
.value("POSITION", POSITION)
.value("TANGENTS", TANGENTS)
@@ -70,6 +82,13 @@ enum_<VertexAttribute>("VertexAttribute")
.value("USHORT", IndexBuffer::IndexType::USHORT)
.value("UINT", IndexBuffer::IndexType::UINT);
enum_<LightManager::Type>("LightManager$Type")
.value("SUN", LightManager::Type::SUN)
.value("DIRECTIONAL", LightManager::Type::DIRECTIONAL)
.value("POINT", LightManager::Type::POINT)
.value("FOCUSED_SPOT", LightManager::Type::FOCUSED_SPOT)
.value("SPOT", LightManager::Type::SPOT);
enum_<RenderableManager::PrimitiveType>("RenderableManager$PrimitiveType")
.value("POINTS", RenderableManager::PrimitiveType::POINTS)
.value("LINES", RenderableManager::PrimitiveType::LINES)
@@ -85,6 +104,10 @@ enum_<VertexAttribute>("VertexAttribute")
.value("PERSPECTIVE", Camera::Projection::PERSPECTIVE)
.value("ORTHO", Camera::Projection::ORTHO);
enum_<Camera::Fov>("Camera$Fov")
.value("VERTICAL", Camera::Fov::VERTICAL)
.value("HORIZONTAL", Camera::Fov::HORIZONTAL);
enum_<Texture::Sampler>("Texture$Sampler") // aka driver::SamplerType
.value("SAMPLER_2D", Texture::Sampler::SAMPLER_2D)
.value("SAMPLER_CUBEMAP", Texture::Sampler::SAMPLER_CUBEMAP)

View File

@@ -12,6 +12,7 @@
<body>
<canvas></canvas>
<script src="filament.js"></script>
<script src="gl-matrix-min.js"></script>
<script src="testwasm.js"></script>
</body>
</html>

View File

@@ -1,51 +1,134 @@
Filament.loadMathExtensions();
var Fov, VertexAttribute, AttributeType, PrimitiveType, IndexType, LightType;
class App {
constructor() {
VertexAttribute = Filament.VertexAttribute;
AttributeType = Filament.VertexBuffer$AttributeType;
PrimitiveType = Filament.RenderableManager$PrimitiveType;
IndexType = Filament.IndexBuffer$IndexType;
Fov = Filament.Camera$Fov;
LightType = Filament.LightManager$Type;
const BAKED_COLOR_PACKAGE = Filament.Buffer(Filament.assets['bakedColor.filamat']);
const SANDBOX_LIT_PACKAGE = Filament.Buffer(Filament.assets['sandboxLit.filamat']);
const TEXTURED_LIT_PACKAGE = Filament.Buffer(Filament.assets['texturedLit.filamat']);
const ALBEDO_KTX = Filament.Buffer(Filament.assets['albedo.ktx']);
const TRIANGLE_POSITIONS = Filament.Buffer(new Float32Array([ 1, 0, -.5, .86, -.5, -.86 ]));
const TRIANGLE_COLORS = Filament.Buffer(new Uint32Array([0xffff0000, 0xff00ff00, 0xff0000ff]));
let vb, ib;
this.canvas = document.getElementsByTagName('canvas')[0];
const engine = this.engine = Filament.Engine.create(this.canvas);
this.scene = engine.createScene();
this.triangle = Filament.EntityManager.get()
.create();
this.scene.addEntity(this.triangle);
const TRIANGLE_POSITIONS = Filament.Buffer(new Float32Array([
1, 0,
Math.cos(Math.PI * 2 / 3), Math.sin(Math.PI * 2 / 3),
Math.cos(Math.PI * 4 / 3), Math.sin(Math.PI * 4 / 3),
]));
const TRIANGLE_COLORS = Filament.Buffer(new Uint32Array([
0xffff0000,
0xff00ff00,
0xff0000ff,
]));
const VertexAttribute = Filament.VertexAttribute;
const AttributeType = Filament.VertexBuffer$AttributeType;
this.vb = Filament.VertexBuffer.Builder()
////////////////////////////////////////////////////////////////////////////////////////////////
this.triangle = Filament.EntityManager.get().create();
vb = Filament.VertexBuffer.Builder()
.vertexCount(3)
.bufferCount(2)
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT2, 0, 8)
.attribute(VertexAttribute.COLOR, 1, AttributeType.UBYTE4, 0, 4)
.normalized(VertexAttribute.COLOR)
.build(engine);
this.vb.setBufferAt(engine, 0, TRIANGLE_POSITIONS);
this.vb.setBufferAt(engine, 1, TRIANGLE_COLORS);
this.ib = Filament.IndexBuffer.Builder()
vb.setBufferAt(engine, 0, TRIANGLE_POSITIONS);
vb.setBufferAt(engine, 1, TRIANGLE_COLORS);
ib = Filament.IndexBuffer.Builder()
.indexCount(3)
.bufferType(Filament.IndexBuffer$IndexType.USHORT)
.bufferType(IndexType.USHORT)
.build(engine);
this.ib.setBuffer(engine, Filament.Buffer(new Uint16Array([0, 1, 2])));
ib.setBuffer(engine, Filament.Buffer(new Uint16Array([0, 1, 2])));
Filament.RenderableManager.Builder(1)
.boundingBox([ [-1, -1, -1], [1, 1, 1] ])
.material(0, engine.createMaterial(BAKED_COLOR_PACKAGE).getDefaultInstance())
.geometry(0, PrimitiveType.TRIANGLES, vb, ib)
.build(engine, this.triangle);
////////////////////////////////////////////////////////////////////////////////////////////////
this.sphere = new Filament.IcoSphere(5);
const sphere = Filament.EntityManager.get().create();
vb = Filament.VertexBuffer.Builder()
.vertexCount(this.sphere.vertices.length / 3)
.bufferCount(2)
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, 0)
.attribute(VertexAttribute.TANGENTS, 1, AttributeType.SHORT4, 0, 0)
.normalized(VertexAttribute.TANGENTS)
.build(engine);
vb.setBufferAt(engine, 0, Filament.Buffer(this.sphere.vertices));
vb.setBufferAt(engine, 1, Filament.Buffer(this.sphere.tangents));
ib = Filament.IndexBuffer.Builder()
.indexCount(this.sphere.triangles.length)
.bufferType(IndexType.USHORT)
.build(engine);
ib.setBuffer(engine, Filament.Buffer(this.sphere.triangles));
const sandboxMaterial = engine.createMaterial(SANDBOX_LIT_PACKAGE);
const sandboxMatInstance = sandboxMaterial.createInstance();
Filament.RenderableManager.Builder(1)
.boundingBox([ [-1, -1, -1], [1, 1, 1] ])
.material(0, sandboxMatInstance)
.geometry(0, PrimitiveType.TRIANGLES, vb, ib)
.build(engine, sphere);
////////////////////////////////////////////////////////////////////////////////////////////////
this.scene.addEntity(sphere);
this.sphereEntity = sphere;
const sunlight = Filament.EntityManager.get().create();
Filament.LightManager.Builder(LightType.SUN)
.color([0.98, 0.92, 0.89])
.intensity(110000.0)
.direction([0.6, -1.0, -0.8])
.castShadows(true)
.sunAngularRadius(1.9)
.sunHaloSize(10.0)
.sunHaloFalloff(80.0)
.build(engine, sunlight);
this.scene.addEntity(sunlight);
const albedo = [158 / 255.0, 118 / 255.0, 74 / 255.0];
sandboxMatInstance.setColorParameter("baseColor", Filament.RgbType.sRGB, albedo);
sandboxMatInstance.setFloatParameter("roughness", 0.6);
sandboxMatInstance.setFloatParameter("metallic", 0.0);
sandboxMatInstance.setFloatParameter("reflectance", 0.5);
sandboxMatInstance.setFloatParameter("clearCoat", 0.7);
sandboxMatInstance.setFloatParameter("clearCoatRoughness", 0.0);
sandboxMatInstance.setFloatParameter("anisotropy", 0.0);
////////////////////////////////////////////////////////////////////////////////////////////////
this.swapChain = engine.createSwapChain();
this.renderer = engine.createRenderer();
this.camera = engine.createCamera();
this.view = engine.createView();
this.view.setCamera(this.camera);
this.view.setScene(this.scene);
this.view.setClearColor([0.1, 0.2, 0.3, 1.0]);
this.resize();
this.render = this.render.bind(this);
this.resize = this.resize.bind(this);
window.addEventListener("resize", this.resize);
window.requestAnimationFrame(this.render);
////////////////////////////////////////////////////////////////////////////////////////////////
const sandboxInstance = sandboxMaterial.createInstance();
sandboxInstance.setFloatParameter("metallic", 1.0)
sandboxInstance.setFloat3Parameter("baseColor", [1.0, 2.0, 3.0]);
const ktx = Window.ktx = new Filament.KtxBundle(ALBEDO_KTX)
const nmips = ktx.getNumMipLevels();
const ta = ktx.getBlob([0, 0, 0]).getBytes();
console.assert(11 == nmips);
console.assert(1024 == ktx.info().pixelWidth)
console.assert(1024 == ktx.info().pixelHeight)
@@ -71,41 +154,13 @@ class App {
const sampler = new Filament.TextureSampler(Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
Filament.MagFilter.LINEAR, Filament.WrapMode.REPEAT);
texturedInstance.setTextureParameter("albedo", tex, sampler);
const mat = engine.createMaterial(BAKED_COLOR_PACKAGE);
const matinst = mat.getDefaultInstance();
Filament.RenderableManager.Builder(1)
.boundingBox([
[-1, -1, -1],
[1, 1, 1]
])
.material(0, matinst)
.geometry(0, Filament.RenderableManager$PrimitiveType.TRIANGLES, this.vb, this.ib)
.build(engine, this.triangle);
this.swapChain = engine.createSwapChain();
this.renderer = engine.createRenderer();
this.camera = engine.createCamera();
this.view = engine.createView();
this.view.setCamera(this.camera);
this.view.setScene(this.scene);
this.view.setClearColor([0.1, 0.2, 0.3, 1.0]); // blue-green background
this.resize(); // adjust the initial viewport
this.render = this.render.bind(this);
this.resize = this.resize.bind(this);
window.addEventListener("resize", this.resize);
window.requestAnimationFrame(this.render);
}
render() {
// Test setting transforms.
const transform = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1];
const transform = mat4.fromTranslation(mat4.create(), [0, 0, -5]);
const tcm = this.engine.getTransformManager();
tcm.setTransform(tcm.getInstance(this.triangle), transform);
tcm.setTransform(tcm.getInstance(this.sphereEntity), transform);
// Render the frame.
if (this.renderer.beginFrame(this.swapChain)) {
@@ -121,9 +176,11 @@ class App {
const width = this.canvas.width = window.innerWidth * dpr;
const height = this.canvas.height = window.innerHeight * dpr;
this.view.setViewport([0, 0, width, height]);
this.camera.setExposure(16.0, 1 / 125.0, 100.0);
const eye = [0, 0, 0], center = [0, 0, -1], up = [0, 1, 0];
this.camera.lookAt(eye, center, up);
const aspect = width / height;
const Projection = Filament.Camera$Projection;
this.camera.setProjection(Projection.ORTHO, -aspect, aspect, -1, 1, 0, 1);
this.camera.setProjectionFov(45, aspect, 0.1, 50.0, aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL);
}
}

View File

@@ -0,0 +1,155 @@
/*
* 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.
*/
// ---------------
// Buffer Wrappers
// ---------------
// These wrappers make it easy for JavaScript clients to pass large swaths of data to Filament. They
// copy the contents of the given typed array into the WASM heap, then return a low-level buffer
// descriptor object. If the given array was taken from the WASM heap, then they create a temporary
// copy because the input pointer becomes invalidated after allocating heap memory for the buffer
// descriptor.
Filament.Buffer = function(typedarray) {
console.assert(typedarray.buffer instanceof ArrayBuffer);
console.assert(typedarray.byteLength > 0);
if (Filament.HEAPU32.buffer == typedarray.buffer) {
typedarray = new Uint8Array(typedarray);
}
const ta = typedarray;
const bd = new Filament.driver$BufferDescriptor(ta);
const uint8array = new Uint8Array(ta.buffer, ta.byteOffset, ta.byteLength);
bd.getBytes().set(uint8array);
return bd;
};
Filament.PixelBuffer = function(typedarray, format, datatype) {
console.assert(typedarray.buffer instanceof ArrayBuffer);
console.assert(typedarray.byteLength > 0);
if (Filament.HEAPU32.buffer == typedarray.buffer) {
typedarray = new Uint8Array(typedarray);
}
const ta = typedarray;
const bd = new Filament.driver$PixelBufferDescriptor(ta, format, datatype);
const uint8array = new Uint8Array(ta.buffer, ta.byteOffset, ta.byteLength);
bd.getBytes().set(uint8array);
return bd;
};
// ------------------
// Geometry Utilities
// ------------------
// These are some lightweight optional functions. Using them requires the presence of gl-matrix,
// which is not bundled into filament.js.
Filament.IcoSphere = function(nsubdivs) {
const X = .525731112119133606;
const Z = .850650808352039932;
const N = 0.;
this.vertices = new Float32Array([
-X, +N, +Z, +X, +N, +Z, -X, +N, -Z, +X, +N, -Z ,
+N, +Z, +X, +N, +Z, -X, +N, -Z, +X, +N, -Z, -X ,
+Z, +X, +N, -Z, +X, +N, +Z, -X, +N, -Z, -X, +N ,
]);
this.triangles = new Uint16Array([
1, 4, 0, 4, 9, 0, 4, 5, 9, 8, 5, 4 , 1, 8, 4 ,
1, 10, 8, 10, 3, 8, 8, 3, 5, 3, 2, 5 , 3, 7, 2 ,
3, 10, 7, 10, 6, 7, 6, 11, 7, 6, 0, 11 , 6, 1, 0 ,
10, 1, 6, 11, 0, 9, 2, 11, 9, 5, 2, 9 , 11, 2, 7 ,
]);
if (nsubdivs) {
while (nsubdivs-- > 0) {
this.subdivide();
}
}
const nverts = this.vertices.length / 3;
this.tangents = new Uint16Array(4 * nverts);
for (var i = 0; i < nverts; ++i) {
const src = this.vertices.subarray(i * 3, i * 3 + 3);
const dst = this.tangents.subarray(i * 4, i * 4 + 4);
const n = vec3.normalize(vec3.create(), src);
const b = vec3.cross(vec3.create(), n, [1, 0, 0]);
const t = vec3.cross(vec3.create(), b, n);
const q = quat.fromMat3(quat.create(), [t[0], t[1], t[2], b[0], b[1], b[2], n[0], n[1], n[2]]);
vec4.packSnorm16(dst, q);
}
}
Filament.IcoSphere.prototype.subdivide = function() {
const srctris = this.triangles;
const srcverts = this.vertices;
const nsrctris = srctris.length / 3;
const ndsttris = nsrctris * 4;
const nsrcverts = srcverts.length / 3;
const ndstverts = nsrcverts + nsrctris * 3;
const dsttris = new Uint16Array(ndsttris * 3);
const dstverts = new Float32Array(ndstverts * 3);
dstverts.set(srcverts);
var srcind = 0, dstind = 0, i3 = nsrcverts * 3, i4 = i3 + 3, i5 = i4 + 3;
for (var tri = 0; tri < nsrctris; tri++, i3 += 9, i4 += 9, i5 += 9) {
const i0 = srctris[srcind++] * 3;
const i1 = srctris[srcind++] * 3;
const i2 = srctris[srcind++] * 3;
const v0 = srcverts.subarray(i0, i0 + 3);
const v1 = srcverts.subarray(i1, i1 + 3);
const v2 = srcverts.subarray(i2, i2 + 3);
const v3 = dstverts.subarray(i3, i3 + 3);
const v4 = dstverts.subarray(i4, i4 + 3);
const v5 = dstverts.subarray(i5, i5 + 3);
vec3.normalize(v3, vec3.add(v3, v0, v1));
vec3.normalize(v4, vec3.add(v4, v1, v2));
vec3.normalize(v5, vec3.add(v5, v2, v0));
dsttris[dstind++] = i0 / 3;
dsttris[dstind++] = i3 / 3;
dsttris[dstind++] = i5 / 3;
dsttris[dstind++] = i3 / 3;
dsttris[dstind++] = i1 / 3;
dsttris[dstind++] = i4 / 3;
dsttris[dstind++] = i5 / 3;
dsttris[dstind++] = i3 / 3;
dsttris[dstind++] = i4 / 3;
dsttris[dstind++] = i2 / 3;
dsttris[dstind++] = i5 / 3;
dsttris[dstind++] = i4 / 3;
}
this.triangles = dsttris;
this.vertices = dstverts;
}
// ---------------
// Math Extensions
// ---------------
function clamp(v, least, most) {
return Math.max(Math.min(most, v), least);
}
function packSnorm16(v) {
return Math.round(clamp(v, -1.0, 1.0) * 32767.0);
}
// This function adds new methods to gl-matrix, its usage is optional.
Filament.loadMathExtensions = function() {
vec4.packSnorm16 = function(out, src) {
out[0] = packSnorm16(src[0]);
out[1] = packSnorm16(src[1]);
out[2] = packSnorm16(src[2]);
out[3] = packSnorm16(src[3]);
return out;
}
};

View File

@@ -63,39 +63,6 @@ Filament.init = function(assets, onready) {
});
};
// This wrapper makes it easy for JavaScript clients to pass large swaths of data to Filament. It
// copies the contents of the given typed array into the WASM heap, then returns a low-level buffer
// descriptor object.
Filament.Buffer = function(typedarray) {
console.assert(typedarray.buffer instanceof ArrayBuffer);
console.assert(typedarray.byteLength > 0);
// If the given array was taken from the WASM heap, then we need to create a copy because its
// pointer will become invalidated after we instantiate the driver$PixelBufferDescriptor.
if (Filament.HEAPU32.buffer == typedarray.buffer) {
typedarray = new Uint8Array(typedarray);
}
const ta = typedarray;
const bd = new Filament.driver$BufferDescriptor(ta);
const uint8array = new Uint8Array(ta.buffer, ta.byteOffset, ta.byteLength);
bd.getBytes().set(uint8array);
return bd;
};
Filament.PixelBuffer = function(typedarray, format, datatype) {
console.assert(typedarray.buffer instanceof ArrayBuffer);
console.assert(typedarray.byteLength > 0);
// If the given array was taken from the WASM heap, then we need to create a copy because its
// pointer will become invalidated after we instantiate the driver$PixelBufferDescriptor.
if (Filament.HEAPU32.buffer == typedarray.buffer) {
typedarray = new Uint8Array(typedarray);
}
const ta = typedarray;
const bd = new Filament.driver$PixelBufferDescriptor(ta, format, datatype);
const uint8array = new Uint8Array(ta.buffer, ta.byteOffset, ta.byteLength);
bd.getBytes().set(uint8array);
return bd;
};
// The postRun method is called by emscripten after it finishes compiling and instancing the
// WebAssembly module. The JS classes that correspond to core Filament classes (e.g., Engine)
// are not guaranteed to exist until this function is called.