Skip to content

Commit

Permalink
Global configs management #758
Browse files Browse the repository at this point in the history
  • Loading branch information
xeolabs committed Nov 2, 2021
1 parent c6a718e commit 97ff1b5
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 6 deletions.
103 changes: 103 additions & 0 deletions examples/Configs_disableDoublePrecisionAndRAF.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>xeokit Example</title>
<link href="css/pageStyle.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>
</head>
<body>
<input type="checkbox" id="info-button"/>
<label for="info-button" class="info-button"><i class="far fa-3x fa-question-circle"></i></label>
<canvas id="myCanvas"></canvas>
<div class="slideout-sidebar">
<h1>Configs - disabling double precision and RAF</h1><br>
<p>In this example we use a <a href="../docs/class/src/viewer/Configs.js~Configs.html"
target="_other">Configs</a> to disable xeokit's double-precision support, which gives a performance and memory boost
on low-power devices. This however also means that we can no longer render double-precision models without jittering.</p>

<p>We're also switching xeokit from using window.requestAnimationFrame to window.setInterval for its main render loop, which can also
give a performance boost for some cases.</p>
<h3>Stats</h3>
<ul>
<li>
<div id="time">Loading JavaScript modules...</div>
</ul>
<h3>Components Used</h3>
<ul>
<li><a href="../docs/class/src/viewer/Configs.js~Configs.html"
target="_other">Configs</a>
</li>
<li>
<a href="../docs/class/src/viewer/Viewer.js~Viewer.html"
target="_other">Viewer</a>
</li>
<li>
<a href="../docs/class/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js~XKTLoaderPlugin.html"
target="_other">XKTLoaderPlugin</a>
</li>
<li>
<a href="http://openifcmodel.cs.auckland.ac.nz/Model/Details/274"
target="_other">Model source</a>
</li>
</ul>
</div>
</body>
<script type="module">

//------------------------------------------------------------------------------------------------------------------
// Import the modules we need for this example
//------------------------------------------------------------------------------------------------------------------

import {Configs, Viewer, XKTLoaderPlugin} from "../dist/xeokit-sdk.min.es.js";

const configs = new Configs();

//------------------------------------------------------------------------------------------------------------------
// Set some global xeokit configs
//------------------------------------------------------------------------------------------------------------------

configs.doublePrecisionEnabled = false; // Disable 64-bit precision for extra speed. Set this once, before you create any Viewers.
configs.rafEnabled = false; // Disable window.requestAnimationFrame (RAF) and use window.setInterval for Viewer render loops. Can be switched dynamically.

//------------------------------------------------------------------------------------------------------------------
// Create a Viewer, arrange the camera
//------------------------------------------------------------------------------------------------------------------

const viewer = new Viewer({
canvasId: "myCanvas",
transparent: true,
antialias: false // <<------------- Disable anti-aliasing
});

viewer.camera.eye = [-3.933, 2.855, 27.018];
viewer.camera.look = [4.400, 3.724, 8.899];
viewer.camera.up = [-0.018, 0.999, 0.039];

viewer.scene.edgeMaterial.edgeWidth = 2;

//----------------------------------------------------------------------------------------------------------------------
// Create a xeokit loader plugin, load a model, fit to view
//----------------------------------------------------------------------------------------------------------------------

const xktLoader = new XKTLoaderPlugin(viewer);

var t0 = performance.now();

document.getElementById("time").innerHTML = "Loading model...";

const model = xktLoader.load({
id: "myModel",
src: "../assets/models/xkt/v8/ifc/Duplex.ifc.xkt",
edges: true
});

model.on("loaded", () => {
var t1 = performance.now();
document.getElementById("time").innerHTML = "Model loaded in " + Math.floor(t1 - t0) / 1000.0 + " seconds<br>Objects: " + model.numEntities;
});

</script>
</html>
5 changes: 5 additions & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,11 @@
// ["DimensionsFootprintModel_example2", "Dimensions footprint experiment #2"]
],

"Configs": [
"#Configuring the xeokit-sdk",
["Configs_disableDoublePrecisionAndRAF", "Disable double precision (and RAF) for extra performance"]
],

