@woosh/meep-engine 2.39.0 → 2.39.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/bvh2/{traversal/__detailed_box_volume_intersection.js → aabb3/aabb3_detailed_volume_intersection.js} +47 -27
- package/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +13 -0
- package/core/bvh2/traversal/ThreeClippingPlaneComputingBVHVisitor.js +5 -3
- package/core/bvh2/traversal/__process_point_if_within_planes.js +1 -0
- package/core/bvh2/traversal/aabb3_detailed_volume_intersection_callback_based.js +60 -0
- package/core/geom/3d/plane/is_point_within_planes.js +46 -0
- package/editor/actions/concrete/ActionUpdateTexture.js +21 -0
- package/editor/actions/concrete/ArrayCopyAction.js +39 -0
- package/editor/actions/concrete/ModifyPatchTextureArray2DAction.js +182 -0
- package/editor/enableEditor.js +30 -2
- package/editor/tools/paint/TerrainPaintTool.js +19 -3
- package/editor/tools/paint/TerrainTexturePaintTool.js +19 -57
- package/editor/tools/paint/prototypeTerrainEditor.js +67 -0
- package/editor/view/ecs/ComponentControlView.js +105 -10
- package/editor/view/ecs/EntityEditor.js +1 -1
- package/engine/ecs/fow/FogOfWarSystem.js +6 -3
- package/engine/ecs/terrain/ecs/Terrain.js +57 -47
- package/engine/ecs/terrain/ecs/layers/TerrainLayer.js +16 -2
- package/engine/ecs/terrain/ecs/layers/TerrainLayers.js +17 -0
- package/engine/ecs/terrain/ecs/splat/SplatMapping.js +24 -78
- package/engine/ecs/terrain/ecs/splat/loadLegacyTerrainSplats.js +73 -0
- package/engine/graphics/camera/camera_compute_distance_to_fit_length.d.ts +1 -0
- package/engine/graphics/camera/camera_compute_distance_to_fit_length.js +16 -0
- package/engine/graphics/camera/testClippingPlaneComputation.js +7 -4
- package/engine/graphics/ecs/camera/Camera.js +2 -2
- package/engine/graphics/ecs/camera/CameraClippingPlaneComputer.js +5 -8
- package/engine/graphics/ecs/camera/CameraSystem.js +18 -184
- package/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.js +32 -0
- package/engine/graphics/ecs/camera/build_three_camera_object.js +29 -0
- package/engine/graphics/ecs/camera/compute_perspective_camera_focal_position.js +27 -0
- package/engine/graphics/ecs/camera/frustum_from_camera.js +20 -0
- package/engine/graphics/ecs/camera/is_valid_distance_value.js +11 -0
- package/engine/graphics/ecs/camera/set_camera_aspect_ratio.js +46 -0
- package/engine/graphics/ecs/camera/update_camera_transform.js +17 -0
- package/engine/graphics/ecs/path/testPathDisplaySystem.js +26 -14
- package/engine/graphics/ecs/path/tube/BasicMaterialDefinition.d.ts +3 -0
- package/engine/graphics/ecs/path/tube/BasicMaterialDefinition.js +8 -0
- package/engine/graphics/ecs/path/tube/StandardMaterialDefinition.js +9 -0
- package/engine/graphics/ecs/path/tube/TubeMaterialType.d.ts +1 -0
- package/engine/graphics/ecs/path/tube/TubeMaterialType.js +1 -0
- package/engine/graphics/ecs/path/tube/TubePathStyle.js +10 -1
- package/engine/graphics/ecs/path/tube/build/TubePathBuilder.js +39 -107
- package/engine/graphics/ecs/path/tube/build/compute_smooth_profile_normals.js +41 -0
- package/engine/graphics/ecs/path/tube/build/fix_shape_normal_order.js +45 -0
- package/engine/graphics/{Utils.js → makeModelView.js} +1 -10
- package/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +2 -2
- package/engine/graphics/render/forward_plus/LightManager.js +2 -2
- package/engine/graphics/render/view/CameraView.js +2 -2
- package/engine/graphics/texture/sampler/Sampler2D.js +1293 -1267
- package/engine/graphics/texture/texture_array_2d_copy.js +45 -0
- package/engine/graphics/util/makeMeshPreviewScene.js +2 -2
- package/package.json +1 -1
- package/view/renderModel.js +1 -1
- package/view/string_tag_to_css_class_name.js +12 -0
- package/engine/graphics/util/computeMeshPreviewCameraDistance.js +0 -10
|
@@ -10,1651 +10,1677 @@ import { mix } from "../../../../core/math/mix.js";
|
|
|
10
10
|
import { BlendingType } from "./BlendingType.js";
|
|
11
11
|
import { assert } from "../../../../core/assert.js";
|
|
12
12
|
import { typedArrayConstructorByInstance } from "./typedArrayConstructorByInstance.js";
|
|
13
|
-
|
|
13
|
+
import { typedArrayToDataType } from "../../../../core/collection/array/typedArrayToDataType.js";
|
|
14
|
+
import {
|
|
15
|
+
compute_typed_array_constructor_from_data_type
|
|
16
|
+
} from "../../../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
|
-
*
|
|
17
|
-
* @param {ArrayLike<number>|number[]|Uint8ClampedArray|Uint8Array|Uint16Array|Uint32Array|Int8Array|Int16Array|Int32Array|Float32Array|Float64Array} data
|
|
18
|
-
* @param {int} itemSize
|
|
19
|
-
* @param {int} width
|
|
20
|
-
* @param {int} height
|
|
21
|
-
* @constructor
|
|
19
|
+
* @class
|
|
22
20
|
*/
|
|
23
|
-
export
|
|
24
|
-
if (!Number.isInteger(itemSize)) {
|
|
25
|
-
throw new Error(`itemSize must be integer, instead was ${itemSize}`);
|
|
26
|
-
}
|
|
27
|
-
if (!Number.isInteger(width)) {
|
|
28
|
-
throw new Error(`width must be integer, instead was ${width}`);
|
|
29
|
-
}
|
|
30
|
-
if (!Number.isInteger(height)) {
|
|
31
|
-
throw new Error(`height must be integer, instead was ${height}`);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (data === undefined) {
|
|
35
|
-
throw new Error("data was undefined");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
*
|
|
40
|
-
* @type {Number}
|
|
41
|
-
*/
|
|
42
|
-
this.width = width;
|
|
43
|
-
|
|
21
|
+
export class Sampler2D {
|
|
44
22
|
/**
|
|
45
23
|
*
|
|
46
|
-
* @
|
|
24
|
+
* @param {ArrayLike<number>|number[]|Uint8ClampedArray|Uint8Array|Uint16Array|Uint32Array|Int8Array|Int16Array|Int32Array|Float32Array|Float64Array} data
|
|
25
|
+
* @param {int} itemSize
|
|
26
|
+
* @param {int} width
|
|
27
|
+
* @param {int} height
|
|
28
|
+
* @constructor
|
|
47
29
|
*/
|
|
48
|
-
|
|
30
|
+
constructor(data = [], itemSize = 1, width = 0, height = 0) {
|
|
31
|
+
if (!Number.isInteger(itemSize)) {
|
|
32
|
+
throw new Error(`itemSize must be integer, instead was ${itemSize}`);
|
|
33
|
+
}
|
|
34
|
+
if (!Number.isInteger(width)) {
|
|
35
|
+
throw new Error(`width must be integer, instead was ${width}`);
|
|
36
|
+
}
|
|
37
|
+
if (!Number.isInteger(height)) {
|
|
38
|
+
throw new Error(`height must be integer, instead was ${height}`);
|
|
39
|
+
}
|
|
49
40
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
*/
|
|
54
|
-
this.itemSize = itemSize;
|
|
41
|
+
if (data === undefined) {
|
|
42
|
+
throw new Error("data was undefined");
|
|
43
|
+
}
|
|
55
44
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
* @type {Number}
|
|
48
|
+
*/
|
|
49
|
+
this.width = width;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
*
|
|
53
|
+
* @type {Number}
|
|
54
|
+
*/
|
|
55
|
+
this.height = height;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Number of channels
|
|
59
|
+
* @type {Number}
|
|
60
|
+
*/
|
|
61
|
+
this.itemSize = itemSize;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
*
|
|
65
|
+
* @type {number[]|Uint8ClampedArray|Uint8Array|Uint16Array|Uint32Array|Int8Array|Int16Array|Int32Array|Float32Array|Float64Array}
|
|
66
|
+
*/
|
|
67
|
+
this.data = data;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Used to tracking changes
|
|
71
|
+
* @type {number}
|
|
72
|
+
*/
|
|
73
|
+
this.version = 0;
|
|
74
|
+
/**
|
|
75
|
+
* @readonly
|
|
76
|
+
* @type {boolean}
|
|
77
|
+
*/
|
|
78
|
+
this.isSampler2D = true;
|
|
79
|
+
}
|
|
61
80
|
|
|
62
81
|
/**
|
|
63
|
-
*
|
|
64
|
-
* @
|
|
82
|
+
* @param {number} [channel=0]
|
|
83
|
+
* @returns {{x: number, index: number, y: number, value: number}}
|
|
65
84
|
*/
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
*
|
|
71
|
-
* @param {int} itemSize
|
|
72
|
-
* @param {int} width
|
|
73
|
-
* @param {int} height
|
|
74
|
-
* @return {Sampler2D}
|
|
75
|
-
*/
|
|
76
|
-
Sampler2D.uint8clamped = function (itemSize, width, height) {
|
|
77
|
-
const data = new Uint8ClampedArray(width * height * itemSize);
|
|
78
|
-
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
79
|
-
return sampler;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
*
|
|
84
|
-
* @param {int} itemSize
|
|
85
|
-
* @param {int} width
|
|
86
|
-
* @param {int} height
|
|
87
|
-
* @return {Sampler2D}
|
|
88
|
-
*/
|
|
89
|
-
Sampler2D.uint8 = function (itemSize, width, height) {
|
|
90
|
-
const data = new Uint8Array(width * height * itemSize);
|
|
91
|
-
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
92
|
-
return sampler;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
*
|
|
97
|
-
* @param {int} itemSize
|
|
98
|
-
* @param {int} width
|
|
99
|
-
* @param {int} height
|
|
100
|
-
* @return {Sampler2D}
|
|
101
|
-
*/
|
|
102
|
-
Sampler2D.uint16 = function (itemSize, width, height) {
|
|
103
|
-
const data = new Uint16Array(width * height * itemSize);
|
|
104
|
-
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
105
|
-
return sampler;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
*
|
|
110
|
-
* @param {int} itemSize
|
|
111
|
-
* @param {int} width
|
|
112
|
-
* @param {int} height
|
|
113
|
-
* @return {Sampler2D}
|
|
114
|
-
*/
|
|
115
|
-
Sampler2D.uint32 = function (itemSize, width, height) {
|
|
116
|
-
const data = new Uint32Array(width * height * itemSize);
|
|
117
|
-
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
118
|
-
return sampler;
|
|
119
|
-
};
|
|
85
|
+
computeMax(channel = 0) {
|
|
86
|
+
const itemSize = this.itemSize;
|
|
120
87
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
* @param {int} width
|
|
125
|
-
* @param {int} height
|
|
126
|
-
* @return {Sampler2D}
|
|
127
|
-
*/
|
|
128
|
-
Sampler2D.int8 = function (itemSize, width, height) {
|
|
129
|
-
const data = new Int8Array(width * height * itemSize);
|
|
130
|
-
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
131
|
-
return sampler;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
*
|
|
136
|
-
* @param {int} itemSize
|
|
137
|
-
* @param {int} width
|
|
138
|
-
* @param {int} height
|
|
139
|
-
* @return {Sampler2D}
|
|
140
|
-
*/
|
|
141
|
-
Sampler2D.int16 = function (itemSize, width, height) {
|
|
142
|
-
const data = new Int16Array(width * height * itemSize);
|
|
143
|
-
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
144
|
-
return sampler;
|
|
145
|
-
};
|
|
146
|
-
/**
|
|
147
|
-
*
|
|
148
|
-
* @param {int} itemSize
|
|
149
|
-
* @param {int} width
|
|
150
|
-
* @param {int} height
|
|
151
|
-
* @return {Sampler2D}
|
|
152
|
-
*/
|
|
153
|
-
Sampler2D.int32 = function (itemSize, width, height) {
|
|
154
|
-
const data = new Int32Array(width * height * itemSize);
|
|
155
|
-
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
156
|
-
return sampler;
|
|
157
|
-
};
|
|
88
|
+
assert.typeOf(channel, "number", "channel");
|
|
89
|
+
assert.ok(channel >= 0, `channel must be >= 0, was ${channel}`);
|
|
90
|
+
assert.ok(channel < itemSize, `channel must be less than itemSize(=${itemSize}), was ${channel}`);
|
|
158
91
|
|
|
159
|
-
|
|
160
|
-
*
|
|
161
|
-
* @param {int} itemSize
|
|
162
|
-
* @param {int} width
|
|
163
|
-
* @param {int} height
|
|
164
|
-
* @return {Sampler2D}
|
|
165
|
-
*/
|
|
166
|
-
Sampler2D.float32 = function (itemSize, width, height) {
|
|
167
|
-
const data = new Float32Array(width * height * itemSize);
|
|
168
|
-
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
169
|
-
return sampler;
|
|
170
|
-
};
|
|
171
|
-
/**
|
|
172
|
-
*
|
|
173
|
-
* @param {int} itemSize
|
|
174
|
-
* @param {int} width
|
|
175
|
-
* @param {int} height
|
|
176
|
-
* @return {Sampler2D}
|
|
177
|
-
*/
|
|
178
|
-
Sampler2D.float64 = function (itemSize, width, height) {
|
|
179
|
-
const data = new Float64Array(width * height * itemSize);
|
|
180
|
-
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
181
|
-
return sampler;
|
|
182
|
-
};
|
|
92
|
+
const data = this.data;
|
|
183
93
|
|
|
184
|
-
|
|
185
|
-
*
|
|
186
|
-
* @param {Sampler2D} input0
|
|
187
|
-
* @param {Sampler2D} input1
|
|
188
|
-
* @param {Sampler2D} result
|
|
189
|
-
* @param {function( value0 : number[], value1 : number[], result : number[], index : number) : void} operation
|
|
190
|
-
*/
|
|
191
|
-
Sampler2D.combine = function (input0, input1, result, operation) {
|
|
192
|
-
assert.notEqual(input0, undefined, "input0 is undefined");
|
|
193
|
-
assert.notEqual(input1, undefined, "input1 is undefined");
|
|
194
|
-
assert.notEqual(result, undefined, "result is undefined");
|
|
94
|
+
const l = data.length;
|
|
195
95
|
|
|
196
|
-
|
|
96
|
+
if (l === 0) {
|
|
97
|
+
//no data
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
197
100
|
|
|
198
|
-
|
|
199
|
-
|
|
101
|
+
let bestValue = data[channel];
|
|
102
|
+
let bestIndex = channel;
|
|
200
103
|
|
|
201
|
-
|
|
202
|
-
|
|
104
|
+
for (let i = channel + itemSize; i < l; i += itemSize) {
|
|
105
|
+
const value = data[i];
|
|
203
106
|
|
|
204
|
-
|
|
205
|
-
|
|
107
|
+
if (bestValue < value) {
|
|
108
|
+
bestValue = value;
|
|
109
|
+
bestIndex = i;
|
|
110
|
+
}
|
|
206
111
|
|
|
207
|
-
|
|
112
|
+
}
|
|
208
113
|
|
|
209
|
-
|
|
210
|
-
const arg1 = [];
|
|
211
|
-
const res = [];
|
|
114
|
+
const width = this.width;
|
|
212
115
|
|
|
213
|
-
|
|
214
|
-
const itemSize1 = input1.itemSize;
|
|
215
|
-
const itemSizeR = result.itemSize;
|
|
116
|
+
const itemIndex = (bestIndex / this.itemSize) | 0;
|
|
216
117
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const dataR = result.data;
|
|
118
|
+
const x = itemIndex % width;
|
|
119
|
+
const y = (itemIndex / width) | 0;
|
|
220
120
|
|
|
121
|
+
return {
|
|
122
|
+
index: bestIndex,
|
|
123
|
+
value: bestValue,
|
|
124
|
+
x,
|
|
125
|
+
y
|
|
126
|
+
};
|
|
127
|
+
}
|
|
221
128
|
|
|
222
|
-
|
|
129
|
+
/**
|
|
130
|
+
* @param {number[]} result
|
|
131
|
+
* @param {number} [channel=0]
|
|
132
|
+
*/
|
|
133
|
+
computeMinIndices(result, channel = 0) {
|
|
134
|
+
const itemSize = this.itemSize;
|
|
223
135
|
|
|
224
|
-
|
|
136
|
+
assert.typeOf(channel, "number", "channel");
|
|
137
|
+
assert.ok(channel >= 0, `channel must be >= 0, was ${channel}`);
|
|
138
|
+
assert.ok(channel < itemSize, `channel must be less than itemSize(=${itemSize}), was ${channel}`);
|
|
225
139
|
|
|
226
|
-
|
|
227
|
-
for (j = 0; j < itemSize0; j++) {
|
|
228
|
-
arg0[j] = data0[j + i * itemSize0];
|
|
229
|
-
}
|
|
140
|
+
assert.ok(Array.isArray(result), "result is not an array");
|
|
230
141
|
|
|
231
|
-
|
|
232
|
-
for (j = 0; j < itemSize0; j++) {
|
|
233
|
-
arg1[j] = data1[j + i * itemSize1];
|
|
234
|
-
}
|
|
142
|
+
const data = this.data;
|
|
235
143
|
|
|
236
|
-
|
|
237
|
-
operation(arg0, arg1, res, i);
|
|
144
|
+
const l = data.length;
|
|
238
145
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
146
|
+
if (l === 0) {
|
|
147
|
+
//no data
|
|
148
|
+
return undefined;
|
|
242
149
|
}
|
|
243
150
|
|
|
244
|
-
|
|
151
|
+
let bestValue = data[channel];
|
|
245
152
|
|
|
246
|
-
|
|
247
|
-
};
|
|
153
|
+
let resultCount = 0;
|
|
248
154
|
|
|
155
|
+
for (let i = channel + itemSize; i < l; i += itemSize) {
|
|
156
|
+
const value = data[i];
|
|
249
157
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
Sampler2D.prototype.computeMax = function (channel = 0) {
|
|
255
|
-
const itemSize = this.itemSize;
|
|
158
|
+
if (bestValue > value) {
|
|
159
|
+
bestValue = value;
|
|
160
|
+
//drop result
|
|
161
|
+
resultCount = 1;
|
|
256
162
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
163
|
+
result[0] = i;
|
|
164
|
+
} else if (value === bestValue) {
|
|
165
|
+
result[resultCount++] = i;
|
|
166
|
+
}
|
|
260
167
|
|
|
261
|
-
|
|
168
|
+
}
|
|
262
169
|
|
|
263
|
-
|
|
170
|
+
//crop results
|
|
171
|
+
if (resultCount < result.length) {
|
|
172
|
+
result.splice(resultCount, result.length - resultCount);
|
|
173
|
+
}
|
|
264
174
|
|
|
265
|
-
|
|
266
|
-
//no data
|
|
267
|
-
return undefined;
|
|
175
|
+
return;
|
|
268
176
|
}
|
|
269
177
|
|
|
270
|
-
|
|
271
|
-
|
|
178
|
+
/**
|
|
179
|
+
* @param {number} [channel=0]
|
|
180
|
+
* @returns {{x: number, index: number, y: number, value: number}}
|
|
181
|
+
*/
|
|
182
|
+
computeMin(channel = 0) {
|
|
183
|
+
const itemSize = this.itemSize;
|
|
272
184
|
|
|
273
|
-
|
|
274
|
-
|
|
185
|
+
assert.typeOf(channel, "number", "channel");
|
|
186
|
+
assert.ok(channel >= 0, `channel must be >= 0, was ${channel}`);
|
|
187
|
+
assert.ok(channel < itemSize, `channel must be less than itemSize(=${itemSize}), was ${channel}`);
|
|
275
188
|
|
|
276
|
-
|
|
277
|
-
bestValue = value;
|
|
278
|
-
bestIndex = i;
|
|
279
|
-
}
|
|
189
|
+
const data = this.data;
|
|
280
190
|
|
|
281
|
-
|
|
191
|
+
const l = data.length;
|
|
282
192
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
193
|
+
if (l === 0) {
|
|
194
|
+
//no data
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
286
197
|
|
|
287
|
-
|
|
288
|
-
|
|
198
|
+
let bestValue = data[channel];
|
|
199
|
+
let bestIndex = channel;
|
|
289
200
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
value: bestValue,
|
|
293
|
-
x,
|
|
294
|
-
y
|
|
295
|
-
};
|
|
296
|
-
};
|
|
201
|
+
for (let i = channel + itemSize; i < l; i += itemSize) {
|
|
202
|
+
const value = data[i];
|
|
297
203
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
Sampler2D.prototype.computeMinIndices = function (result, channel = 0) {
|
|
303
|
-
const itemSize = this.itemSize;
|
|
204
|
+
if (bestValue > value) {
|
|
205
|
+
bestValue = value;
|
|
206
|
+
bestIndex = i;
|
|
207
|
+
}
|
|
304
208
|
|
|
305
|
-
|
|
306
|
-
assert.ok(channel >= 0, `channel must be >= 0, was ${channel}`);
|
|
307
|
-
assert.ok(channel < itemSize, `channel must be less than itemSize(=${itemSize}), was ${channel}`);
|
|
209
|
+
}
|
|
308
210
|
|
|
309
|
-
|
|
211
|
+
const width = this.width;
|
|
310
212
|
|
|
311
|
-
|
|
213
|
+
const itemIndex = (bestIndex / this.itemSize) | 0;
|
|
312
214
|
|
|
313
|
-
|
|
215
|
+
const x = itemIndex % width;
|
|
216
|
+
const y = (itemIndex / width) | 0;
|
|
314
217
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
218
|
+
return {
|
|
219
|
+
index: bestIndex,
|
|
220
|
+
value: bestValue,
|
|
221
|
+
x,
|
|
222
|
+
y
|
|
223
|
+
};
|
|
318
224
|
}
|
|
319
225
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
226
|
+
/**
|
|
227
|
+
*
|
|
228
|
+
* @deprecated
|
|
229
|
+
* @param {number} x
|
|
230
|
+
* @param {number}y
|
|
231
|
+
* @param {Vector1|Vector2|Vector3|Vector4} result
|
|
232
|
+
* @returns {number}
|
|
233
|
+
*/
|
|
234
|
+
get(x, y, result) {
|
|
235
|
+
console.warn("Deprecated method, use sampleBilinear instead");
|
|
323
236
|
|
|
324
|
-
|
|
325
|
-
const value = data[i];
|
|
237
|
+
const t = [];
|
|
326
238
|
|
|
327
|
-
|
|
328
|
-
bestValue = value;
|
|
329
|
-
//drop result
|
|
330
|
-
resultCount = 1;
|
|
239
|
+
this.sampleBilinear(x, y, t, 0);
|
|
331
240
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
result
|
|
241
|
+
if (result !== undefined) {
|
|
242
|
+
result.readFromArray(t, 0);
|
|
243
|
+
return result;
|
|
244
|
+
} else {
|
|
245
|
+
return t[0];
|
|
335
246
|
}
|
|
336
|
-
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
//crop results
|
|
340
|
-
if (resultCount < result.length) {
|
|
341
|
-
result.splice(resultCount, result.length - resultCount);
|
|
342
247
|
}
|
|
343
248
|
|
|
344
|
-
|
|
345
|
-
|
|
249
|
+
/**
|
|
250
|
+
*
|
|
251
|
+
* @param {number} u
|
|
252
|
+
* @param {number} v
|
|
253
|
+
* @param {number[]} result
|
|
254
|
+
*/
|
|
255
|
+
sampleCatmullRomUV(u, v, result) {
|
|
256
|
+
const itemSize = this.itemSize;
|
|
346
257
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
Sampler2D.prototype.computeMin = function (channel = 0) {
|
|
352
|
-
const itemSize = this.itemSize;
|
|
258
|
+
for (let i = 0; i < itemSize; i++) {
|
|
259
|
+
result[i] = this.sampleChannelCatmullRomUV(u, v, i);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
353
262
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
263
|
+
/**
|
|
264
|
+
*
|
|
265
|
+
* @param {number} u
|
|
266
|
+
* @param {number} v
|
|
267
|
+
* @param {number} channel
|
|
268
|
+
* @returns {number}
|
|
269
|
+
*/
|
|
270
|
+
sampleChannelCatmullRomUV(u, v, channel) {
|
|
271
|
+
const x = u * (this.width);
|
|
272
|
+
const y = v * (this.height);
|
|
357
273
|
|
|
358
|
-
|
|
274
|
+
return this.sampleChannelCatmullRom(x - 0.5, y - 0.5, channel);
|
|
275
|
+
}
|
|
359
276
|
|
|
360
|
-
|
|
277
|
+
/**
|
|
278
|
+
*
|
|
279
|
+
* @see https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1
|
|
280
|
+
* @param {number} x
|
|
281
|
+
* @param {number} y
|
|
282
|
+
* @param {number} channel
|
|
283
|
+
* @returns {number}
|
|
284
|
+
*/
|
|
285
|
+
sampleChannelCatmullRom(x, y, channel) {
|
|
286
|
+
// We're going to sample a a 4x4 grid of texels surrounding the target UV coordinate. We'll do this by rounding
|
|
287
|
+
// down the sample location to get the exact center of our "starting" texel. The starting texel will be at
|
|
288
|
+
// location [1, 1] in the grid, where [0, 0] is the top-left corner.
|
|
289
|
+
const texPos1_x = Math.floor(x - 0.5) + 0.5;
|
|
290
|
+
const texPos1_y = Math.floor(y - 0.5) + 0.5;
|
|
291
|
+
|
|
292
|
+
// Compute the fractional offset from our starting texel to our original sample location, which we'll
|
|
293
|
+
// feed into the Catmull-Rom spline function to get our filter weights.
|
|
294
|
+
const f_x = x - texPos1_x;
|
|
295
|
+
const f_y = y - texPos1_y;
|
|
296
|
+
|
|
297
|
+
// Compute the Catmull-Rom weights using the fractional offset that we calculated earlier.
|
|
298
|
+
// These equations are pre-expanded based on our knowledge of where the texels will be located,
|
|
299
|
+
// which lets us avoid having to evaluate a piece-wise function.
|
|
300
|
+
const w0_x = f_x * (-0.5 + f_x * (1.0 - 0.5 * f_x));
|
|
301
|
+
const w0_y = f_y * (-0.5 + f_y * (1.0 - 0.5 * f_y));
|
|
302
|
+
|
|
303
|
+
const w1_x = 1.0 + f_x * f_x * (-2.5 + 1.5 * f_x);
|
|
304
|
+
const w1_y = 1.0 + f_y * f_y * (-2.5 + 1.5 * f_y);
|
|
305
|
+
|
|
306
|
+
const w2_x = f_x * (0.5 + f_x * (2.0 - 1.5 * f_x));
|
|
307
|
+
const w2_y = f_y * (0.5 + f_y * (2.0 - 1.5 * f_y));
|
|
308
|
+
|
|
309
|
+
const w3_x = f_x * f_x * (-0.5 + 0.5 * f_x);
|
|
310
|
+
const w3_y = f_y * f_y * (-0.5 + 0.5 * f_y);
|
|
311
|
+
|
|
312
|
+
// Work out weighting factors and sampling offsets that will let us use bilinear filtering to
|
|
313
|
+
// simultaneously evaluate the middle 2 samples from the 4x4 grid.
|
|
314
|
+
const w12_x = w1_x + w2_x;
|
|
315
|
+
const w12_y = w1_y + w2_y;
|
|
316
|
+
const offset12_x = w2_x / w12_x;
|
|
317
|
+
const offset12_y = w2_y / w12_y;
|
|
318
|
+
|
|
319
|
+
// Compute the final coordinates we'll use for sampling the texture
|
|
320
|
+
const texPos0_x = texPos1_x - 1;
|
|
321
|
+
const texPos0_y = texPos1_y - 1;
|
|
322
|
+
const texPos3_x = texPos1_x + 2;
|
|
323
|
+
const texPos3_y = texPos1_y + 2;
|
|
324
|
+
const texPos12_x = texPos1_x + offset12_x;
|
|
325
|
+
const texPos12_y = texPos1_y + offset12_y;
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
let result = 0.0;
|
|
329
|
+
result += this.sampleChannelBilinear(texPos0_x, texPos0_y, channel) * w0_x * w0_y;
|
|
330
|
+
result += this.sampleChannelBilinear(texPos12_x, texPos0_y, channel) * w12_x * w0_y;
|
|
331
|
+
result += this.sampleChannelBilinear(texPos3_x, texPos0_y, channel) * w3_x * w0_y;
|
|
332
|
+
|
|
333
|
+
result += this.sampleChannelBilinear(texPos0_x, texPos12_y, channel) * w0_x * w12_y;
|
|
334
|
+
result += this.sampleChannelBilinear(texPos12_x, texPos12_y, channel) * w12_x * w12_y;
|
|
335
|
+
result += this.sampleChannelBilinear(texPos3_x, texPos12_y, channel) * w3_x * w12_y;
|
|
336
|
+
|
|
337
|
+
result += this.sampleChannelBilinear(texPos0_x, texPos3_y, channel) * w0_x * w3_y;
|
|
338
|
+
result += this.sampleChannelBilinear(texPos12_x, texPos3_y, channel) * w12_x * w3_y;
|
|
339
|
+
result += this.sampleChannelBilinear(texPos3_x, texPos3_y, channel) * w3_x * w3_y;
|
|
361
340
|
|
|
362
|
-
|
|
363
|
-
//no data
|
|
364
|
-
return undefined;
|
|
341
|
+
return result;
|
|
365
342
|
}
|
|
366
343
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
344
|
+
/**
|
|
345
|
+
*
|
|
346
|
+
* @param {number} u
|
|
347
|
+
* @param {number} v
|
|
348
|
+
* @param {number[]} result
|
|
349
|
+
*/
|
|
350
|
+
sampleBicubicUV(u, v, result) {
|
|
351
|
+
const itemSize = this.itemSize;
|
|
372
352
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
bestIndex = i;
|
|
353
|
+
for (let i = 0; i < itemSize; i++) {
|
|
354
|
+
result[i] = this.sampleChannelBicubicUV(u, v, i);
|
|
376
355
|
}
|
|
377
|
-
|
|
378
356
|
}
|
|
379
357
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
358
|
+
/**
|
|
359
|
+
*
|
|
360
|
+
* @param {number} u
|
|
361
|
+
* @param {number} v
|
|
362
|
+
* @param {number} channel
|
|
363
|
+
* @returns {number}
|
|
364
|
+
*/
|
|
365
|
+
sampleChannelBicubicUV(u, v, channel) {
|
|
366
|
+
const x = u * (this.width);
|
|
367
|
+
const y = v * (this.height);
|
|
383
368
|
|
|
384
|
-
|
|
385
|
-
|
|
369
|
+
return this.sampleChannelBicubic(x - 0.5, y - 0.5, channel);
|
|
370
|
+
}
|
|
386
371
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
372
|
+
/**
|
|
373
|
+
* Bicubic-filtered sampling
|
|
374
|
+
* @param {number} x
|
|
375
|
+
* @param {number} y
|
|
376
|
+
* @param {number} channel
|
|
377
|
+
* @returns {number}
|
|
378
|
+
*/
|
|
379
|
+
sampleChannelBicubic(x, y, channel) {
|
|
394
380
|
|
|
395
|
-
|
|
396
|
-
*
|
|
397
|
-
* @deprecated
|
|
398
|
-
* @param {number} x
|
|
399
|
-
* @param {number}y
|
|
400
|
-
* @param {Vector1|Vector2|Vector3|Vector4} result
|
|
401
|
-
* @returns {number}
|
|
402
|
-
*/
|
|
403
|
-
Sampler2D.prototype.get = function (x, y, result) {
|
|
404
|
-
console.warn("Deprecated method, use sampleBilinear instead");
|
|
381
|
+
const itemSize = this.itemSize;
|
|
405
382
|
|
|
406
|
-
|
|
383
|
+
const width = this.width;
|
|
384
|
+
const height = this.height;
|
|
407
385
|
|
|
408
|
-
|
|
386
|
+
const data = this.data;
|
|
409
387
|
|
|
410
|
-
|
|
411
|
-
result.readFromArray(t, 0);
|
|
412
|
-
return result;
|
|
413
|
-
} else {
|
|
414
|
-
return t[0];
|
|
415
|
-
}
|
|
416
|
-
};
|
|
388
|
+
const rowSize = width * itemSize;
|
|
417
389
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
* @param {number} u
|
|
421
|
-
* @param {number} v
|
|
422
|
-
* @param {number[]} result
|
|
423
|
-
*/
|
|
424
|
-
Sampler2D.prototype.sampleCatmullRomUV = function (u, v, result) {
|
|
425
|
-
const itemSize = this.itemSize;
|
|
390
|
+
const x_max = width - 1;
|
|
391
|
+
const y_max = height - 1;
|
|
426
392
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
}
|
|
430
|
-
};
|
|
393
|
+
const clamped_x = clamp(x, 0, x_max)
|
|
394
|
+
const clamped_y = clamp(y, 0, y_max)
|
|
431
395
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
* @param {number} v
|
|
436
|
-
* @param {number} channel
|
|
437
|
-
* @returns {number}
|
|
438
|
-
*/
|
|
439
|
-
Sampler2D.prototype.sampleChannelCatmullRomUV = function (u, v, channel) {
|
|
440
|
-
const x = u * (this.width);
|
|
441
|
-
const y = v * (this.height);
|
|
396
|
+
// fractional texel position (from the nearest low texel)
|
|
397
|
+
const x1 = clamped_x | 0;
|
|
398
|
+
const y1 = clamped_y | 0;
|
|
442
399
|
|
|
443
|
-
|
|
444
|
-
|
|
400
|
+
const xd = clamped_x - x1;
|
|
401
|
+
const yd = clamped_y - y1;
|
|
445
402
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
* @see https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1
|
|
449
|
-
* @param {number} x
|
|
450
|
-
* @param {number} y
|
|
451
|
-
* @param {number} channel
|
|
452
|
-
* @returns {number}
|
|
453
|
-
*/
|
|
454
|
-
Sampler2D.prototype.sampleChannelCatmullRom = function (x, y, channel) {
|
|
455
|
-
// We're going to sample a a 4x4 grid of texels surrounding the target UV coordinate. We'll do this by rounding
|
|
456
|
-
// down the sample location to get the exact center of our "starting" texel. The starting texel will be at
|
|
457
|
-
// location [1, 1] in the grid, where [0, 0] is the top-left corner.
|
|
458
|
-
const texPos1_x = Math.floor(x - 0.5) + 0.5;
|
|
459
|
-
const texPos1_y = Math.floor(y - 0.5) + 0.5;
|
|
460
|
-
|
|
461
|
-
// Compute the fractional offset from our starting texel to our original sample location, which we'll
|
|
462
|
-
// feed into the Catmull-Rom spline function to get our filter weights.
|
|
463
|
-
const f_x = x - texPos1_x;
|
|
464
|
-
const f_y = y - texPos1_y;
|
|
465
|
-
|
|
466
|
-
// Compute the Catmull-Rom weights using the fractional offset that we calculated earlier.
|
|
467
|
-
// These equations are pre-expanded based on our knowledge of where the texels will be located,
|
|
468
|
-
// which lets us avoid having to evaluate a piece-wise function.
|
|
469
|
-
const w0_x = f_x * (-0.5 + f_x * (1.0 - 0.5 * f_x));
|
|
470
|
-
const w0_y = f_y * (-0.5 + f_y * (1.0 - 0.5 * f_y));
|
|
471
|
-
|
|
472
|
-
const w1_x = 1.0 + f_x * f_x * (-2.5 + 1.5 * f_x);
|
|
473
|
-
const w1_y = 1.0 + f_y * f_y * (-2.5 + 1.5 * f_y);
|
|
474
|
-
|
|
475
|
-
const w2_x = f_x * (0.5 + f_x * (2.0 - 1.5 * f_x));
|
|
476
|
-
const w2_y = f_y * (0.5 + f_y * (2.0 - 1.5 * f_y));
|
|
477
|
-
|
|
478
|
-
const w3_x = f_x * f_x * (-0.5 + 0.5 * f_x);
|
|
479
|
-
const w3_y = f_y * f_y * (-0.5 + 0.5 * f_y);
|
|
480
|
-
|
|
481
|
-
// Work out weighting factors and sampling offsets that will let us use bilinear filtering to
|
|
482
|
-
// simultaneously evaluate the middle 2 samples from the 4x4 grid.
|
|
483
|
-
const w12_x = w1_x + w2_x;
|
|
484
|
-
const w12_y = w1_y + w2_y;
|
|
485
|
-
const offset12_x = w2_x / w12_x;
|
|
486
|
-
const offset12_y = w2_y / w12_y;
|
|
487
|
-
|
|
488
|
-
// Compute the final coordinates we'll use for sampling the texture
|
|
489
|
-
const texPos0_x = texPos1_x - 1;
|
|
490
|
-
const texPos0_y = texPos1_y - 1;
|
|
491
|
-
const texPos3_x = texPos1_x + 2;
|
|
492
|
-
const texPos3_y = texPos1_y + 2;
|
|
493
|
-
const texPos12_x = texPos1_x + offset12_x;
|
|
494
|
-
const texPos12_y = texPos1_y + offset12_y;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
let result = 0.0;
|
|
498
|
-
result += this.sampleChannelBilinear(texPos0_x, texPos0_y, channel) * w0_x * w0_y;
|
|
499
|
-
result += this.sampleChannelBilinear(texPos12_x, texPos0_y, channel) * w12_x * w0_y;
|
|
500
|
-
result += this.sampleChannelBilinear(texPos3_x, texPos0_y, channel) * w3_x * w0_y;
|
|
501
|
-
|
|
502
|
-
result += this.sampleChannelBilinear(texPos0_x, texPos12_y, channel) * w0_x * w12_y;
|
|
503
|
-
result += this.sampleChannelBilinear(texPos12_x, texPos12_y, channel) * w12_x * w12_y;
|
|
504
|
-
result += this.sampleChannelBilinear(texPos3_x, texPos12_y, channel) * w3_x * w12_y;
|
|
505
|
-
|
|
506
|
-
result += this.sampleChannelBilinear(texPos0_x, texPos3_y, channel) * w0_x * w3_y;
|
|
507
|
-
result += this.sampleChannelBilinear(texPos12_x, texPos3_y, channel) * w12_x * w3_y;
|
|
508
|
-
result += this.sampleChannelBilinear(texPos3_x, texPos3_y, channel) * w3_x * w3_y;
|
|
509
|
-
|
|
510
|
-
return result;
|
|
511
|
-
}
|
|
403
|
+
const x0 = max2(0, x1 - 1);
|
|
404
|
+
const y0 = max2(0, y1 - 1);
|
|
512
405
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
* @param {number} t
|
|
516
|
-
* @param {number} a
|
|
517
|
-
* @param {number} b
|
|
518
|
-
* @param {number} c
|
|
519
|
-
* @param {number} d
|
|
520
|
-
* @returns {number}
|
|
521
|
-
*/
|
|
522
|
-
function bicubic_terp(t, a, b, c, d) {
|
|
523
|
-
return 0.5 * (c - a + (2.0 * a - 5.0 * b + 4.0 * c - d + (3.0 * (b - c) + d - a) * t) * t) * t + b;
|
|
524
|
-
}
|
|
406
|
+
const x2 = min2(x_max, x1 + 1);
|
|
407
|
+
const y2 = min2(y_max, y1 + 1);
|
|
525
408
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
* @param {number} u
|
|
529
|
-
* @param {number} v
|
|
530
|
-
* @param {number[]} result
|
|
531
|
-
*/
|
|
532
|
-
Sampler2D.prototype.sampleBicubicUV = function (u, v, result) {
|
|
533
|
-
const itemSize = this.itemSize;
|
|
409
|
+
const x3 = min2(x_max, x2 + 1);
|
|
410
|
+
const y3 = min2(y_max, y2 + 1);
|
|
534
411
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
412
|
+
// compute row offsets
|
|
413
|
+
const row0 = y0 * rowSize;
|
|
414
|
+
const row1 = y1 * rowSize;
|
|
415
|
+
const row2 = y2 * rowSize;
|
|
416
|
+
const row3 = y3 * rowSize;
|
|
539
417
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
* @param {number} channel
|
|
545
|
-
* @returns {number}
|
|
546
|
-
*/
|
|
547
|
-
Sampler2D.prototype.sampleChannelBicubicUV = function (u, v, channel) {
|
|
548
|
-
const x = u * (this.width);
|
|
549
|
-
const y = v * (this.height);
|
|
418
|
+
const row0_address = row0 + channel;
|
|
419
|
+
const row1_address = row1 + channel;
|
|
420
|
+
const row2_address = row2 + channel;
|
|
421
|
+
const row3_address = row3 + channel;
|
|
550
422
|
|
|
551
|
-
|
|
552
|
-
|
|
423
|
+
const col0_offset = x0 * itemSize;
|
|
424
|
+
const col1_offset = x1 * itemSize;
|
|
425
|
+
const col2_offset = x2 * itemSize;
|
|
426
|
+
const col3_offset = x3 * itemSize;
|
|
553
427
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
* @returns {number}
|
|
560
|
-
*/
|
|
561
|
-
Sampler2D.prototype.sampleChannelBicubic = function (x, y, channel) {
|
|
428
|
+
// read samples
|
|
429
|
+
const vi0 = data[row0_address + col0_offset];
|
|
430
|
+
const vi1 = data[row0_address + col1_offset];
|
|
431
|
+
const vi2 = data[row0_address + col2_offset];
|
|
432
|
+
const vi3 = data[row0_address + col3_offset];
|
|
562
433
|
|
|
563
|
-
|
|
434
|
+
const vj0 = data[row1_address + col0_offset];
|
|
435
|
+
const vj1 = data[row1_address + col1_offset];
|
|
436
|
+
const vj2 = data[row1_address + col2_offset];
|
|
437
|
+
const vj3 = data[row1_address + col3_offset];
|
|
564
438
|
|
|
565
|
-
|
|
566
|
-
|
|
439
|
+
const vk0 = data[row2_address + col0_offset];
|
|
440
|
+
const vk1 = data[row2_address + col1_offset];
|
|
441
|
+
const vk2 = data[row2_address + col2_offset];
|
|
442
|
+
const vk3 = data[row2_address + col3_offset];
|
|
567
443
|
|
|
568
|
-
|
|
444
|
+
const vl0 = data[row3_address + col0_offset];
|
|
445
|
+
const vl1 = data[row3_address + col1_offset];
|
|
446
|
+
const vl2 = data[row3_address + col2_offset];
|
|
447
|
+
const vl3 = data[row3_address + col3_offset];
|
|
569
448
|
|
|
570
|
-
const rowSize = width * itemSize;
|
|
571
449
|
|
|
572
|
-
|
|
573
|
-
|
|
450
|
+
// return bicubic(xd, yd,
|
|
451
|
+
// vi0, vi1, vi2, vi3,
|
|
452
|
+
// vj0, vj1, vj2, vj3,
|
|
453
|
+
// vk0, vk1, vk2, vk3,
|
|
454
|
+
// vl0, vl1, vl2, vl3,
|
|
455
|
+
// );
|
|
574
456
|
|
|
575
|
-
const clamped_x = clamp(x, 0, x_max)
|
|
576
|
-
const clamped_y = clamp(y, 0, y_max)
|
|
577
457
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
458
|
+
// perform filtering in X (rows)
|
|
459
|
+
const s0 = bicubic_terp(xd, vi0, vi1, vi2, vi3);
|
|
460
|
+
const s1 = bicubic_terp(xd, vj0, vj1, vj2, vj3);
|
|
461
|
+
const s2 = bicubic_terp(xd, vk0, vk1, vk2, vk3);
|
|
462
|
+
const s3 = bicubic_terp(xd, vl0, vl1, vl2, vl3);
|
|
581
463
|
|
|
582
|
-
|
|
583
|
-
|
|
464
|
+
// filter in Y (columns)
|
|
465
|
+
return bicubic_terp(yd, s0, s1, s2, s3);
|
|
466
|
+
}
|
|
584
467
|
|
|
585
|
-
|
|
586
|
-
|
|
468
|
+
/**
|
|
469
|
+
*
|
|
470
|
+
* @param {number} u
|
|
471
|
+
* @param {number} v
|
|
472
|
+
* @param {number[]} result
|
|
473
|
+
* @param {number} result_offset
|
|
474
|
+
*/
|
|
475
|
+
sampleBilinearUV(u, v, result, result_offset = 0) {
|
|
587
476
|
|
|
588
|
-
|
|
589
|
-
const y2 = min2(y_max, y1 + 1);
|
|
477
|
+
const itemSize = this.itemSize;
|
|
590
478
|
|
|
591
|
-
|
|
592
|
-
|
|
479
|
+
for (let i = 0; i < itemSize; i++) {
|
|
480
|
+
result[i + result_offset] = this.sampleChannelBilinearUV(u, v, i);
|
|
593
481
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
const row1 = y1 * rowSize;
|
|
597
|
-
const row2 = y2 * rowSize;
|
|
598
|
-
const row3 = y3 * rowSize;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
599
484
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
485
|
+
/**
|
|
486
|
+
*
|
|
487
|
+
* @param {number} x
|
|
488
|
+
* @param {number} y
|
|
489
|
+
* @param {number[]} result
|
|
490
|
+
* @param {number} result_offset
|
|
491
|
+
*/
|
|
492
|
+
sampleBilinear(x, y, result, result_offset = 0) {
|
|
604
493
|
|
|
605
|
-
|
|
606
|
-
const col1_offset = x1 * itemSize;
|
|
607
|
-
const col2_offset = x2 * itemSize;
|
|
608
|
-
const col3_offset = x3 * itemSize;
|
|
494
|
+
const itemSize = this.itemSize;
|
|
609
495
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
const vi2 = data[row0_address + col2_offset];
|
|
614
|
-
const vi3 = data[row0_address + col3_offset];
|
|
496
|
+
for (let i = 0; i < itemSize; i++) {
|
|
497
|
+
//TODO this can be optimized greatly
|
|
498
|
+
result[i + result_offset] = this.sampleChannelBilinear(x, y, i);
|
|
615
499
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
const vj2 = data[row1_address + col2_offset];
|
|
619
|
-
const vj3 = data[row1_address + col3_offset];
|
|
500
|
+
}
|
|
501
|
+
}
|
|
620
502
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
503
|
+
/**
|
|
504
|
+
*
|
|
505
|
+
* @param {number} u
|
|
506
|
+
* @param {number} v
|
|
507
|
+
* @param {number} channel
|
|
508
|
+
* @return {number}
|
|
509
|
+
*/
|
|
510
|
+
sampleChannelBilinearUV(u, v, channel) {
|
|
511
|
+
const x = u * (this.width);
|
|
512
|
+
const y = v * (this.height);
|
|
625
513
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
const vl2 = data[row3_address + col2_offset];
|
|
629
|
-
const vl3 = data[row3_address + col3_offset];
|
|
514
|
+
return this.sampleChannelBilinear(x - 0.5, y - 0.5, channel);
|
|
515
|
+
}
|
|
630
516
|
|
|
517
|
+
/**
|
|
518
|
+
*
|
|
519
|
+
* @param {number} x
|
|
520
|
+
* @param {number} y
|
|
521
|
+
* @param {number} channel
|
|
522
|
+
* @returns {number}
|
|
523
|
+
*/
|
|
524
|
+
sampleChannelBilinear(x, y, channel) {
|
|
631
525
|
|
|
632
|
-
|
|
633
|
-
// vi0, vi1, vi2, vi3,
|
|
634
|
-
// vj0, vj1, vj2, vj3,
|
|
635
|
-
// vk0, vk1, vk2, vk3,
|
|
636
|
-
// vl0, vl1, vl2, vl3,
|
|
637
|
-
// );
|
|
526
|
+
const itemSize = this.itemSize;
|
|
638
527
|
|
|
528
|
+
const width = this.width;
|
|
529
|
+
const height = this.height;
|
|
639
530
|
|
|
640
|
-
|
|
641
|
-
const s0 = bicubic_terp(xd, vi0, vi1, vi2, vi3);
|
|
642
|
-
const s1 = bicubic_terp(xd, vj0, vj1, vj2, vj3);
|
|
643
|
-
const s2 = bicubic_terp(xd, vk0, vk1, vk2, vk3);
|
|
644
|
-
const s3 = bicubic_terp(xd, vl0, vl1, vl2, vl3);
|
|
531
|
+
const rowSize = width * itemSize;
|
|
645
532
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
533
|
+
//sample 4 points
|
|
534
|
+
const x_max = width - 1;
|
|
535
|
+
const y_max = height - 1;
|
|
649
536
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
* @param {number} u
|
|
653
|
-
* @param {number} v
|
|
654
|
-
* @param {number[]} result
|
|
655
|
-
* @param {number} result_offset
|
|
656
|
-
*/
|
|
657
|
-
Sampler2D.prototype.sampleBilinearUV = function (u, v, result, result_offset = 0) {
|
|
537
|
+
const clamped_x = clamp(x, 0, x_max);
|
|
538
|
+
const clamped_y = clamp(y, 0, y_max);
|
|
658
539
|
|
|
659
|
-
|
|
540
|
+
const x0 = clamped_x | 0;
|
|
541
|
+
const y0 = clamped_y | 0;
|
|
660
542
|
|
|
661
|
-
|
|
662
|
-
|
|
543
|
+
//
|
|
544
|
+
const row0 = y0 * rowSize;
|
|
545
|
+
const col0_offset = x0 * itemSize + channel;
|
|
663
546
|
|
|
664
|
-
|
|
665
|
-
}
|
|
547
|
+
const i0 = row0 + col0_offset;
|
|
666
548
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
* @param {number} x
|
|
670
|
-
* @param {number} y
|
|
671
|
-
* @param {number[]} result
|
|
672
|
-
* @param {number} result_offset
|
|
673
|
-
*/
|
|
674
|
-
Sampler2D.prototype.sampleBilinear = function (x, y, result, result_offset = 0) {
|
|
549
|
+
//
|
|
550
|
+
let x1, y1;
|
|
675
551
|
|
|
676
|
-
|
|
552
|
+
if (clamped_x === x0 || x0 >= x_max) {
|
|
553
|
+
x1 = x0;
|
|
554
|
+
} else {
|
|
555
|
+
x1 = x0 + 1;
|
|
556
|
+
}
|
|
677
557
|
|
|
678
|
-
for (let i = 0; i < itemSize; i++) {
|
|
679
|
-
//TODO this can be optimized greatly
|
|
680
|
-
result[i + result_offset] = this.sampleChannelBilinear(x, y, i);
|
|
681
558
|
|
|
682
|
-
|
|
683
|
-
|
|
559
|
+
if (clamped_y === y0 || y0 >= y_max) {
|
|
560
|
+
y1 = y0;
|
|
561
|
+
} else {
|
|
562
|
+
y1 = y0 + 1;
|
|
563
|
+
}
|
|
684
564
|
|
|
685
|
-
|
|
686
|
-
*
|
|
687
|
-
* @param {number} u
|
|
688
|
-
* @param {number} v
|
|
689
|
-
* @param {number} channel
|
|
690
|
-
* @return {number}
|
|
691
|
-
*/
|
|
692
|
-
Sampler2D.prototype.sampleChannelBilinearUV = function (u, v, channel) {
|
|
693
|
-
const x = u * (this.width);
|
|
694
|
-
const y = v * (this.height);
|
|
565
|
+
const data = this.data;
|
|
695
566
|
|
|
696
|
-
|
|
697
|
-
};
|
|
567
|
+
const q0 = data[i0];
|
|
698
568
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
* @param {number} y
|
|
703
|
-
* @param {number} channel
|
|
704
|
-
* @returns {number}
|
|
705
|
-
*/
|
|
706
|
-
Sampler2D.prototype.sampleChannelBilinear = function (x, y, channel) {
|
|
569
|
+
if (x0 === x1 && y0 === y1) {
|
|
570
|
+
return q0;
|
|
571
|
+
}
|
|
707
572
|
|
|
708
|
-
|
|
573
|
+
//
|
|
574
|
+
const xd = clamped_x - x0;
|
|
575
|
+
const yd = clamped_y - y0;
|
|
709
576
|
|
|
710
|
-
|
|
711
|
-
const height = this.height;
|
|
577
|
+
const col1_offset = x1 * itemSize + channel;
|
|
712
578
|
|
|
713
|
-
|
|
579
|
+
const i1 = row0 + col1_offset;
|
|
714
580
|
|
|
715
|
-
|
|
716
|
-
const x_max = width - 1;
|
|
717
|
-
const y_max = height - 1;
|
|
581
|
+
const row1 = y1 * rowSize;
|
|
718
582
|
|
|
719
|
-
|
|
720
|
-
|
|
583
|
+
const j0 = row1 + col0_offset;
|
|
584
|
+
const j1 = row1 + col1_offset;
|
|
721
585
|
|
|
722
|
-
|
|
723
|
-
|
|
586
|
+
const q1 = data[i1];
|
|
587
|
+
const p0 = data[j0];
|
|
588
|
+
const p1 = data[j1];
|
|
724
589
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
590
|
+
// perform Bi-Linear interpolation
|
|
591
|
+
const s0 = mix(q0, q1, xd);
|
|
592
|
+
const s1 = mix(p0, p1, xd);
|
|
728
593
|
|
|
729
|
-
|
|
594
|
+
return mix(s0, s1, yd);
|
|
595
|
+
}
|
|
730
596
|
|
|
731
|
-
|
|
732
|
-
|
|
597
|
+
sampleNearestUV(u, v, result) {
|
|
598
|
+
const x = Math.round(u * (this.width) - 0.5);
|
|
599
|
+
const y = Math.round(v * (this.height) - 0.5);
|
|
733
600
|
|
|
734
|
-
|
|
735
|
-
x1 = x0;
|
|
736
|
-
} else {
|
|
737
|
-
x1 = x0 + 1;
|
|
601
|
+
this.read(min2(x, this.width - 1), min2(y, this.height - 1), result);
|
|
738
602
|
}
|
|
739
603
|
|
|
604
|
+
/**
|
|
605
|
+
*
|
|
606
|
+
* @param {number} x
|
|
607
|
+
* @param {number} y
|
|
608
|
+
* @param {number} channel
|
|
609
|
+
* @returns {number}
|
|
610
|
+
*/
|
|
611
|
+
readChannel(x, y, channel) {
|
|
612
|
+
assert.isNumber(x, "x");
|
|
613
|
+
assert.isNumber(y, "y");
|
|
614
|
+
assert.isNumber(channel, "channel");
|
|
740
615
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
616
|
+
assert.isNonNegativeInteger(channel, 'channel');
|
|
617
|
+
|
|
618
|
+
const index = (y * this.width + x) * this.itemSize + channel;
|
|
619
|
+
|
|
620
|
+
return this.data[index];
|
|
745
621
|
}
|
|
746
622
|
|
|
747
|
-
|
|
623
|
+
/**
|
|
624
|
+
*
|
|
625
|
+
* @param {number} x
|
|
626
|
+
* @param {number} y
|
|
627
|
+
* @param {number[]} result
|
|
628
|
+
*/
|
|
629
|
+
read(x, y, result) {
|
|
748
630
|
|
|
749
|
-
|
|
631
|
+
const width = this.width;
|
|
750
632
|
|
|
751
|
-
|
|
752
|
-
return q0;
|
|
753
|
-
}
|
|
633
|
+
const itemSize = this.itemSize;
|
|
754
634
|
|
|
755
|
-
|
|
756
|
-
const xd = clamped_x - x0;
|
|
757
|
-
const yd = clamped_y - y0;
|
|
635
|
+
const i0 = (y * width + x) * itemSize;
|
|
758
636
|
|
|
759
|
-
|
|
637
|
+
for (let i = 0; i < itemSize; i++) {
|
|
638
|
+
const v = this.data[i0 + i];
|
|
760
639
|
|
|
761
|
-
|
|
640
|
+
result[i] = v;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
762
643
|
|
|
763
|
-
|
|
644
|
+
/**
|
|
645
|
+
*
|
|
646
|
+
* @param {number} u
|
|
647
|
+
* @param {number} v
|
|
648
|
+
* @param {Vector4|Vector3|Vector2} [result]
|
|
649
|
+
* @deprecated
|
|
650
|
+
*/
|
|
651
|
+
sample(u, v, result) {
|
|
652
|
+
console.warn("Deprecated method, use sampleBilinear instead");
|
|
764
653
|
|
|
765
|
-
|
|
766
|
-
const j1 = row1 + col1_offset;
|
|
654
|
+
const temp = [];
|
|
767
655
|
|
|
768
|
-
|
|
769
|
-
const p0 = data[j0];
|
|
770
|
-
const p1 = data[j1];
|
|
656
|
+
this.sampleBilinear(u * (this.width - 1), v * (this.height - 1), temp, 0);
|
|
771
657
|
|
|
772
|
-
|
|
773
|
-
const s0 = mix(q0, q1, xd);
|
|
774
|
-
const s1 = mix(p0, p1, xd);
|
|
658
|
+
result.readFromArray(temp);
|
|
775
659
|
|
|
776
|
-
|
|
777
|
-
}
|
|
660
|
+
return temp[0];
|
|
661
|
+
}
|
|
778
662
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
663
|
+
/**
|
|
664
|
+
*
|
|
665
|
+
* @param {number} index
|
|
666
|
+
* @param {number[]} result
|
|
667
|
+
*/
|
|
668
|
+
computeNeighbors(index, result) {
|
|
669
|
+
const width = this.width;
|
|
670
|
+
const height = this.height;
|
|
671
|
+
|
|
672
|
+
const x = index % width;
|
|
673
|
+
const y = (index / width) | 0;
|
|
674
|
+
if (x > 0) {
|
|
675
|
+
result.push(index - 1);
|
|
676
|
+
}
|
|
677
|
+
if (x < width - 1) {
|
|
678
|
+
result.push(index + 1);
|
|
679
|
+
}
|
|
680
|
+
if (y > 0) {
|
|
681
|
+
result.push(index - width);
|
|
682
|
+
}
|
|
683
|
+
if (y < height - 1) {
|
|
684
|
+
result.push(index + width);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
782
687
|
|
|
783
|
-
|
|
784
|
-
|
|
688
|
+
/**
|
|
689
|
+
*
|
|
690
|
+
* @param {number} x
|
|
691
|
+
* @param {number} y
|
|
692
|
+
* @returns {number}
|
|
693
|
+
*/
|
|
694
|
+
point2index(x, y) {
|
|
695
|
+
return x + y * this.width;
|
|
696
|
+
}
|
|
785
697
|
|
|
786
|
-
/**
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
Sampler2D.prototype.readChannel = function (x, y, channel) {
|
|
794
|
-
assert.isNumber(x, "x");
|
|
795
|
-
assert.isNumber(y, "y");
|
|
796
|
-
assert.isNumber(channel, "channel");
|
|
698
|
+
/**
|
|
699
|
+
*
|
|
700
|
+
* @param {number} index
|
|
701
|
+
* @param {Vector2} result
|
|
702
|
+
*/
|
|
703
|
+
index2point(index, result) {
|
|
704
|
+
const width = this.width;
|
|
797
705
|
|
|
798
|
-
|
|
706
|
+
const x = index % width;
|
|
707
|
+
const y = (index / width) | 0;
|
|
799
708
|
|
|
800
|
-
|
|
709
|
+
result.set(x, y);
|
|
710
|
+
}
|
|
801
711
|
|
|
802
|
-
|
|
803
|
-
|
|
712
|
+
/**
|
|
713
|
+
*
|
|
714
|
+
* @param {number} scale
|
|
715
|
+
* @param {number} offset
|
|
716
|
+
* @return {function(index:int, array:ArrayLike, x:int, y:int)}
|
|
717
|
+
*/
|
|
718
|
+
makeArrayFiller(scale, offset) {
|
|
719
|
+
scale = scale || 255;
|
|
720
|
+
offset = offset || 0;
|
|
721
|
+
|
|
722
|
+
const sampler = this;
|
|
723
|
+
const v4 = [1 / scale, 1 / scale, 1 / scale, 1 / scale];
|
|
724
|
+
|
|
725
|
+
//
|
|
726
|
+
function fillDD1(index, array, x, y) {
|
|
727
|
+
const val = (sampler.sampleChannelBilinear(x, y, 0) + offset) * scale | 0;
|
|
728
|
+
array[index] = val;
|
|
729
|
+
array[index + 1] = val;
|
|
730
|
+
array[index + 2] = val;
|
|
731
|
+
array[index + 3] = 255;
|
|
732
|
+
}
|
|
804
733
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
*
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
Sampler2D.prototype.read = function (x, y, result) {
|
|
734
|
+
function fillDD2(index, array, x, y) {
|
|
735
|
+
sampler.sampleBilinear(x, y, v4, 0);
|
|
736
|
+
const val = (v4[0] + offset) * scale | 0;
|
|
737
|
+
array.fill(val, index, index + 3);
|
|
738
|
+
array[index + 3] = (v4[1] + offset) * scale | 0;
|
|
739
|
+
}
|
|
812
740
|
|
|
813
|
-
|
|
741
|
+
function fillDD3(index, array, x, y) {
|
|
814
742
|
|
|
815
|
-
|
|
743
|
+
sampler.sampleBilinear(x, y, v4, 0);
|
|
816
744
|
|
|
817
|
-
|
|
745
|
+
array[index] = (v4[0] + offset) * scale | 0;
|
|
746
|
+
array[index + 1] = (v4[1] + offset) * scale | 0;
|
|
747
|
+
array[index + 2] = (v4[2] + offset) * scale | 0;
|
|
748
|
+
array[index + 3] = 255;
|
|
749
|
+
}
|
|
818
750
|
|
|
819
|
-
|
|
820
|
-
|
|
751
|
+
function fillDD4(index, array, x, y) {
|
|
752
|
+
sampler.sampleBilinear(x, y, v4, 0);
|
|
753
|
+
array[index] = (v4[0] + offset) * scale | 0;
|
|
754
|
+
array[index + 1] = (v4[1] + offset) * scale | 0;
|
|
755
|
+
array[index + 2] = (v4[2] + offset) * scale | 0;
|
|
756
|
+
array[index + 3] = (v4[3] + offset) * scale | 0;
|
|
757
|
+
}
|
|
821
758
|
|
|
822
|
-
|
|
759
|
+
let fillDD;
|
|
760
|
+
switch (sampler.itemSize) {
|
|
761
|
+
case 1:
|
|
762
|
+
fillDD = fillDD1;
|
|
763
|
+
break;
|
|
764
|
+
case 2:
|
|
765
|
+
fillDD = fillDD2;
|
|
766
|
+
break;
|
|
767
|
+
case 3:
|
|
768
|
+
fillDD = fillDD3;
|
|
769
|
+
break;
|
|
770
|
+
case 4:
|
|
771
|
+
fillDD = fillDD4;
|
|
772
|
+
break;
|
|
773
|
+
default :
|
|
774
|
+
throw new Error("unsupported item size");
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
777
|
+
return fillDD;
|
|
823
778
|
}
|
|
824
|
-
};
|
|
825
779
|
|
|
780
|
+
/**
|
|
781
|
+
* Copy a patch from another sampler with a margin.
|
|
782
|
+
* This is useful for texture rendering where filtering can cause bleeding along the edges of the patch.
|
|
783
|
+
* @param {Sampler2D} source where to copy from
|
|
784
|
+
* @param {Number} sourceX where to start reading from, X coordinate
|
|
785
|
+
* @param {Number} sourceY where to start reading from, X coordinate
|
|
786
|
+
* @param {Number} destinationX where to start writing to, X coordinate
|
|
787
|
+
* @param {Number} destinationY where to start writing to, X coordinate
|
|
788
|
+
* @param {Number} width size of the patch that is to be copied
|
|
789
|
+
* @param {Number} height size of the patch that is to be copied
|
|
790
|
+
* @param {Number} marginLeft
|
|
791
|
+
* @param {Number} marginRight
|
|
792
|
+
* @param {Number} marginTop
|
|
793
|
+
* @param {Number} marginBottom
|
|
794
|
+
*/
|
|
795
|
+
copyWithMargin(source, sourceX, sourceY, destinationX, destinationY, width, height, marginLeft, marginRight, marginTop, marginBottom) {
|
|
796
|
+
const dItemSize = this.itemSize;
|
|
797
|
+
const sItemSize = source.itemSize;
|
|
798
|
+
const _itemSize = Math.min(dItemSize, sItemSize);
|
|
826
799
|
|
|
827
|
-
/**
|
|
828
|
-
*
|
|
829
|
-
* @param {number} u
|
|
830
|
-
* @param {number} v
|
|
831
|
-
* @param {Vector4|Vector3|Vector2} [result]
|
|
832
|
-
* @deprecated
|
|
833
|
-
*/
|
|
834
|
-
Sampler2D.prototype.sample = function (u, v, result) {
|
|
835
|
-
console.warn("Deprecated method, use sampleBilinear instead");
|
|
836
800
|
|
|
837
|
-
|
|
801
|
+
const dRowSize = dItemSize * this.width;
|
|
802
|
+
const sRowSize = sItemSize * source.width;
|
|
838
803
|
|
|
839
|
-
|
|
804
|
+
const sData = source.data;
|
|
805
|
+
const dData = this.data;
|
|
840
806
|
|
|
841
|
-
|
|
807
|
+
let x, y, i, j;
|
|
842
808
|
|
|
843
|
-
|
|
844
|
-
};
|
|
809
|
+
let xMax, yMax;
|
|
845
810
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
*
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
Sampler2D.prototype.computeNeighbors = function (index, result) {
|
|
852
|
-
const width = this.width;
|
|
853
|
-
const height = this.height;
|
|
854
|
-
|
|
855
|
-
const x = index % width;
|
|
856
|
-
const y = (index / width) | 0;
|
|
857
|
-
if (x > 0) {
|
|
858
|
-
result.push(index - 1);
|
|
859
|
-
}
|
|
860
|
-
if (x < width - 1) {
|
|
861
|
-
result.push(index + 1);
|
|
862
|
-
}
|
|
863
|
-
if (y > 0) {
|
|
864
|
-
result.push(index - width);
|
|
865
|
-
}
|
|
866
|
-
if (y < height - 1) {
|
|
867
|
-
result.push(index + width);
|
|
868
|
-
}
|
|
869
|
-
};
|
|
811
|
+
let dA, sA, dOffset, sOffset;
|
|
812
|
+
//Write top-left corner
|
|
813
|
+
sOffset = sourceY * sRowSize + sourceX * dItemSize;
|
|
814
|
+
for (y = Math.max(0, destinationY - marginTop), yMax = destinationY; y < yMax; y++) {
|
|
815
|
+
dA = y * dRowSize;
|
|
870
816
|
|
|
871
|
-
|
|
872
|
-
*
|
|
873
|
-
* @param {number} x
|
|
874
|
-
* @param {number} y
|
|
875
|
-
* @returns {number}
|
|
876
|
-
*/
|
|
877
|
-
Sampler2D.prototype.point2index = function (x, y) {
|
|
878
|
-
return x + y * this.width;
|
|
879
|
-
};
|
|
817
|
+
for (x = Math.max(0, destinationX - marginLeft), xMax = destinationX; x < xMax; x++) {
|
|
880
818
|
|
|
881
|
-
|
|
882
|
-
*
|
|
883
|
-
* @param {number} index
|
|
884
|
-
* @param {Vector2} result
|
|
885
|
-
*/
|
|
886
|
-
Sampler2D.prototype.index2point = function (index, result) {
|
|
887
|
-
const width = this.width;
|
|
819
|
+
dOffset = dA + x * dItemSize;
|
|
888
820
|
|
|
889
|
-
|
|
890
|
-
|
|
821
|
+
for (i = 0; i < _itemSize; i++) {
|
|
822
|
+
dData[dOffset + i] = sData[sOffset + i];
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
//Write top margin
|
|
827
|
+
sA = sourceY * sRowSize;
|
|
828
|
+
for (y = Math.max(0, destinationY - marginTop), yMax = destinationY; y < yMax; y++) {
|
|
829
|
+
dA = y * dRowSize;
|
|
891
830
|
|
|
892
|
-
|
|
893
|
-
};
|
|
831
|
+
for (x = 0; x < width; x++) {
|
|
894
832
|
|
|
895
|
-
|
|
896
|
-
*
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
const v4 = [1 / scale, 1 / scale, 1 / scale, 1 / scale];
|
|
907
|
-
|
|
908
|
-
//
|
|
909
|
-
function fillDD1(index, array, x, y) {
|
|
910
|
-
const val = (sampler.sampleChannelBilinear(x, y, 0) + offset) * scale | 0;
|
|
911
|
-
array[index] = val;
|
|
912
|
-
array[index + 1] = val;
|
|
913
|
-
array[index + 2] = val;
|
|
914
|
-
array[index + 3] = 255;
|
|
915
|
-
}
|
|
833
|
+
dOffset = dA + (x + destinationX) * dItemSize;
|
|
834
|
+
sOffset = sA + (x + sourceX) * dItemSize;
|
|
835
|
+
for (i = 0; i < _itemSize; i++) {
|
|
836
|
+
dData[dOffset + i] = sData[sOffset + i];
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
//Write top-right corner
|
|
841
|
+
sOffset = sourceY * sRowSize + (sourceX + width - 1) * dItemSize;
|
|
842
|
+
for (y = Math.max(0, destinationY - marginTop), yMax = destinationY; y < yMax; y++) {
|
|
843
|
+
dA = y * dRowSize;
|
|
916
844
|
|
|
917
|
-
|
|
918
|
-
sampler.sampleBilinear(x, y, v4, 0);
|
|
919
|
-
const val = (v4[0] + offset) * scale | 0;
|
|
920
|
-
array.fill(val, index, index + 3);
|
|
921
|
-
array[index + 3] = (v4[1] + offset) * scale | 0;
|
|
922
|
-
}
|
|
845
|
+
for (x = destinationX + width, xMax = Math.min(this.width, x + marginRight); x < xMax; x++) {
|
|
923
846
|
|
|
924
|
-
|
|
847
|
+
dOffset = dA + x * dItemSize;
|
|
925
848
|
|
|
926
|
-
|
|
849
|
+
for (i = 0; i < _itemSize; i++) {
|
|
850
|
+
dData[dOffset + i] = sData[sOffset + i];
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
//Write left margin
|
|
855
|
+
for (y = 0; y < height; y++) {
|
|
856
|
+
dA = (y + destinationY) * dRowSize;
|
|
857
|
+
sA = (y + sourceY) * sRowSize;
|
|
927
858
|
|
|
928
|
-
|
|
929
|
-
array[index + 1] = (v4[1] + offset) * scale | 0;
|
|
930
|
-
array[index + 2] = (v4[2] + offset) * scale | 0;
|
|
931
|
-
array[index + 3] = 255;
|
|
932
|
-
}
|
|
859
|
+
sOffset = sA + (sourceX) * dItemSize;
|
|
933
860
|
|
|
934
|
-
|
|
935
|
-
sampler.sampleBilinear(x, y, v4, 0);
|
|
936
|
-
array[index] = (v4[0] + offset) * scale | 0;
|
|
937
|
-
array[index + 1] = (v4[1] + offset) * scale | 0;
|
|
938
|
-
array[index + 2] = (v4[2] + offset) * scale | 0;
|
|
939
|
-
array[index + 3] = (v4[3] + offset) * scale | 0;
|
|
940
|
-
}
|
|
861
|
+
for (x = Math.max(0, destinationX - marginLeft), xMax = destinationX; x < xMax; x++) {
|
|
941
862
|
|
|
942
|
-
|
|
943
|
-
switch (sampler.itemSize) {
|
|
944
|
-
case 1:
|
|
945
|
-
fillDD = fillDD1;
|
|
946
|
-
break;
|
|
947
|
-
case 2:
|
|
948
|
-
fillDD = fillDD2;
|
|
949
|
-
break;
|
|
950
|
-
case 3:
|
|
951
|
-
fillDD = fillDD3;
|
|
952
|
-
break;
|
|
953
|
-
case 4:
|
|
954
|
-
fillDD = fillDD4;
|
|
955
|
-
break;
|
|
956
|
-
default :
|
|
957
|
-
throw new Error("unsupported item size");
|
|
958
|
-
break;
|
|
959
|
-
}
|
|
960
|
-
return fillDD;
|
|
961
|
-
};
|
|
863
|
+
dOffset = dA + x * dItemSize;
|
|
962
864
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
* @param {Number} destinationY where to start writing to, X coordinate
|
|
971
|
-
* @param {Number} width size of the patch that is to be copied
|
|
972
|
-
* @param {Number} height size of the patch that is to be copied
|
|
973
|
-
* @param {Number} marginLeft
|
|
974
|
-
* @param {Number} marginRight
|
|
975
|
-
* @param {Number} marginTop
|
|
976
|
-
* @param {Number} marginBottom
|
|
977
|
-
*/
|
|
978
|
-
Sampler2D.prototype.copyWithMargin = function (source, sourceX, sourceY, destinationX, destinationY, width, height, marginLeft, marginRight, marginTop, marginBottom) {
|
|
979
|
-
const dItemSize = this.itemSize;
|
|
980
|
-
const sItemSize = source.itemSize;
|
|
981
|
-
const _itemSize = Math.min(dItemSize, sItemSize);
|
|
865
|
+
for (i = 0; i < _itemSize; i++) {
|
|
866
|
+
dData[dOffset + i] = sData[sOffset + i];
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
//write actual patch
|
|
871
|
+
this.copy(source, sourceX, sourceY, destinationX, destinationY, width, height);
|
|
982
872
|
|
|
873
|
+
//Write right margin
|
|
874
|
+
for (y = 0; y < height; y++) {
|
|
875
|
+
dA = (y + destinationY) * dRowSize;
|
|
876
|
+
sA = (y + sourceY) * sRowSize;
|
|
983
877
|
|
|
984
|
-
|
|
985
|
-
const sRowSize = sItemSize * source.width;
|
|
878
|
+
sOffset = sA + (sourceX + width - 1) * dItemSize;
|
|
986
879
|
|
|
987
|
-
|
|
988
|
-
const dData = this.data;
|
|
880
|
+
for (x = destinationX + width, xMax = Math.min(this.width, x + marginRight); x < xMax; x++) {
|
|
989
881
|
|
|
990
|
-
|
|
882
|
+
dOffset = dA + x * dItemSize;
|
|
991
883
|
|
|
992
|
-
|
|
884
|
+
for (i = 0; i < _itemSize; i++) {
|
|
885
|
+
dData[dOffset + i] = sData[sOffset + i];
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
993
889
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
dA = y * dRowSize;
|
|
890
|
+
//Write Bottom-left margin
|
|
891
|
+
sOffset = (sourceY + height - 1) * sRowSize + sourceX * dItemSize;
|
|
892
|
+
for (y = destinationY + width, yMax = Math.min(this.height, y + marginBottom); y < yMax; y++) {
|
|
893
|
+
dA = y * dRowSize;
|
|
999
894
|
|
|
1000
|
-
|
|
895
|
+
for (x = Math.max(0, destinationX - marginLeft), xMax = destinationX; x < xMax; x++) {
|
|
1001
896
|
|
|
1002
|
-
|
|
897
|
+
dOffset = dA + x * dItemSize;
|
|
1003
898
|
|
|
1004
|
-
|
|
1005
|
-
|
|
899
|
+
for (i = 0; i < _itemSize; i++) {
|
|
900
|
+
dData[dOffset + i] = sData[sOffset + i];
|
|
901
|
+
}
|
|
1006
902
|
}
|
|
1007
903
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
dA = y * dRowSize;
|
|
904
|
+
//Write Bottom margin
|
|
905
|
+
sA = (sourceY + height - 1) * sRowSize;
|
|
906
|
+
for (y = destinationY + width, yMax = Math.min(this.height, y + marginBottom); y < yMax; y++) {
|
|
907
|
+
dA = y * dRowSize;
|
|
1013
908
|
|
|
1014
|
-
|
|
909
|
+
for (x = 0; x < width; x++) {
|
|
1015
910
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
911
|
+
dOffset = dA + (x + destinationX) * dItemSize;
|
|
912
|
+
sOffset = sA + (x + sourceX) * dItemSize;
|
|
913
|
+
for (i = 0; i < _itemSize; i++) {
|
|
914
|
+
dData[dOffset + i] = sData[sOffset + i];
|
|
915
|
+
}
|
|
1020
916
|
}
|
|
1021
917
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
dA = y * dRowSize;
|
|
918
|
+
//Write Bottom-right margin
|
|
919
|
+
sOffset = (sourceY + height - 1) * sRowSize + (sourceX + width - 1) * dItemSize;
|
|
920
|
+
for (y = destinationY + width, yMax = Math.min(this.height, y + marginBottom); y < yMax; y++) {
|
|
921
|
+
dA = y * dRowSize;
|
|
1027
922
|
|
|
1028
|
-
|
|
923
|
+
for (x = destinationX + width, xMax = Math.min(this.width, x + marginRight); x < xMax; x++) {
|
|
1029
924
|
|
|
1030
|
-
|
|
925
|
+
dOffset = dA + x * dItemSize;
|
|
1031
926
|
|
|
1032
|
-
|
|
1033
|
-
|
|
927
|
+
for (i = 0; i < _itemSize; i++) {
|
|
928
|
+
dData[dOffset + i] = sData[sOffset + i];
|
|
929
|
+
}
|
|
1034
930
|
}
|
|
1035
931
|
}
|
|
932
|
+
|
|
933
|
+
this.version++;
|
|
1036
934
|
}
|
|
1037
|
-
//Write left margin
|
|
1038
|
-
for (y = 0; y < height; y++) {
|
|
1039
|
-
dA = (y + destinationY) * dRowSize;
|
|
1040
|
-
sA = (y + sourceY) * sRowSize;
|
|
1041
935
|
|
|
1042
|
-
|
|
936
|
+
/**
|
|
937
|
+
* Copy a patch from another sampler
|
|
938
|
+
* @param {Sampler2D} source where to copy from
|
|
939
|
+
* @param {Number} sourceX where to start reading from, X coordinate
|
|
940
|
+
* @param {Number} sourceY where to start reading from, X coordinate
|
|
941
|
+
* @param {Number} destinationX where to start writing to, X coordinate
|
|
942
|
+
* @param {Number} destinationY where to start writing to, X coordinate
|
|
943
|
+
* @param {Number} width size of the patch that is to be copied
|
|
944
|
+
* @param {Number} height size of the patch that is to be copied
|
|
945
|
+
*/
|
|
946
|
+
copy(
|
|
947
|
+
source, sourceX, sourceY,
|
|
948
|
+
destinationX, destinationY, width, height
|
|
949
|
+
) {
|
|
1043
950
|
|
|
1044
|
-
|
|
951
|
+
assert.isNumber(sourceX, 'sourceX');
|
|
952
|
+
assert.isNumber(sourceY, 'sourceY');
|
|
1045
953
|
|
|
1046
|
-
|
|
954
|
+
assert.isNumber(destinationX, 'destinationX');
|
|
955
|
+
assert.isNumber(destinationY, 'destinationY');
|
|
1047
956
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
//write actual patch
|
|
1054
|
-
this.copy(source, sourceX, sourceY, destinationX, destinationY, width, height);
|
|
957
|
+
assert.isNumber(width, 'width');
|
|
958
|
+
assert.isNumber(height, 'height');
|
|
1055
959
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
dA = (y + destinationY) * dRowSize;
|
|
1059
|
-
sA = (y + sourceY) * sRowSize;
|
|
960
|
+
const _w = Math.min(width, source.width - sourceX, this.width - destinationX);
|
|
961
|
+
const _h = Math.min(height, source.height - sourceY, this.height - destinationY);
|
|
1060
962
|
|
|
1061
|
-
sOffset = sA + (sourceX + width - 1) * dItemSize;
|
|
1062
963
|
|
|
1063
|
-
|
|
964
|
+
const dItemSize = this.itemSize;
|
|
965
|
+
const sItemSize = source.itemSize;
|
|
966
|
+
const _itemSize = Math.min(dItemSize, sItemSize);
|
|
1064
967
|
|
|
1065
|
-
dOffset = dA + x * dItemSize;
|
|
1066
968
|
|
|
1067
|
-
|
|
1068
|
-
|
|
969
|
+
const dRowSize = dItemSize * this.width;
|
|
970
|
+
const sRowSize = sItemSize * source.width;
|
|
971
|
+
|
|
972
|
+
const sData = source.data;
|
|
973
|
+
const dData = this.data;
|
|
974
|
+
|
|
975
|
+
let x, y, i;
|
|
976
|
+
|
|
977
|
+
for (y = 0; y < _h; y++) {
|
|
978
|
+
const dA = (y + destinationY) * dRowSize;
|
|
979
|
+
const sA = (y + sourceY) * sRowSize;
|
|
980
|
+
for (x = 0; x < _w; x++) {
|
|
981
|
+
const dOffset = dA + (x + destinationX) * dItemSize;
|
|
982
|
+
const sOffset = sA + (x + sourceX) * sItemSize;
|
|
983
|
+
for (i = 0; i < _itemSize; i++) {
|
|
984
|
+
dData[dOffset + i] = sData[sOffset + i];
|
|
985
|
+
}
|
|
1069
986
|
}
|
|
1070
987
|
}
|
|
988
|
+
|
|
989
|
+
this.version++;
|
|
1071
990
|
}
|
|
1072
991
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
992
|
+
/**
|
|
993
|
+
* Copy a patch from another sampler with the same itemSize
|
|
994
|
+
* @param {Sampler2D} source where to copy from
|
|
995
|
+
* @param {Number} sourceX where to start reading from, X coordinate
|
|
996
|
+
* @param {Number} sourceY where to start reading from, X coordinate
|
|
997
|
+
* @param {Number} destinationX where to start writing to, X coordinate
|
|
998
|
+
* @param {Number} destinationY where to start writing to, X coordinate
|
|
999
|
+
* @param {Number} width size of the patch that is to be copied
|
|
1000
|
+
* @param {Number} height size of the patch that is to be copied
|
|
1001
|
+
*/
|
|
1002
|
+
copy_sameItemSize(source, sourceX, sourceY, destinationX, destinationY, width, height) {
|
|
1003
|
+
const itemSize = this.itemSize;
|
|
1004
|
+
const sItemSize = source.itemSize;
|
|
1077
1005
|
|
|
1078
|
-
|
|
1006
|
+
assert.equal(sItemSize, sItemSize, `source.itemSize(=${sItemSize}) != this.itemSize(=${itemSize})`);
|
|
1079
1007
|
|
|
1080
|
-
|
|
1008
|
+
const _w = Math.min(width, source.width - sourceX, this.width - destinationX);
|
|
1009
|
+
const _h = Math.min(height, source.height - sourceY, this.height - destinationY);
|
|
1081
1010
|
|
|
1082
|
-
for (i = 0; i < _itemSize; i++) {
|
|
1083
|
-
dData[dOffset + i] = sData[sOffset + i];
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
//Write Bottom margin
|
|
1088
|
-
sA = (sourceY + height - 1) * sRowSize;
|
|
1089
|
-
for (y = destinationY + width, yMax = Math.min(this.height, y + marginBottom); y < yMax; y++) {
|
|
1090
|
-
dA = y * dRowSize;
|
|
1091
1011
|
|
|
1092
|
-
|
|
1012
|
+
const dRowSize = itemSize * this.width;
|
|
1013
|
+
const sRowSize = itemSize * source.width;
|
|
1093
1014
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
for (i = 0; i < _itemSize; i++) {
|
|
1097
|
-
dData[dOffset + i] = sData[sOffset + i];
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
//Write Bottom-right margin
|
|
1102
|
-
sOffset = (sourceY + height - 1) * sRowSize + (sourceX + width - 1) * dItemSize;
|
|
1103
|
-
for (y = destinationY + width, yMax = Math.min(this.height, y + marginBottom); y < yMax; y++) {
|
|
1104
|
-
dA = y * dRowSize;
|
|
1015
|
+
const sData = source.data;
|
|
1016
|
+
const dData = this.data;
|
|
1105
1017
|
|
|
1106
|
-
|
|
1018
|
+
const patchRowSize = _w * itemSize;
|
|
1107
1019
|
|
|
1108
|
-
|
|
1020
|
+
let y, i;
|
|
1021
|
+
|
|
1022
|
+
for (y = 0; y < _h; y++) {
|
|
1023
|
+
const dA = (y + destinationY) * dRowSize;
|
|
1024
|
+
const sA = (y + sourceY) * sRowSize;
|
|
1025
|
+
|
|
1026
|
+
const dOffset = dA + destinationX * itemSize;
|
|
1027
|
+
const sOffset = sA + sourceX * itemSize;
|
|
1028
|
+
|
|
1029
|
+
for (i = 0; i < patchRowSize; i++) {
|
|
1109
1030
|
|
|
1110
|
-
for (i = 0; i < _itemSize; i++) {
|
|
1111
1031
|
dData[dOffset + i] = sData[sOffset + i];
|
|
1032
|
+
|
|
1112
1033
|
}
|
|
1113
1034
|
}
|
|
1035
|
+
|
|
1036
|
+
this.version++;
|
|
1114
1037
|
}
|
|
1115
1038
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1039
|
+
/**
|
|
1040
|
+
* Assumes both samplers are uint8 with values 0-255
|
|
1041
|
+
* @param {Sampler2D} source
|
|
1042
|
+
* @param sourceX
|
|
1043
|
+
* @param sourceY
|
|
1044
|
+
* @param destinationX
|
|
1045
|
+
* @param destinationY
|
|
1046
|
+
* @param width
|
|
1047
|
+
* @param height
|
|
1048
|
+
* @param {BlendingType} [blendMode]
|
|
1049
|
+
*/
|
|
1050
|
+
paint(source, sourceX, sourceY, destinationX, destinationY, width, height, blendMode = BlendingType.Normal) {
|
|
1051
|
+
let blendFunction;
|
|
1052
|
+
if (blendMode === BlendingType.Normal) {
|
|
1053
|
+
blendFunction = blendFunctionNormal;
|
|
1054
|
+
} else {
|
|
1055
|
+
throw new Error(`Unsupported blendType(=${blendMode})`);
|
|
1056
|
+
}
|
|
1118
1057
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
* @param {Sampler2D} source where to copy from
|
|
1122
|
-
* @param {Number} sourceX where to start reading from, X coordinate
|
|
1123
|
-
* @param {Number} sourceY where to start reading from, X coordinate
|
|
1124
|
-
* @param {Number} destinationX where to start writing to, X coordinate
|
|
1125
|
-
* @param {Number} destinationY where to start writing to, X coordinate
|
|
1126
|
-
* @param {Number} width size of the patch that is to be copied
|
|
1127
|
-
* @param {Number} height size of the patch that is to be copied
|
|
1128
|
-
*/
|
|
1129
|
-
Sampler2D.prototype.copy = function (
|
|
1130
|
-
source, sourceX, sourceY,
|
|
1131
|
-
destinationX, destinationY, width, height
|
|
1132
|
-
) {
|
|
1058
|
+
const _w = Math.min(width, source.width - sourceX, this.width - destinationX);
|
|
1059
|
+
const _h = Math.min(height, source.height - sourceY, this.height - destinationY);
|
|
1133
1060
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1061
|
+
const _x0 = Math.max(0, -destinationX);
|
|
1062
|
+
const _y0 = Math.max(0, -destinationY);
|
|
1136
1063
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1064
|
+
const c0 = [0, 0, 0, 255];
|
|
1065
|
+
const c1 = [0, 0, 0, 255];
|
|
1139
1066
|
|
|
1140
|
-
|
|
1141
|
-
assert.isNumber(height, 'height');
|
|
1067
|
+
const c3 = [];
|
|
1142
1068
|
|
|
1143
|
-
|
|
1144
|
-
const _h = Math.min(height, source.height - sourceY, this.height - destinationY);
|
|
1069
|
+
let x, y;
|
|
1145
1070
|
|
|
1071
|
+
for (y = _y0; y < _h; y++) {
|
|
1072
|
+
for (x = _x0; x < _w; x++) {
|
|
1073
|
+
const d_x = Math.round(x + destinationX);
|
|
1074
|
+
const d_y = Math.round(y + destinationY);
|
|
1146
1075
|
|
|
1147
|
-
|
|
1148
|
-
const sItemSize = source.itemSize;
|
|
1149
|
-
const _itemSize = Math.min(dItemSize, sItemSize);
|
|
1076
|
+
this.read(d_x, d_y, c0);
|
|
1150
1077
|
|
|
1078
|
+
const s_x = Math.round(x + sourceY);
|
|
1079
|
+
const s_y = Math.round(y + sourceY);
|
|
1151
1080
|
|
|
1152
|
-
|
|
1153
|
-
const sRowSize = sItemSize * source.width;
|
|
1081
|
+
source.read(s_x, s_y, c1);
|
|
1154
1082
|
|
|
1155
|
-
|
|
1156
|
-
const dData = this.data;
|
|
1083
|
+
blendFunction(c1, c0, c3);
|
|
1157
1084
|
|
|
1158
|
-
|
|
1085
|
+
this.set(d_x, d_y, c3);
|
|
1159
1086
|
|
|
1160
|
-
for (y = 0; y < _h; y++) {
|
|
1161
|
-
const dA = (y + destinationY) * dRowSize;
|
|
1162
|
-
const sA = (y + sourceY) * sRowSize;
|
|
1163
|
-
for (x = 0; x < _w; x++) {
|
|
1164
|
-
const dOffset = dA + (x + destinationX) * dItemSize;
|
|
1165
|
-
const sOffset = sA + (x + sourceX) * sItemSize;
|
|
1166
|
-
for (i = 0; i < _itemSize; i++) {
|
|
1167
|
-
dData[dOffset + i] = sData[sOffset + i];
|
|
1168
1087
|
}
|
|
1169
1088
|
}
|
|
1170
|
-
}
|
|
1171
1089
|
|
|
1172
|
-
this.version++;
|
|
1173
|
-
};
|
|
1174
1090
|
|
|
1091
|
+
}
|
|
1175
1092
|
|
|
1176
|
-
/**
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
* @param {Number} height size of the patch that is to be copied
|
|
1185
|
-
*/
|
|
1186
|
-
Sampler2D.prototype.copy_sameItemSize = function (source, sourceX, sourceY, destinationX, destinationY, width, height) {
|
|
1187
|
-
const itemSize = this.itemSize;
|
|
1188
|
-
const sItemSize = source.itemSize;
|
|
1093
|
+
/**
|
|
1094
|
+
* Fill data values with zeros for a given area
|
|
1095
|
+
* @param {Number} x
|
|
1096
|
+
* @param {Number} y
|
|
1097
|
+
* @param {Number} width
|
|
1098
|
+
* @param {Number} height
|
|
1099
|
+
*/
|
|
1100
|
+
zeroFill(x, y, width, height) {
|
|
1189
1101
|
|
|
1190
|
-
|
|
1102
|
+
const x0 = clamp(x, 0, this.width);
|
|
1103
|
+
const y0 = clamp(y, 0, this.height);
|
|
1104
|
+
const x1 = clamp(x + width, 0, this.width);
|
|
1105
|
+
const y1 = clamp(y + height, 0, this.height);
|
|
1191
1106
|
|
|
1192
|
-
|
|
1193
|
-
|
|
1107
|
+
const data = this.data;
|
|
1108
|
+
const itemSize = this.itemSize;
|
|
1194
1109
|
|
|
1110
|
+
const rowSize = itemSize * this.width;
|
|
1195
1111
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1112
|
+
const clearRowOffset0 = x0 * itemSize;
|
|
1113
|
+
const clearRowOffset1 = x1 * itemSize;
|
|
1198
1114
|
|
|
1199
|
-
|
|
1200
|
-
const dData = this.data;
|
|
1115
|
+
let _y;
|
|
1201
1116
|
|
|
1202
|
-
|
|
1117
|
+
for (_y = y0; _y < y1; _y++) {
|
|
1203
1118
|
|
|
1204
|
-
|
|
1119
|
+
const a = _y * rowSize;
|
|
1205
1120
|
|
|
1206
|
-
|
|
1207
|
-
const dA = (y + destinationY) * dRowSize;
|
|
1208
|
-
const sA = (y + sourceY) * sRowSize;
|
|
1121
|
+
data.fill(0, a + clearRowOffset0, a + clearRowOffset1);
|
|
1209
1122
|
|
|
1210
|
-
|
|
1211
|
-
const sOffset = sA + sourceX * itemSize;
|
|
1123
|
+
}
|
|
1212
1124
|
|
|
1213
|
-
|
|
1125
|
+
this.version++;
|
|
1126
|
+
}
|
|
1214
1127
|
|
|
1215
|
-
|
|
1128
|
+
/**
|
|
1129
|
+
*
|
|
1130
|
+
* @param {number} channel_index
|
|
1131
|
+
* @param {number} value
|
|
1132
|
+
*/
|
|
1133
|
+
fill_channel(channel_index, value) {
|
|
1134
|
+
const itemSize = this.itemSize;
|
|
1135
|
+
const data = this.data;
|
|
1136
|
+
const length = data.length;
|
|
1216
1137
|
|
|
1138
|
+
for (let i = channel_index; i < length; i += itemSize) {
|
|
1139
|
+
data[i] = value;
|
|
1217
1140
|
}
|
|
1141
|
+
|
|
1142
|
+
this.version++;
|
|
1218
1143
|
}
|
|
1219
1144
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1145
|
+
/**
|
|
1146
|
+
*
|
|
1147
|
+
* @param {Number} x
|
|
1148
|
+
* @param {Number} y
|
|
1149
|
+
* @param {Number} width
|
|
1150
|
+
* @param {Number} height
|
|
1151
|
+
* @param {Array.<Number>} value
|
|
1152
|
+
*/
|
|
1153
|
+
fill(x, y, width, height, value) {
|
|
1154
|
+
|
|
1155
|
+
const _w = this.width;
|
|
1156
|
+
const _h = this.height;
|
|
1222
1157
|
|
|
1158
|
+
const x0 = clamp(x, 0, _w);
|
|
1159
|
+
const y0 = clamp(y, 0, _h);
|
|
1160
|
+
const x1 = clamp(x + width, 0, _w);
|
|
1161
|
+
const y1 = clamp(y + height, 0, _h);
|
|
1223
1162
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
* @param {number[]} source
|
|
1227
|
-
* @param {number[]} destination
|
|
1228
|
-
* @param {Array} result
|
|
1229
|
-
*/
|
|
1230
|
-
function blendFunctionNormal(source, destination, result) {
|
|
1163
|
+
const data = this.data;
|
|
1164
|
+
const itemSize = this.itemSize;
|
|
1231
1165
|
|
|
1232
|
-
|
|
1233
|
-
const a0 = destination[3] / 255;
|
|
1166
|
+
const rowSize = itemSize * _w;
|
|
1234
1167
|
|
|
1235
|
-
|
|
1236
|
-
result[1] = source[1] * a1 + destination[1] * (1 - a1);
|
|
1237
|
-
result[2] = source[2] * a1 + destination[2] * (1 - a1);
|
|
1238
|
-
result[3] = (a1 + a0 * (1 - a1)) * 255;
|
|
1239
|
-
}
|
|
1168
|
+
let _y, _x, i;
|
|
1240
1169
|
|
|
1241
|
-
|
|
1242
|
-
* Assumes both samplers are uint8 with values 0-255
|
|
1243
|
-
* @param {Sampler2D} source
|
|
1244
|
-
* @param sourceX
|
|
1245
|
-
* @param sourceY
|
|
1246
|
-
* @param destinationX
|
|
1247
|
-
* @param destinationY
|
|
1248
|
-
* @param width
|
|
1249
|
-
* @param height
|
|
1250
|
-
* @param {BlendingType} [blendMode]
|
|
1251
|
-
*/
|
|
1252
|
-
Sampler2D.prototype.paint = function (source, sourceX, sourceY, destinationX, destinationY, width, height, blendMode = BlendingType.Normal) {
|
|
1253
|
-
let blendFunction;
|
|
1254
|
-
if (blendMode === BlendingType.Normal) {
|
|
1255
|
-
blendFunction = blendFunctionNormal;
|
|
1256
|
-
} else {
|
|
1257
|
-
throw new Error(`Unsupported blendType(=${blendMode})`);
|
|
1258
|
-
}
|
|
1170
|
+
for (_y = y0; _y < y1; _y++) {
|
|
1259
1171
|
|
|
1260
|
-
|
|
1261
|
-
const _h = Math.min(height, source.height - sourceY, this.height - destinationY);
|
|
1172
|
+
const a = _y * rowSize;
|
|
1262
1173
|
|
|
1263
|
-
|
|
1264
|
-
const _y0 = Math.max(0, -destinationY);
|
|
1174
|
+
for (_x = x0; _x < x1; _x++) {
|
|
1265
1175
|
|
|
1266
|
-
|
|
1267
|
-
const c1 = [0, 0, 0, 255];
|
|
1176
|
+
const offset = a + _x * itemSize;
|
|
1268
1177
|
|
|
1269
|
-
|
|
1178
|
+
for (i = 0; i < itemSize; i++) {
|
|
1270
1179
|
|
|
1271
|
-
|
|
1180
|
+
data[offset + i] = value[i];
|
|
1272
1181
|
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1277
1186
|
|
|
1278
|
-
|
|
1187
|
+
this.version++;
|
|
1188
|
+
}
|
|
1279
1189
|
|
|
1280
|
-
|
|
1281
|
-
|
|
1190
|
+
/**
|
|
1191
|
+
* Set channel value of a specific texel
|
|
1192
|
+
* @param {number} x
|
|
1193
|
+
* @param {number} y
|
|
1194
|
+
* @param {number} channel
|
|
1195
|
+
* @param {number} value
|
|
1196
|
+
*/
|
|
1197
|
+
writeChannel(x, y, channel, value) {
|
|
1198
|
+
assert.isNumber(x, "x");
|
|
1199
|
+
assert.isNumber(y, "y");
|
|
1282
1200
|
|
|
1283
|
-
|
|
1201
|
+
assert.greaterThanOrEqual(x, 0);
|
|
1202
|
+
assert.greaterThanOrEqual(y, 0);
|
|
1203
|
+
assert.lessThan(x, this.width);
|
|
1204
|
+
assert.lessThan(y, this.height);
|
|
1284
1205
|
|
|
1285
|
-
|
|
1206
|
+
const pointIndex = y * this.width + x;
|
|
1207
|
+
const pointAddress = pointIndex * this.itemSize;
|
|
1208
|
+
const channelAddress = pointAddress + channel;
|
|
1286
1209
|
|
|
1287
|
-
|
|
1210
|
+
this.data[channelAddress] = value;
|
|
1288
1211
|
|
|
1289
|
-
|
|
1212
|
+
this.version++;
|
|
1290
1213
|
}
|
|
1291
1214
|
|
|
1215
|
+
/**
|
|
1216
|
+
*
|
|
1217
|
+
* @param {number} x
|
|
1218
|
+
* @param {number} y
|
|
1219
|
+
* @param {number[]} value
|
|
1220
|
+
*/
|
|
1221
|
+
set(x, y, value) {
|
|
1222
|
+
const data = this.data;
|
|
1223
|
+
const itemSize = this.itemSize;
|
|
1224
|
+
|
|
1225
|
+
const rowSize = itemSize * this.width;
|
|
1292
1226
|
|
|
1293
|
-
|
|
1227
|
+
const offset = (rowSize * y) + x * itemSize;
|
|
1294
1228
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
* @param {Number} y
|
|
1299
|
-
* @param {Number} width
|
|
1300
|
-
* @param {Number} height
|
|
1301
|
-
*/
|
|
1302
|
-
Sampler2D.prototype.zeroFill = function (x, y, width, height) {
|
|
1229
|
+
for (let i = 0; i < itemSize; i++) {
|
|
1230
|
+
data[offset + i] = value[i];
|
|
1231
|
+
}
|
|
1303
1232
|
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
const x1 = clamp(x + width, 0, this.width);
|
|
1307
|
-
const y1 = clamp(y + height, 0, this.height);
|
|
1233
|
+
this.version++;
|
|
1234
|
+
}
|
|
1308
1235
|
|
|
1309
|
-
|
|
1310
|
-
|
|
1236
|
+
/**
|
|
1237
|
+
* Traverses area inside a circle
|
|
1238
|
+
* NOTE: Based on palm3d answer on stack overflow: https://stackoverflow.com/questions/1201200/fast-algorithm-for-drawing-filled-circles
|
|
1239
|
+
* @param {number} centerX
|
|
1240
|
+
* @param {number} centerY
|
|
1241
|
+
* @param {number} radius
|
|
1242
|
+
* @param {function(x:number,y:number, sampler:Sampler2D)} visitor
|
|
1243
|
+
*/
|
|
1244
|
+
traverseCircle(centerX, centerY, radius, visitor) {
|
|
1245
|
+
let x, y;
|
|
1311
1246
|
|
|
1312
|
-
|
|
1247
|
+
//convert offsets to integers for safety
|
|
1248
|
+
const offsetX = centerX | 0;
|
|
1249
|
+
const offsetY = centerY | 0;
|
|
1313
1250
|
|
|
1314
|
-
|
|
1315
|
-
const clearRowOffset1 = x1 * itemSize;
|
|
1251
|
+
const r2 = radius * radius;
|
|
1316
1252
|
|
|
1317
|
-
|
|
1253
|
+
const radiusCeil = Math.ceil(radius);
|
|
1318
1254
|
|
|
1319
|
-
|
|
1255
|
+
for (y = -radiusCeil; y <= radiusCeil; y++) {
|
|
1256
|
+
const y2 = y * y;
|
|
1320
1257
|
|
|
1321
|
-
|
|
1258
|
+
for (x = -radiusCeil; x <= radiusCeil; x++) {
|
|
1322
1259
|
|
|
1323
|
-
|
|
1260
|
+
if (x * x + y2 <= r2) {
|
|
1261
|
+
visitor(offsetX + x, offsetY + y, this);
|
|
1262
|
+
}
|
|
1324
1263
|
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1325
1266
|
}
|
|
1326
1267
|
|
|
1327
|
-
|
|
1328
|
-
|
|
1268
|
+
/**
|
|
1269
|
+
*
|
|
1270
|
+
* @param {number} x
|
|
1271
|
+
* @param {number} y
|
|
1272
|
+
* @param {boolean} [preserveData=true]
|
|
1273
|
+
*/
|
|
1274
|
+
resize(x, y, preserveData = true) {
|
|
1275
|
+
assert.isNonNegativeInteger(x, 'x');
|
|
1276
|
+
assert.isNonNegativeInteger(y, 'y');
|
|
1329
1277
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
* @param {number} channel_index
|
|
1333
|
-
* @param {number} value
|
|
1334
|
-
*/
|
|
1335
|
-
Sampler2D.prototype.fill_channel = function (channel_index, value) {
|
|
1336
|
-
const itemSize = this.itemSize;
|
|
1337
|
-
const data = this.data;
|
|
1338
|
-
const length = data.length;
|
|
1278
|
+
const _w = this.width;
|
|
1279
|
+
const _h = this.height;
|
|
1339
1280
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1281
|
+
if (_w === x && _h === y) {
|
|
1282
|
+
// size didn't change
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1343
1285
|
|
|
1344
|
-
|
|
1345
|
-
};
|
|
1286
|
+
const itemSize = this.itemSize;
|
|
1346
1287
|
|
|
1347
|
-
|
|
1348
|
-
*
|
|
1349
|
-
* @param {Number} x
|
|
1350
|
-
* @param {Number} y
|
|
1351
|
-
* @param {Number} width
|
|
1352
|
-
* @param {Number} height
|
|
1353
|
-
* @param {Array.<Number>} value
|
|
1354
|
-
*/
|
|
1355
|
-
Sampler2D.prototype.fill = function (x, y, width, height, value) {
|
|
1288
|
+
const length = x * y * itemSize;
|
|
1356
1289
|
|
|
1357
|
-
|
|
1358
|
-
const _h = this.height;
|
|
1290
|
+
const oldData = this.data;
|
|
1359
1291
|
|
|
1360
|
-
|
|
1361
|
-
const y0 = clamp(y, 0, _h);
|
|
1362
|
-
const x1 = clamp(x + width, 0, _w);
|
|
1363
|
-
const y1 = clamp(y + height, 0, _h);
|
|
1292
|
+
const Constructor = typedArrayConstructorByInstance(oldData);
|
|
1364
1293
|
|
|
1365
|
-
|
|
1366
|
-
const itemSize = this.itemSize;
|
|
1294
|
+
const newData = new Constructor(length);
|
|
1367
1295
|
|
|
1368
|
-
|
|
1296
|
+
if (preserveData) {
|
|
1297
|
+
//copy old data
|
|
1298
|
+
if (x === _w) {
|
|
1299
|
+
// number of columns is preserved, we can just copy the old data across
|
|
1300
|
+
newData.set(oldData.subarray(0, Math.min(oldData.length, length)));
|
|
1301
|
+
} else {
|
|
1302
|
+
//we need to copy new data row-by-row
|
|
1303
|
+
const rowCount = min2(y, _h);
|
|
1369
1304
|
|
|
1370
|
-
|
|
1305
|
+
const columnCount = min2(x, _w);
|
|
1371
1306
|
|
|
1372
|
-
|
|
1307
|
+
for (let i = 0; i < rowCount; i++) {
|
|
1308
|
+
for (let j = 0; j < columnCount; j++) {
|
|
1373
1309
|
|
|
1374
|
-
|
|
1310
|
+
const targetItemAddress = (i * x + j) * itemSize;
|
|
1311
|
+
const sourceItemAddress = (i * _w + j) * itemSize;
|
|
1375
1312
|
|
|
1376
|
-
|
|
1313
|
+
for (let k = 0; k < itemSize; k++) {
|
|
1377
1314
|
|
|
1378
|
-
|
|
1315
|
+
newData[targetItemAddress + k] = oldData[sourceItemAddress + k];
|
|
1379
1316
|
|
|
1380
|
-
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1381
1322
|
|
|
1382
|
-
|
|
1323
|
+
this.width = x;
|
|
1324
|
+
this.height = y;
|
|
1383
1325
|
|
|
1384
|
-
|
|
1326
|
+
this.data = newData;
|
|
1385
1327
|
|
|
1386
|
-
|
|
1328
|
+
this.version++;
|
|
1387
1329
|
}
|
|
1388
1330
|
|
|
1389
|
-
|
|
1390
|
-
|
|
1331
|
+
/**
|
|
1332
|
+
* Estimate memory requirement of the object
|
|
1333
|
+
* @return {number}
|
|
1334
|
+
*/
|
|
1335
|
+
computeByteSize() {
|
|
1336
|
+
let dataSize;
|
|
1391
1337
|
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
* @param {number} value
|
|
1398
|
-
*/
|
|
1399
|
-
Sampler2D.prototype.writeChannel = function (x, y, channel, value) {
|
|
1400
|
-
assert.isNumber(x, "x");
|
|
1401
|
-
assert.isNumber(y, "y");
|
|
1338
|
+
if (Array.isArray(this.data)) {
|
|
1339
|
+
dataSize = 8 * this.data.length;
|
|
1340
|
+
} else {
|
|
1341
|
+
dataSize = this.data.buffer.byteLength;
|
|
1342
|
+
}
|
|
1402
1343
|
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
assert.lessThan(x, this.width);
|
|
1406
|
-
assert.lessThan(y, this.height);
|
|
1344
|
+
return dataSize + 280;
|
|
1345
|
+
}
|
|
1407
1346
|
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1347
|
+
/**
|
|
1348
|
+
* @deprecated Use {@link Sampler2DSerializationAdapter} adapter instead
|
|
1349
|
+
* @param {BinaryBuffer} buffer
|
|
1350
|
+
*/
|
|
1351
|
+
toBinaryBuffer(buffer) {
|
|
1352
|
+
const width = this.width;
|
|
1353
|
+
const height = this.height;
|
|
1411
1354
|
|
|
1412
|
-
|
|
1355
|
+
const itemSize = this.itemSize;
|
|
1413
1356
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1357
|
+
buffer.writeUint16(width);
|
|
1358
|
+
buffer.writeUint16(height);
|
|
1416
1359
|
|
|
1417
|
-
|
|
1418
|
-
*
|
|
1419
|
-
* @param {number} x
|
|
1420
|
-
* @param {number} y
|
|
1421
|
-
* @param {number[]} value
|
|
1422
|
-
*/
|
|
1423
|
-
Sampler2D.prototype.set = function (x, y, value) {
|
|
1424
|
-
const data = this.data;
|
|
1425
|
-
const itemSize = this.itemSize;
|
|
1360
|
+
buffer.writeUint8(itemSize);
|
|
1426
1361
|
|
|
1427
|
-
|
|
1362
|
+
if (this.data instanceof Uint8Array) {
|
|
1363
|
+
//data type
|
|
1364
|
+
buffer.writeUint8(0);
|
|
1428
1365
|
|
|
1429
|
-
const offset = (rowSize * y) + x * itemSize;
|
|
1430
1366
|
|
|
1431
|
-
|
|
1432
|
-
data[offset + i] = value[i];
|
|
1433
|
-
}
|
|
1367
|
+
const byteSize = width * height * itemSize;
|
|
1434
1368
|
|
|
1435
|
-
|
|
1436
|
-
};
|
|
1369
|
+
buffer.writeBytes(this.data, 0, byteSize);
|
|
1437
1370
|
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
* @param {number} centerY
|
|
1443
|
-
* @param {number} radius
|
|
1444
|
-
* @param {function(x:number,y:number, sampler:Sampler2D)} visitor
|
|
1445
|
-
*/
|
|
1446
|
-
Sampler2D.prototype.traverseCircle = function (centerX, centerY, radius, visitor) {
|
|
1447
|
-
let x, y;
|
|
1371
|
+
} else {
|
|
1372
|
+
throw new TypeError(`Unsupported data type`);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1448
1375
|
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1376
|
+
/**
|
|
1377
|
+
* @deprecated Use {@link Sampler2DSerializationAdapter} adapter instead
|
|
1378
|
+
* @param {BinaryBuffer} buffer
|
|
1379
|
+
*/
|
|
1380
|
+
fromBinaryBuffer(buffer) {
|
|
1381
|
+
this.width = buffer.readUint16();
|
|
1382
|
+
this.height = buffer.readUint16();
|
|
1452
1383
|
|
|
1453
|
-
|
|
1384
|
+
this.itemSize = buffer.readUint8();
|
|
1454
1385
|
|
|
1455
|
-
|
|
1386
|
+
const dataType = buffer.readUint8();
|
|
1456
1387
|
|
|
1457
|
-
|
|
1458
|
-
const y2 = y * y;
|
|
1388
|
+
if (dataType === 0) {
|
|
1459
1389
|
|
|
1460
|
-
|
|
1390
|
+
const numBytes = this.height * this.width * this.itemSize;
|
|
1391
|
+
this.data = new Uint8Array(numBytes);
|
|
1461
1392
|
|
|
1462
|
-
|
|
1463
|
-
visitor(offsetX + x, offsetY + y, this);
|
|
1464
|
-
}
|
|
1393
|
+
buffer.readBytes(this.data, 0, numBytes);
|
|
1465
1394
|
|
|
1395
|
+
this.version++;
|
|
1396
|
+
} else {
|
|
1397
|
+
throw new TypeError(`Unsupported data type (${dataType})`);
|
|
1466
1398
|
}
|
|
1467
1399
|
}
|
|
1468
|
-
};
|
|
1469
1400
|
|
|
1470
|
-
/**
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1401
|
+
/**
|
|
1402
|
+
*
|
|
1403
|
+
* @param {number} x
|
|
1404
|
+
* @param {number} y
|
|
1405
|
+
* @param {function(x:number, y:number, value:number, index:number):boolean?} visitor
|
|
1406
|
+
* @param {*} [thisArg]
|
|
1407
|
+
*/
|
|
1408
|
+
traverseOrthogonalNeighbours(x, y, visitor, thisArg) {
|
|
1409
|
+
const width = this.width;
|
|
1410
|
+
const height = this.height;
|
|
1479
1411
|
|
|
1480
|
-
|
|
1481
|
-
const _h = this.height;
|
|
1412
|
+
const index = this.point2index(x, y);
|
|
1482
1413
|
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1414
|
+
let i = 0;
|
|
1415
|
+
const data = this.data;
|
|
1416
|
+
if (x > 0) {
|
|
1417
|
+
i = index - 1;
|
|
1418
|
+
visitor.call(thisArg, x - 1, y, data[i], i);
|
|
1419
|
+
}
|
|
1420
|
+
if (x < width - 1) {
|
|
1421
|
+
i = index + 1;
|
|
1422
|
+
visitor.call(thisArg, x + 1, y, data[i], i);
|
|
1423
|
+
}
|
|
1424
|
+
if (y > 0) {
|
|
1425
|
+
i = index - width;
|
|
1426
|
+
visitor.call(thisArg, x, y - 1, data[i], i);
|
|
1427
|
+
}
|
|
1428
|
+
if (y < height - 1) {
|
|
1429
|
+
i = index + width;
|
|
1430
|
+
visitor.call(thisArg, x, y + 1, data[i], i);
|
|
1431
|
+
}
|
|
1486
1432
|
}
|
|
1487
1433
|
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1434
|
+
/**
|
|
1435
|
+
* @returns {Sampler2D}
|
|
1436
|
+
*/
|
|
1437
|
+
clone() {
|
|
1438
|
+
let data_clone;
|
|
1491
1439
|
|
|
1492
|
-
|
|
1440
|
+
if (Array.isArray(this.data)) {
|
|
1441
|
+
data_clone = this.data.slice();
|
|
1442
|
+
} else {
|
|
1443
|
+
// storage is a typed array
|
|
1444
|
+
const T = this.data.constructor;
|
|
1493
1445
|
|
|
1494
|
-
|
|
1446
|
+
data_clone = new T(this.data);
|
|
1447
|
+
}
|
|
1495
1448
|
|
|
1496
|
-
|
|
1449
|
+
return new Sampler2D(data_clone, this.itemSize, this.width, this.height);
|
|
1450
|
+
}
|
|
1497
1451
|
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1452
|
+
toJSON() {
|
|
1453
|
+
return {
|
|
1454
|
+
height: this.height,
|
|
1455
|
+
width: this.width,
|
|
1456
|
+
itemSize: this.itemSize,
|
|
1457
|
+
type: typedArrayToDataType(this.data),
|
|
1458
|
+
data: Array.from(this.data)
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1506
1461
|
|
|
1507
|
-
|
|
1462
|
+
fromJSON({ height, width, itemSize, type, data }) {
|
|
1463
|
+
const CTOR = compute_typed_array_constructor_from_data_type(type);
|
|
1508
1464
|
|
|
1509
|
-
|
|
1510
|
-
|
|
1465
|
+
this.data = new CTOR(data);
|
|
1466
|
+
this.height = height;
|
|
1467
|
+
this.width = width;
|
|
1468
|
+
this.itemSize = itemSize;
|
|
1469
|
+
}
|
|
1511
1470
|
|
|
1512
|
-
|
|
1513
|
-
|
|
1471
|
+
/**
|
|
1472
|
+
*
|
|
1473
|
+
* @param {int} itemSize
|
|
1474
|
+
* @param {int} width
|
|
1475
|
+
* @param {int} height
|
|
1476
|
+
* @return {Sampler2D}
|
|
1477
|
+
*/
|
|
1478
|
+
static uint8clamped(itemSize, width, height) {
|
|
1479
|
+
const data = new Uint8ClampedArray(width * height * itemSize);
|
|
1480
|
+
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
1481
|
+
return sampler;
|
|
1482
|
+
}
|
|
1514
1483
|
|
|
1515
|
-
|
|
1484
|
+
/**
|
|
1485
|
+
*
|
|
1486
|
+
* @param {int} itemSize
|
|
1487
|
+
* @param {int} width
|
|
1488
|
+
* @param {int} height
|
|
1489
|
+
* @return {Sampler2D}
|
|
1490
|
+
*/
|
|
1491
|
+
static uint8(itemSize, width, height) {
|
|
1492
|
+
const data = new Uint8Array(width * height * itemSize);
|
|
1493
|
+
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
1494
|
+
return sampler;
|
|
1495
|
+
}
|
|
1516
1496
|
|
|
1517
|
-
|
|
1497
|
+
/**
|
|
1498
|
+
*
|
|
1499
|
+
* @param {int} itemSize
|
|
1500
|
+
* @param {int} width
|
|
1501
|
+
* @param {int} height
|
|
1502
|
+
* @return {Sampler2D}
|
|
1503
|
+
*/
|
|
1504
|
+
static uint16(itemSize, width, height) {
|
|
1505
|
+
const data = new Uint16Array(width * height * itemSize);
|
|
1506
|
+
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
1507
|
+
return sampler;
|
|
1508
|
+
}
|
|
1518
1509
|
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1510
|
+
/**
|
|
1511
|
+
*
|
|
1512
|
+
* @param {int} itemSize
|
|
1513
|
+
* @param {int} width
|
|
1514
|
+
* @param {int} height
|
|
1515
|
+
* @return {Sampler2D}
|
|
1516
|
+
*/
|
|
1517
|
+
static uint32(itemSize, width, height) {
|
|
1518
|
+
const data = new Uint32Array(width * height * itemSize);
|
|
1519
|
+
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
1520
|
+
return sampler;
|
|
1523
1521
|
}
|
|
1524
1522
|
|
|
1525
|
-
|
|
1526
|
-
|
|
1523
|
+
/**
|
|
1524
|
+
*
|
|
1525
|
+
* @param {int} itemSize
|
|
1526
|
+
* @param {int} width
|
|
1527
|
+
* @param {int} height
|
|
1528
|
+
* @return {Sampler2D}
|
|
1529
|
+
*/
|
|
1530
|
+
static int8(itemSize, width, height) {
|
|
1531
|
+
const data = new Int8Array(width * height * itemSize);
|
|
1532
|
+
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
1533
|
+
return sampler;
|
|
1534
|
+
}
|
|
1527
1535
|
|
|
1528
|
-
|
|
1536
|
+
/**
|
|
1537
|
+
*
|
|
1538
|
+
* @param {int} itemSize
|
|
1539
|
+
* @param {int} width
|
|
1540
|
+
* @param {int} height
|
|
1541
|
+
* @return {Sampler2D}
|
|
1542
|
+
*/
|
|
1543
|
+
static int16(itemSize, width, height) {
|
|
1544
|
+
const data = new Int16Array(width * height * itemSize);
|
|
1545
|
+
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
1546
|
+
return sampler;
|
|
1547
|
+
}
|
|
1529
1548
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1549
|
+
/**
|
|
1550
|
+
*
|
|
1551
|
+
* @param {int} itemSize
|
|
1552
|
+
* @param {int} width
|
|
1553
|
+
* @param {int} height
|
|
1554
|
+
* @return {Sampler2D}
|
|
1555
|
+
*/
|
|
1556
|
+
static int32(itemSize, width, height) {
|
|
1557
|
+
const data = new Int32Array(width * height * itemSize);
|
|
1558
|
+
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
1559
|
+
return sampler;
|
|
1560
|
+
}
|
|
1532
1561
|
|
|
1533
|
-
/**
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1562
|
+
/**
|
|
1563
|
+
*
|
|
1564
|
+
* @param {int} itemSize
|
|
1565
|
+
* @param {int} width
|
|
1566
|
+
* @param {int} height
|
|
1567
|
+
* @return {Sampler2D}
|
|
1568
|
+
*/
|
|
1569
|
+
static float32(itemSize, width, height) {
|
|
1570
|
+
const data = new Float32Array(width * height * itemSize);
|
|
1571
|
+
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
1572
|
+
return sampler;
|
|
1573
|
+
}
|
|
1539
1574
|
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1575
|
+
/**
|
|
1576
|
+
*
|
|
1577
|
+
* @param {int} itemSize
|
|
1578
|
+
* @param {int} width
|
|
1579
|
+
* @param {int} height
|
|
1580
|
+
* @return {Sampler2D}
|
|
1581
|
+
*/
|
|
1582
|
+
static float64(itemSize, width, height) {
|
|
1583
|
+
const data = new Float64Array(width * height * itemSize);
|
|
1584
|
+
const sampler = new Sampler2D(data, itemSize, width, height);
|
|
1585
|
+
return sampler;
|
|
1544
1586
|
}
|
|
1545
1587
|
|
|
1546
|
-
|
|
1547
|
-
|
|
1588
|
+
/**
|
|
1589
|
+
*
|
|
1590
|
+
* @param {Sampler2D} input0
|
|
1591
|
+
* @param {Sampler2D} input1
|
|
1592
|
+
* @param {Sampler2D} result
|
|
1593
|
+
* @param {function( value0 : number[], value1 : number[], result : number[], index : number) : void} operation
|
|
1594
|
+
*/
|
|
1595
|
+
static combine(input0, input1, result, operation) {
|
|
1596
|
+
assert.notEqual(input0, undefined, "input0 is undefined");
|
|
1597
|
+
assert.notEqual(input1, undefined, "input1 is undefined");
|
|
1598
|
+
assert.notEqual(result, undefined, "result is undefined");
|
|
1548
1599
|
|
|
1600
|
+
assert.typeOf(operation, "function", "operation");
|
|
1549
1601
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
* @param {BinaryBuffer} buffer
|
|
1553
|
-
*/
|
|
1554
|
-
Sampler2D.prototype.toBinaryBuffer = function (buffer) {
|
|
1555
|
-
const width = this.width;
|
|
1556
|
-
const height = this.height;
|
|
1602
|
+
assert.equal(input0.width, input1.width, `input0.width(=${input0.width}) is not equal to input1.width(=${input1.width})`);
|
|
1603
|
+
assert.equal(input0.height, input1.height, `input0.height(=${input0.height}) is not equal to input1.height(=${input1.height})`);
|
|
1557
1604
|
|
|
1558
|
-
|
|
1605
|
+
assert.equal(input0.width, result.width, `input width(=${input0.width}) is not equal to result.width(=${result.width})`);
|
|
1606
|
+
assert.equal(input0.height, result.height, `input height(=${input0.height}) is not equal to result.height(=${result.height})`);
|
|
1559
1607
|
|
|
1560
|
-
|
|
1561
|
-
|
|
1608
|
+
const width = input0.width;
|
|
1609
|
+
const height = input0.height;
|
|
1562
1610
|
|
|
1563
|
-
|
|
1611
|
+
const length = width * height;
|
|
1564
1612
|
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1613
|
+
const arg0 = [];
|
|
1614
|
+
const arg1 = [];
|
|
1615
|
+
const res = [];
|
|
1568
1616
|
|
|
1617
|
+
const itemSize0 = input0.itemSize;
|
|
1618
|
+
const itemSize1 = input1.itemSize;
|
|
1619
|
+
const itemSizeR = result.itemSize;
|
|
1569
1620
|
|
|
1570
|
-
const
|
|
1621
|
+
const data0 = input0.data;
|
|
1622
|
+
const data1 = input1.data;
|
|
1623
|
+
const dataR = result.data;
|
|
1571
1624
|
|
|
1572
|
-
buffer.writeBytes(this.data, 0, byteSize);
|
|
1573
1625
|
|
|
1574
|
-
|
|
1575
|
-
throw new TypeError(`Unsupported data type`);
|
|
1576
|
-
}
|
|
1577
|
-
};
|
|
1626
|
+
let i, j;
|
|
1578
1627
|
|
|
1579
|
-
|
|
1580
|
-
* @deprecated Use {@link Sampler2DSerializationAdapter} adapter instead
|
|
1581
|
-
* @param {BinaryBuffer} buffer
|
|
1582
|
-
*/
|
|
1583
|
-
Sampler2D.prototype.fromBinaryBuffer = function (buffer) {
|
|
1584
|
-
this.width = buffer.readUint16();
|
|
1585
|
-
this.height = buffer.readUint16();
|
|
1628
|
+
for (i = 0; i < length; i++) {
|
|
1586
1629
|
|
|
1587
|
-
|
|
1630
|
+
// read input 0
|
|
1631
|
+
for (j = 0; j < itemSize0; j++) {
|
|
1632
|
+
arg0[j] = data0[j + i * itemSize0];
|
|
1633
|
+
}
|
|
1588
1634
|
|
|
1589
|
-
|
|
1635
|
+
// read input 1
|
|
1636
|
+
for (j = 0; j < itemSize0; j++) {
|
|
1637
|
+
arg1[j] = data1[j + i * itemSize1];
|
|
1638
|
+
}
|
|
1590
1639
|
|
|
1591
|
-
|
|
1640
|
+
//perform operation
|
|
1641
|
+
operation(arg0, arg1, res, i);
|
|
1592
1642
|
|
|
1593
|
-
|
|
1594
|
-
|
|
1643
|
+
//write result
|
|
1644
|
+
for (j = 0; j < itemSizeR; j++) {
|
|
1645
|
+
dataR[j + i * itemSizeR] = res[j];
|
|
1646
|
+
}
|
|
1595
1647
|
|
|
1596
|
-
|
|
1648
|
+
}
|
|
1597
1649
|
|
|
1598
|
-
|
|
1599
|
-
} else {
|
|
1600
|
-
throw new TypeError(`Unsupported data type (${dataType})`);
|
|
1650
|
+
result.version++;
|
|
1601
1651
|
}
|
|
1602
|
-
}
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1603
1654
|
|
|
1604
1655
|
/**
|
|
1605
|
-
*
|
|
1606
|
-
* @param {number}
|
|
1607
|
-
* @param {number}
|
|
1608
|
-
* @param {
|
|
1609
|
-
* @param {
|
|
1656
|
+
* Based on code from reddit https://www.reddit.com/r/javascript/comments/jxa8x/bicubic_interpolation/
|
|
1657
|
+
* @param {number} t
|
|
1658
|
+
* @param {number} a
|
|
1659
|
+
* @param {number} b
|
|
1660
|
+
* @param {number} c
|
|
1661
|
+
* @param {number} d
|
|
1662
|
+
* @returns {number}
|
|
1610
1663
|
*/
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
const index = this.point2index(x, y);
|
|
1664
|
+
function bicubic_terp(t, a, b, c, d) {
|
|
1665
|
+
return 0.5 * (c - a + (2.0 * a - 5.0 * b + 4.0 * c - d + (3.0 * (b - c) + d - a) * t) * t) * t + b;
|
|
1666
|
+
}
|
|
1616
1667
|
|
|
1617
|
-
let i = 0;
|
|
1618
|
-
const data = this.data;
|
|
1619
|
-
if (x > 0) {
|
|
1620
|
-
i = index - 1;
|
|
1621
|
-
visitor.call(thisArg, x - 1, y, data[i], i);
|
|
1622
|
-
}
|
|
1623
|
-
if (x < width - 1) {
|
|
1624
|
-
i = index + 1;
|
|
1625
|
-
visitor.call(thisArg, x + 1, y, data[i], i);
|
|
1626
|
-
}
|
|
1627
|
-
if (y > 0) {
|
|
1628
|
-
i = index - width;
|
|
1629
|
-
visitor.call(thisArg, x, y - 1, data[i], i);
|
|
1630
|
-
}
|
|
1631
|
-
if (y < height - 1) {
|
|
1632
|
-
i = index + width;
|
|
1633
|
-
visitor.call(thisArg, x, y + 1, data[i], i);
|
|
1634
|
-
}
|
|
1635
|
-
};
|
|
1636
1668
|
|
|
1637
1669
|
/**
|
|
1638
|
-
*
|
|
1670
|
+
*
|
|
1671
|
+
* @param {number[]} source
|
|
1672
|
+
* @param {number[]} destination
|
|
1673
|
+
* @param {Array} result
|
|
1639
1674
|
*/
|
|
1640
|
-
|
|
1641
|
-
let data_clone;
|
|
1642
|
-
|
|
1643
|
-
if (Array.isArray(this.data)) {
|
|
1644
|
-
data_clone = this.data.slice();
|
|
1645
|
-
} else {
|
|
1646
|
-
// storage is a typed array
|
|
1647
|
-
const T = this.data.constructor;
|
|
1675
|
+
function blendFunctionNormal(source, destination, result) {
|
|
1648
1676
|
|
|
1649
|
-
|
|
1650
|
-
|
|
1677
|
+
const a1 = source[3] / 255;
|
|
1678
|
+
const a0 = destination[3] / 255;
|
|
1651
1679
|
|
|
1652
|
-
|
|
1653
|
-
|
|
1680
|
+
result[0] = source[0] * a1 + destination[0] * (1 - a1);
|
|
1681
|
+
result[1] = source[1] * a1 + destination[1] * (1 - a1);
|
|
1682
|
+
result[2] = source[2] * a1 + destination[2] * (1 - a1);
|
|
1683
|
+
result[3] = (a1 + a0 * (1 - a1)) * 255;
|
|
1684
|
+
}
|
|
1654
1685
|
|
|
1655
|
-
/**
|
|
1656
|
-
* @readonly
|
|
1657
|
-
* @type {boolean}
|
|
1658
|
-
*/
|
|
1659
|
-
Sampler2D.prototype.isSampler2D = true;
|
|
1660
1686
|
|