@woosh/meep-engine 2.42.8 → 2.43.1

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.
Files changed (137) hide show
  1. package/core/binary/BitSet.js +4 -4
  2. package/core/binary/ctz32.js +40 -0
  3. package/core/collection/ObservedMap.js +61 -57
  4. package/core/collection/heap/FastBinaryHeap.js +7 -1
  5. package/core/collection/heap/Uint32Heap.js +19 -0
  6. package/core/collection/map/AsyncLoadingCache.js +3 -1
  7. package/core/geom/2d/compute_polygon_area_2d.js +32 -0
  8. package/core/geom/2d/compute_polygon_area_2d.spec.js +10 -0
  9. package/core/geom/2d/compute_triangle_area_2d.js +15 -0
  10. package/core/geom/2d/compute_triangle_area_2d.spec.js +9 -0
  11. package/core/geom/2d/convex-hull/convex_hull_jarvis_2d.js +64 -0
  12. package/core/geom/2d/convex-hull/convex_hull_jarvis_2d.spec.js +33 -0
  13. package/core/geom/2d/convex-hull/convex_hull_monotone_2d.js +82 -0
  14. package/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +135 -0
  15. package/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +282 -0
  16. package/core/geom/2d/convex-hull/orientation3.js +444 -0
  17. package/core/geom/2d/convex-hull/orientation3_array.js +22 -0
  18. package/core/geom/2d/convex-hull/orientation3_v2.js +12 -0
  19. package/core/geom/2d/intersect_ray_2d.js +56 -0
  20. package/core/geom/2d/quad-tree/QuadTreeNode.js +0 -81
  21. package/core/geom/2d/quad-tree/qt_match_data_by_circle.js +70 -0
  22. package/core/geom/3d/matrix/m4_multiply_alphatensor.js +131 -0
  23. package/core/geom/3d/plane/orient3d_fast.js +2 -6
  24. package/core/geom/3d/tetrahedra/README.md +7 -0
  25. package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.js +3 -1
  26. package/core/geom/3d/tetrahedra/delaunay/Cavity.js +48 -0
  27. package/core/geom/3d/tetrahedra/{compute_delaunay_tetrahedral_mesh.js → delaunay/compute_delaunay_tetrahedral_mesh.js} +15 -7
  28. package/core/geom/3d/tetrahedra/{compute_delaunay_tetrahedral_mesh.spec.js → delaunay/compute_delaunay_tetrahedral_mesh.spec.js} +0 -0
  29. package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity.js +73 -0
  30. package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_walk_toward_cavity.js +48 -0
  31. package/core/geom/3d/tetrahedra/hxt/a.js +524 -0
  32. package/core/geom/3d/tetrahedra/hxt/hxt.js +140 -0
  33. package/core/geom/3d/tetrahedra/hxt/hxt.wasm +0 -0
  34. package/core/geom/3d/tetrahedra/point_in_tetrahedron_circumsphere.js +35 -20
  35. package/core/geom/3d/tetrahedra/prototypeTetrahedraBuilder.js +98 -0
  36. package/core/geom/3d/tetrahedra/tetrahedra_collection.js +60 -131
  37. package/core/geom/packing/{MaxRectangles.js → max-rect/MaxRectangles.js} +28 -124
  38. package/core/geom/packing/max-rect/removeRedundantBoxes.js +69 -0
  39. package/core/geom/packing/max-rect/removeRedundantBoxesArray.js +40 -0
  40. package/core/geom/v3_distance_above_plane.js +1 -1
  41. package/core/graph/layout/BoxLayouter.js +2 -88
  42. package/core/graph/layout/CircleLayout.js +2 -1
  43. package/core/graph/layout/box/forceIntoBox.js +45 -0
  44. package/core/graph/layout/box/pullBoxTowardsPoint.js +20 -0
  45. package/core/graph/layout/box/resolveAABB2Overlap.js +22 -0
  46. package/core/math/bessel_3.js +11 -0
  47. package/core/math/bessel_i0.js +26 -0
  48. package/core/process/executor/ConcurrentExecutor.spec.js +2 -1
  49. package/core/process/task/util/actionTask.js +19 -0
  50. package/core/process/task/util/countTask.js +62 -0
  51. package/core/process/task/util/delayTask.js +45 -0
  52. package/core/process/task/util/emptyTask.js +19 -0
  53. package/core/process/task/util/failingTask.js +17 -0
  54. package/core/process/task/util/futureTask.js +48 -0
  55. package/core/process/task/util/promiseTask.js +42 -0
  56. package/core/process/task/util/randomCountTask.js +64 -0
  57. package/core/process/task/util/wrapTaskIgnoreFailure.js +47 -0
  58. package/engine/Engine.js +8 -8
  59. package/engine/EngineBootstrapper.js +1 -1
  60. package/engine/asset/AssetManager.d.ts +2 -0
  61. package/engine/asset/AssetManager.js +197 -53
  62. package/engine/asset/AssetRequest.js +32 -0
  63. package/engine/asset/loaders/ArrayBufferLoader.js +62 -50
  64. package/engine/asset/loaders/image/png/PNG.js +15 -1
  65. package/engine/asset/loaders/image/png/PNGReader.js +3 -2
  66. package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +2 -1
  67. package/engine/ecs/storage/BinaryBufferDeSerializer.js +1 -1
  68. package/engine/ecs/storage/JSONDeSerializer.js +2 -1
  69. package/engine/ecs/terrain/ecs/splat/SplatMapOptimizer.js +2 -1
  70. package/engine/ecs/terrain/ecs/splat/SplatMapping.js +1 -1
  71. package/engine/graphics/camera/makeScreenScissorFrustum.js +1 -1
  72. package/engine/graphics/camera/testClippingPlaneComputation.js +4 -45
  73. package/engine/graphics/ecs/camera/FrustumProjector.js +6 -0
  74. package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +5 -0
  75. package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +23 -4
  76. package/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.js +1 -1
  77. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +11 -0
  78. package/engine/graphics/geometry/FULL_SCREEN_TRIANGLE_GEOMETRY.js +1 -2
  79. package/engine/graphics/impostors/octahedral/ImpostorBaker.js +5 -2
  80. package/engine/graphics/impostors/octahedral/ImpostorDescription.js +18 -0
  81. package/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +15 -0
  82. package/engine/graphics/impostors/octahedral/prototypeBaker.js +66 -79
  83. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderWireframeV0.js +134 -0
  84. package/engine/graphics/impostors/octahedral/util/build_cutout_from_atlas_by_alpha.js +128 -0
  85. package/engine/graphics/impostors/octahedral/util/build_geometry_from_cutout_shape.js +32 -0
  86. package/engine/graphics/impostors/octahedral/util/load_mesh_for_bake.js +31 -0
  87. package/engine/graphics/impostors/octahedral/util/makeImpostorAtlasPreview.js +107 -0
  88. package/engine/graphics/material/manager/ManagedMaterial.js +4 -0
  89. package/engine/graphics/material/manager/MaterialManager.js +1 -0
  90. package/engine/graphics/material/optimization/MaterialOptimizationContext.js +7 -3
  91. package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +2 -2
  92. package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +2 -2
  93. package/engine/graphics/render/visibility/hiz/buildCanvasViewFromTexture.js +83 -27
  94. package/engine/graphics/shadows/ShadowMapRenderer.js +11 -4
  95. package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +2 -1
  96. package/engine/graphics/texture/atlas/CachingTextureAtlas.js +208 -38
  97. package/engine/graphics/texture/atlas/TextureAtlas.js +31 -24
  98. package/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.js +1 -1
  99. package/engine/graphics/texture/sampler/filter/box.js +16 -0
  100. package/engine/graphics/texture/sampler/filter/cubic2.js +32 -0
  101. package/engine/graphics/texture/sampler/filter/gaussian.js +16 -0
  102. package/engine/graphics/texture/sampler/filter/kaiser_1.js +19 -0
  103. package/engine/graphics/texture/sampler/filter/kaiser_bessel_window.js +19 -0
  104. package/engine/graphics/texture/sampler/filter/mitchell.js +55 -0
  105. package/engine/graphics/texture/sampler/filter/sampler2d_scale_down_generic.js +109 -0
  106. package/engine/graphics/texture/sampler/filter/triangle.js +19 -0
  107. package/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +187 -86
  108. package/engine/graphics/texture/sampler/sampler2_d_scale_down_lanczos.js +77 -25
  109. package/engine/graphics/texture/sampler/search/make_edge_condition_channel_threshold.js +34 -0
  110. package/engine/graphics/texture/sampler/search/sampler2d_find_pixels.js +24 -0
  111. package/engine/graphics/texture/sprite/prototypeSpriteCutoutGeometry.js +212 -0
  112. package/engine/knowledge/database/StaticKnowledgeDataTable.js +1 -1
  113. package/engine/navigation/grid/AStar.js +1 -1
  114. package/engine/scene/Scene.js +1 -1
  115. package/engine/scene/SerializedScene.js +1 -1
  116. package/engine/scene/transitionToScene.js +3 -1
  117. package/generation/example/main.js +1 -1
  118. package/generation/grid/generation/GridTaskApplyActionToCells.js +1 -1
  119. package/generation/grid/generation/GridTaskDensityMarkerDistribution.js +1 -1
  120. package/generation/grid/generation/GridTaskExecuteRuleTimes.js +1 -1
  121. package/generation/grid/generation/NoopGridTaskGenerator.js +1 -1
  122. package/generation/grid/generation/discrete/GridTaskCellularAutomata.js +2 -1
  123. package/generation/grid/generation/discrete/GridTaskConnectRooms.js +1 -1
  124. package/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +3 -2
  125. package/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +1 -1
  126. package/generation/grid/generation/grid/GridTaskAddNodesFixed.js +1 -1
  127. package/generation/grid/generation/road/GridTaskGenerateRoads.js +3 -2
  128. package/generation/grid/generation/util/buildDistanceMapToObjective.js +1 -1
  129. package/generation/markers/GridActionRuleSet.js +2 -1
  130. package/generation/placement/GridCellActionTransformNearbyMarkers.js +2 -4
  131. package/generation/theme/ThemeEngine.js +4 -1
  132. package/package.json +1 -1
  133. package/view/asset/AssetLoaderStatusView.js +5 -5
  134. package/view/minimap/gl/MinimapTerrainGL.js +1 -2
  135. package/view/renderModel.js +1 -1
  136. package/view/tooltip/TooltipView.js +5 -5
  137. package/core/process/task/TaskUtils.js +0 -352
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @see https://github.com/terifan/ImageResampler/blob/dbc212ce6aaa769bf3c9623cb6ead58ffd51d76c/src/org/terifan/image_resampler/FilterFactory.java#L348
3
+ * @param {number} x
4
+ * @returns {number}
5
+ */
6
+ export function triangle(x) {
7
+ if (x < -1) {
8
+ return 0;
9
+ }
10
+ if (x < 0) {
11
+ return 1 + x;
12
+ }
13
+ if (x < 1) {
14
+ return 1 - x;
15
+ }
16
+ return 0;
17
+ }
18
+
19
+ triangle.support = 1;
@@ -2,18 +2,30 @@ import { EngineHarness } from "../../../EngineHarness.js";
2
2
  import { ImageRGBADataLoader } from "../../../asset/loaders/image/ImageRGBADataLoader.js";
