1 | const twgl = require('twgl.js');
|
2 |
|
3 | const Skin = require('./Skin');
|
4 |
|
5 | class BitmapSkin extends Skin {
|
6 | /**
|
7 | * Create a new Bitmap Skin.
|
8 | * @extends Skin
|
9 | * @param {!int} id - The ID for this Skin.
|
10 | * @param {!RenderWebGL} renderer - The renderer which will use this skin.
|
11 | */
|
12 | constructor (id, renderer) {
|
13 | super(id);
|
14 |
|
15 | /** @type {!int} */
|
16 | this._costumeResolution = 1;
|
17 |
|
18 | /** @type {!RenderWebGL} */
|
19 | this._renderer = renderer;
|
20 |
|
21 | /** @type {Array<int>} */
|
22 | this._textureSize = [0, 0];
|
23 | }
|
24 |
|
25 | /**
|
26 | * Dispose of this object. Do not use it after calling this method.
|
27 | */
|
28 | dispose () {
|
29 | if (this._texture) {
|
30 | this._renderer.gl.deleteTexture(this._texture);
|
31 | this._texture = null;
|
32 | }
|
33 | super.dispose();
|
34 | }
|
35 |
|
36 | /**
|
37 | * @returns {boolean} true for a raster-style skin (like a BitmapSkin), false for vector-style (like SVGSkin).
|
38 | */
|
39 | get isRaster () {
|
40 | return true;
|
41 | }
|
42 |
|
43 | /**
|
44 | * @return {Array<number>} the "native" size, in texels, of this skin.
|
45 | */
|
46 | get size () {
|
47 | return [this._textureSize[0] / this._costumeResolution, this._textureSize[1] / this._costumeResolution];
|
48 | }
|
49 |
|
50 | /**
|
51 | * @param {Array<number>} scale - The scaling factors to be used.
|
52 | * @return {WebGLTexture} The GL texture representation of this skin when drawing at the given scale.
|
53 | */
|
54 | // eslint-disable-next-line no-unused-vars
|
55 | getTexture (scale) {
|
56 | return this._texture || super.getTexture();
|
57 | }
|
58 |
|
59 | /**
|
60 | * Set the contents of this skin to a snapshot of the provided bitmap data.
|
61 | * @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} bitmapData - new contents for this skin.
|
62 | * @param {int} [costumeResolution=1] - The resolution to use for this bitmap.
|
63 | * @param {Array<number>} [rotationCenter] - Optional rotation center for the bitmap. If not supplied, it will be
|
64 | * calculated from the bounding box
|
65 | * @fires Skin.event:WasAltered
|
66 | */
|
67 | setBitmap (bitmapData, costumeResolution, rotationCenter) {
|
68 | if (!bitmapData.width || !bitmapData.height) {
|
69 | super.setEmptyImageData();
|
70 | return;
|
71 | }
|
72 | const gl = this._renderer.gl;
|
73 |
|
74 | // Preferably bitmapData is ImageData. ImageData speeds up updating
|
75 | // Silhouette and is better handled by more browsers in regards to
|
76 | // memory.
|
77 | let textureData = bitmapData;
|
78 | if (bitmapData instanceof HTMLCanvasElement) {
|
79 | // Given a HTMLCanvasElement get the image data to pass to webgl and
|
80 | // Silhouette.
|
81 | const context = bitmapData.getContext('2d');
|
82 | textureData = context.getImageData(0, 0, bitmapData.width, bitmapData.height);
|
83 | }
|
84 |
|
85 | if (this._texture === null) {
|
86 | const textureOptions = {
|
87 | auto: false,
|
88 | wrap: gl.CLAMP_TO_EDGE
|
89 | };
|
90 |
|
91 | this._texture = twgl.createTexture(gl, textureOptions);
|
92 | }
|
93 |
|
94 | this._setTexture(textureData);
|
95 |
|
96 | // Do these last in case any of the above throws an exception
|
97 | this._costumeResolution = costumeResolution || 2;
|
98 | this._textureSize = BitmapSkin._getBitmapSize(bitmapData);
|
99 |
|
100 | if (typeof rotationCenter === 'undefined') rotationCenter = this.calculateRotationCenter();
|
101 | this._rotationCenter[0] = rotationCenter[0];
|
102 | this._rotationCenter[1] = rotationCenter[1];
|
103 |
|
104 | this.emit(Skin.Events.WasAltered);
|
105 | }
|
106 |
|
107 | /**
|
108 | * @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} bitmapData - bitmap data to inspect.
|
109 | * @returns {Array<int>} the width and height of the bitmap data, in pixels.
|
110 | * @private
|
111 | */
|
112 | static _getBitmapSize (bitmapData) {
|
113 | if (bitmapData instanceof HTMLImageElement) {
|
114 | return [bitmapData.naturalWidth || bitmapData.width, bitmapData.naturalHeight || bitmapData.height];
|
115 | }
|
116 |
|
117 | if (bitmapData instanceof HTMLVideoElement) {
|
118 | return [bitmapData.videoWidth || bitmapData.width, bitmapData.videoHeight || bitmapData.height];
|
119 | }
|
120 |
|
121 | // ImageData or HTMLCanvasElement
|
122 | return [bitmapData.width, bitmapData.height];
|
123 | }
|
124 |
|
125 | }
|
126 |
|
127 | module.exports = BitmapSkin;
|