@animech-public/playcanvas
Version:
PlayCanvas WebGL game engine
931 lines (918 loc) • 26.9 kB
JavaScript
/**
* @license
* PlayCanvas Engine v1.36.1-rc.1 revision 76f1ffbc8
* Copyright 2011-2020 PlayCanvas Ltd. All rights reserved.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.pcx = {}));
}(this, (function (exports) { 'use strict';
function CpuTimer(app) {
this._frameIndex = 0;
this._frameTimings = [];
this._timings = [];
this._prevTimings = [];
this.unitsName = "ms";
this.decimalPlaces = 1;
this.enabled = true;
app.on('frameupdate', this.begin.bind(this, 'update'));
app.on('framerender', this.mark.bind(this, 'render'));
app.on('frameend', this.mark.bind(this, 'other'));
}
Object.assign(CpuTimer.prototype, {
begin: function (name) {
if (!this.enabled) {
return;
}
if (this._frameIndex < this._frameTimings.length) {
this._frameTimings.splice(this._frameIndex);
}
var tmp = this._prevTimings;
this._prevTimings = this._timings;
this._timings = this._frameTimings;
this._frameTimings = tmp;
this._frameIndex = 0;
this.mark(name);
},
mark: function (name) {
if (!this.enabled) {
return;
}
var timestamp = pc.now();
var prev;
if (this._frameIndex > 0) {
prev = this._frameTimings[this._frameIndex - 1];
prev[1] = timestamp - prev[1];
} else if (this._timings.length > 0) {
prev = this._timings[this._timings.length - 1];
prev[1] = timestamp - prev[1];
}
if (this._frameIndex >= this._frameTimings.length) {
this._frameTimings.push([name, timestamp]);
} else {
var timing = this._frameTimings[this._frameIndex];
timing[0] = name;
timing[1] = timestamp;
}
this._frameIndex++;
}
});
Object.defineProperty(CpuTimer.prototype, 'timings', {
get: function () {
return this._timings.slice(0, -1).map(function (v) {
return v[1];
});
}
});
function GpuTimer(app) {
this._gl = app.graphicsDevice.gl;
this._ext = app.graphicsDevice.extDisjointTimerQuery;
this._freeQueries = [];
this._frameQueries = [];
this._frames = [];
this._timings = [];
this._prevTimings = [];
this.enabled = true;
this.unitsName = "ms";
this.decimalPlaces = 1;
app.on('frameupdate', this.begin.bind(this, 'update'));
app.on('framerender', this.mark.bind(this, 'render'));
app.on('frameend', this.end.bind(this));
}
Object.assign(GpuTimer.prototype, {
begin: function (name) {
if (!this.enabled) {
return;
}
if (this._frameQueries.length > 0) {
this.end();
}
this._checkDisjoint();
if (this._frames.length > 0) {
if (this._resolveFrameTimings(this._frames[0], this._prevTimings)) {
var tmp = this._prevTimings;
this._prevTimings = this._timings;
this._timings = tmp;
this._freeQueries = this._freeQueries.concat(this._frames.splice(0, 1)[0]);
}
}
this.mark(name);
},
mark: function (name) {
if (!this.enabled) {
return;
}
if (this._frameQueries.length > 0) {
this._gl.endQuery(this._ext.TIME_ELAPSED_EXT);
}
var query = this._allocateQuery();
query[0] = name;
this._gl.beginQuery(this._ext.TIME_ELAPSED_EXT, query[1]);
this._frameQueries.push(query);
},
end: function () {
if (!this.enabled) {
return;
}
this._gl.endQuery(this._ext.TIME_ELAPSED_EXT);
this._frames.push(this._frameQueries);
this._frameQueries = [];
},
_checkDisjoint: function () {
var disjoint = this._gl.getParameter(this._ext.GPU_DISJOINT_EXT);
if (disjoint) {
this._freeQueries = [this._frames, [this._frameQueries], [this._freeQueries]].flat(2);
this._frameQueries = [];
this._frames = [];
}
},
_allocateQuery: function () {
return (this._freeQueries.length > 0) ?
this._freeQueries.splice(-1, 1)[0] : ["", this._gl.createQuery()];
},
_resolveFrameTimings: function (frame, timings) {
if (!this._gl.getQueryParameter(frame[frame.length - 1][1], this._gl.QUERY_RESULT_AVAILABLE)) {
return false;
}
for (var i = 0; i < frame.length; ++i) {
timings[i] = [frame[i][0], this._gl.getQueryParameter(frame[i][1], this._gl.QUERY_RESULT) * 0.000001];
}
return true;
}
});
Object.defineProperty(GpuTimer.prototype, 'timings', {
get: function () {
return this._timings.map(function (v) {
return v[1];
});
}
});
var StatsTimer = function (app, statNames, decimalPlaces, unitsName, multiplier) {
this.app = app;
this.values = [];
this.statNames = statNames;
if (this.statNames.length > 3)
this.statNames.length = 3;
this.unitsName = unitsName;
this.decimalPlaces = decimalPlaces;
this.multiplier = multiplier || 1;
var self = this;
function resolve(path, obj) {
return path.split('.').reduce(function (prev, curr) {
return prev ? prev[curr] : null;
}, obj || self);
}
app.on('frameupdate', function (ms) {
for (var i = 0; i < self.statNames.length; i++) {
self.values[i] = resolve(self.statNames[i], self.app.stats) * self.multiplier;
}
});
};
Object.defineProperty(StatsTimer.prototype, 'timings', {
get: function () {
return this.values;
}
});
function Graph(name, app, watermark, textRefreshRate, timer) {
this.name = name;
this.device = app.graphicsDevice;
this.timer = timer;
this.watermark = watermark;
this.enabled = false;
this.textRefreshRate = textRefreshRate;
this.avgTotal = 0;
this.avgTimer = 0;
this.avgCount = 0;
this.timingText = "";
this.texture = null;
this.yOffset = 0;
this.cursor = 0;
this.sample = new Uint8ClampedArray(4);
this.sample.set([0, 0, 0, 255]);
app.on('frameupdate', this.update.bind(this));
this.counter = 0;
}
Object.assign(Graph.prototype, {
update: function (ms) {
var timings = this.timer.timings;
var total = timings.reduce(function (a, v) {
return a + v;
}, 0);
this.avgTotal += total;
this.avgTimer += ms;
this.avgCount++;
if (this.avgTimer > this.textRefreshRate) {
this.timingText = (this.avgTotal / this.avgCount).toFixed(this.timer.decimalPlaces);
this.avgTimer = 0;
this.avgTotal = 0;
this.avgCount = 0;
}
if (this.enabled) {
var value = 0;
var range = 1.5 * this.watermark;
for (var i = 0; i < timings.length; ++i) {
value += Math.floor(timings[i] / range * 255);
this.sample[i] = value;
}
this.sample[3] = this.watermark / range * 255;
var gl = this.device.gl;
this.device.bindTexture(this.texture);
gl.texSubImage2D(gl.TEXTURE_2D,
0,
this.cursor,
this.yOffset,
1,
1,
gl.RGBA,
gl.UNSIGNED_BYTE,
this.sample);
this.cursor++;
if (this.cursor === this.texture.width) {
this.cursor = 0;
}
}
},
render: function (render2d, x, y, w, h) {
render2d.quad(this.texture,
x + w,
y,
-w,
h,
this.cursor,
0.5 + this.yOffset,
-w, 0,
this.enabled);
}
});
function WordAtlas(texture, words) {
var canvas = document.createElement('canvas');
canvas.width = texture.width;
canvas.height = texture.height;
var context = canvas.getContext('2d', { alpha: true });
context.font = '10px "Lucida Console", Monaco, monospace';
context.textAlign = "left";
context.textBaseline = "alphabetic";
context.fillStyle = "rgb(255, 255, 255)";
var padding = 5;
var x = padding;
var y = padding;
var placements = [];
var i;
for (i = 0; i < words.length; ++i) {
var measurement = context.measureText(words[i]);
var l = Math.ceil(-measurement.actualBoundingBoxLeft);
var r = Math.ceil(measurement.actualBoundingBoxRight);
var a = Math.ceil(measurement.actualBoundingBoxAscent);
var d = Math.ceil(measurement.actualBoundingBoxDescent);
var w = l + r;
var h = a + d;
if (x + w >= canvas.width) {
x = padding;
y += 16;
}
context.fillStyle = words[i].length === 1 ? "rgb(255, 255, 255)" : "rgb(150, 150, 150)";
context.fillText(words[i], x - l, y + a);
placements.push({
l: l, r: r, a: a, d: d,
x: x, y: y, w: w, h: h
});
x += w + padding;
}
var wordMap = { };
words.forEach(function (w, i) {
wordMap[w] = i;
});
this.words = words;
this.wordMap = wordMap;
this.placements = placements;
this.texture = texture;
var source = context.getImageData(0, 0, canvas.width, canvas.height);
var dest = texture.lock();
var red, alpha;
for (y = 0; y < source.height; ++y) {
for (x = 0; x < source.width; ++x) {
var offset = (x + y * texture.width) * 4;
dest[offset] = 255;
dest[offset + 1] = 255;
dest[offset + 2] = 255;
red = source.data[(x + (source.height - 1 - y) * source.width) * 4];
alpha = source.data[(x + (source.height - 1 - y) * source.width) * 4 + 3];
dest[offset + 3] = alpha * (red > 150 ? 1 : 0.7);
}
}
}
Object.assign(WordAtlas.prototype, {
render: function (render2d, word, x, y) {
var p = this.placements[this.wordMap[word]];
if (p) {
var padding = 1;
render2d.quad(this.texture,
x + p.l - padding,
y - p.d + padding,
p.w + padding * 2,
p.h + padding * 2,
p.x - padding,
64 - p.y - p.h - padding,
undefined, undefined,
true);
return p.w;
}
return 0;
}
});
function Render2d(device, colors, maxQuads) {
maxQuads = maxQuads || 512;
var vertexShader =
'attribute vec3 vertex_position;\n' +
'attribute vec4 vertex_texCoord0;\n' +
'uniform vec4 screenAndTextureSize;\n' +
'varying vec4 uv0;\n' +
'varying float enabled;\n' +
'void main(void) {\n' +
' vec2 pos = vertex_position.xy / screenAndTextureSize.xy;\n' +
' gl_Position = vec4(pos * 2.0 - 1.0, 0.5, 1.0);\n' +
' uv0 = vec4(vertex_texCoord0.xy / screenAndTextureSize.zw, vertex_texCoord0.zw);\n' +
' enabled = vertex_position.z;\n' +
'}\n';
var fragmentShader =
'varying vec4 uv0;\n' +
'varying float enabled;\n' +
'uniform vec4 clr;\n' +
'uniform vec4 col0;\n' +
'uniform vec4 col1;\n' +
'uniform vec4 col2;\n' +
'uniform vec4 watermark;\n' +
'uniform float watermarkSize;\n' +
'uniform vec4 background;\n' +
'uniform sampler2D source;\n' +
'void main (void) {\n' +
' vec4 tex = texture2D(source, uv0.xy);\n' +
' if (!(tex.rgb == vec3(1.0, 1.0, 1.0))) {\n' +
' if (enabled < 0.5)\n' +
' tex = background;\n' +
' else if (abs(uv0.w - tex.a) < watermarkSize)\n' +
' tex = watermark;\n' +
' else if (uv0.w < tex.r)\n' +
' tex = col0;\n' +
' else if (uv0.w < tex.g)\n' +
' tex = col1;\n' +
' else if (uv0.w < tex.b)\n' +
' tex = col2;\n' +
' else\n' +
' tex = background;\n' +
' }\n' +
' gl_FragColor = tex * clr;\n' +
'}\n';
var format = new pc.VertexFormat(device, [{
semantic: pc.SEMANTIC_POSITION,
components: 3,
type: pc.TYPE_FLOAT32
}, {
semantic: pc.SEMANTIC_TEXCOORD0,
components: 4,
type: pc.TYPE_FLOAT32
}]);
var indices = new Uint16Array(maxQuads * 6);
for (var i = 0; i < maxQuads; ++i) {
indices[i * 6 + 0] = i * 4;
indices[i * 6 + 1] = i * 4 + 1;
indices[i * 6 + 2] = i * 4 + 2;
indices[i * 6 + 3] = i * 4;
indices[i * 6 + 4] = i * 4 + 2;
indices[i * 6 + 5] = i * 4 + 3;
}
this.device = device;
this.shader = pc.shaderChunks.createShaderFromCode(device,
vertexShader,
fragmentShader,
"mini-stats");
this.buffer = new pc.VertexBuffer(device, format, maxQuads * 4, pc.BUFFER_STREAM);
this.data = new Float32Array(this.buffer.numBytes / 4);
this.indexBuffer = new pc.IndexBuffer(device, pc.INDEXFORMAT_UINT16, maxQuads * 6, pc.BUFFER_STATIC, indices);
this.prims = [];
this.prim = null;
this.primIndex = -1;
this.quads = 0;
var setupColor = function (name, value) {
this[name] = new Float32Array([value.r, value.g, value.b, value.a]);
this[name + "Id"] = device.scope.resolve(name);
}.bind(this);
setupColor("col0", colors.graph0);
setupColor("col1", colors.graph1);
setupColor("col2", colors.graph2);
setupColor("watermark", colors.watermark);
setupColor("background", colors.background);
this.watermarkSizeId = device.scope.resolve('watermarkSize');
this.clrId = device.scope.resolve('clr');
this.clr = new Float32Array(4);
this.screenTextureSizeId = device.scope.resolve('screenAndTextureSize');
this.screenTextureSize = new Float32Array(4);
}
Object.assign(Render2d.prototype, {
quad: function (texture, x, y, w, h, u, v, uw, uh, enabled) {
var quad = this.quads++;
var prim = this.prim;
if (prim && prim.texture === texture) {
prim.count += 6;
} else {
this.primIndex++;
if (this.primIndex === this.prims.length) {
prim = {
type: pc.PRIMITIVE_TRIANGLES,
indexed: true,
base: quad * 6,
count: 6,
texture: texture
};
this.prims.push(prim);
} else {
prim = this.prims[this.primIndex];
prim.base = quad * 6;
prim.count = 6;
prim.texture = texture;
}
this.prim = prim;
}
var x1 = x + w;
var y1 = y + h;
var u1 = u + (uw === undefined ? w : uw);
var v1 = v + (uh === undefined ? h : uh);
var colorize = enabled ? 1 : 0;
this.data.set([
x, y, colorize, u, v, 0, 0,
x1, y, colorize, u1, v, 1, 0,
x1, y1, colorize, u1, v1, 1, 1,
x, y1, colorize, u, v1, 0, 1
], 4 * 7 * quad);
},
render: function (clr, height) {
var device = this.device;
var buffer = this.buffer;
buffer.setData(this.data.buffer);
device.updateBegin();
device.setDepthTest(false);
device.setDepthWrite(false);
device.setCullMode(pc.CULLFACE_NONE);
device.setBlending(true);
device.setBlendFunctionSeparate(pc.BLENDMODE_SRC_ALPHA,
pc.BLENDMODE_ONE_MINUS_SRC_ALPHA,
pc.BLENDMODE_ONE,
pc.BLENDMODE_ONE);
device.setBlendEquationSeparate(pc.BLENDEQUATION_ADD, pc.BLENDEQUATION_ADD);
device.setVertexBuffer(buffer, 0);
device.setIndexBuffer(this.indexBuffer);
device.setShader(this.shader);
var pr = Math.min(device.maxPixelRatio, window.devicePixelRatio);
this.clr.set(clr, 0);
this.clrId.setValue(this.clr);
this.screenTextureSize[0] = device.width / pr;
this.screenTextureSize[1] = device.height / pr;
this.col0Id.setValue(this.col0);
this.col1Id.setValue(this.col1);
this.col2Id.setValue(this.col2);
this.watermarkId.setValue(this.watermark);
this.backgroundId.setValue(this.background);
for (var i = 0; i <= this.primIndex; ++i) {
var prim = this.prims[i];
this.screenTextureSize[2] = prim.texture.width;
this.screenTextureSize[3] = prim.texture.height;
this.screenTextureSizeId.setValue(this.screenTextureSize);
device.constantTexSource.setValue(prim.texture);
this.watermarkSizeId.setValue(0.5 / height);
device.draw(prim);
}
device.updateEnd();
this.prim = null;
this.primIndex = -1;
this.quads = 0;
}
});
var math = {
DEG_TO_RAD: Math.PI / 180,
RAD_TO_DEG: 180 / Math.PI,
clamp: function (value, min, max) {
if (value >= max) return max;
if (value <= min) return min;
return value;
},
intToBytes24: function (i) {
var r, g, b;
r = (i >> 16) & 0xff;
g = (i >> 8) & 0xff;
b = (i) & 0xff;
return [r, g, b];
},
intToBytes32: function (i) {
var r, g, b, a;
r = (i >> 24) & 0xff;
g = (i >> 16) & 0xff;
b = (i >> 8) & 0xff;
a = (i) & 0xff;
return [r, g, b, a];
},
bytesToInt24: function (r, g, b) {
if (r.length) {
b = r[2];
g = r[1];
r = r[0];
}
return ((r << 16) | (g << 8) | b);
},
bytesToInt32: function (r, g, b, a) {
if (r.length) {
a = r[3];
b = r[2];
g = r[1];
r = r[0];
}
return ((r << 24) | (g << 16) | (b << 8) | a) >>> 32;
},
lerp: function (a, b, alpha) {
return a + (b - a) * math.clamp(alpha, 0, 1);
},
lerpAngle: function (a, b, alpha) {
if (b - a > 180 ) {
b -= 360;
}
if (b - a < -180 ) {
b += 360;
}
return math.lerp(a, b, math.clamp(alpha, 0, 1));
},
powerOfTwo: function (x) {
return ((x !== 0) && !(x & (x - 1)));
},
nextPowerOfTwo: function (val) {
val--;
val |= (val >> 1);
val |= (val >> 2);
val |= (val >> 4);
val |= (val >> 8);
val |= (val >> 16);
val++;
return val;
},
random: function (min, max) {
var diff = max - min;
return Math.random() * diff + min;
},
smoothstep: function (min, max, x) {
if (x <= min) return 0;
if (x >= max) return 1;
x = (x - min) / (max - min);
return x * x * (3 - 2 * x);
},
smootherstep: function (min, max, x) {
if (x <= min) return 0;
if (x >= max) return 1;
x = (x - min) / (max - min);
return x * x * x * (x * (x * 6 - 15) + 10);
},
roundUp: function (numToRound, multiple) {
if (multiple === 0)
return numToRound;
return Math.ceil(numToRound / multiple) * multiple;
},
float2Half: (function () {
var floatView = new Float32Array(1);
var int32View = new Int32Array(floatView.buffer);
return function (val) {
floatView[0] = val;
var x = int32View[0];
var bits = (x >> 16) & 0x8000;
var m = (x >> 12) & 0x07ff;
var e = (x >> 23) & 0xff;
if (e < 103) {
return bits;
}
if (e > 142) {
bits |= 0x7c00;
bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff);
return bits;
}
if (e < 113) {
m |= 0x0800;
bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
return bits;
}
bits |= ((e - 112) << 10) | (m >> 1);
bits += m & 1;
return bits;
};
}())
};
function Color(r, g, b, a) {
var length = r && r.length;
if (length === 3 || length === 4) {
this.r = r[0];
this.g = r[1];
this.b = r[2];
this.a = r[3] !== undefined ? r[3] : 1;
} else {
this.r = r || 0;
this.g = g || 0;
this.b = b || 0;
this.a = a !== undefined ? a : 1;
}
}
Object.assign(Color.prototype, {
clone: function () {
return new Color(this.r, this.g, this.b, this.a);
},
copy: function (rhs) {
this.r = rhs.r;
this.g = rhs.g;
this.b = rhs.b;
this.a = rhs.a;
return this;
},
equals: function (rhs) {
return this.r === rhs.r && this.g === rhs.g && this.b === rhs.b && this.a === rhs.a;
},
set: function (r, g, b, a) {
this.r = r;
this.g = g;
this.b = b;
this.a = (a === undefined) ? 1 : a;
return this;
},
lerp: function (lhs, rhs, alpha) {
this.r = lhs.r + alpha * (rhs.r - lhs.r);
this.g = lhs.g + alpha * (rhs.g - lhs.g);
this.b = lhs.b + alpha * (rhs.b - lhs.b);
this.a = lhs.a + alpha * (rhs.a - lhs.a);
return this;
},
fromString: function (hex) {
var i = parseInt(hex.replace('#', '0x'), 16);
var bytes;
if (hex.length > 7) {
bytes = math.intToBytes32(i);
} else {
bytes = math.intToBytes24(i);
bytes[3] = 255;
}
this.set(bytes[0] / 255, bytes[1] / 255, bytes[2] / 255, bytes[3] / 255);
return this;
},
toString: function (alpha) {
var s = "#" + ((1 << 24) + (Math.round(this.r * 255) << 16) + (Math.round(this.g * 255) << 8) + Math.round(this.b * 255)).toString(16).slice(1);
if (alpha === true) {
var a = Math.round(this.a * 255).toString(16);
if (this.a < 16 / 255) {
s += '0' + a;
} else {
s += a;
}
}
return s;
}
});
Object.defineProperties(Color, {
BLACK: { value: new Color(0, 0, 0, 1) },
WHITE: { value: new Color(1, 1, 1, 1) },
YELLOW: { value: new Color(1, 1, 0, 1) },
RED: { value: new Color(1, 0, 0, 1) },
MAGENTA: { value: new Color(1, 0, 1, 1) },
GREEN: { value: new Color(0, 1, 0, 1) },
GRAY: { value: new Color(0.5, 0.5, 0.5, 1) },
CYAN: { value: new Color(0, 1, 1, 1) },
BLUE: { value: new Color(0, 0, 1, 1) }
});
Object.freeze(Color.BLACK);
Object.freeze(Color.WHITE);
Object.freeze(Color.YELLOW);
Object.freeze(Color.RED);
Object.freeze(Color.MAGENTA);
Object.freeze(Color.GREEN);
Object.freeze(Color.GRAY);
Object.freeze(Color.CYAN);
Object.freeze(Color.BLUE);
function MiniStats(app, options) {
var device = app.graphicsDevice;
options = options || MiniStats.getDefaultOptions();
var graphs = this.initGraphs(app, device, options);
var words = ["", "ms", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."];
graphs.forEach(function (graph) {
words.push(graph.name);
});
if (options.stats) {
options.stats.forEach(function (stat) {
if (stat.unitsName)
words.push(stat.unitsName);
});
}
words = words.filter(function (item, index) {
return words.indexOf(item) >= index;
});
var maxWidth = options.sizes.reduce(function (max, v) {
return v.width > max ? v.width : max;
}, 0);
var wordAtlasData = this.initWordAtlas(device, words, maxWidth, graphs.length);
var texture = wordAtlasData.texture;
graphs.forEach(function (graph, i) {
graph.texture = texture;
graph.yOffset = i;
});
this.sizes = options.sizes;
this._activeSizeIndex = options.startSizeIndex;
var self = this;
var div = document.createElement('div');
div.style.cssText = 'position:fixed;bottom:0;left:0;background:transparent;';
document.body.appendChild(div);
div.addEventListener('mouseenter', function (event) {
self.opacity = 1.0;
});
div.addEventListener('mouseleave', function (event) {
self.opacity = 0.5;
});
div.addEventListener('click', function (event) {
event.preventDefault();
if (self._enabled) {
self.activeSizeIndex = (self.activeSizeIndex + 1) % self.sizes.length;
self.resize(self.sizes[self.activeSizeIndex].width, self.sizes[self.activeSizeIndex].height, self.sizes[self.activeSizeIndex].graphs);
}
});
device.on("resizecanvas", function () {
self.updateDiv();
});
app.on('postrender', function () {
if (self._enabled) {
self.render();
}
});
this.device = device;
this.texture = texture;
this.wordAtlas = wordAtlasData.atlas;
this.render2d = new Render2d(device, options.colors);
this.graphs = graphs;
this.div = div;
this.width = 0;
this.height = 0;
this.gspacing = 2;
this.clr = [1, 1, 1, 0.5];
this._enabled = true;
this.activeSizeIndex = this._activeSizeIndex;
}
MiniStats.getDefaultOptions = function () {
return {
sizes: [
{ width: 100, height: 16, spacing: 0, graphs: false },
{ width: 128, height: 32, spacing: 2, graphs: true },
{ width: 256, height: 64, spacing: 2, graphs: true }
],
startSizeIndex: 0,
textRefreshRate: 500,
colors: {
graph0: new Color(0.7, 0.2, 0.2, 1),
graph1: new Color(0.2, 0.7, 0.2, 1),
graph2: new Color(0.2, 0.2, 0.7, 1),
watermark: new Color(0.4, 0.4, 0.2, 1),
background: new Color(0, 0, 0, 1.0)
},
cpu: {
enabled: true,
watermark: 33
},
gpu: {
enabled: true,
watermark: 33
},
stats: [
{
name: "Frame",
stats: ["frame.ms"],
decimalPlaces: 1,
unitsName: "ms",
watermark: 33
},
{
name: "DrawCalls",
stats: ["drawCalls.total"],
watermark: 1000
}
]
};
};
Object.defineProperties(MiniStats.prototype, {
activeSizeIndex: {
get: function () {
return this._activeSizeIndex;
},
set: function (value) {
this._activeSizeIndex = value;
this.gspacing = this.sizes[value].spacing;
this.resize(this.sizes[value].width, this.sizes[value].height, this.sizes[value].graphs);
}
},
opacity: {
get: function () {
return this.clr[3];
},
set: function (value) {
this.clr[3] = value;
}
},
overallHeight: {
get: function () {
var graphs = this.graphs;
var spacing = this.gspacing;
return this.height * graphs.length + spacing * (graphs.length - 1);
}
},
enabled: {
get: function () {
return this._enabled;
},
set: function (value) {
if (value !== this._enabled) {
this._enabled = value;
for (var i = 0; i < this.graphs.length; ++i) {
this.graphs[i].enabled = value;
this.graphs[i].timer.enabled = value;
}
}
}
}
});
Object.assign(MiniStats.prototype, {
initWordAtlas: function (device, words, maxWidth, numGraphs) {
var texture = new pc.Texture(device, {
name: 'mini-stats',
width: math.nextPowerOfTwo(maxWidth),
height: 64,
mipmaps: false,
minFilter: pc.FILTER_NEAREST,
magFilter: pc.FILTER_NEAREST
});
var wordAtlas = new WordAtlas(texture, words);
var dest = texture.lock();
for (var i = 0; i < texture.width * numGraphs; ++i) {
dest.set([0, 0, 0, 255], i * 4);
}
texture.unlock();
device.setTexture(texture, 0);
return { atlas: wordAtlas, texture: texture };
},
initGraphs: function (app, device, options) {
var graphs = [];
if (options.cpu.enabled) {
graphs.push(new Graph('CPU', app, options.cpu.watermark, options.textRefreshRate, new CpuTimer(app)));
}
if (options.gpu.enabled && device.extDisjointTimerQuery) {
graphs.push(new Graph('GPU', app, options.gpu.watermark, options.textRefreshRate, new GpuTimer(app)));
}
if (options.stats) {
options.stats.forEach(function (entry) {
graphs.push(new Graph(entry.name, app, entry.watermark, options.textRefreshRate, new StatsTimer(app, entry.stats, entry.decimalPlaces, entry.unitsName, entry.multiplier)));
});
}
return graphs;
},
render: function () {
var graphs = this.graphs;
var wordAtlas = this.wordAtlas;
var render2d = this.render2d;
var width = this.width;
var height = this.height;
var gspacing = this.gspacing;
var i, j, x, y, graph;
for (i = 0; i < graphs.length; ++i) {
graph = graphs[i];
y = i * (height + gspacing);
graph.render(render2d, 0, y, width, height);
x = 1;
y += height - 13;
x += wordAtlas.render(render2d, graph.name, x, y) + 10;
var timingText = graph.timingText;
for (j = 0; j < timingText.length; ++j) {
x += wordAtlas.render(render2d, timingText[j], x, y);
}
if (graph.timer.unitsName) {
x += 3;
wordAtlas.render(render2d, graph.timer.unitsName, x, y);
}
}
render2d.render(this.clr, height);
},
resize: function (width, height, showGraphs) {
var graphs = this.graphs;
for (var i = 0; i < graphs.length; ++i) {
graphs[i].enabled = showGraphs;
}
this.width = width;
this.height = height;
this.updateDiv();
},
updateDiv: function () {
var rect = this.device.canvas.getBoundingClientRect();
this.div.style.left = rect.left + "px";
this.div.style.bottom = (window.innerHeight - rect.bottom) + "px";
this.div.style.width = this.width + "px";
this.div.style.height = this.overallHeight + "px";
}
});
exports.MiniStats = MiniStats;
Object.defineProperty(exports, '__esModule', { value: true });
})));