3
3
  import sampler2D2Canvas from "./Sampler2D2Canvas.js";
4
4
  import { CanvasView } from "../../../../view/elements/CanvasView.js";
5
- import { sampler2D_scale_down_lanczos } from "./sampler2_d_scale_down_lanczos.js";
5
+ import { filter_lanczos3, sampler2D_scale_down_lanczos } from "./sampler2_d_scale_down_lanczos.js";
6
6
  import { Sampler2D } from "./Sampler2D.js";
7
7
  import { genericResampleSampler2D } from "./genericResampleSampler2D.js";
8
8
  import Vector2 from "../../../../core/geom/Vector2.js";
9
9
  import LabelView from "../../../../view/common/LabelView.js";
10
10
  import EmptyView from "../../../../view/elements/EmptyView.js";
11
11
  import { sampler2d_downsample_mipmap } from "./resize/sampler2d_downsample_mipmap.js";
12
+ import { kaiser_bessel_window } from "./filter/kaiser_bessel_window.js";
13
+ import { sampler2d_scale_down_generic } from "./filter/sampler2d_scale_down_generic.js";
14
+ import { mitchell, mitchell_v1 } from "./filter/mitchell.js";
15
+ import { kaiser_1 } from "./filter/kaiser_1.js";
16
+ import { triangle } from "./filter/triangle.js";
17
+ import { box } from "./filter/box.js";
18
+ import { gaussian } from "./filter/gaussian.js";
12
19
 
