jsbindings: add JS utilities, enhance testwasm.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
155
libs/filamentjs/utilities.js
Normal file
155
libs/filamentjs/utilities.js
Normal 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;
|
||||
}
|
||||
};
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user