mt-lang 0.3.1 → 0.3.4
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.
- checksums.yaml +4 -4
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/lsp/diagnostics.rb +1 -1
- data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -3
- data/lib/milk_tea/tooling/linter/release_rules.rb +24 -3
- data/lib/milk_tea/tooling/linter/visitors.rb +1 -0
- data/std/blackboard.mt +100 -0
- data/std/cmd.mt +132 -0
- data/std/color.mt +245 -0
- data/std/graph.mt +237 -0
- data/std/htn.mt +254 -0
- data/std/input.mt +132 -0
- data/std/iter.mt +304 -0
- data/std/mem/ptr.mt +12 -0
- data/std/noise.mt +201 -0
- data/std/pool.mt +82 -0
- data/std/signal.mt +66 -0
- data/std/simd.mt +100 -0
- data/std/steering.mt +132 -0
- data/std/timer.mt +81 -0
- data/std/tween.mt +374 -0
- data/std/utility.mt +208 -0
- metadata +17 -2
data/std/iter.mt
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
## std.iter — composable, lazy iteration adaptors.
|
|
2
|
+
##
|
|
3
|
+
## Each source/adaptor creates heap-allocated state linked through
|
|
4
|
+
## function pointers. Release walks the chain to free all allocations.
|
|
5
|
+
## Callbacks use fn types (function pointers, no captures).
|
|
6
|
+
##
|
|
7
|
+
## iter_map stores the mapped value inline in the adaptor state and
|
|
8
|
+
## returns a pointer to it — no per-item allocation.
|
|
9
|
+
##
|
|
10
|
+
## Usage:
|
|
11
|
+
## import std.iter
|
|
12
|
+
## let it = iter.from_array(ref_of(arr))
|
|
13
|
+
## let it2 = iter.iter_filter(it, pred)
|
|
14
|
+
## let v = iter.collect_vec(it2)
|
|
15
|
+
|
|
16
|
+
import std.mem.heap as heap
|
|
17
|
+
import std.mem.ptr as ptr
|
|
18
|
+
import std.vec as v
|
|
19
|
+
|
|
20
|
+
## ── Core Iter type ───────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
struct Iter[T]:
|
|
23
|
+
state: ptr[void]
|
|
24
|
+
next_fn: fn(state: ptr[void]) -> ptr[T]?
|
|
25
|
+
release_fn: fn(state: ptr[void]) -> void
|
|
26
|
+
|
|
27
|
+
## ── Ownership helpers ────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
public function own_to_ptr[T](owned: own[T]) -> ptr[void]:
|
|
30
|
+
return unsafe: ptr[void]<-owned
|
|
31
|
+
|
|
32
|
+
## ── Source: Vec ─────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
public function from_vec[T](vec: ref[v.Vec[T]]) -> Iter[T]:
|
|
35
|
+
return from_span(vec.as_span())
|
|
36
|
+
|
|
37
|
+
## ── Source: array ────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
public function from_array[T, N](arr: ref[array[T, N]]) -> Iter[T]:
|
|
40
|
+
return from_span(arr.as_span())
|
|
41
|
+
|
|
42
|
+
## ── .as_iter() extending blocks ──────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
extending v.Vec[T]:
|
|
45
|
+
public editable function as_iter() -> Iter[T]:
|
|
46
|
+
return from_vec(ref_of(this))
|
|
47
|
+
|
|
48
|
+
extending array[T, N]:
|
|
49
|
+
public editable function as_iter() -> Iter[T]:
|
|
50
|
+
return from_array[T, N](ref_of(this))
|
|
51
|
+
|
|
52
|
+
extending span[T]:
|
|
53
|
+
public function as_iter() -> Iter[T]:
|
|
54
|
+
return from_span(this)
|
|
55
|
+
|
|
56
|
+
## ── Source: span ─────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
struct SpanIterState[T]:
|
|
59
|
+
sp: span[T]
|
|
60
|
+
index: ptr_uint
|
|
61
|
+
|
|
62
|
+
public function span_advance[T](state: ptr[void]) -> ptr[T]?:
|
|
63
|
+
let s = unsafe: ptr[SpanIterState[T]]<-state
|
|
64
|
+
let _this = unsafe: read(s)
|
|
65
|
+
if _this.index >= _this.sp.len:
|
|
66
|
+
return null
|
|
67
|
+
let item = unsafe: _this.sp.data + _this.index
|
|
68
|
+
unsafe: read(s).index += 1
|
|
69
|
+
return item
|
|
70
|
+
|
|
71
|
+
public function span_release[T](state: ptr[void]) -> void:
|
|
72
|
+
let s = unsafe: ptr[SpanIterState[T]]<-state
|
|
73
|
+
heap.release[SpanIterState[T]](s)
|
|
74
|
+
|
|
75
|
+
public function from_span[T](sp: span[T]) -> Iter[T]:
|
|
76
|
+
let state = heap.must_alloc[SpanIterState[T]](1)
|
|
77
|
+
state.index = 0
|
|
78
|
+
state.sp = sp
|
|
79
|
+
let p = own_to_ptr(state)
|
|
80
|
+
return Iter[T](state = p, next_fn = span_advance[T], release_fn = span_release[T])
|
|
81
|
+
|
|
82
|
+
## ── Adaptor: Filter ──────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
struct FilterState[T]:
|
|
85
|
+
inner: Iter[T]
|
|
86
|
+
pred: fn(value: T) -> bool
|
|
87
|
+
|
|
88
|
+
public function filter_advance[T](state: ptr[void]) -> ptr[T]?:
|
|
89
|
+
let s = unsafe: ptr[FilterState[T]]<-state
|
|
90
|
+
let _this = unsafe: read(s)
|
|
91
|
+
var item = _this.inner.next_fn(_this.inner.state)
|
|
92
|
+
while item != null:
|
|
93
|
+
if _this.pred(item.load()):
|
|
94
|
+
return item
|
|
95
|
+
item = _this.inner.next_fn(_this.inner.state)
|
|
96
|
+
return null
|
|
97
|
+
|
|
98
|
+
public function filter_release[T](state: ptr[void]) -> void:
|
|
99
|
+
let s = unsafe: ptr[FilterState[T]]<-state
|
|
100
|
+
let _this = unsafe: read(s)
|
|
101
|
+
_this.inner.release_fn(_this.inner.state)
|
|
102
|
+
heap.release[FilterState[T]](s)
|
|
103
|
+
|
|
104
|
+
public function iter_filter[T](iter: Iter[T], pred: fn(value: T) -> bool) -> Iter[T]:
|
|
105
|
+
let state = heap.must_alloc[FilterState[T]](1)
|
|
106
|
+
state.inner = iter
|
|
107
|
+
state.pred = pred
|
|
108
|
+
let p = own_to_ptr(state)
|
|
109
|
+
return Iter[T](state = p, next_fn = filter_advance[T], release_fn = filter_release[T])
|
|
110
|
+
|
|
111
|
+
## ── Adaptor: Map ─────────────────────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
struct MapState[T, U]:
|
|
114
|
+
inner: Iter[T]
|
|
115
|
+
map_fn: fn(value: T) -> U
|
|
116
|
+
current: U
|
|
117
|
+
|
|
118
|
+
public function map_advance[T, U](state: ptr[void]) -> ptr[U]?:
|
|
119
|
+
let s = unsafe: ptr[MapState[T, U]]<-state
|
|
120
|
+
let current_offset = offset_of(MapState[T, U], current)
|
|
121
|
+
let p = unsafe: read(s)
|
|
122
|
+
let item = p.inner.next_fn(p.inner.state) else:
|
|
123
|
+
return null
|
|
124
|
+
let base: ptr[ubyte] = unsafe: ptr[ubyte]<-s
|
|
125
|
+
let field_ptr = unsafe: base + ptr_uint<-current_offset
|
|
126
|
+
let target: ptr[U] = unsafe: ptr[U]<-field_ptr
|
|
127
|
+
target.store(p.map_fn(item.load()))
|
|
128
|
+
return target
|
|
129
|
+
|
|
130
|
+
public function map_release[T, U](state: ptr[void]) -> void:
|
|
131
|
+
let s = unsafe: ptr[MapState[T, U]]<-state
|
|
132
|
+
let _this = unsafe: read(s)
|
|
133
|
+
_this.inner.release_fn(_this.inner.state)
|
|
134
|
+
heap.release[MapState[T, U]](s)
|
|
135
|
+
|
|
136
|
+
public function iter_map[T, U](iter: Iter[T], f: fn(value: T) -> U) -> Iter[U]:
|
|
137
|
+
let state = heap.must_alloc[MapState[T, U]](1)
|
|
138
|
+
state.inner = iter
|
|
139
|
+
state.map_fn = f
|
|
140
|
+
let p = own_to_ptr(state)
|
|
141
|
+
return Iter[U](state = p, next_fn = map_advance[T, U], release_fn = map_release[T, U])
|
|
142
|
+
|
|
143
|
+
## ── Adaptor: Take ────────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
struct TakeState[T]:
|
|
146
|
+
inner: Iter[T]
|
|
147
|
+
remaining: int
|
|
148
|
+
|
|
149
|
+
public function take_advance[T](state: ptr[void]) -> ptr[T]?:
|
|
150
|
+
let s = unsafe: ptr[TakeState[T]]<-state
|
|
151
|
+
let _this = unsafe: read(s)
|
|
152
|
+
if _this.remaining <= 0:
|
|
153
|
+
return null
|
|
154
|
+
unsafe: read(s).remaining -= 1
|
|
155
|
+
return _this.inner.next_fn(_this.inner.state)
|
|
156
|
+
|
|
157
|
+
public function take_release[T](state: ptr[void]) -> void:
|
|
158
|
+
let s = unsafe: ptr[TakeState[T]]<-state
|
|
159
|
+
let _this = unsafe: read(s)
|
|
160
|
+
_this.inner.release_fn(_this.inner.state)
|
|
161
|
+
heap.release[TakeState[T]](s)
|
|
162
|
+
|
|
163
|
+
public function iter_take[T](iter: Iter[T], n: int) -> Iter[T]:
|
|
164
|
+
let state = heap.must_alloc[TakeState[T]](1)
|
|
165
|
+
state.inner = iter
|
|
166
|
+
state.remaining = n
|
|
167
|
+
let p = own_to_ptr(state)
|
|
168
|
+
return Iter[T](state = p, next_fn = take_advance[T], release_fn = take_release[T])
|
|
169
|
+
|
|
170
|
+
## ── Adaptor: Skip ────────────────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
struct SkipState[T]:
|
|
173
|
+
inner: Iter[T]
|
|
174
|
+
skip_count: int
|
|
175
|
+
|
|
176
|
+
public function skip_advance[T](state: ptr[void]) -> ptr[T]?:
|
|
177
|
+
let s = unsafe: ptr[SkipState[T]]<-state
|
|
178
|
+
let _this = unsafe: read(s)
|
|
179
|
+
while _this.skip_count > 0:
|
|
180
|
+
let _ = _this.inner.next_fn(_this.inner.state) else:
|
|
181
|
+
return null
|
|
182
|
+
unsafe: read(s).skip_count -= 1
|
|
183
|
+
return _this.inner.next_fn(_this.inner.state)
|
|
184
|
+
|
|
185
|
+
public function skip_release[T](state: ptr[void]) -> void:
|
|
186
|
+
let s = unsafe: ptr[SkipState[T]]<-state
|
|
187
|
+
let _this = unsafe: read(s)
|
|
188
|
+
_this.inner.release_fn(_this.inner.state)
|
|
189
|
+
heap.release[SkipState[T]](s)
|
|
190
|
+
|
|
191
|
+
public function iter_skip[T](iter: Iter[T], n: int) -> Iter[T]:
|
|
192
|
+
let state = heap.must_alloc[SkipState[T]](1)
|
|
193
|
+
state.inner = iter
|
|
194
|
+
state.skip_count = n
|
|
195
|
+
let p = own_to_ptr(state)
|
|
196
|
+
return Iter[T](state = p, next_fn = skip_advance[T], release_fn = skip_release[T])
|
|
197
|
+
|
|
198
|
+
## ── Adaptor: Enumerate ────────────────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
struct Enumerated[T]:
|
|
201
|
+
index: ptr_uint
|
|
202
|
+
value: T
|
|
203
|
+
|
|
204
|
+
struct EnumerateState[T]:
|
|
205
|
+
inner: Iter[T]
|
|
206
|
+
index: ptr_uint
|
|
207
|
+
current: Enumerated[T]
|
|
208
|
+
|
|
209
|
+
public function enum_advance[T](state: ptr[void]) -> ptr[Enumerated[T]]?:
|
|
210
|
+
let s = unsafe: ptr[EnumerateState[T]]<-state
|
|
211
|
+
let current_offset = offset_of(EnumerateState[T], current)
|
|
212
|
+
let p = unsafe: read(s)
|
|
213
|
+
let item = p.inner.next_fn(p.inner.state) else:
|
|
214
|
+
return null
|
|
215
|
+
let base: ptr[ubyte] = unsafe: ptr[ubyte]<-s
|
|
216
|
+
let field_ptr = unsafe: base + ptr_uint<-current_offset
|
|
217
|
+
let target: ptr[Enumerated[T]] = unsafe: ptr[Enumerated[T]]<-field_ptr
|
|
218
|
+
target.store(Enumerated[T](index = p.index, value = item.load()))
|
|
219
|
+
unsafe: read(s).index += 1
|
|
220
|
+
return target
|
|
221
|
+
|
|
222
|
+
public function enum_release[T](state: ptr[void]) -> void:
|
|
223
|
+
let s = unsafe: ptr[EnumerateState[T]]<-state
|
|
224
|
+
let _this = unsafe: read(s)
|
|
225
|
+
_this.inner.release_fn(_this.inner.state)
|
|
226
|
+
heap.release[EnumerateState[T]](s)
|
|
227
|
+
|
|
228
|
+
public function iter_enumerate[T](iter: Iter[T]) -> Iter[Enumerated[T]]:
|
|
229
|
+
let state = heap.must_alloc[EnumerateState[T]](1)
|
|
230
|
+
state.inner = iter
|
|
231
|
+
state.index = 0
|
|
232
|
+
let p = own_to_ptr(state)
|
|
233
|
+
let enum_it = Iter[Enumerated[T]](state = p, next_fn = enum_advance[T], release_fn = enum_release[T])
|
|
234
|
+
return enum_it
|
|
235
|
+
|
|
236
|
+
## ── Consumer: Fold ───────────────────────────────────────────────────
|
|
237
|
+
|
|
238
|
+
public function iter_fold[T, U](iter: Iter[T], init: U, f: fn(accum: U, value: T) -> U) -> U:
|
|
239
|
+
var accum = init
|
|
240
|
+
var item = iter.next_fn(iter.state)
|
|
241
|
+
while item != null:
|
|
242
|
+
accum = f(accum, item.load())
|
|
243
|
+
item = iter.next_fn(iter.state)
|
|
244
|
+
iter.release_fn(iter.state)
|
|
245
|
+
return accum
|
|
246
|
+
|
|
247
|
+
## ── Consumer: Find ───────────────────────────────────────────────────
|
|
248
|
+
|
|
249
|
+
public function iter_find[T](iter: Iter[T], pred: fn(value: T) -> bool) -> Option[T]:
|
|
250
|
+
var item = iter.next_fn(iter.state)
|
|
251
|
+
while item != null:
|
|
252
|
+
if pred(item.load()):
|
|
253
|
+
let val = item.load()
|
|
254
|
+
iter.release_fn(iter.state)
|
|
255
|
+
return Option[T].some(value = val)
|
|
256
|
+
item = iter.next_fn(iter.state)
|
|
257
|
+
iter.release_fn(iter.state)
|
|
258
|
+
return Option[T].none
|
|
259
|
+
|
|
260
|
+
## ── Consumer: Any ────────────────────────────────────────────────────
|
|
261
|
+
|
|
262
|
+
public function iter_any[T](iter: Iter[T], pred: fn(value: T) -> bool) -> bool:
|
|
263
|
+
var item = iter.next_fn(iter.state)
|
|
264
|
+
while item != null:
|
|
265
|
+
if pred(item.load()):
|
|
266
|
+
iter.release_fn(iter.state)
|
|
267
|
+
return true
|
|
268
|
+
item = iter.next_fn(iter.state)
|
|
269
|
+
iter.release_fn(iter.state)
|
|
270
|
+
return false
|
|
271
|
+
|
|
272
|
+
## ── Consumer: All ────────────────────────────────────────────────────
|
|
273
|
+
|
|
274
|
+
public function iter_all[T](iter: Iter[T], pred: fn(value: T) -> bool) -> bool:
|
|
275
|
+
var item = iter.next_fn(iter.state)
|
|
276
|
+
while item != null:
|
|
277
|
+
if not pred(item.load()):
|
|
278
|
+
iter.release_fn(iter.state)
|
|
279
|
+
return false
|
|
280
|
+
item = iter.next_fn(iter.state)
|
|
281
|
+
iter.release_fn(iter.state)
|
|
282
|
+
return true
|
|
283
|
+
|
|
284
|
+
## ── Consumer: Count ──────────────────────────────────────────────────
|
|
285
|
+
|
|
286
|
+
public function iter_count[T](iter: Iter[T]) -> ptr_uint:
|
|
287
|
+
var count: ptr_uint = 0
|
|
288
|
+
var item = iter.next_fn(iter.state)
|
|
289
|
+
while item != null:
|
|
290
|
+
count += 1
|
|
291
|
+
item = iter.next_fn(iter.state)
|
|
292
|
+
iter.release_fn(iter.state)
|
|
293
|
+
return count
|
|
294
|
+
|
|
295
|
+
## ── Collect: Vec ─────────────────────────────────────────────────────
|
|
296
|
+
|
|
297
|
+
public function collect_vec[T](iter: Iter[T]) -> v.Vec[T]:
|
|
298
|
+
var result = v.Vec[T].create()
|
|
299
|
+
var item = iter.next_fn(iter.state)
|
|
300
|
+
while item != null:
|
|
301
|
+
result.push(item.load())
|
|
302
|
+
item = iter.next_fn(iter.state)
|
|
303
|
+
iter.release_fn(iter.state)
|
|
304
|
+
return result
|
data/std/mem/ptr.mt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
## Pointer load/store — safe wrappers around unsafe: read(ptr).
|
|
2
|
+
##
|
|
3
|
+
## import std.mem.ptr as ptr
|
|
4
|
+
## p.store(42)
|
|
5
|
+
## let v = p.load()
|
|
6
|
+
|
|
7
|
+
extending ptr[T]:
|
|
8
|
+
public function load() -> T:
|
|
9
|
+
return unsafe: read(this)
|
|
10
|
+
|
|
11
|
+
public function store(value: T) -> void:
|
|
12
|
+
unsafe: read(this) = value
|
data/std/noise.mt
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
## Coherent noise generation — Perlin noise and fractal variants.
|
|
2
|
+
##
|
|
3
|
+
## Seed-based deterministic noise for procedural generation:
|
|
4
|
+
## terrain, textures, fog, animation, and more.
|
|
5
|
+
##
|
|
6
|
+
## import std.noise as ns
|
|
7
|
+
## var noise = ns.Noise.create(42)
|
|
8
|
+
## let h = noise.fbm2d(x * 0.01, y * 0.01)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
public struct Noise:
|
|
12
|
+
perm: array[ubyte, 512]
|
|
13
|
+
octaves: int
|
|
14
|
+
lacunarity: float
|
|
15
|
+
gain: float
|
|
16
|
+
frequency: float
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# ── fade / interpolation ──
|
|
20
|
+
|
|
21
|
+
function fade(t: float) -> float:
|
|
22
|
+
return t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
function lerp(a: float, b: float, t: float) -> float:
|
|
26
|
+
return a + t * (b - a)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# ── gradient functions ──
|
|
30
|
+
|
|
31
|
+
function grad2d(hash: int, x: float, y: float) -> float:
|
|
32
|
+
let h = hash & 3
|
|
33
|
+
let u = if h == 0 or h == 1: x else: y
|
|
34
|
+
let v = if h == 0 or h == 3: y else: x
|
|
35
|
+
return (if (h & 1) == 0: u else: -u) + (if (h & 2) == 0: v else: -v)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
function grad3d(hash: int, x: float, y: float, z: float) -> float:
|
|
39
|
+
let h = hash & 15
|
|
40
|
+
let u = if h < 8: x else: y
|
|
41
|
+
let v = if h < 4: y else: if h == 12 or h == 14: x else: z
|
|
42
|
+
let mu = if (h & 1) == 0: u else: -u
|
|
43
|
+
let mv = if (h & 2) == 0: v else: -v
|
|
44
|
+
return mu + mv
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# ── internal noise functions ──
|
|
48
|
+
|
|
49
|
+
function perlin2d_impl(perm: array[ubyte, 512], x: float, y: float) -> float:
|
|
50
|
+
let ix = int<-(x)
|
|
51
|
+
let iy = int<-(y)
|
|
52
|
+
let X = ix & 255
|
|
53
|
+
let Y = iy & 255
|
|
54
|
+
let xf = x - float<-(ix - (ix & ~255))
|
|
55
|
+
let yf = y - float<-(iy - (iy & ~255))
|
|
56
|
+
|
|
57
|
+
let u = fade(if xf < 0.0: xf + 1.0 else: xf)
|
|
58
|
+
let v = fade(if yf < 0.0: yf + 1.0 else: yf)
|
|
59
|
+
|
|
60
|
+
let A = int<-(perm[X]) + Y
|
|
61
|
+
let B = int<-(perm[X + 1]) + Y
|
|
62
|
+
let aa = int<-(perm[A])
|
|
63
|
+
let ab = int<-(perm[A + 1])
|
|
64
|
+
let ba = int<-(perm[B])
|
|
65
|
+
let bb = int<-(perm[B + 1])
|
|
66
|
+
|
|
67
|
+
let x1 = lerp(grad2d(aa, xf, yf), grad2d(ba, xf - 1.0, yf), u)
|
|
68
|
+
let x2 = lerp(grad2d(ab, xf, yf - 1.0), grad2d(bb, xf - 1.0, yf - 1.0), u)
|
|
69
|
+
|
|
70
|
+
return lerp(x1, x2, v)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
function perlin3d_impl(perm: array[ubyte, 512], x: float, y: float, z: float) -> float:
|
|
74
|
+
let ix = int<-(x)
|
|
75
|
+
let iy = int<-(y)
|
|
76
|
+
let iz = int<-(z)
|
|
77
|
+
let X = ix & 255
|
|
78
|
+
let Y = iy & 255
|
|
79
|
+
let Z = iz & 255
|
|
80
|
+
let xf = x - float<-(ix - (ix & ~255))
|
|
81
|
+
let yf = y - float<-(iy - (iy & ~255))
|
|
82
|
+
let zf = z - float<-(iz - (iz & ~255))
|
|
83
|
+
|
|
84
|
+
let u = fade(if xf < 0.0: xf + 1.0 else: xf)
|
|
85
|
+
let v = fade(if yf < 0.0: yf + 1.0 else: yf)
|
|
86
|
+
let w = fade(if zf < 0.0: zf + 1.0 else: zf)
|
|
87
|
+
|
|
88
|
+
let A = int<-(perm[X]) + Y
|
|
89
|
+
let AA = int<-(perm[A]) + Z
|
|
90
|
+
let AB = int<-(perm[A + 1]) + Z
|
|
91
|
+
let B = int<-(perm[X + 1]) + Y
|
|
92
|
+
let BA = int<-(perm[B]) + Z
|
|
93
|
+
let BB = int<-(perm[B + 1]) + Z
|
|
94
|
+
|
|
95
|
+
let x1 = lerp(grad3d(int<-(perm[AA]), xf, yf, zf), grad3d(int<-(perm[BA]), xf - 1.0, yf, zf), u)
|
|
96
|
+
let x2 = lerp(grad3d(int<-(perm[AB]), xf, yf - 1.0, zf), grad3d(int<-(perm[BB]), xf - 1.0, yf - 1.0, zf), u)
|
|
97
|
+
let y1 = lerp(x1, x2, v)
|
|
98
|
+
|
|
99
|
+
let x3 = lerp(grad3d(int<-(perm[AA + 1]), xf, yf, zf - 1.0), grad3d(int<-(perm[BA + 1]), xf - 1.0, yf, zf - 1.0), u)
|
|
100
|
+
let x4 = lerp(grad3d(int<-(perm[AB + 1]), xf, yf - 1.0, zf - 1.0), grad3d(int<-(perm[BB + 1]), xf - 1.0, yf - 1.0, zf - 1.0), u)
|
|
101
|
+
let y2 = lerp(x3, x4, v)
|
|
102
|
+
|
|
103
|
+
return lerp(y1, y2, w)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# ── float floor for negative numbers ──
|
|
107
|
+
|
|
108
|
+
function floor_f(x: float) -> int:
|
|
109
|
+
let i = int<-(x)
|
|
110
|
+
if x < 0.0 and float<-(i) != x:
|
|
111
|
+
return i - 1
|
|
112
|
+
return i
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# ── public API ──
|
|
116
|
+
|
|
117
|
+
extending Noise:
|
|
118
|
+
public static function create(seed: ulong) -> Noise:
|
|
119
|
+
var n = Noise(
|
|
120
|
+
perm = zero[array[ubyte, 512]],
|
|
121
|
+
octaves = 6,
|
|
122
|
+
lacunarity = 2.0,
|
|
123
|
+
gain = 0.5,
|
|
124
|
+
frequency = 1.0
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
var i: int = 0
|
|
128
|
+
while i < 256:
|
|
129
|
+
n.perm[i] = ubyte<-i
|
|
130
|
+
i += 1
|
|
131
|
+
|
|
132
|
+
var state: ulong = seed
|
|
133
|
+
var j: int = 255
|
|
134
|
+
while j > 0:
|
|
135
|
+
state = state * 6364136223846793005 + 1442695040888963407
|
|
136
|
+
let r = int<-(state % ulong<-(j + 1))
|
|
137
|
+
let tmp = n.perm[j]
|
|
138
|
+
n.perm[j] = n.perm[r]
|
|
139
|
+
n.perm[r] = tmp
|
|
140
|
+
j -= 1
|
|
141
|
+
|
|
142
|
+
i = 0
|
|
143
|
+
while i < 256:
|
|
144
|
+
n.perm[i + 256] = n.perm[i]
|
|
145
|
+
i += 1
|
|
146
|
+
|
|
147
|
+
return n
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
public function perlin2d(x: float, y: float) -> float:
|
|
151
|
+
return perlin2d_impl(this.perm, x, y)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
public function perlin3d(x: float, y: float, z: float) -> float:
|
|
155
|
+
return perlin3d_impl(this.perm, x, y, z)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
public function fbm2d(x: float, y: float) -> float:
|
|
159
|
+
var value: float = 0.0
|
|
160
|
+
var freq: float = this.frequency
|
|
161
|
+
var amp: float = 1.0
|
|
162
|
+
var max_val: float = 0.0
|
|
163
|
+
var i: int = 0
|
|
164
|
+
while i < this.octaves:
|
|
165
|
+
value = value + amp * perlin2d_impl(this.perm, x * freq, y * freq)
|
|
166
|
+
max_val = max_val + amp
|
|
167
|
+
amp = amp * this.gain
|
|
168
|
+
freq = freq * this.lacunarity
|
|
169
|
+
i += 1
|
|
170
|
+
return value / max_val
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
public function fbm3d(x: float, y: float, z: float) -> float:
|
|
174
|
+
var value: float = 0.0
|
|
175
|
+
var freq: float = this.frequency
|
|
176
|
+
var amp: float = 1.0
|
|
177
|
+
var max_val: float = 0.0
|
|
178
|
+
var i: int = 0
|
|
179
|
+
while i < this.octaves:
|
|
180
|
+
value = value + amp * perlin3d_impl(this.perm, x * freq, y * freq, z * freq)
|
|
181
|
+
max_val = max_val + amp
|
|
182
|
+
amp = amp * this.gain
|
|
183
|
+
freq = freq * this.lacunarity
|
|
184
|
+
i += 1
|
|
185
|
+
return value / max_val
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
public editable function set_octaves(n: int) -> void:
|
|
189
|
+
this.octaves = n
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
public editable function set_lacunarity(v: float) -> void:
|
|
193
|
+
this.lacunarity = v
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
public editable function set_gain(v: float) -> void:
|
|
197
|
+
this.gain = v
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
public editable function set_frequency(v: float) -> void:
|
|
201
|
+
this.frequency = v
|
data/std/pool.mt
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
## Object pool — fixed-capacity reusable object storage.
|
|
2
|
+
##
|
|
3
|
+
## Pre-allocate objects once, then acquire/release without
|
|
4
|
+
## allocation churn. O(1) acquire and release via free stack.
|
|
5
|
+
##
|
|
6
|
+
## import std.pool as pool
|
|
7
|
+
## var p = pool.Pool[Bullet].create(64)
|
|
8
|
+
## let id = p.acquire() else: /* pool exhausted */
|
|
9
|
+
## let bullet = p.get(id) # ptr to object
|
|
10
|
+
## p.release(id)
|
|
11
|
+
|
|
12
|
+
import std.vec as vec
|
|
13
|
+
import std.mem.heap as heap
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
public struct Pool[T]:
|
|
17
|
+
objects: ptr[T]
|
|
18
|
+
free_stack: vec.Vec[ptr_uint]
|
|
19
|
+
capacity: ptr_uint
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ── public API ──
|
|
23
|
+
|
|
24
|
+
extending Pool[T]:
|
|
25
|
+
public static function create(capacity: ptr_uint) -> Pool[T]:
|
|
26
|
+
var p = Pool[T](
|
|
27
|
+
objects = heap.must_alloc[T](capacity),
|
|
28
|
+
free_stack = vec.Vec[ptr_uint].with_capacity(capacity),
|
|
29
|
+
capacity = capacity
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Push all indices onto the free stack in reverse order so
|
|
33
|
+
# acquire() returns them in ascending order (0 first).
|
|
34
|
+
var i = capacity
|
|
35
|
+
while i > 0:
|
|
36
|
+
i -= 1
|
|
37
|
+
p.free_stack.push(i)
|
|
38
|
+
|
|
39
|
+
return p
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
public editable function acquire() -> Option[ptr_uint]:
|
|
43
|
+
let idx = this.free_stack.pop() else:
|
|
44
|
+
return Option[ptr_uint].none
|
|
45
|
+
return Option[ptr_uint].some(value = idx)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
public function get(index: ptr_uint) -> ptr[T]?:
|
|
49
|
+
if index >= this.capacity:
|
|
50
|
+
return null
|
|
51
|
+
unsafe:
|
|
52
|
+
return this.objects + index
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
public editable function release_object(index: ptr_uint) -> void:
|
|
56
|
+
if index >= this.capacity:
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
# Check for double-release by scanning free stack.
|
|
60
|
+
# Skip this check for simplicity — caller must not double-release.
|
|
61
|
+
this.free_stack.push(index)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
public function available() -> ptr_uint:
|
|
65
|
+
return this.free_stack.len()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
public function count() -> ptr_uint:
|
|
69
|
+
return this.capacity - this.free_stack.len()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
public editable function clear() -> void:
|
|
73
|
+
this.free_stack.clear()
|
|
74
|
+
var i = this.capacity
|
|
75
|
+
while i > 0:
|
|
76
|
+
i -= 1
|
|
77
|
+
this.free_stack.push(i)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
public editable function release() -> void:
|
|
81
|
+
this.free_stack.release()
|
|
82
|
+
heap.release(this.objects)
|
data/std/signal.mt
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
## Signal — fixed-capacity observer / publish-subscribe.
|
|
2
|
+
##
|
|
3
|
+
## Connect callbacks to signals and fire typed payloads.
|
|
4
|
+
## Up to 16 subscribers per signal, stack-allocated.
|
|
5
|
+
##
|
|
6
|
+
## import std.signal as sig
|
|
7
|
+
## var on_damage = sig.Signal[int].create()
|
|
8
|
+
## on_damage.connect(handle_damage)
|
|
9
|
+
## on_damage.fire(25)
|
|
10
|
+
|
|
11
|
+
public struct Signal[Payload]:
|
|
12
|
+
slots: array[fn(payload: Payload) -> void, 16]
|
|
13
|
+
count: ptr_uint
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ── public API ──
|
|
17
|
+
|
|
18
|
+
extending Signal[Payload]:
|
|
19
|
+
public static function create() -> Signal[Payload]:
|
|
20
|
+
var s = Signal[Payload](
|
|
21
|
+
slots = zero[array[fn(payload: Payload) -> void, 16]],
|
|
22
|
+
count = 0
|
|
23
|
+
)
|
|
24
|
+
return s
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
public editable function connect(callback: fn(payload: Payload) -> void) -> void:
|
|
28
|
+
if this.count >= 16:
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
var i: ptr_uint = 0
|
|
32
|
+
while i < this.count:
|
|
33
|
+
unsafe:
|
|
34
|
+
if this.slots[i] == callback:
|
|
35
|
+
return
|
|
36
|
+
i += 1
|
|
37
|
+
|
|
38
|
+
unsafe:
|
|
39
|
+
this.slots[this.count] = callback
|
|
40
|
+
this.count = this.count + 1
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
public editable function disconnect(callback: fn(payload: Payload) -> void) -> void:
|
|
44
|
+
var i: ptr_uint = 0
|
|
45
|
+
while i < this.count:
|
|
46
|
+
unsafe:
|
|
47
|
+
if this.slots[i] == callback:
|
|
48
|
+
# swap-remove with last
|
|
49
|
+
this.count = this.count - 1
|
|
50
|
+
if i < this.count:
|
|
51
|
+
this.slots[i] = this.slots[this.count]
|
|
52
|
+
return
|
|
53
|
+
i += 1
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
public function fire(payload: Payload) -> void:
|
|
57
|
+
var i: ptr_uint = 0
|
|
58
|
+
while i < this.count:
|
|
59
|
+
unsafe:
|
|
60
|
+
let cb = this.slots[i]
|
|
61
|
+
cb(payload)
|
|
62
|
+
i += 1
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
public function count() -> ptr_uint:
|
|
66
|
+
return this.count
|