13
- function grid(engine, input, transforms, size = new Vector2(input.width, input.height)) {
20
+ function grid({ engine, input, transforms, size = new Vector2(input.width, input.height), display_labels = true }) {
21
+
22
+ const GAP_SIZE = 4;
14
23
 
15
24
  let draw_index = 0;
16
25
 
26
+ const viewport_width = window.innerWidth;
27
+ const tiles_x = Math.floor(viewport_width / (size.x + GAP_SIZE));
28
+
17
29
  for (let i = 0; i < transforms.length; i++) {
18
30
  const out = input.clone();
19
31
 
@@ -24,21 +36,33 @@ function grid(engine, input, transforms, size = new Vector2(input.width, input.h
24
36
  skip: false
25
37
  };
26
38
 
39
+ const t0 = performance.now();
40
+
27
41
  try {
28
42
  transforms[i](out, input, params);
29
43
  } catch (e) {
30
44
  // error, skip
45
+ console.error(`Failed '${params.label}'. Reason: ${e.message}`)
31
46
  }
32
47
 
48
+ const t1 = performance.now();
49
+
33
50
  if (params.skip) {
34
51
  continue;
35
52
  }
36
53
 
54
+ const t_duration = t1 - t0;
55
+
56
+ console.log(`Executed ${params.label} in ${t_duration}ms`);
37
57
 
38
- const view = display(engine, out, draw_index * (size.x + 4), 0);
39
58
 
40
- if (params.label.length > 0) {
41
- view.addChild(new LabelView(params.label, {
59
+ const draw_x = (draw_index % tiles_x) * (size.x + GAP_SIZE);
60
+ const draw_y = Math.floor(draw_index / tiles_x) * (size.y + GAP_SIZE);
61
+
62
+ const view = display(engine, out, draw_x, draw_y);
63
+
64
+ if (params.label.length > 0 && display_labels) {
65
+ const vLabel = new LabelView(params.label, {
42
66
  css: {
43
67
  position: 'absolute',
44
68
  fontFamily: 'sans-serif',
@@ -51,7 +75,9 @@ function grid(engine, input, transforms, size = new Vector2(input.width, input.h
51
75
  background: 'rgba(255,255,255,0.7)',
52
76
  padding: '2px'
53
77
  }
54
- }));
78
+ });
79
+
80
+ view.addChild(vLabel);
55
81
  }
56
82
 
57
83
  draw_index++;
@@ -95,16 +121,22 @@ new EngineHarness().initialize({
95
121
  }
96
122
  }).then(async engine => {
97
123
 
98
- // const asset = await engine.assetManager.promise("data/textures/utility/Lenna.png", 'image');
99
- // const asset = await engine.assetManager.promise("data/textures/utility/uv_map_reference.jpg", 'image');
100
- const asset = await engine.assetManager.promise("data/textures/utility/image018.jpg", 'image');
101
- // const asset = await engine.assetManager.promise("data/textures/utility/TESTIMAGES/SAMPLING/8BIT/RGB/2448x2448/SRC/img_2448x2448_3x8bit_SRC_RGB_clips.png", 'image');
102
- // const asset = await engine.assetManager.promise("data/textures/utility/TESTIMAGES/SAMPLING/8BIT/RGB/2448x2448/SRC/img_2448x2448_3x8bit_SRC_RGB_coins.png", 'image');
103
- // const asset = await engine.assetManager.promise("data/models/LowPolyTownshipSet/Small_house/diffuse_512.png", 'image');
104
- // const asset = await engine.assetManager.promise("data/models/LowPolyTownshipSet/Barrel/diffuse_256.png", 'image');
105
- // const asset = await engine.assetManager.promise("data/textures/utility/resolver.jpeg", 'image');
106
- // const asset = await engine.assetManager.promise("data/textures/icons/500_skill_icons_02/Skill_nobg/skill_492_noBG.png", 'image');
107
- // const asset = await engine.assetManager.promise("data/textures/utility/sampling-test.png", 'image');
124
+ // const path = "data/textures/utility/image018.jpg";
125
+ // const path = "data/textures/decal/ISO 7010 - Safety Signs/Fire Protection/200px/F001 – Fire extinguisher.png";
126
+ // const path = "data/textures/decal/ISO 7010 - Safety Signs/Prohibited Actions/400px/P069 - Not to be serviced by users.png";
127
+ const path = "data/textures/utility/Lenna.png";
128
+ // const path = "data/textures/utility/dragon.jpg";
129
+ // const path = "data/textures/utility/grid_tileable.png";
130
+ // const path = "data/textures/utility/uv_map_reference.jpg";
131
+ // const path ="data/textures/utility/TESTIMAGES/SAMPLING/8BIT/RGB/2448x2448/SRC/img_2448x2448_3x8bit_SRC_RGB_clips.png";
132
+ // const path ="data/textures/utility/TESTIMAGES/SAMPLING/8BIT/RGB/2448x2448/SRC/img_2448x2448_3x8bit_SRC_RGB_coins.png";
133
+ // const path ="data/models/LowPolyTownshipSet/Small_house/diffuse_512.png";
134
+ // const path ="data/models/LowPolyTownshipSet/Barrel/diffuse_256.png";
135
+ // const path ="data/textures/utility/resolver.jpeg";
136
+ // const path ="data/textures/icons/500_skill_icons_02/Skill_nobg/skill_492_noBG.png";
137
+ // const path = "data/textures/utility/sampling-test.png";
138
+
139
+ const asset = await engine.assetManager.promise(path, 'image');
108
140
 
109
141
  const source = asset.create();
110
142
 
@@ -144,109 +176,178 @@ new EngineHarness().initialize({
144
176
  })
145
177
 
146
178
  function test_sampling(source, engine) {
147
- grid(engine, source, [
148
- (out, input, params) => {
149
- params.label = 'Nearest';
179
+ grid({
180
+ engine: engine,
181
+ input: source,
182
+ // display_labels: false,
183
+ transforms: [
184
+ (out, input, params) => {
185
+ params.label = 'Nearest';
150
186
 
151
- const sample = [];
152
- for (let y = 0; y < out.height; y++) {
187
+ const sample = [];
188
+ for (let y = 0; y < out.height; y++) {
153
189
 
154
- for (let x = 0; x < out.width; x++) {
190
+ for (let x = 0; x < out.width; x++) {
155
191
 
156
- input.sampleNearestUV(x / (out.width - 1), y / (out.height - 1), sample);
192
+ input.sampleNearestUV(x / (out.width - 1), y / (out.height - 1), sample);
157
193
 
158
- out.set(x, y, sample);
194
+ out.set(x, y, sample);
195
+ }
159
196
  }
160
- }
161
- },
162
- (out, input, params) => {
197
+ },
198
+ (out, input, params) => {
163
199
 
164
- params.label = 'Bilinear';
165
- params.skip = true;
200
+ params.label = 'Bilinear';
201
+ params.skip = true;
166
202
 
167
- const sample = new Uint8ClampedArray(4);
168
- for (let y = 0; y < out.height; y++) {
203
+ return;
169
204
 
170
- for (let x = 0; x < out.width; x++) {
205
+ const sample = new Uint8ClampedArray(4);
206
+ for (let y = 0; y < out.height; y++) {
171
207
 
172
- input.sampleBilinearUV(x / (out.width - 1), y / (out.height - 1), sample);
208
+ for (let x = 0; x < out.width; x++) {
173
209
 
174
- out.set(x, y, sample);
210
+ input.sampleBilinearUV(x / (out.width - 1), y / (out.height - 1), sample);
211
+
212
+ out.set(x, y, sample);
213
+ }
175
214
  }
176
- }
177
- },
178
- (out, input, params) => {
179
- params.label = 'Bicubic';
180
- params.skip = true;
215
+ },
216
+ (out, input, params) => {
217
+ params.label = 'Bicubic';
218
+ params.skip = true;
219
+
220
+ return;
181
221
 
182
- const sample = new Uint8ClampedArray(4);
183
- for (let y = 0; y < out.height; y++) {
222
+ const sample = new Uint8ClampedArray(4);
223
+ for (let y = 0; y < out.height; y++) {
184
224
 
185
- for (let x = 0; x < out.width; x++) {
225
+ for (let x = 0; x < out.width; x++) {
186
226
 
187
- input.sampleBicubicUV(x / (out.width - 1), y / (out.height - 1), sample);
227
+ input.sampleBicubicUV(x / (out.width - 1), y / (out.height - 1), sample);
188
228
 
189
- out.set(x, y, sample);
229
+ out.set(x, y, sample);
230
+ }
190
231
  }
191
- }
192
- },
193
- (out, input, params) => {
194
- params.label = 'catmull-rom';
195
- params.skip = true;
232
+ },
233
+ (out, input, params) => {
234
+ params.label = 'catmull-rom';
235
+ params.skip = true;
236
+
237
+ return;
196
238
 
197
- const sample = new Uint8ClampedArray(4);
198
- for (let y = 0; y < out.height; y++) {
239
+ const sample = new Uint8ClampedArray(4);
240
+ for (let y = 0; y < out.height; y++) {
199
241
 
200
- for (let x = 0; x < out.width; x++) {
242
+ for (let x = 0; x < out.width; x++) {
201
243
 
202
- input.sampleCatmullRomUV(x / (out.width - 1), y / (out.height - 1), sample);
244
+ input.sampleCatmullRomUV(x / (out.width - 1), y / (out.height - 1), sample);
203
245
 
204
- out.set(x, y, sample);
246
+ out.set(x, y, sample);
247
+ }
205
248
  }
206
- }
207
- },
208
- (out, input, params) => {
209
- params.label = 'mip';
249
+ },
250
+ (out, input, params) => {
251
+ params.label = 'mip';
210
252
 
211
253
 
212
- sampler2d_downsample_mipmap(input, out);
254
+ sampler2d_downsample_mipmap(input, out);
213
255
 
214
- },
215
- (out, input, params) => {
216
- const lobes = 2;
217
- params.label = `lanczos_${lobes}`;
218
- params.skip = true;
256
+ },
257
+ (out, input, params) => {
258
+ const lobes = 2;
259
+ params.label = `lanczos_${lobes}`;
260
+ // params.skip = true;
219
261
 
220
- return;
262
+ // return;
221
263
 
222
- sampler2D_scale_down_lanczos(input, out, lobes);
264
+ sampler2D_scale_down_lanczos(input, out, lobes);
223
265
 
224
- },
225
- (out, input, params) => {
226
- const lobes = 3;
227
- params.label = `lanczos_${lobes}`;
266
+ },
267
+ (out, input, params) => {
268
+ const lobes = 3;
269
+ params.label = `lanczos_${lobes}`;
270
+ params.skip = true;
228
271
 
272
+ return;
229
273
 
230
- sampler2D_scale_down_lanczos(input, out, lobes);
231
274
 
232
- },
233
- (out, input, params) => {
234
- const lobes = 5;
235
- params.skip = true;
236
- params.label = `lanczos_${lobes}`;
275
+ sampler2d_scale_down_generic(input, out, filter_lanczos3, 3);
276
+ // sampler2D_scale_down_lanczos(input, out, lobes);
237
277
 
238
- return;
278
+ },
279
+ (out, input, params) => {
280
+ const lobes = 5;
281
+ params.label = `lanczos_${lobes}`;
282
+ params.skip = true;
239
283
 
240
- sampler2D_scale_down_lanczos(input, out, lobes);
284
+ return;
241
285
 
242
- }
243
- ], new Vector2(
244
- // 100, 100
245
- 1024, 1024
246
- // 136, 136
247
- ));
248
- }
286
+ sampler2D_scale_down_lanczos(input, out, lobes);
287
+
288
+ },
289
+ (out, input, params) => {
290
+ params.label = `mitchell`;
291
+ // params.skip = true;
249
292
 
250
- function lanczos() {
293
+ // return;
251
294
 
295
+ sampler2d_scale_down_generic(input, out, mitchell_v1);
296
+
297
+ },
298
+ (out, input, params) => {
299
+ params.label = `kaiser_3`;
300
+ // params.skip = true;
301
+
302
+ // return;
303
+
304
+ sampler2d_scale_down_generic(input, out, kaiser_bessel_window);
305
+
306
+ },
307
+ (out, input, params) => {
308
+ params.label = `kaiser_1`;
309
+ // params.skip = true;
310
+
311
+ // return;
312
+
313
+ sampler2d_scale_down_generic(input, out, kaiser_1);
314
+
315
+ },
316
+ (out, input, params) => {
317
+ params.label = `triangle`;
318
+ // params.skip = true;
319
+
320
+ // return;
321
+
322
+ sampler2d_scale_down_generic(input, out, triangle);
323
+
324
+ },
325
+ (out, input, params) => {
326
+ params.label = `box`;
327
+ // params.skip = true;
328
+
329
+ // return;
330
+
331
+ sampler2d_scale_down_generic(input, out, box);
332
+
333
+ },
334
+ (out, input, params) => {
335
+ params.label = `gaussian`;
336
+ // params.skip = true;
337
+
338
+ // return;
339
+
340
+ sampler2d_scale_down_generic(input, out, gaussian);
341
+
342
+ }
343
+ ], size: new Vector2(
344
+ // 100, 100
345
+ // 1024, 1024
346
+ 136, 136
347
+ // 64, 64
348
+ // 32,32
349
+ // 400,400
350
+ // 200, 200
351
+ )
352
+ });
252
353
  }
@@ -23,23 +23,63 @@ function lanczos(x, lobes) {
23
23
  return 0;
24
24
  }
25
25
 
26
- if (x < 1e-16) {
26
+ if (x < 1.1920929e-7) {
27
27
  return 1;
28
28
  }
29
29
 
30
+ x *= Math.PI;
31
+
30
32
  const xx = x / lobes;
31
33
 
32
- return Math.sin(Math.PI * x) * Math.sin(Math.PI * xx) / (x * x);
34
+ return (Math.sin(x) / x) * Math.sin(xx) / (xx);
35
+ }
36
+
37
+ /**
38
+ * Original formulation version from wiki
39
+ * @see https://en.wikipedia.org/wiki/Lanczos_resampling
40
+ * Calculate lanczos weight
41
+ * @param {number} x
42
+ * @param {number} lobes
43
+ * @returns {number}
44
+ */
45
+ function lanczos_orig(x, lobes) {
46
+
47
+ /*
48
+ // not needed in our case, as X is always positive
49
+ if (x < 0) {
50
+ x = -x;
51
+ }
52
+
53
+ */
54
+
55
+ if (x > lobes) {
56
+ return 0;
57
+ }
58
+
59
+ if (x < 1.1920929e-7) {
60
+ return 1;
61
+ }
62
+
63
+ return (lobes * Math.sin(Math.PI * x) * Math.sin(Math.PI * x / lobes)) / (Math.PI * Math.PI * x * x);
33
64
  }
34
65
 
35
- export function filter_lanczos3(t) {
36
- if (t < 0) {
37
- t = -t;
66
+ export function filter_lanczos3(x) {
67
+ // assume the input is positive
68
+
69
+ // if (x < 0) {
70
+ // x = -x;
71
+ // }
72
+
73
+ if (x > 3) {
74
+ return 0;
38
75
  }
39
- if (t < 3.0) {
40
- return Math.sin(t) * Math.sin(t / 3.0);
76
+
77
+ if (x < 1.1920929e-7) {
78
+ return 1;
41
79
  }
42
- return 0.0;
80
+
81
+ return (3 * Math.sin(Math.PI * x) * Math.sin(Math.PI * x / 3)) / (Math.PI * Math.PI * x * x);
82
+
43
83
  }
44
84
 
45
85
  filter_lanczos3.support = 3;
@@ -51,7 +91,7 @@ filter_lanczos3.support = 3;
51
91
  * @param {Sampler2D} destination
52
92
  * @param {number} [lobes]
53
93
  */
54
- export function sampler2D_scale_down_lanczos(source, destination, lobes = 3) {
94
+ export function sampler2D_scale_down_lanczos(source, destination, lobes = 2) {
55
95
 
56
96
  const d_w = destination.width;
57
97
  const d_h = destination.height;
@@ -61,15 +101,22 @@ export function sampler2D_scale_down_lanczos(source, destination, lobes = 3) {
61
101
  const source_width = source.width;
62
102
  const source_height = source.height;
63
103
 
104
+ if (source_width < d_w || source_height < d_h) {
105
+ throw new Error('Invalid scale, source is larger than destination in at least 1 dimension');
106
+ }
107
+
64
108
  const source_data = source.data;
65
109
  const destination_data = destination.data;
66
110
 
67
111
  const ratio_x = source_width / d_w;
68
112
  const ratio_y = source_height / d_h;
69
113
 
114
+ const rcp_ratio_y = 2 / ratio_x;
115
+ const rcp_ratio_x = 2 / ratio_x;
116
+
70
117
 
71
- const range2_x = Math.ceil(ratio_x * lobes / 2);
72
- const range2_y = Math.ceil(ratio_y * lobes / 2);
118
+ const range2_x = Math.ceil(ratio_x * lobes * 0.5);
119
+ const range2_y = Math.ceil(ratio_y * lobes * 0.5);
73
120
 
74
121
  const sample = new Array(item_size);
75
122
 
@@ -77,17 +124,20 @@ export function sampler2D_scale_down_lanczos(source, destination, lobes = 3) {
77
124
 
78
125
  for (v = 0; v < d_h; v++) {
79
126
 
80
- const center_y = (v) * ratio_y - 0.5;
81
- const source_y0 = max2(Math.ceil(center_y - range2_y), 0);
82
- const source_y1 = min2(Math.floor(center_y + range2_y), source_height - 1);
127
+ const center_y = (v + 0.5) * ratio_y;
128
+ const i_center_y = Math.floor(center_y);
129
+ //
130
+ const source_y0 = max2(0, i_center_y - range2_y);
131
+ const source_y1 = min2(i_center_y + range2_y, source_height - 1);
83
132
 
84
133
  for (u = 0; u < d_w; u++) {
85
- const center_x = (u) * ratio_x - 0.5;
134
+ const center_x = (u + 0.5) * ratio_x;
135
+ const i_center_x = Math.floor(center_x);
86
136
 
87
- const source_x0 = max2(Math.ceil(center_x - range2_x), 0);
88
- const source_x1 = min2(Math.floor(center_x + range2_x), source_width - 1);
137
+ const source_x0 = max2(i_center_x - range2_x, 0);
138
+ const source_x1 = min2(i_center_x + range2_x, source_width - 1);
89
139
 
90
- let z = 0;
140
+ let weight_sum = 0;
91
141
  // reset sample
92
142
  for (i = 0; i < item_size; i++) {
93
143
  sample[i] = 0;
@@ -97,29 +147,31 @@ export function sampler2D_scale_down_lanczos(source, destination, lobes = 3) {
97
147
 
98
148
  const f_y = (j - center_y);
99
149
 
100
- const f_y_rcp2 = f_y * f_y;
150
+ const f_y_rcp = f_y * rcp_ratio_y;
151
+ const f_y_rcp2 = f_y_rcp * f_y_rcp;
101
152
 
102
153
  for (i = source_x0; i <= source_x1; i++) {
103
154
 
104
155
  const f_x = (i - center_x);
105
156
 
106
- const f_x_rcp2 = f_x * f_x;
157
+ const f_x_rcp = f_x * rcp_ratio_x;
158
+ const f_x_rcp2 = f_x_rcp * f_x_rcp;
107
159
 
108
160
  const distance_from_center_sqr = f_x_rcp2 + f_y_rcp2;
109
161
  const distance_from_center = Math.sqrt(distance_from_center_sqr);
110
162
 
111
- const lanczos_weight = lanczos(distance_from_center, lobes);
163
+ const weight = lanczos(distance_from_center, lobes);
112
164
 
113
- if (lanczos_weight <= 0) {
165
+ if (weight <= 0) {
114
166
  continue;
115
167
  }
116
168
 
117
- z += lanczos_weight;
169
+ weight_sum += weight;
118
170
 
119
171
  const source_texel_address = (j * source_width + i) * item_size;
120
172
 
121
173
  for (k = 0; k < item_size; k++) {
122
- sample[k] += lanczos_weight * source_data[source_texel_address + k];
174
+ sample[k] += weight * source_data[source_texel_address + k];
123
175
  }
124
176
 
125
177
  }
@@ -127,7 +179,7 @@ export function sampler2D_scale_down_lanczos(source, destination, lobes = 3) {
127
179
 
128
180
 
129
181
  // dilute sample and write to destination
130
- const inv_z = 1 / z;
182
+ const inv_z = 1 / weight_sum;
131
183
 
132
184
  const texel_address = (v * d_w + u) * item_size;
133
185
 
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Edge detection condition generator
3
+ * @param {number} channel
4
+ * @param {number} threshold
5
+ * @returns {(sampler:Sampler2D, x:number, y:number) => boolean}
6
+ */
7
+ export function make_edge_condition_channel_threshold(channel, threshold) {
8
+ /**
9
+ * @param {Sampler2D} sampler
10
+ * @param {number} x
11
+ * @param {number} y
12
+ * @returns {boolean}
13
+ */
14
+ return function (sampler, x, y) {
15
+ const v = sampler.readChannel(x, y, channel);
16
+
17
+ if (v < threshold) {
18
+ return false;
19
+ }
20
+
21
+ if (
22
+ (y > 0 && sampler.readChannel(x, y - 1, channel) < threshold) // up
23
+ || (x > 0 && sampler.readChannel(x - 1, y, channel) < threshold) //left
24
+ || (x < (sampler.width - 1) && sampler.readChannel(x + 1, y, channel) < threshold) //right
25
+ || (y < (sampler.height - 1) && sampler.readChannel(x, y + 1, channel) < threshold) //bottom
26
+ ) {
27
+ return true;
28
+ }
29
+
30
+
31
+ // not edge, probably interior
32
+ return false;
33
+ }
34
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ *
3
+ * @param {Sampler2D} sampler
4
+ * @param {(sampler:Sampler2D,x:number, y:number)=>boolean} matcher
5
+ * @returns {number[]} flat array of x,y coordinates
6
+ */
7
+ export function sampler2d_find_pixels(sampler, matcher) {
8
+ const result = [];
9
+
10
+ const h = sampler.height;
11
+ const w = sampler.width;
12
+
13
+ for (let y = 0; y < h; y++) {
14
+ for (let x = 0; x < w; x++) {
15
+
16
+ if (matcher(sampler, x, y)) {
17
+ result.push(x, y);
18
+ }
19
+
20
+ }
21
+ }
22
+
23
+ return result;
24
+ }