@woosh/meep-engine 3.29.0 → 3.30.0
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/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +14 -2
- package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BVH.js +14 -1
- package/src/core/cache/FrequencySketch.d.ts +3 -1
- package/src/core/cache/FrequencySketch.d.ts.map +1 -1
- package/src/core/cache/FrequencySketch.js +10 -4
- package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -1
- package/src/core/cache/wtinylfu/CacheWTinylfu.js +24 -2
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts +20 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +69 -4
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +48 -18
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +262 -70
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts +25 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +228 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts +13 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js +10 -128
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +11 -1
- package/src/core/graph/mn_graph_collapse_weighted_edge.js +6 -6
- package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
- package/src/core/math/lookup/ParameterLookupTable.js +10 -5
- package/src/core/math/noise/sdnoise.d.ts.map +1 -1
- package/src/core/math/noise/sdnoise.js +16 -10
- package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
- package/src/core/model/object/ImmutableObjectPool.js +17 -7
- package/src/core/process/executor/ConcurrentExecutor.d.ts +1 -5
- package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
- package/src/core/process/executor/ConcurrentExecutor.js +95 -1
- package/src/core/process/task/task_find_dependency_cycle.d.ts +17 -0
- package/src/core/process/task/task_find_dependency_cycle.d.ts.map +1 -0
- package/src/core/process/task/task_find_dependency_cycle.js +81 -0
- package/src/core/wfc/WFCCellChoice.d.ts +17 -0
- package/src/core/wfc/WFCCellChoice.d.ts.map +1 -0
- package/src/core/wfc/WFCCellChoice.js +36 -0
- package/src/core/wfc/WFCLattice.d.ts +105 -0
- package/src/core/wfc/WFCLattice.d.ts.map +1 -0
- package/src/core/wfc/WFCLattice.js +235 -0
- package/src/core/wfc/WFCRuleTable.d.ts +172 -0
- package/src/core/wfc/WFCRuleTable.d.ts.map +1 -0
- package/src/core/wfc/WFCRuleTable.js +334 -0
- package/src/core/wfc/WFCState.d.ts +273 -0
- package/src/core/wfc/WFCState.d.ts.map +1 -0
- package/src/core/wfc/WFCState.js +552 -0
- package/src/core/wfc/WFCStatus.d.ts +11 -0
- package/src/core/wfc/WFCStatus.d.ts.map +1 -0
- package/src/core/wfc/WFCStatus.js +28 -0
- package/src/core/wfc/WFCTileWeights.d.ts +48 -0
- package/src/core/wfc/WFCTileWeights.d.ts.map +1 -0
- package/src/core/wfc/WFCTileWeights.js +86 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts +12 -0
- package/src/core/wfc/WFC_UNRESOLVED.d.ts.map +1 -0
- package/src/core/wfc/WFC_UNRESOLVED.js +11 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts +24 -0
- package/src/core/wfc/wfc_estimate_bytes.d.ts.map +1 -0
- package/src/core/wfc/wfc_estimate_bytes.js +47 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts +27 -0
- package/src/core/wfc/wfc_rule_table_tile_components.d.ts.map +1 -0
- package/src/core/wfc/wfc_rule_table_tile_components.js +80 -0
- package/src/core/wfc/wfc_solve.d.ts +21 -0
- package/src/core/wfc/wfc_solve.d.ts.map +1 -0
- package/src/core/wfc/wfc_solve.js +154 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts +18 -0
- package/src/core/wfc/wfc_state_apply_boundary.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_apply_boundary.js +61 -0
- package/src/core/wfc/wfc_state_assign.d.ts +11 -0
- package/src/core/wfc/wfc_state_assign.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_assign.js +36 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts +17 -0
- package/src/core/wfc/wfc_state_ban_bits.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_ban_bits.js +81 -0
- package/src/core/wfc/wfc_state_collapse.d.ts +12 -0
- package/src/core/wfc/wfc_state_collapse.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_collapse.js +73 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts +12 -0
- package/src/core/wfc/wfc_state_flush_dirty.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_flush_dirty.js +39 -0
- package/src/core/wfc/wfc_state_propagate.d.ts +14 -0
- package/src/core/wfc/wfc_state_propagate.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_propagate.js +155 -0
- package/src/core/wfc/wfc_state_read.d.ts +11 -0
- package/src/core/wfc/wfc_state_read.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_read.js +38 -0
- package/src/core/wfc/wfc_state_restrict.d.ts +18 -0
- package/src/core/wfc/wfc_state_restrict.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_restrict.js +39 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts +24 -0
- package/src/core/wfc/wfc_state_set_eligible.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_set_eligible.js +49 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts +13 -0
- package/src/core/wfc/wfc_state_undo_to.d.ts.map +1 -0
- package/src/core/wfc/wfc_state_undo_to.js +84 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts +11 -0
- package/src/core/wfc/wfc_words_per_cell.d.ts.map +1 -0
- package/src/core/wfc/wfc_words_per_cell.js +16 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts +8 -0
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +37 -14
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +8 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +37 -2
- package/src/engine/ecs/guid/UUID.d.ts.map +1 -1
- package/src/engine/ecs/guid/UUID.js +45 -17
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +1 -1
- package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +3 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +366 -360
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +24 -10
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
- package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +24 -5
- package/src/engine/interpolation/Interpoland.d.ts +7 -1
- package/src/engine/interpolation/Interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/Interpoland.js +8 -1
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationSystem.js +3 -0
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +5 -3
- package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
- package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -3
- package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -1
- package/src/engine/interpolation/pose_interpoland.js +2 -0
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +15 -10
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +17 -0
- package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
- package/src/engine/physics/mls-mpm/MLS_MPM.js +14 -0
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +1 -1
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +2 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +12 -3
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -0
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.js +4 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.d.ts.map +1 -1
- package/src/format/image/avif/av1/decode/decode_coefficients.js +248 -259
- package/src/format/image/avif/av1/decode/read_golomb.d.ts +21 -0
- package/src/format/image/avif/av1/decode/read_golomb.d.ts.map +1 -0
- package/src/format/image/avif/av1/decode/read_golomb.js +49 -0
- package/src/format/image/avif/av1/filter/loop_restoration.js +461 -451
- package/src/format/image/avif/av1/util/round2.d.ts +19 -2
- package/src/format/image/avif/av1/util/round2.d.ts.map +1 -1
- package/src/format/image/avif/av1/util/round2.js +51 -27
- package/src/format/image/avif/heif/parse_avif_file.js +24 -0
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +14 -0
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +46 -3
- package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +91 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +0 -13
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +0 -15
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +5 -5
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +11 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +18 -9
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +20 -26
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +1 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +2 -5
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +14 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +12 -3
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.js +7 -1
- package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/GPULightMap.js +349 -336
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/load_gltf.js +1137 -1128
- package/src/shade/renderer/particles/DESIGN.md +14 -5
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts +25 -10
- package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
- package/src/shade/renderer/particles/GPUParticleSystem.js +182 -38
- package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/simplex_reference.js +16 -10
- package/src/shade/renderer/particles/graph_particles.d.ts +4 -2
- package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph_particles.js +8 -2
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +8 -2
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -4
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +31 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +1 -0
- package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +62 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +13 -0
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +95 -17
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +21 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +28 -0
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +19 -2
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +19 -2
- package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUStruct.js +12 -0
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts +8 -2
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +41 -6
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2383 -2356
- package/src/view/tooltip/DomTooltipManager.d.ts +7 -0
- package/src/view/tooltip/DomTooltipManager.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipManager.js +22 -0
- package/src/view/tooltip/DomTooltipObserver.d.ts.map +1 -1
- package/src/view/tooltip/DomTooltipObserver.js +13 -3
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +0 -45
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Relative placement likelihoods, one per tile.
|
|
5
|
+
*
|
|
6
|
+
* Nothing is normalised — `[1, 9]` and `[0.1, 0.9]` behave identically.
|
|
7
|
+
*
|
|
8
|
+
* Weights must be finite and strictly positive; a non-positive one throws. A zero-weight tile
|
|
9
|
+
* would sit in a cell's domain, count toward its possibility count and never be selected, which
|
|
10
|
+
* surfaces much later as a solve that cannot finish. A tile you do not want is one you leave out
|
|
11
|
+
* of the rule table.
|
|
12
|
+
*
|
|
13
|
+
* Held apart from {@link WFCRuleTable} so the same structure can be solved with different
|
|
14
|
+
* preferences.
|
|
15
|
+
*
|
|
16
|
+
* @author Alex Goldring
|
|
17
|
+
* @copyright Company Named Limited (c) 2026
|
|
18
|
+
*/
|
|
19
|
+
export class WFCTileWeights {
|
|
20
|
+
/**
|
|
21
|
+
* @param {number[]|Float64Array} weights one strictly positive, finite weight per tile
|
|
22
|
+
*/
|
|
23
|
+
constructor(weights) {
|
|
24
|
+
assert.isArrayLike(weights, 'weights');
|
|
25
|
+
|
|
26
|
+
const tile_count = weights.length;
|
|
27
|
+
|
|
28
|
+
assert.isPositiveInteger(tile_count, 'weights.length');
|
|
29
|
+
|
|
30
|
+
/** @type {number} */
|
|
31
|
+
this.tile_count = tile_count;
|
|
32
|
+
|
|
33
|
+
/** @type {Float64Array} */
|
|
34
|
+
this.weight = new Float64Array(tile_count);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* `w · ln(w)`, the numerator term of the Shannon entropy of a weighted domain.
|
|
38
|
+
* @type {Float64Array}
|
|
39
|
+
*/
|
|
40
|
+
this.weight_log_weight = new Float64Array(tile_count);
|
|
41
|
+
|
|
42
|
+
let total = 0;
|
|
43
|
+
let total_log = 0;
|
|
44
|
+
|
|
45
|
+
for (let t = 0; t < tile_count; t++) {
|
|
46
|
+
const w = weights[t];
|
|
47
|
+
|
|
48
|
+
// a real throw, not an assertion: consumers strip assert.* out of shipped builds, and
|
|
49
|
+
// a non-positive weight here surfaces much later as a solve that never terminates
|
|
50
|
+
if (!(w > 0) || !Number.isFinite(w)) {
|
|
51
|
+
throw new Error(`weight[${t}](=${w}) must be finite and strictly positive`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const wlw = w * Math.log(w);
|
|
55
|
+
|
|
56
|
+
this.weight[t] = w;
|
|
57
|
+
this.weight_log_weight[t] = wlw;
|
|
58
|
+
|
|
59
|
+
total += w;
|
|
60
|
+
total_log += wlw;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Sum over every tile — the value a pristine cell's running sum starts at.
|
|
65
|
+
* @type {number}
|
|
66
|
+
*/
|
|
67
|
+
this.total_weight = total;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @type {number}
|
|
71
|
+
*/
|
|
72
|
+
this.total_weight_log_weight = total_log;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Every tile equally likely — the same as passing an array of ones.
|
|
77
|
+
*
|
|
78
|
+
* @param {number} tile_count
|
|
79
|
+
* @returns {WFCTileWeights}
|
|
80
|
+
*/
|
|
81
|
+
static uniform(tile_count) {
|
|
82
|
+
assert.isPositiveInteger(tile_count, 'tile_count');
|
|
83
|
+
|
|
84
|
+
return new WFCTileWeights(new Float64Array(tile_count).fill(1));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Written into the output of {@link wfc_state_read} for a cell that is not down to a single
|
|
3
|
+
* possibility — either the solve has not finished, or the cell was never eligible to be collapsed.
|
|
4
|
+
*
|
|
5
|
+
* Non-negative so the output can be a `Uint32Array`. {@link WFCRuleTable} rejects tile counts that
|
|
6
|
+
* would reach it, so it can never collide with a real tile id.
|
|
7
|
+
*
|
|
8
|
+
* @readonly
|
|
9
|
+
* @type {number}
|
|
10
|
+
*/
|
|
11
|
+
export const WFC_UNRESOLVED: number;
|
|
12
|
+
//# sourceMappingURL=WFC_UNRESOLVED.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WFC_UNRESOLVED.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/WFC_UNRESOLVED.js"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,6BAFU,MAAM,CAEyB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Written into the output of {@link wfc_state_read} for a cell that is not down to a single
|
|
3
|
+
* possibility — either the solve has not finished, or the cell was never eligible to be collapsed.
|
|
4
|
+
*
|
|
5
|
+
* Non-negative so the output can be a `Uint32Array`. {@link WFCRuleTable} rejects tile counts that
|
|
6
|
+
* would reach it, so it can never collide with a real tile id.
|
|
7
|
+
*
|
|
8
|
+
* @readonly
|
|
9
|
+
* @type {number}
|
|
10
|
+
*/
|
|
11
|
+
export const WFC_UNRESOLVED = 0xFFFFFFFF;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a solve of this shape costs in memory, before building anything.
|
|
3
|
+
*
|
|
4
|
+
* Reported separately because the terms scale differently: `rules` grows as `tile_count²` and
|
|
5
|
+
* wants to stay in cache, `state` grows with the grid and decides whether a problem fits at all,
|
|
6
|
+
* `lattice` is a flat four bytes a cell, and `heap` is only allocated by the cell-choice policies
|
|
7
|
+
* that need one.
|
|
8
|
+
*
|
|
9
|
+
* Excludes the undo trail and decision stack, which grow with how hard the search turns out to be
|
|
10
|
+
* rather than with the problem's shape.
|
|
11
|
+
*
|
|
12
|
+
* @param {number} tile_count
|
|
13
|
+
* @param {number} direction_count
|
|
14
|
+
* @param {number} cell_count
|
|
15
|
+
* @returns {{rules:number, state:number, lattice:number, heap:number, total:number}}
|
|
16
|
+
*/
|
|
17
|
+
export function wfc_estimate_bytes(tile_count: number, direction_count: number, cell_count: number): {
|
|
18
|
+
rules: number;
|
|
19
|
+
state: number;
|
|
20
|
+
lattice: number;
|
|
21
|
+
heap: number;
|
|
22
|
+
total: number;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=wfc_estimate_bytes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wfc_estimate_bytes.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/wfc_estimate_bytes.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,+CALW,MAAM,mBACN,MAAM,cACN,MAAM,GACJ;IAAC,KAAK,EAAC,MAAM,CAAC;IAAC,KAAK,EAAC,MAAM,CAAC;IAAC,OAAO,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,MAAM,CAAC;IAAC,KAAK,EAAC,MAAM,CAAA;CAAC,CA6BnF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
import { wfc_words_per_cell } from "./wfc_words_per_cell.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* What a solve of this shape costs in memory, before building anything.
|
|
6
|
+
*
|
|
7
|
+
* Reported separately because the terms scale differently: `rules` grows as `tile_count²` and
|
|
8
|
+
* wants to stay in cache, `state` grows with the grid and decides whether a problem fits at all,
|
|
9
|
+
* `lattice` is a flat four bytes a cell, and `heap` is only allocated by the cell-choice policies
|
|
10
|
+
* that need one.
|
|
11
|
+
*
|
|
12
|
+
* Excludes the undo trail and decision stack, which grow with how hard the search turns out to be
|
|
13
|
+
* rather than with the problem's shape.
|
|
14
|
+
*
|
|
15
|
+
* @param {number} tile_count
|
|
16
|
+
* @param {number} direction_count
|
|
17
|
+
* @param {number} cell_count
|
|
18
|
+
* @returns {{rules:number, state:number, lattice:number, heap:number, total:number}}
|
|
19
|
+
*/
|
|
20
|
+
export function wfc_estimate_bytes(tile_count, direction_count, cell_count) {
|
|
21
|
+
assert.isPositiveInteger(tile_count, 'tile_count');
|
|
22
|
+
assert.isPositiveInteger(direction_count, 'direction_count');
|
|
23
|
+
assert.isPositiveInteger(cell_count, 'cell_count');
|
|
24
|
+
|
|
25
|
+
const words_per_cell = wfc_words_per_cell(tile_count);
|
|
26
|
+
|
|
27
|
+
const rules = (direction_count * tile_count * words_per_cell * 4)
|
|
28
|
+
+ (direction_count * words_per_cell * 4);
|
|
29
|
+
|
|
30
|
+
// weight_sum + weight_log_sum (8 each), wave (4 per word), possibility_count + queue +
|
|
31
|
+
// dirty_list (4 each), in_queue + dirty + eligible (1 each)
|
|
32
|
+
const state = cell_count * (16 + (words_per_cell * 4) + 12 + 3);
|
|
33
|
+
|
|
34
|
+
const lattice = cell_count * 4;
|
|
35
|
+
|
|
36
|
+
// IndexedFloatMinHeap: a 4-byte id->slot entry per cell, plus 8 bytes per occupied slot, and
|
|
37
|
+
// every cell can be in it at once
|
|
38
|
+
const heap = cell_count * 12;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
rules,
|
|
42
|
+
state,
|
|
43
|
+
lattice,
|
|
44
|
+
heap,
|
|
45
|
+
total: rules + state + lattice + heap
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Partition the tiles into connected components of the adjacency graph — `t` and `u` are joined
|
|
3
|
+
* when `t` may touch `u` in any direction.
|
|
4
|
+
*
|
|
5
|
+
* **Every solution draws its tiles from exactly one component**, because a lattice is connected
|
|
6
|
+
* and each step along a path between two cells forces their tiles to be adjacent in this graph.
|
|
7
|
+
*
|
|
8
|
+
* More than one component is therefore worth knowing about: the solve still succeeds, it just
|
|
9
|
+
* picks a component and never emits anything from the others, so a tile set that has accidentally
|
|
10
|
+
* split loses tiles with no error anywhere.
|
|
11
|
+
* {@link WFCRuleTable#rows_without_support} does not catch this — every tile in every island can
|
|
12
|
+
* still have support in every direction.
|
|
13
|
+
*
|
|
14
|
+
* Reported rather than acted on, since a tile set deliberately holding two alternatives to pick
|
|
15
|
+
* between per solve is legitimate.
|
|
16
|
+
*
|
|
17
|
+
* The graph unions over every direction, which can only merge components a lattice using fewer
|
|
18
|
+
* directions would keep apart. The partition is therefore coarser than the truth, so "different
|
|
19
|
+
* components" is always sound while "same component" does not prove reachability.
|
|
20
|
+
*
|
|
21
|
+
* @param {Uint32Array|number[]} out_component at least `tile_count` long; receives a component id
|
|
22
|
+
* in `[0, count)` for each tile, numbered by the smallest tile in each so they are stable
|
|
23
|
+
* @param {WFCRuleTable} rules
|
|
24
|
+
* @returns {number} number of components
|
|
25
|
+
*/
|
|
26
|
+
export function wfc_rule_table_tile_components(out_component: Uint32Array | number[], rules: WFCRuleTable): number;
|
|
27
|
+
//# sourceMappingURL=wfc_rule_table_tile_components.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wfc_rule_table_tile_components.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/wfc_rule_table_tile_components.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,8DALW,WAAW,GAAC,MAAM,EAAE,wBAGlB,MAAM,CAoDlB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
import { ctz32 } from "../binary/ctz32.js";
|
|
3
|
+
import { uf_find, uf_init, uf_union } from "../collection/union-find/union_find.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Partition the tiles into connected components of the adjacency graph — `t` and `u` are joined
|
|
7
|
+
* when `t` may touch `u` in any direction.
|
|
8
|
+
*
|
|
9
|
+
* **Every solution draws its tiles from exactly one component**, because a lattice is connected
|
|
10
|
+
* and each step along a path between two cells forces their tiles to be adjacent in this graph.
|
|
11
|
+
*
|
|
12
|
+
* More than one component is therefore worth knowing about: the solve still succeeds, it just
|
|
13
|
+
* picks a component and never emits anything from the others, so a tile set that has accidentally
|
|
14
|
+
* split loses tiles with no error anywhere.
|
|
15
|
+
* {@link WFCRuleTable#rows_without_support} does not catch this — every tile in every island can
|
|
16
|
+
* still have support in every direction.
|
|
17
|
+
*
|
|
18
|
+
* Reported rather than acted on, since a tile set deliberately holding two alternatives to pick
|
|
19
|
+
* between per solve is legitimate.
|
|
20
|
+
*
|
|
21
|
+
* The graph unions over every direction, which can only merge components a lattice using fewer
|
|
22
|
+
* directions would keep apart. The partition is therefore coarser than the truth, so "different
|
|
23
|
+
* components" is always sound while "same component" does not prove reachability.
|
|
24
|
+
*
|
|
25
|
+
* @param {Uint32Array|number[]} out_component at least `tile_count` long; receives a component id
|
|
26
|
+
* in `[0, count)` for each tile, numbered by the smallest tile in each so they are stable
|
|
27
|
+
* @param {WFCRuleTable} rules
|
|
28
|
+
* @returns {number} number of components
|
|
29
|
+
*/
|
|
30
|
+
export function wfc_rule_table_tile_components(out_component, rules) {
|
|
31
|
+
assert.defined(rules, 'rules');
|
|
32
|
+
assert.isArrayLike(out_component, 'out_component');
|
|
33
|
+
assert.greaterThanOrEqual(out_component.length, rules.tile_count, 'out_component.length >= tile_count');
|
|
34
|
+
|
|
35
|
+
const { data, tile_count, direction_count, words_per_cell } = rules;
|
|
36
|
+
|
|
37
|
+
// one allocation for a diagnostic that runs once per rule table, rather than module-static
|
|
38
|
+
// scratch that two callers could share
|
|
39
|
+
const parent = new Uint32Array(tile_count);
|
|
40
|
+
|
|
41
|
+
uf_init(parent, tile_count);
|
|
42
|
+
|
|
43
|
+
for (let d = 0; d < direction_count; d++) {
|
|
44
|
+
const direction_base = d * tile_count * words_per_cell;
|
|
45
|
+
|
|
46
|
+
for (let t = 0; t < tile_count; t++) {
|
|
47
|
+
const row = direction_base + t * words_per_cell;
|
|
48
|
+
|
|
49
|
+
for (let w = 0; w < words_per_cell; w++) {
|
|
50
|
+
let word = data[row + w];
|
|
51
|
+
const tile_base = w << 5;
|
|
52
|
+
|
|
53
|
+
while (word !== 0) {
|
|
54
|
+
const low = word & -word;
|
|
55
|
+
|
|
56
|
+
word ^= low;
|
|
57
|
+
|
|
58
|
+
uf_union(parent, t, tile_base + ctz32(low));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// `uf_union` keeps the smallest index as the root, so walking tiles in ascending order and
|
|
65
|
+
// numbering each root the first time it appears gives ids ordered by their smallest member
|
|
66
|
+
let count = 0;
|
|
67
|
+
|
|
68
|
+
for (let t = 0; t < tile_count; t++) {
|
|
69
|
+
const root = uf_find(parent, t);
|
|
70
|
+
|
|
71
|
+
if (root === t) {
|
|
72
|
+
out_component[t] = count;
|
|
73
|
+
count++;
|
|
74
|
+
} else {
|
|
75
|
+
out_component[t] = out_component[root];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return count;
|
|
80
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drive the solve until it finishes, proves the instance unsatisfiable, or runs out of budget.
|
|
3
|
+
*
|
|
4
|
+
* Returning {@link WFCStatus.RUNNING} means only that the budget ran out; call again to continue,
|
|
5
|
+
* including part-way through a propagation wave. That makes the solver drivable from a task graph
|
|
6
|
+
* or a frame loop without this module knowing about either.
|
|
7
|
+
*
|
|
8
|
+
* An operation is one edge relaxation or one collapse, so the budget tracks work rather than
|
|
9
|
+
* wall-clock.
|
|
10
|
+
*
|
|
11
|
+
* @param {WFCState} state
|
|
12
|
+
* @param {number} [max_operations] relaxations and collapses this call may perform
|
|
13
|
+
* @param {number} [max_backtracks] cumulative across calls, not per call; defaults to one per
|
|
14
|
+
* cell. Exceeding it returns {@link WFCStatus.EXHAUSTED}, whose conventional answer is to
|
|
15
|
+
* restart with a different seed.
|
|
16
|
+
* @returns {WFCStatus}
|
|
17
|
+
*/
|
|
18
|
+
export function wfc_solve(state: WFCState, max_operations?: number, max_backtracks?: number): WFCStatus;
|
|
19
|
+
import { WFCState } from "./WFCState.js";
|
|
20
|
+
import { WFCStatus } from "./WFCStatus.js";
|
|
21
|
+
//# sourceMappingURL=wfc_solve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wfc_solve.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/wfc_solve.js"],"names":[],"mappings":"AA2EA;;;;;;;;;;;;;;;;GAgBG;AACH,iCAPW,QAAQ,mBACR,MAAM,mBACN,MAAM,GAGJ,SAAS,CA+DrB;yBAxJwB,eAAe;0BACd,gBAAgB"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
import { WFCState } from "./WFCState.js";
|
|
3
|
+
import { WFCStatus } from "./WFCStatus.js";
|
|
4
|
+
import { wfc_state_ban_bits } from "./wfc_state_ban_bits.js";
|
|
5
|
+
import { wfc_state_collapse } from "./wfc_state_collapse.js";
|
|
6
|
+
import { wfc_state_flush_dirty } from "./wfc_state_flush_dirty.js";
|
|
7
|
+
import { wfc_state_propagate } from "./wfc_state_propagate.js";
|
|
8
|
+
import { wfc_state_undo_to } from "./wfc_state_undo_to.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Next cell to collapse, or `-1` when none is left.
|
|
12
|
+
*
|
|
13
|
+
* @param {WFCState} state
|
|
14
|
+
* @returns {number}
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
17
|
+
function select_cell(state) {
|
|
18
|
+
const heap = state.heap;
|
|
19
|
+
|
|
20
|
+
if (heap !== null) {
|
|
21
|
+
// the flush keeps the heap in step with the wave, so a popped cell should always still be
|
|
22
|
+
// undecided; skipping rather than trusting turns a bookkeeping slip into a wasted decision
|
|
23
|
+
// instead of a spurious contradiction
|
|
24
|
+
for (let cell = heap.pop_min(); cell !== -1; cell = heap.pop_min()) {
|
|
25
|
+
if (state.possibility_count[cell] > 1 && state.eligible[cell] === 1) {
|
|
26
|
+
return cell;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return -1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const { cell_count, eligible, possibility_count } = state;
|
|
34
|
+
|
|
35
|
+
let cursor = state.scan_cursor;
|
|
36
|
+
|
|
37
|
+
while (cursor < cell_count && (eligible[cursor] === 0 || possibility_count[cursor] <= 1)) {
|
|
38
|
+
cursor++;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
state.scan_cursor = cursor;
|
|
42
|
+
|
|
43
|
+
return cursor < cell_count ? cursor : -1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Undo the newest decision and forbid the tile it tried, popping further if that empties the cell.
|
|
48
|
+
*
|
|
49
|
+
* @param {WFCState} state
|
|
50
|
+
* @param {Uint32Array} decision scratch, three entries
|
|
51
|
+
* @returns {boolean} false when the decision stack is empty — the instance is unsatisfiable
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
function backtrack(state, decision) {
|
|
55
|
+
while (state.decision_pop(decision)) {
|
|
56
|
+
const cell = decision[0];
|
|
57
|
+
const trail_mark = decision[1];
|
|
58
|
+
const tile = decision[2];
|
|
59
|
+
|
|
60
|
+
wfc_state_undo_to(state, trail_mark);
|
|
61
|
+
|
|
62
|
+
wfc_state_ban_bits(state, cell, tile >> 5, (1 << (tile & 31)) >>> 0);
|
|
63
|
+
|
|
64
|
+
if (state.contradiction) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
wfc_state_flush_dirty(state);
|
|
69
|
+
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Drive the solve until it finishes, proves the instance unsatisfiable, or runs out of budget.
|
|
78
|
+
*
|
|
79
|
+
* Returning {@link WFCStatus.RUNNING} means only that the budget ran out; call again to continue,
|
|
80
|
+
* including part-way through a propagation wave. That makes the solver drivable from a task graph
|
|
81
|
+
* or a frame loop without this module knowing about either.
|
|
82
|
+
*
|
|
83
|
+
* An operation is one edge relaxation or one collapse, so the budget tracks work rather than
|
|
84
|
+
* wall-clock.
|
|
85
|
+
*
|
|
86
|
+
* @param {WFCState} state
|
|
87
|
+
* @param {number} [max_operations] relaxations and collapses this call may perform
|
|
88
|
+
* @param {number} [max_backtracks] cumulative across calls, not per call; defaults to one per
|
|
89
|
+
* cell. Exceeding it returns {@link WFCStatus.EXHAUSTED}, whose conventional answer is to
|
|
90
|
+
* restart with a different seed.
|
|
91
|
+
* @returns {WFCStatus}
|
|
92
|
+
*/
|
|
93
|
+
export function wfc_solve(state, max_operations = Infinity, max_backtracks = state.cell_count) {
|
|
94
|
+
assert.isInstanceOf(state, WFCState, 'state');
|
|
95
|
+
assert.isNumber(max_operations, 'max_operations');
|
|
96
|
+
assert.isNumber(max_backtracks, 'max_backtracks');
|
|
97
|
+
assert.greaterThanOrEqual(max_operations, 0, 'max_operations >= 0');
|
|
98
|
+
assert.greaterThanOrEqual(max_backtracks, 0, 'max_backtracks >= 0');
|
|
99
|
+
|
|
100
|
+
const decision = new Uint32Array(3);
|
|
101
|
+
|
|
102
|
+
let budget = max_operations;
|
|
103
|
+
|
|
104
|
+
while (true) {
|
|
105
|
+
budget -= wfc_state_propagate(state, budget);
|
|
106
|
+
|
|
107
|
+
if (state.contradiction) {
|
|
108
|
+
if (!backtrack(state, decision)) {
|
|
109
|
+
return WFCStatus.UNSATISFIABLE;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
state.backtrack_count++;
|
|
113
|
+
|
|
114
|
+
if (state.backtrack_count > max_backtracks) {
|
|
115
|
+
return WFCStatus.EXHAUSTED;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (state.queue_count > 0) {
|
|
122
|
+
// the budget ran out mid-wave; the queue carries the rest
|
|
123
|
+
return WFCStatus.RUNNING;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
wfc_state_flush_dirty(state);
|
|
127
|
+
|
|
128
|
+
if (state.undecided_eligible === 0) {
|
|
129
|
+
return WFCStatus.SOLVED;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (budget <= 0) {
|
|
133
|
+
return WFCStatus.RUNNING;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const cell = select_cell(state);
|
|
137
|
+
|
|
138
|
+
if (cell === -1) {
|
|
139
|
+
// undecided_eligible said there was work left and the selection queue disagreed. A
|
|
140
|
+
// real throw rather than an assert.* (consumers strip those) and rather than reporting
|
|
141
|
+
// SOLVED, which would hand back a grid with holes in it and no way to tell.
|
|
142
|
+
throw new Error(
|
|
143
|
+
`no cell to collapse with ${state.undecided_eligible} eligible cells still undecided`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const trail_mark = state.trail_length;
|
|
148
|
+
const tile = wfc_state_collapse(state, cell);
|
|
149
|
+
|
|
150
|
+
state.decision_push(cell, trail_mark, tile);
|
|
151
|
+
|
|
152
|
+
budget--;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constrain what may face the outside of the lattice.
|
|
3
|
+
*
|
|
4
|
+
* A cell on a face has no neighbour that way, so by default anything may sit there. Use this for a
|
|
5
|
+
* closed border, a floor, or a wall of a particular tile.
|
|
6
|
+
*
|
|
7
|
+
* `masks[d * words_per_cell + w]` is the set of tiles allowed in a cell whose `d` side faces
|
|
8
|
+
* outward. A wrapping axis has no outward-facing cells, so its entries are ignored.
|
|
9
|
+
*
|
|
10
|
+
* Apply before the first {@link wfc_solve} call: it narrows domains like any other restriction, so
|
|
11
|
+
* a backtrack that rewound past it would restore the tiles.
|
|
12
|
+
*
|
|
13
|
+
* @param {WFCState} state
|
|
14
|
+
* @param {Uint32Array|number[]} masks `direction_count × words_per_cell` words
|
|
15
|
+
* @returns {boolean} false when the boundary emptied some cell
|
|
16
|
+
*/
|
|
17
|
+
export function wfc_state_apply_boundary(state: WFCState, masks: Uint32Array | number[]): boolean;
|
|
18
|
+
//# sourceMappingURL=wfc_state_apply_boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wfc_state_apply_boundary.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/wfc_state_apply_boundary.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;GAeG;AACH,iEAHW,WAAW,GAAC,MAAM,EAAE,GAClB,OAAO,CA2CnB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
import { wfc_state_ban_bits } from "./wfc_state_ban_bits.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Constrain what may face the outside of the lattice.
|
|
6
|
+
*
|
|
7
|
+
* A cell on a face has no neighbour that way, so by default anything may sit there. Use this for a
|
|
8
|
+
* closed border, a floor, or a wall of a particular tile.
|
|
9
|
+
*
|
|
10
|
+
* `masks[d * words_per_cell + w]` is the set of tiles allowed in a cell whose `d` side faces
|
|
11
|
+
* outward. A wrapping axis has no outward-facing cells, so its entries are ignored.
|
|
12
|
+
*
|
|
13
|
+
* Apply before the first {@link wfc_solve} call: it narrows domains like any other restriction, so
|
|
14
|
+
* a backtrack that rewound past it would restore the tiles.
|
|
15
|
+
*
|
|
16
|
+
* @param {WFCState} state
|
|
17
|
+
* @param {Uint32Array|number[]} masks `direction_count × words_per_cell` words
|
|
18
|
+
* @returns {boolean} false when the boundary emptied some cell
|
|
19
|
+
*/
|
|
20
|
+
export function wfc_state_apply_boundary(state, masks) {
|
|
21
|
+
assert.defined(state, 'state');
|
|
22
|
+
assert.isArrayLike(masks, 'masks');
|
|
23
|
+
|
|
24
|
+
const { cell_count, words_per_cell, direction_count, wave } = state;
|
|
25
|
+
const edge_flags = state.lattice.edge_flags;
|
|
26
|
+
const wrap = state.lattice.wrap;
|
|
27
|
+
|
|
28
|
+
assert.greaterThanOrEqual(
|
|
29
|
+
masks.length,
|
|
30
|
+
direction_count * words_per_cell,
|
|
31
|
+
'masks.length >= direction_count * words_per_cell'
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
for (let cell = 0; cell < cell_count; cell++) {
|
|
35
|
+
const flags = edge_flags[cell];
|
|
36
|
+
|
|
37
|
+
if (flags === 0) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const base = cell * words_per_cell;
|
|
42
|
+
|
|
43
|
+
for (let d = 0; d < direction_count; d++) {
|
|
44
|
+
if (((flags >> d) & 1) === 0 || wrap[d >> 1] === 1) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const mask_base = d * words_per_cell;
|
|
49
|
+
|
|
50
|
+
for (let w = 0; w < words_per_cell; w++) {
|
|
51
|
+
const removable = wave[base + w] & ~masks[mask_base + w];
|
|
52
|
+
|
|
53
|
+
if (removable !== 0) {
|
|
54
|
+
wfc_state_ban_bits(state, cell, w, removable);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return !state.contradiction;
|
|
61
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pin a cell to one tile — the singleton case of {@link wfc_state_restrict}, and the usual way a
|
|
3
|
+
* caller expresses "this part of the grid is already decided".
|
|
4
|
+
*
|
|
5
|
+
* @param {WFCState} state
|
|
6
|
+
* @param {number} cell
|
|
7
|
+
* @param {number} tile
|
|
8
|
+
* @returns {boolean} false when the tile was already ruled out here, leaving the cell empty
|
|
9
|
+
*/
|
|
10
|
+
export function wfc_state_assign(state: WFCState, cell: number, tile: number): boolean;
|
|
11
|
+
//# sourceMappingURL=wfc_state_assign.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wfc_state_assign.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/wfc_state_assign.js"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wDAJW,MAAM,QACN,MAAM,GACJ,OAAO,CAyBnB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
import { wfc_state_ban_bits } from "./wfc_state_ban_bits.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pin a cell to one tile — the singleton case of {@link wfc_state_restrict}, and the usual way a
|
|
6
|
+
* caller expresses "this part of the grid is already decided".
|
|
7
|
+
*
|
|
8
|
+
* @param {WFCState} state
|
|
9
|
+
* @param {number} cell
|
|
10
|
+
* @param {number} tile
|
|
11
|
+
* @returns {boolean} false when the tile was already ruled out here, leaving the cell empty
|
|
12
|
+
*/
|
|
13
|
+
export function wfc_state_assign(state, cell, tile) {
|
|
14
|
+
assert.defined(state, 'state');
|
|
15
|
+
assert.isNonNegativeInteger(cell, 'cell');
|
|
16
|
+
assert.isNonNegativeInteger(tile, 'tile');
|
|
17
|
+
assert.lessThan(cell, state.cell_count, 'cell < cell_count');
|
|
18
|
+
assert.lessThan(tile, state.tile_count, 'tile < tile_count');
|
|
19
|
+
|
|
20
|
+
const { wave, words_per_cell } = state;
|
|
21
|
+
const base = cell * words_per_cell;
|
|
22
|
+
const tile_word = tile >> 5;
|
|
23
|
+
const tile_bit = (1 << (tile & 31)) >>> 0;
|
|
24
|
+
|
|
25
|
+
for (let w = 0; w < words_per_cell; w++) {
|
|
26
|
+
const removable = w === tile_word
|
|
27
|
+
? (wave[base + w] & ~tile_bit)
|
|
28
|
+
: wave[base + w];
|
|
29
|
+
|
|
30
|
+
if (removable !== 0) {
|
|
31
|
+
wfc_state_ban_bits(state, cell, w, removable);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return !state.contradiction;
|
|
36
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remove a set of tiles from one word of one cell's domain.
|
|
3
|
+
*
|
|
4
|
+
* Every domain shrink goes through here: it moves the wave, the undo trail, the possibility count,
|
|
5
|
+
* both weight accumulators and the cell's queue membership together, and applying a shrink any
|
|
6
|
+
* other way desynchronises them.
|
|
7
|
+
*
|
|
8
|
+
* An emptied domain is reported on `state.contradiction` rather than returned, so the propagator
|
|
9
|
+
* checks it once per relaxation instead of once per call.
|
|
10
|
+
*
|
|
11
|
+
* @param {WFCState} state
|
|
12
|
+
* @param {number} cell
|
|
13
|
+
* @param {number} word_index which word of the cell's domain, in `[0, words_per_cell)`
|
|
14
|
+
* @param {number} bits tiles to remove; bits already clear are ignored
|
|
15
|
+
*/
|
|
16
|
+
export function wfc_state_ban_bits(state: WFCState, cell: number, word_index: number, bits: number): void;
|
|
17
|
+
//# sourceMappingURL=wfc_state_ban_bits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wfc_state_ban_bits.d.ts","sourceRoot":"","sources":["../../../../src/core/wfc/wfc_state_ban_bits.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,0DAJW,MAAM,cACN,MAAM,QACN,MAAM,QAiEhB"}
|