"Viewer": [
"#General viewer techniques",
["viewer_createDestroyRepeat", "Testing repeated viewer creation and deletion"],
Expand Down
115 changes: 115 additions & 0 deletions src/viewer/Configs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {math} from "./scene/math/math.js";
import {core} from "./scene/core";

/**
* Manages global configurations for all {@link Viewer}s.
*
* ## Usage
*
* In the example below, we'll disable xeokit's double-precision support, which gives a performance and memory boost
* on low-power devices, but means that we can no longer render double-precision models without jittering.
*
* We'll also switch from window.requestAnimationFrame to window.setInterval for xeokit's animations, which can also give a
* performance boost in some cases.
*
* [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#Configs_disableDoublePrecisionAndRAF)]
*
* ````javascript
* import {Configs, Viewer, XKTLoaderPlugin} from "../dist/xeokit-sdk.min.es.js";
*
* // Access xeoit-sdk global configs.
* // We typically set configs only before we create any Viewers.
* const configs = new Configs();
*
* // Disable 64-bit precision for extra speed.
* // Only set this config once, before you create any Viewers.
* configs.doublePrecisionEnabled = false;
*
* // Disable window.requestAnimationFrame (RAF) and use
* // window.setInterval for Viewer render loops.
* // This config can be switched dynamically, if needed.
* configs.rafEnabled = false;
*
* const viewer = new Viewer({
* canvasId: "myCanvas"
* });
*
* viewer.camera.eye = [-3.933, 2.855, 27.018];
* viewer.camera.look = [4.400, 3.724, 8.899];
* viewer.camera.up = [-0.018, 0.999, 0.039];
*
* const xktLoader = new XKTLoaderPlugin(viewer);
*
* const model = xktLoader.load({
* src: "../assets/models/xkt/v8/ifc/Duplex.ifc.xkt"
* });
* ````
*/
class Configs {

/**
* Creates a Configs.
*/
constructor() {

}

/**
* Sets whether double precision mode is enabled for {@link Viewer}s.
*
* When double precision mode is enabled (default), {@link Viewer}s will accurately render models that contain
* double-precision coordinates, without jittering.
*
* Internally, double precision incurs extra performance and memory overhead, so if we're certain that
* we're not going to render models that rely on double-precision coordinates, then it's a good idea to disable
* it, especially on low-power devices.
*
* This should only be set once, before creating any {@link Viewer}s.
*
* @returns {boolean}
*/
set doublePrecisionEnabled(doublePrecision) {
math.setDoublePrecisionEnabled(doublePrecision);
}

/**
* Gets whether double precision mode is enabled for all {@link Viewer}s.
*
* @returns {boolean}
*/
get doublePrecisionEnabled() {
return math.getDoublePrecisionEnabled();
}



/**
* Sets whether Viewers currently use window.requestAnimationFrame (RAF) or window.setInterval for animations.
*
* With RAF, the render loop is suspended whenever we switch away from the browser tab that
* contains our application. With setInterval, the render loop will continue running. Since a {@link Viewer} only
* renders frames when the view has actually updated, disabling RAF can actually give a performance boost.
*
* This is ````true```` by default, to use RAF.
*
* This can be dynamically set at any time.
*
* @returns {boolean}
*/
set rafEnabled(rafEnabled) {
core.setRAFEnabled(rafEnabled);
}

/**
* Gets whether {@link Viewer}s currently use window.requestAnimationFrame (RAF) or window.setInterval for animations.
*
* @returns {boolean}
*/
get rafEnabled() {
return core.getRAFEnabled();
}


}

export {Configs};
3 changes: 2 additions & 1 deletion src/viewer/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./localization/LocaleService.js";
export * from "./scene/index.js";
export * from "./Plugin.js";
export * from "./Viewer.js";
export * from "./Viewer.js";
export * from "./Configs.js";
40 changes: 37 additions & 3 deletions src/viewer/scene/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import {Map} from './utils/Map.js';
import {stats} from './stats.js';
import {utils} from './utils.js';

let rafEnabled = true;
let interval = null;

const scenesRenderInfo = {}; // Used for throttling FPS for each Scene
const sceneIDMap = new Map(); // Ensures unique scene IDs
const taskQueue = new Queue(); // Task queue, which is pumped on each frame; tasks are pushed to it with calls to xeokit.schedule
Expand All @@ -11,7 +14,6 @@ const taskBudget = 10; // Millisecs we're allowed to spend on tasks in each fram
const fpsSamples = [];
const numFPSSamples = 30;

let defaultScene = null;// Default singleton Scene, lazy-initialized in getter
let lastTime = 0;
let elapsedTime;
let totalFPS = 0;
Expand Down Expand Up @@ -71,6 +73,32 @@ function Core() {
});
};

/**
* @private
*/
this.setRAFEnabled = function(value) {
if (value === rafEnabled) {
return;
}
rafEnabled = value;
if (rafEnabled) {
if (interval !== null) {
clearInterval(interval);
interval = null;
}
window.requestAnimationFrame(frame);
} else {
interval = setInterval(frame, 16);
}
};

/**
* @private
*/
this.getRAFEnabled = function() {
return rafEnabled;
}

/**
* @private
*/
Expand Down Expand Up @@ -153,7 +181,9 @@ const frame = function () {
fireTickEvents(time);
renderScenes();
lastTime = time;
window.requestAnimationFrame(frame);
if (rafEnabled) {
window.requestAnimationFrame(frame);
}
};

function runTasks(time) { // Process as many enqueued tasks as we can within the per-frame task budget
Expand Down Expand Up @@ -229,6 +259,10 @@ function renderScenes() {
}
}

window.requestAnimationFrame(frame);
if (rafEnabled) {
window.requestAnimationFrame(frame);
} else {
interval = setInterval(frame, 16);
}

export {core};
13 changes: 11 additions & 2 deletions src/viewer/scene/math/math.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Some temporary vars to help avoid garbage collection

const doublePrecision = true;
const FloatArrayType = doublePrecision ? Float64Array : Float32Array;
let doublePrecision = true;
let FloatArrayType = doublePrecision ? Float64Array : Float32Array;

const tempMat1 = new FloatArrayType(16);
const tempMat2 = new FloatArrayType(16);
Expand All @@ -13,6 +13,15 @@ const tempVec4 = new FloatArrayType(4);
*/
const math = {

setDoublePrecisionEnabled(enable) {
doublePrecision = enable;
FloatArrayType = doublePrecision ? Float64Array : Float32Array;
},

getDoublePrecisionEnabled() {
return doublePrecision;
},

MIN_DOUBLE: -Number.MAX_SAFE_INTEGER,
MAX_DOUBLE: Number.MAX_SAFE_INTEGER,

Expand Down

0 comments on commit 97ff1b5

Please sign in to comment.