JavaScript: concise texture creation functions
This makes our createTexture* helpers more consistent with the
createMaterial helper, and extends the wrapped Engine class with new
methods.
Before, clients did something like this:
const ao = Filament.createTextureFromPng(Filament.assets['foo.png'], engine);
...
engine.destroyTexture(ao);
Now, they can do:
const ao = engine.createTextureFromPng('foo.png');
...
engine.destroyTexture(ao);
This is more symmetric and concise. In general the JS API now supports a
class of "buffer-like" objects which exploit dynamic typing in order to
accept any of the following: BufferDescriptor, asset string, or
Uint8Array.
This commit is contained in:
@@ -4,6 +4,7 @@ project(filamentjs)
|
||||
|
||||
set(JAVASCRIPT_SRC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasmloader.js
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/extensions.js
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/utilities.js)
|
||||
|
||||
set(CPP_SRC
|
||||
|
||||
@@ -278,6 +278,15 @@ def gather_docstrings(paths):
|
||||
"detail": None,
|
||||
"children": []
|
||||
}
|
||||
|
||||
# Check if this is continuation of a previous type.
|
||||
if brief== '':
|
||||
for existing_type in result:
|
||||
if existing_type['name'] == name:
|
||||
entity = existing_type
|
||||
result.remove(existing_type)
|
||||
break
|
||||
|
||||
top = stack[-1]["tags"]
|
||||
if 'root' in top:
|
||||
result.append(entity)
|
||||
@@ -436,6 +445,7 @@ def build_reference():
|
||||
ROOT_DIR + 'libs/filamentjs/jsenums.cpp',
|
||||
ROOT_DIR + 'libs/filamentjs/utilities.js',
|
||||
ROOT_DIR + 'libs/filamentjs/wasmloader.js',
|
||||
ROOT_DIR + 'libs/filamentjs/extensions.js',
|
||||
])
|
||||
markdown = build_reference_markdown(doctree)
|
||||
rendered = mistletoe.markdown(markdown, PygmentsRenderer)
|
||||
|
||||
@@ -139,8 +139,7 @@ Next let's create a material instance from the package that we built at the begi
|
||||
Replace the **create material** comment with the following snippet.
|
||||
|
||||
```js {fragment="create material"}
|
||||
const material_package = Filament.Buffer(Filament.assets['plastic.filamat']);
|
||||
const material = engine.createMaterial(material_package);
|
||||
const material = engine.createMaterial('plastic.filamat');
|
||||
const matinstance = material.createInstance();
|
||||
|
||||
const red = [0.8, 0.0, 0.0];
|
||||
@@ -269,8 +268,7 @@ Filament provides a JavaScript utility to make this simpler,
|
||||
simply replace the **create IBL** comment with the following snippet.
|
||||
|
||||
```js {fragment="create IBL"}
|
||||
const ibldata = Filament.assets['pillars_2k_ibl.ktx'];
|
||||
const indirectLight = Filament.createIblFromKtx(ibldata, engine, {'rgbm': true});
|
||||
const indirectLight = engine.createIblFromKtx('pillars_2k_ibl.ktx');
|
||||
indirectLight.setIntensity(50000);
|
||||
scene.setIndirectLight(indirectLight);
|
||||
```
|
||||
@@ -302,9 +300,7 @@ Filament provides a Javascript utility to make this easier.
|
||||
Replace **create skybox** with the following.
|
||||
|
||||
```js {fragment="create skybox"}
|
||||
const skydata = Filament.assets['pillars_2k_skybox.ktx'];
|
||||
const skytex = Filament.createTextureFromKtx(skydata, engine, {'rgbm': true});
|
||||
const skybox = Filament.Skybox.Builder().environment(skytex).build(engine);
|
||||
const skybox = engine.createSkyFromKtx('pillars_2k_skybox.ktx');
|
||||
scene.setSkybox(skybox);
|
||||
```
|
||||
|
||||
|
||||
@@ -135,8 +135,6 @@ const TRIANGLE_COLORS = Filament.Buffer(new Uint32Array([
|
||||
0xff00ff00,
|
||||
0xff0000ff,
|
||||
]));
|
||||
|
||||
const MATERIAL_PACKAGE = Filament.Buffer(Filament.assets['triangle.filamat']);
|
||||
```
|
||||
|
||||
Next we'll use the positions and colors buffers to create a single `VertexBuffer` object.
|
||||
@@ -195,7 +193,7 @@ After extracting the material instance, we can finally create a renderable compo
|
||||
triangle by setting up a bounding box and passing in the vertex and index buffers.
|
||||
|
||||
```js {fragment="create entities"}
|
||||
const mat = engine.createMaterial(MATERIAL_PACKAGE);
|
||||
const mat = engine.createMaterial('triangle.filamat');
|
||||
const matinst = mat.getDefaultInstance();
|
||||
Filament.RenderableManager.Builder(1)
|
||||
.boundingBox([[ -1, -1, -1 ], [ 1, 1, 1 ]])
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Private utility that converts an asset string or Uint8Array into a low-level buffer descriptor.
|
||||
function getBufferDescriptor(buffer) {
|
||||
if ('string' == typeof buffer || buffer instanceof String) {
|
||||
buffer = Filament.assets[buffer];
|
||||
}
|
||||
if (buffer instanceof Uint8Array) {
|
||||
buffer = Filament.Buffer(buffer);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Filament.loadClassExtensions = function() {
|
||||
|
||||
/// Engine ::core class::
|
||||
|
||||
/// create ::static method::
|
||||
/// canvas ::argument::
|
||||
/// options ::argument::
|
||||
/// ::retval:: an instance of [Engine]
|
||||
Filament.Engine.create = function(canvas, options) {
|
||||
const defaults = {
|
||||
majorVersion: 2,
|
||||
minorVersion: 0,
|
||||
antialias: false,
|
||||
depth: false,
|
||||
alpha: false
|
||||
};
|
||||
options = Object.assign(defaults, options);
|
||||
Filament.createContext(canvas, true, true, options);
|
||||
return Filament.Engine._create();
|
||||
};
|
||||
|
||||
/// createMaterial ::method::
|
||||
/// package ::argument:: asset string, or Uint8Array, or [Buffer] with filamat contents
|
||||
/// ::retval:: an instance of [createMaterial]
|
||||
Filament.Engine.prototype.createMaterial = function(buffer) {
|
||||
return this._createMaterial(getBufferDescriptor(buffer));
|
||||
};
|
||||
|
||||
/// createTextureFromKtx ::method:: Utility function that creates a [Texture] from a KTX file.
|
||||
/// buffer ::argument:: asset string, or Uint8Array, or [Buffer] with KTX file contents
|
||||
/// options ::argument:: Options dictionary. For now, the `rgbm` boolean is the only option.
|
||||
/// ::retval:: [Texture]
|
||||
Filament.Engine.prototype.createTextureFromKtx = function(buffer, options) {
|
||||
return Filament._createTextureFromKtx(getBufferDescriptor(buffer), this, options);
|
||||
};
|
||||
|
||||
/// createIblFromKtx ::method:: Utility function that creates an [IndirectLight] from a KTX file.
|
||||
/// buffer ::argument:: asset string, or Uint8Array, or [Buffer] with KTX file contents
|
||||
/// options ::argument:: Options dictionary. For now, the `rgbm` boolean is the only option.
|
||||
/// ::retval:: [IndirectLight]
|
||||
Filament.Engine.prototype.createIblFromKtx = function(buffer, options) {
|
||||
return Filament._createIblFromKtx(getBufferDescriptor(buffer), this, options);
|
||||
}
|
||||
|
||||
/// createSkyFromKtx ::method:: Utility function that creates a [Skybox] from a KTX file.
|
||||
/// buffer ::argument:: asset string, or Uint8Array, or [Buffer] with KTX file contents
|
||||
/// options ::argument:: Options dictionary. For now, the `rgbm` boolean is the only option.
|
||||
/// ::retval:: [Skybox]
|
||||
Filament.Engine.prototype.createSkyFromKtx = function(buffer, options) {
|
||||
options = options || {'rgbm': true};
|
||||
const skytex = this.createTextureFromKtx(buffer, options);
|
||||
return Filament.Skybox.Builder().environment(skytex).build(this);
|
||||
};
|
||||
|
||||
/// createTextureFromPng ::method:: Creates a 2D [Texture] from the raw contents of a PNG file.
|
||||
/// buffer ::argument:: asset string, or Uint8Array, or [Buffer] with PNG file contents
|
||||
/// options ::argument:: JavaScript object with optional `rgbm`, `noalpha`, and `nomips` keys.
|
||||
/// ::retval:: [Texture]
|
||||
Filament.Engine.prototype.createTextureFromPng = function(buffer, options) {
|
||||
return Filament._createTextureFromPng(getBufferDescriptor(buffer), this, options);
|
||||
}
|
||||
|
||||
/// loadFilamesh ::method:: Consumes the contents of a filamesh file and creates a renderable.
|
||||
/// buffer ::argument:: asset string, or Uint8Array, or [Buffer] with filamesh contents
|
||||
/// definstance ::argument:: Optional default [MaterialInstance]
|
||||
/// matinstances ::argument:: Optional object that gets populated with name => [MaterialInstance]
|
||||
/// ::retval:: JavaScript object with keys `renderable`, `vertexBuffer`, and `indexBuffer`. \
|
||||
/// These are of type [Entity], [VertexBuffer], and [IndexBuffer].
|
||||
Filament.Engine.prototype.loadFilamesh = function(buffer, definstance, matinstances) {
|
||||
return Filament._loadFilamesh(this, getBufferDescriptor(buffer), definstance, matinstances);
|
||||
}
|
||||
|
||||
};
|
||||
@@ -260,7 +260,7 @@ value_array<flatmat3>("mat3")
|
||||
// CORE FILAMENT CLASSES
|
||||
// ---------------------
|
||||
|
||||
/// Engine ::core class:: Central manager and resource owner. Typically this is a singleton.
|
||||
/// Engine ::core class:: Central manager and resource owner.
|
||||
class_<Engine>("Engine")
|
||||
.class_function("_create", (Engine* (*)()) [] { return Engine::create(); },
|
||||
allow_raw_pointers())
|
||||
@@ -317,12 +317,7 @@ class_<Engine>("Engine")
|
||||
.function("destroyCamera", (void (*)(Engine*, Camera*)) []
|
||||
(Engine* engine, Camera* camera) { engine->destroy(camera); },
|
||||
allow_raw_pointers())
|
||||
/// createMaterial ::method::
|
||||
/// package ::argument:: buffer descriptor created with [Buffer] with filamat contents
|
||||
/// ::retval:: an instance of [createMaterial]
|
||||
.function("createMaterial", EMBIND_LAMBDA(Material*, (Engine* engine, BufferDescriptor mbd), {
|
||||
// TODO: consider adding a BufferDescriptor API to Material::Builder, then possibly removing
|
||||
// this convenient helper method.
|
||||
.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::
|
||||
|
||||
@@ -37,21 +37,19 @@ class App {
|
||||
.build(engine, sunlight);
|
||||
this.scene.addEntity(sunlight);
|
||||
|
||||
const ibldata = Filament.assets['venetian_crossroads_2k_ibl.ktx'];
|
||||
const indirectLight = this.ibl = Filament.createIblFromKtx(ibldata, engine, {'rgbm': true});
|
||||
const ibldata = 'venetian_crossroads_2k_ibl.ktx';
|
||||
const indirectLight = this.ibl = engine.createIblFromKtx(ibldata);
|
||||
this.scene.setIndirectLight(indirectLight);
|
||||
|
||||
const radians = 1.0;
|
||||
indirectLight.setRotation(mat3.fromRotation(mat3.create(), radians, [0, 1, 0]))
|
||||
indirectLight.setIntensity(10000);
|
||||
|
||||
const skydata = Filament.assets['venetian_crossroads_2k_skybox.ktx'];
|
||||
const skytex = Filament.createTextureFromKtx(skydata, engine, {'rgbm': true});
|
||||
const skybox = Filament.Skybox.Builder().environment(skytex).build(engine);
|
||||
const skydata = 'venetian_crossroads_2k_skybox.ktx';
|
||||
const skybox = engine.createSkyFromKtx(skydata);
|
||||
this.scene.setSkybox(skybox);
|
||||
|
||||
const MATERIAL_PACKAGE = Filament.Buffer(Filament.assets['parquet.filamat']);
|
||||
const material = engine.createMaterial(MATERIAL_PACKAGE);
|
||||
const material = engine.createMaterial('parquet.filamat');
|
||||
const matinstance = material.createInstance();
|
||||
|
||||
const sampler = new Filament.TextureSampler(
|
||||
@@ -59,17 +57,14 @@ class App {
|
||||
Filament.MagFilter.LINEAR,
|
||||
Filament.WrapMode.CLAMP_TO_EDGE);
|
||||
|
||||
const ao = Filament.createTextureFromPng(
|
||||
Filament.assets['floor_ao_roughness_metallic.png'], engine);
|
||||
const basecolor = Filament.createTextureFromPng(
|
||||
Filament.assets['floor_basecolor.png'], engine, {'srgb': true});
|
||||
const normal = Filament.createTextureFromPng(Filament.assets['floor_normal.png'], engine);
|
||||
const ao = engine.createTextureFromPng('floor_ao_roughness_metallic.png');
|
||||
const basecolor = engine.createTextureFromPng('floor_basecolor.png', {'srgb': true});
|
||||
const normal = engine.createTextureFromPng('floor_normal.png');
|
||||
matinstance.setTextureParameter('aoRoughnessMetallic', ao, sampler)
|
||||
matinstance.setTextureParameter('baseColor', basecolor, sampler)
|
||||
matinstance.setTextureParameter('normal', normal, sampler)
|
||||
|
||||
const meshdata = Filament.assets['shader_ball.filamesh'];
|
||||
const mesh = Filament.loadFilamesh(engine, meshdata, matinstance);
|
||||
const mesh = engine.loadFilamesh('shader_ball.filamesh', matinstance);
|
||||
this.shaderball = mesh.renderable;
|
||||
this.scene.addEntity(mesh.renderable);
|
||||
|
||||
|
||||
@@ -59,14 +59,7 @@ Filament.PixelBuffer = function(typedarray, format, datatype) {
|
||||
return bd;
|
||||
};
|
||||
|
||||
/// loadFilamesh ::function:: Consumes the contents of a filamesh file and creates a renderable.
|
||||
/// engine ::argument:: [Engine]
|
||||
/// typedarray ::argument:: Uint8Array with contents of filamesh file
|
||||
/// definstance ::argument:: Optional default [MaterialInstance]
|
||||
/// matinstances ::argument:: Optional object that gets populated with name => [MaterialInstance]
|
||||
/// ::retval:: JavaScript object with keys `renderable`, `vertexBuffer`, and `indexBuffer`. \
|
||||
/// These are of type [Entity], [VertexBuffer], and [IndexBuffer].
|
||||
Filament.loadFilamesh = function(engine, typedarray, definstance, matinstances) {
|
||||
Filament._loadFilamesh = function(engine, buffer, definstance, matinstances) {
|
||||
matinstances = matinstances || {};
|
||||
const registry = new Filament.MeshIO$MaterialRegistry();
|
||||
for (var key in matinstances) {
|
||||
@@ -75,7 +68,7 @@ Filament.loadFilamesh = function(engine, typedarray, definstance, matinstances)
|
||||
if (definstance) {
|
||||
registry.set("DefaultMaterial", definstance);
|
||||
}
|
||||
const mesh = Filament.MeshIO.loadMeshFromBuffer(engine, Filament.Buffer(typedarray), registry);
|
||||
const mesh = Filament.MeshIO.loadMeshFromBuffer(engine, buffer, registry);
|
||||
const keys = registry.keys();
|
||||
for (var i = 0; i < keys.size(); i++) {
|
||||
const key = keys.get(i);
|
||||
@@ -223,12 +216,7 @@ Filament.loadMathExtensions = function() {
|
||||
// Texture helpers
|
||||
// ---------------
|
||||
|
||||
/// createTextureFromKtx ::function:: Utility function that creates a [Texture] from a KTX file.
|
||||
/// ktxdata ::argument:: Uint8Array with the contents of a KTX file.
|
||||
/// engine ::argument:: [Engine]
|
||||
/// options ::argument:: Options dictionary. For now, the `rgbm` boolean is the only option.
|
||||
/// ::retval:: [Texture]
|
||||
Filament.createTextureFromKtx = function(ktxdata, engine, options) {
|
||||
Filament._createTextureFromKtx = function(ktxdata, engine, options) {
|
||||
options = options || {};
|
||||
|
||||
const Sampler = Filament.Texture$Sampler;
|
||||
@@ -236,7 +224,7 @@ Filament.createTextureFromKtx = function(ktxdata, engine, options) {
|
||||
const PixelDataFormat = Filament.PixelDataFormat;
|
||||
const gl = Filament.ctx;
|
||||
|
||||
const ktx = options['ktx'] || new Filament.KtxBundle(Filament.Buffer(ktxdata));
|
||||
const ktx = options['ktx'] || new Filament.KtxBundle(ktxdata);
|
||||
const nlevels = ktx.getNumMipLevels();
|
||||
const ktxformat = ktx.info().glInternalFormat;
|
||||
const rgbm = !!options['rgbm'];
|
||||
@@ -285,15 +273,10 @@ Filament.createTextureFromKtx = function(ktxdata, engine, options) {
|
||||
return tex;
|
||||
};
|
||||
|
||||
/// createIblFromKtx ::function:: Utility function that creates an [IndirectLight] from a KTX file.
|
||||
/// ktxdata ::argument:: Uint8Array with the contents of a KTX file.
|
||||
/// engine ::argument:: [Engine]
|
||||
/// options ::argument:: Options dictionary. For now, the `rgbm` boolean is the only option.
|
||||
/// ::retval:: [IndirectLight]
|
||||
Filament.createIblFromKtx = function(ktxdata, engine, options) {
|
||||
options = options || {};
|
||||
const iblktx = options['ktx'] = new Filament.KtxBundle(Filament.Buffer(ktxdata));
|
||||
const ibltex = Filament.createTextureFromKtx(ktxdata, engine, options);
|
||||
Filament._createIblFromKtx = function(ktxdata, engine, options) {
|
||||
options = options || {'rgbm': true};
|
||||
const iblktx = options['ktx'] = new Filament.KtxBundle(ktxdata);
|
||||
const ibltex = Filament._createTextureFromKtx(ktxdata, engine, options);
|
||||
const shstring = iblktx.getMetadata("sh");
|
||||
const shfloats = shstring.split(/\s/, 9 * 3).map(parseFloat);
|
||||
return Filament.IndirectLight.Builder()
|
||||
@@ -302,12 +285,7 @@ Filament.createIblFromKtx = function(ktxdata, engine, options) {
|
||||
.build(engine);
|
||||
};
|
||||
|
||||
/// createTextureFromPng ::function:: Creates a 2D [Texture] from the raw contents of a PNG file.
|
||||
/// pngdata ::argument:: Uint8Array with the contents of a PNG file.
|
||||
/// engine ::argument:: [Engine]
|
||||
/// options ::argument:: JS object with optional `srgb`, `rgbm`, `noalpha`, and `nomips` keys.
|
||||
/// ::retval:: [Texture]
|
||||
Filament.createTextureFromPng = function(pngdata, engine, options) {
|
||||
Filament._createTextureFromPng = function(pngdata, engine, options) {
|
||||
const Sampler = Filament.Texture$Sampler;
|
||||
const TextureFormat = Filament.Texture$InternalFormat;
|
||||
const PixelDataFormat = Filament.PixelDataFormat;
|
||||
@@ -317,7 +295,8 @@ Filament.createTextureFromPng = function(pngdata, engine, options) {
|
||||
const rgbm = !!options['rgbm'];
|
||||
const noalpha = !!options['noalpha'];
|
||||
const nomips = !!options['nomips'];
|
||||
const decodedpng = Filament.decodePng(Filament.Buffer(pngdata), noalpha ? 3 : 4);
|
||||
|
||||
const decodedpng = Filament.decodePng(pngdata, noalpha ? 3 : 4);
|
||||
|
||||
var texformat, pbformat, pbtype;
|
||||
if (noalpha) {
|
||||
|
||||
@@ -77,18 +77,7 @@ Filament.init = function(assets, onready) {
|
||||
// WebAssembly module. The JS classes that correspond to core Filament classes (e.g., Engine)
|
||||
// are not guaranteed to exist until this function is called.
|
||||
Filament.postRun = function() {
|
||||
Filament.Engine.create = function(canvas, options) {
|
||||
const defaults = {
|
||||
majorVersion: 2,
|
||||
minorVersion: 0,
|
||||
antialias: false,
|
||||
depth: false,
|
||||
alpha: false
|
||||
};
|
||||
options = Object.assign(defaults, options);
|
||||
Filament.createContext(canvas, true, true, options);
|
||||
return Filament.Engine._create();
|
||||
};
|
||||
Filament.loadClassExtensions();
|
||||
if (--Filament.remainingInitializationTasks == 0 && Filament.onReady) {
|
||||
Filament.onReady();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user