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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7cd20acdc903389647adc4c6c7e552fdbbf35694f69328b0427134109782b21f
|
|
4
|
+
data.tar.gz: 5cc1498f88f6ddb87eaa2d7a7da9f54c76a6ee9a38fe3e33f68ddc6120160057
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bcf70e8639131a5d7198028d7f70e632ebb817eba816635d24d753dfa4023bc0364e0b8a6082f2ccd747d40bf7c5f7d778ad2efeb2b6283e6c10604a4f44492b
|
|
7
|
+
data.tar.gz: b802f4c8cc2654c8464ec156967430573577a76316d916e31e5b043d81a61a8e2279bf5fadc037b38f2f388e3241507b4f17be08b78558fa2424da4b72315c31
|
data/lib/milk_tea/base.rb
CHANGED
|
@@ -211,7 +211,7 @@ module MilkTea
|
|
|
211
211
|
unresolved_import_paths.include?(import_path)
|
|
212
212
|
end
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
def self.path_to_uri(path)
|
|
215
215
|
escaped_path = path.split('/').map { |seg| CGI.escape(seg).gsub('+', '%20') }.join('/')
|
|
216
216
|
"file://#{escaped_path}"
|
|
217
217
|
end
|
|
@@ -605,10 +605,13 @@ module MilkTea
|
|
|
605
605
|
end
|
|
606
606
|
|
|
607
607
|
def collect_method_provider_import_uses(receiver, member_name, used, binding_resolution)
|
|
608
|
-
return unless receiver.is_a?(AST::Identifier)
|
|
609
608
|
return unless @sema_facts.respond_to?(:imports)
|
|
610
609
|
|
|
611
|
-
receiver_type =
|
|
610
|
+
receiver_type = if receiver.is_a?(AST::Identifier)
|
|
611
|
+
identifier_binding_type(receiver, binding_resolution)
|
|
612
|
+
else
|
|
613
|
+
resolved_expr_type(receiver)
|
|
614
|
+
end
|
|
612
615
|
return unless receiver_type
|
|
613
616
|
|
|
614
617
|
@sema_facts.imports.each do |local_name, module_binding|
|
|
@@ -619,6 +622,14 @@ module MilkTea
|
|
|
619
622
|
end
|
|
620
623
|
end
|
|
621
624
|
|
|
625
|
+
def resolved_expr_type(expr)
|
|
626
|
+
return nil unless @sema_facts.respond_to?(:ast) && @sema_facts.ast.respond_to?(:node_ids)
|
|
627
|
+
return nil unless @sema_facts.respond_to?(:resolved_expr_types)
|
|
628
|
+
|
|
629
|
+
node_id = @sema_facts.ast.node_ids[expr.object_id]
|
|
630
|
+
node_id ? @sema_facts.resolved_expr_types[node_id] : nil
|
|
631
|
+
end
|
|
632
|
+
|
|
622
633
|
def identifier_binding_type(identifier, binding_resolution)
|
|
623
634
|
binding_id = binding_resolution.identifier_binding_ids[identifier.object_id]
|
|
624
635
|
return nil unless binding_id
|
|
@@ -653,7 +664,7 @@ module MilkTea
|
|
|
653
664
|
Types::Registry.generic_instance(
|
|
654
665
|
receiver_type.name,
|
|
655
666
|
receiver_type.arguments.each_with_index.map do |argument, index|
|
|
656
|
-
argument.is_a?(Types::LiteralTypeArg) ? argument : Types::TypeVar.new("
|
|
667
|
+
argument.is_a?(Types::LiteralTypeArg) ? argument : Types::TypeVar.new("__receiver_arg#{index}")
|
|
657
668
|
end,
|
|
658
669
|
)
|
|
659
670
|
when Types::StructInstance
|
|
@@ -239,16 +239,37 @@ module MilkTea
|
|
|
239
239
|
true
|
|
240
240
|
elsif stmt.is_a?(AST::Assignment) && stmt.value.is_a?(AST::Identifier) && stmt.value.name == name
|
|
241
241
|
true
|
|
242
|
+
elsif stmt.is_a?(AST::ReturnStmt) && own_cast_in_unsafe?(stmt.value, name)
|
|
243
|
+
true
|
|
242
244
|
else
|
|
243
245
|
false
|
|
244
246
|
end
|
|
245
247
|
end
|
|
246
248
|
end
|
|
247
249
|
|
|
250
|
+
def own_cast_in_unsafe?(expr, name)
|
|
251
|
+
case expr
|
|
252
|
+
when AST::UnsafeExpr
|
|
253
|
+
case expr.expression
|
|
254
|
+
when AST::PrefixCast
|
|
255
|
+
expr.expression.expression.is_a?(AST::Identifier) && expr.expression.expression.name == name
|
|
256
|
+
end
|
|
257
|
+
else
|
|
258
|
+
false
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
248
262
|
def own_struct_field_transfer?(expr, name)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
263
|
+
case expr
|
|
264
|
+
when AST::Call
|
|
265
|
+
expr.arguments.any? do |arg|
|
|
266
|
+
next unless arg.is_a?(AST::Argument)
|
|
267
|
+
|
|
268
|
+
arg.value.is_a?(AST::Identifier) && arg.value.name == name ||
|
|
269
|
+
own_struct_field_transfer?(arg.value, name)
|
|
270
|
+
end
|
|
271
|
+
else
|
|
272
|
+
false
|
|
252
273
|
end
|
|
253
274
|
end
|
|
254
275
|
|
|
@@ -152,6 +152,7 @@ module MilkTea
|
|
|
152
152
|
column: statement.column,
|
|
153
153
|
var: statement.kind == :var
|
|
154
154
|
)
|
|
155
|
+
with_scope { visit_statement_list(statement.else_body) } if statement.else_body
|
|
155
156
|
check_redundant_type_annotation(statement)
|
|
156
157
|
flag_redundant_widening_cast(statement.value) if statement.type && statement.value
|
|
157
158
|
record_ptr_candidate(statement)
|
data/std/blackboard.mt
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
## Blackboard — typed key-value shared state for AI.
|
|
2
|
+
##
|
|
3
|
+
## Store and retrieve named values that multiple AI systems
|
|
4
|
+
## can read and write. Linear O(n) lookup (tuned for small
|
|
5
|
+
## sizes — typical AI blackboards have under 20 entries).
|
|
6
|
+
##
|
|
7
|
+
## import std.blackboard as bb
|
|
8
|
+
## var board = bb.Blackboard[float].create()
|
|
9
|
+
## board.set("health", 100.0)
|
|
10
|
+
## let h = board.get("health") else: 0.0
|
|
11
|
+
|
|
12
|
+
import std.vec as vec
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
public struct BlackboardEntry[T]:
|
|
16
|
+
key: str
|
|
17
|
+
value: T
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
public struct Blackboard[T]:
|
|
21
|
+
entries: vec.Vec[BlackboardEntry[T]]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ── internal helpers ──
|
|
25
|
+
|
|
26
|
+
function find_entry[T](board: ref[Blackboard[T]], key: str) -> ptr[BlackboardEntry[T]]?:
|
|
27
|
+
for entry in board.entries:
|
|
28
|
+
unsafe:
|
|
29
|
+
if read(entry).key == key:
|
|
30
|
+
return entry
|
|
31
|
+
return null
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# ── public API ──
|
|
35
|
+
|
|
36
|
+
extending Blackboard[T]:
|
|
37
|
+
public static function create() -> Blackboard[T]:
|
|
38
|
+
return Blackboard[T](
|
|
39
|
+
entries = vec.Vec[BlackboardEntry[T]].create()
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
public editable function set(key: str, value: T) -> void:
|
|
44
|
+
let existing = find_entry(ref_of(this), key)
|
|
45
|
+
if existing != null:
|
|
46
|
+
unsafe:
|
|
47
|
+
read(ptr[BlackboardEntry[T]]<-existing).value = value
|
|
48
|
+
return
|
|
49
|
+
this.entries.push(BlackboardEntry[T](key = key, value = value))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
public function get(key: str) -> Option[T]:
|
|
53
|
+
var n = this.entries.len()
|
|
54
|
+
var i: ptr_uint = 0
|
|
55
|
+
while i < n:
|
|
56
|
+
let entry_ptr = this.entries.get(i) else:
|
|
57
|
+
break
|
|
58
|
+
unsafe:
|
|
59
|
+
if read(entry_ptr).key == key:
|
|
60
|
+
return Option[T].some(value = read(entry_ptr).value)
|
|
61
|
+
i += 1
|
|
62
|
+
return Option[T].none
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
public function has(key: str) -> bool:
|
|
66
|
+
var n = this.entries.len()
|
|
67
|
+
var i: ptr_uint = 0
|
|
68
|
+
while i < n:
|
|
69
|
+
let entry_ptr = this.entries.get(i) else:
|
|
70
|
+
break
|
|
71
|
+
unsafe:
|
|
72
|
+
if read(entry_ptr).key == key:
|
|
73
|
+
return true
|
|
74
|
+
i += 1
|
|
75
|
+
return false
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
public editable function remove(key: str) -> void:
|
|
79
|
+
var n = this.entries.len()
|
|
80
|
+
var i: ptr_uint = 0
|
|
81
|
+
while i < n:
|
|
82
|
+
let entry_ptr = this.entries.get(i) else:
|
|
83
|
+
break
|
|
84
|
+
unsafe:
|
|
85
|
+
if read(entry_ptr).key == key:
|
|
86
|
+
this.entries.swap_remove(i)
|
|
87
|
+
return
|
|
88
|
+
i += 1
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
public editable function clear() -> void:
|
|
92
|
+
this.entries.clear()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
public function count() -> ptr_uint:
|
|
96
|
+
return this.entries.len()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
public editable function release() -> void:
|
|
100
|
+
this.entries.release()
|
data/std/cmd.mt
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
## Command pattern — undo/redo with paired do/undo callbacks.
|
|
2
|
+
##
|
|
3
|
+
## Encapsulate reversible actions as value-objects. Stack-based
|
|
4
|
+
## history for linear undo/redo. Recording for replay capture.
|
|
5
|
+
##
|
|
6
|
+
## import std.cmd as cmd
|
|
7
|
+
## var hist = cmd.History[Editor].create()
|
|
8
|
+
## hist.execute(cmd.Cmd[Editor].create(ctx, do_insert, undo_delete))
|
|
9
|
+
## hist.undo()
|
|
10
|
+
|
|
11
|
+
import std.vec as vec
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
public struct Cmd[Context]:
|
|
15
|
+
context: ptr[Context]
|
|
16
|
+
do_fn: fn(context: ptr[Context]) -> void
|
|
17
|
+
undo_fn: fn(context: ptr[Context]) -> void
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
public struct History[Context]:
|
|
21
|
+
undos: vec.Vec[Cmd[Context]]
|
|
22
|
+
redos: vec.Vec[Cmd[Context]]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
public struct Recording[Context]:
|
|
26
|
+
cmds: vec.Vec[Cmd[Context]]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# ── Cmd ──
|
|
30
|
+
|
|
31
|
+
extending Cmd[Context]:
|
|
32
|
+
public static function create(
|
|
33
|
+
context: ptr[Context],
|
|
34
|
+
do_fn: fn(context: ptr[Context]) -> void,
|
|
35
|
+
undo_fn: fn(context: ptr[Context]) -> void
|
|
36
|
+
) -> Cmd[Context]:
|
|
37
|
+
return Cmd[Context](context = context, do_fn = do_fn, undo_fn = undo_fn)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
public function invoke() -> void:
|
|
41
|
+
this.do_fn(this.context)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
public function revert() -> void:
|
|
45
|
+
this.undo_fn(this.context)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ── History ──
|
|
49
|
+
|
|
50
|
+
extending History[Context]:
|
|
51
|
+
public static function create() -> History[Context]:
|
|
52
|
+
return History[Context](
|
|
53
|
+
undos = vec.Vec[Cmd[Context]].create(),
|
|
54
|
+
redos = vec.Vec[Cmd[Context]].create()
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
public editable function execute(cmd: Cmd[Context]) -> void:
|
|
59
|
+
cmd.invoke()
|
|
60
|
+
this.undos.push(cmd)
|
|
61
|
+
this.redos.clear()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
public editable function undo() -> bool:
|
|
65
|
+
let cmd = this.undos.pop() else:
|
|
66
|
+
return false
|
|
67
|
+
cmd.revert()
|
|
68
|
+
this.redos.push(cmd)
|
|
69
|
+
return true
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
public editable function redo() -> bool:
|
|
73
|
+
let cmd = this.redos.pop() else:
|
|
74
|
+
return false
|
|
75
|
+
cmd.invoke()
|
|
76
|
+
this.undos.push(cmd)
|
|
77
|
+
return true
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
public function can_undo() -> bool:
|
|
81
|
+
return this.undos.len() > 0
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
public function can_redo() -> bool:
|
|
85
|
+
return this.redos.len() > 0
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
public function undo_count() -> ptr_uint:
|
|
89
|
+
return this.undos.len()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
public function redo_count() -> ptr_uint:
|
|
93
|
+
return this.redos.len()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
public editable function clear() -> void:
|
|
97
|
+
this.undos.clear()
|
|
98
|
+
this.redos.clear()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
public editable function release() -> void:
|
|
102
|
+
this.undos.release()
|
|
103
|
+
this.redos.release()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# ── Recording ──
|
|
107
|
+
|
|
108
|
+
extending Recording[Context]:
|
|
109
|
+
public static function create() -> Recording[Context]:
|
|
110
|
+
return Recording[Context](cmds = vec.Vec[Cmd[Context]].create())
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
public editable function record(cmd: Cmd[Context]) -> void:
|
|
114
|
+
this.cmds.push(cmd)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
public editable function replay(history: ref[History[Context]]) -> void:
|
|
118
|
+
for entry in this.cmds:
|
|
119
|
+
unsafe:
|
|
120
|
+
history.execute(read(entry))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
public function count() -> ptr_uint:
|
|
124
|
+
return this.cmds.len()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
public editable function clear() -> void:
|
|
128
|
+
this.cmds.clear()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
public editable function release() -> void:
|
|
132
|
+
this.cmds.release()
|
data/std/color.mt
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
## Color utilities — RGBA conversion, blending, and presets.
|
|
2
|
+
##
|
|
3
|
+
## Provides an RGBA Color struct compatible with raylib/FBO
|
|
4
|
+
## layouts, plus HSL/HSV conversion, hex parsing, alpha
|
|
5
|
+
## blending, and common named-color constants.
|
|
6
|
+
##
|
|
7
|
+
## import std.color as clr
|
|
8
|
+
## let c = clr.Color.from_hsl(210.0, 0.8, 0.6)
|
|
9
|
+
## let blended = c.alpha_blend(clr.WHITE)
|
|
10
|
+
|
|
11
|
+
public struct Color:
|
|
12
|
+
r: ubyte
|
|
13
|
+
g: ubyte
|
|
14
|
+
b: ubyte
|
|
15
|
+
a: ubyte
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
public const WHITE: Color = Color(r = 255, g = 255, b = 255, a = 255)
|
|
19
|
+
public const BLACK: Color = Color(r = 0, g = 0, b = 0, a = 255)
|
|
20
|
+
public const RED: Color = Color(r = 255, g = 0, b = 0, a = 255)
|
|
21
|
+
public const GREEN: Color = Color(r = 0, g = 255, b = 0, a = 255)
|
|
22
|
+
public const BLUE: Color = Color(r = 0, g = 0, b = 255, a = 255)
|
|
23
|
+
public const YELLOW: Color = Color(r = 255, g = 255, b = 0, a = 255)
|
|
24
|
+
public const CYAN: Color = Color(r = 0, g = 255, b = 255, a = 255)
|
|
25
|
+
public const MAGENTA:Color = Color(r = 255, g = 0, b = 255, a = 255)
|
|
26
|
+
public const GRAY: Color = Color(r = 128, g = 128, b = 128, a = 255)
|
|
27
|
+
public const ORANGE: Color = Color(r = 255, g = 165, b = 0, a = 255)
|
|
28
|
+
public const PINK: Color = Color(r = 255, g = 192, b = 203, a = 255)
|
|
29
|
+
public const PURPLE: Color = Color(r = 128, g = 0, b = 128, a = 255)
|
|
30
|
+
public const TRANSPARENT: Color = Color(r = 0, g = 0, b = 0, a = 0)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# ── math helpers ──
|
|
34
|
+
|
|
35
|
+
function fmin(a: float, b: float) -> float:
|
|
36
|
+
if a < b: return a
|
|
37
|
+
return b
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
function fmax(a: float, b: float) -> float:
|
|
41
|
+
if a > b: return a
|
|
42
|
+
return b
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
function fabs(x: float) -> float:
|
|
46
|
+
if x < 0.0: return -x
|
|
47
|
+
return x
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
function fmod(x: float, m: float) -> float:
|
|
51
|
+
# x - floor(x / m) * m
|
|
52
|
+
let div = x / m
|
|
53
|
+
let fl = float<-(int<-(div))
|
|
54
|
+
if div < 0.0 and float<-(int<-(div)) != div:
|
|
55
|
+
return x - (fl - 1.0) * m
|
|
56
|
+
return x - fl * m
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# ── public API ──
|
|
60
|
+
|
|
61
|
+
extending Color:
|
|
62
|
+
public static function from_rgba(r: ubyte, g: ubyte, b: ubyte, a: ubyte) -> Color:
|
|
63
|
+
return Color(r = r, g = g, b = b, a = a)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
public static function from_hsl(h: float, s: float, l: float) -> Color:
|
|
67
|
+
# h: 0..360, s: 0..1, l: 0..1
|
|
68
|
+
var hh = fmod(h, 360.0)
|
|
69
|
+
if hh < 0.0: hh = hh + 360.0
|
|
70
|
+
|
|
71
|
+
let c = (1.0 - fabs(2.0 * l - 1.0)) * s
|
|
72
|
+
let x = c * (1.0 - fabs(fmod(hh / 60.0, 2.0) - 1.0))
|
|
73
|
+
let m = l - c / 2.0
|
|
74
|
+
|
|
75
|
+
var r1: float = 0.0
|
|
76
|
+
var g1: float = 0.0
|
|
77
|
+
var b1: float = 0.0
|
|
78
|
+
|
|
79
|
+
if hh < 60.0:
|
|
80
|
+
r1 = c
|
|
81
|
+
g1 = x
|
|
82
|
+
else if hh < 120.0:
|
|
83
|
+
r1 = x
|
|
84
|
+
g1 = c
|
|
85
|
+
else if hh < 180.0:
|
|
86
|
+
g1 = c
|
|
87
|
+
b1 = x
|
|
88
|
+
else if hh < 240.0:
|
|
89
|
+
g1 = x
|
|
90
|
+
b1 = c
|
|
91
|
+
else if hh < 300.0:
|
|
92
|
+
r1 = x
|
|
93
|
+
b1 = c
|
|
94
|
+
else:
|
|
95
|
+
r1 = c
|
|
96
|
+
b1 = x
|
|
97
|
+
|
|
98
|
+
return Color(
|
|
99
|
+
r = ubyte<-((r1 + m) * 255.0),
|
|
100
|
+
g = ubyte<-((g1 + m) * 255.0),
|
|
101
|
+
b = ubyte<-((b1 + m) * 255.0),
|
|
102
|
+
a = 255
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
public static function from_hsv(h: float, s: float, v: float) -> Color:
|
|
107
|
+
var hh = fmod(h, 360.0)
|
|
108
|
+
if hh < 0.0: hh = hh + 360.0
|
|
109
|
+
|
|
110
|
+
let c = v * s
|
|
111
|
+
let x = c * (1.0 - fabs(fmod(hh / 60.0, 2.0) - 1.0))
|
|
112
|
+
let m = v - c
|
|
113
|
+
|
|
114
|
+
var r1: float = 0.0
|
|
115
|
+
var g1: float = 0.0
|
|
116
|
+
var b1: float = 0.0
|
|
117
|
+
|
|
118
|
+
if hh < 60.0:
|
|
119
|
+
r1 = c
|
|
120
|
+
g1 = x
|
|
121
|
+
else if hh < 120.0:
|
|
122
|
+
r1 = x
|
|
123
|
+
g1 = c
|
|
124
|
+
else if hh < 180.0:
|
|
125
|
+
g1 = c
|
|
126
|
+
b1 = x
|
|
127
|
+
else if hh < 240.0:
|
|
128
|
+
g1 = x
|
|
129
|
+
b1 = c
|
|
130
|
+
else if hh < 300.0:
|
|
131
|
+
r1 = x
|
|
132
|
+
b1 = c
|
|
133
|
+
else:
|
|
134
|
+
r1 = c
|
|
135
|
+
b1 = x
|
|
136
|
+
|
|
137
|
+
return Color(
|
|
138
|
+
r = ubyte<-((r1 + m) * 255.0),
|
|
139
|
+
g = ubyte<-((g1 + m) * 255.0),
|
|
140
|
+
b = ubyte<-((b1 + m) * 255.0),
|
|
141
|
+
a = 255
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
public function to_hsl() -> (float, float, float):
|
|
146
|
+
let rf = float<-(this.r) / 255.0
|
|
147
|
+
let gf = float<-(this.g) / 255.0
|
|
148
|
+
let bf = float<-(this.b) / 255.0
|
|
149
|
+
|
|
150
|
+
let mx = fmax(fmax(rf, gf), bf)
|
|
151
|
+
let mn = fmin(fmin(rf, gf), bf)
|
|
152
|
+
let delta = mx - mn
|
|
153
|
+
|
|
154
|
+
let l = (mx + mn) / 2.0
|
|
155
|
+
|
|
156
|
+
var h: float = 0.0
|
|
157
|
+
let s = if delta == 0.0: 0.0 else: delta / (1.0 - fabs(2.0 * l - 1.0))
|
|
158
|
+
|
|
159
|
+
if delta != 0.0:
|
|
160
|
+
if mx == rf:
|
|
161
|
+
h = fmod((gf - bf) / delta, 6.0)
|
|
162
|
+
else if mx == gf:
|
|
163
|
+
h = (bf - rf) / delta + 2.0
|
|
164
|
+
else:
|
|
165
|
+
h = (rf - gf) / delta + 4.0
|
|
166
|
+
h = h * 60.0
|
|
167
|
+
if h < 0.0:
|
|
168
|
+
h = h + 360.0
|
|
169
|
+
|
|
170
|
+
return (h, s, l)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
public function to_hsv() -> (float, float, float):
|
|
174
|
+
let rf = float<-(this.r) / 255.0
|
|
175
|
+
let gf = float<-(this.g) / 255.0
|
|
176
|
+
let bf = float<-(this.b) / 255.0
|
|
177
|
+
|
|
178
|
+
let mx = fmax(fmax(rf, gf), bf)
|
|
179
|
+
let mn = fmin(fmin(rf, gf), bf)
|
|
180
|
+
let delta = mx - mn
|
|
181
|
+
|
|
182
|
+
var h: float = 0.0
|
|
183
|
+
let s = if mx == 0.0: 0.0 else: delta / mx
|
|
184
|
+
let v = mx
|
|
185
|
+
|
|
186
|
+
if delta != 0.0:
|
|
187
|
+
if mx == rf:
|
|
188
|
+
h = fmod((gf - bf) / delta, 6.0)
|
|
189
|
+
else if mx == gf:
|
|
190
|
+
h = (bf - rf) / delta + 2.0
|
|
191
|
+
else:
|
|
192
|
+
h = (rf - gf) / delta + 4.0
|
|
193
|
+
h = h * 60.0
|
|
194
|
+
if h < 0.0:
|
|
195
|
+
h = h + 360.0
|
|
196
|
+
|
|
197
|
+
return (h, s, v)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
public function lerp(target: Color, t: float) -> Color:
|
|
201
|
+
let r = float<-(this.r) + (float<-(target.r) - float<-(this.r)) * t
|
|
202
|
+
let g = float<-(this.g) + (float<-(target.g) - float<-(this.g)) * t
|
|
203
|
+
let b = float<-(this.b) + (float<-(target.b) - float<-(this.b)) * t
|
|
204
|
+
let a = float<-(this.a) + (float<-(target.a) - float<-(this.a)) * t
|
|
205
|
+
return Color(r = ubyte<-(r), g = ubyte<-(g), b = ubyte<-(b), a = ubyte<-(a))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
public function alpha_blend(background: Color) -> Color:
|
|
209
|
+
if this.a == 0:
|
|
210
|
+
return background
|
|
211
|
+
if this.a == 255:
|
|
212
|
+
return this
|
|
213
|
+
|
|
214
|
+
let sa = float<-(this.a) / 255.0
|
|
215
|
+
let da = float<-(background.a) / 255.0
|
|
216
|
+
|
|
217
|
+
let r_out = float<-(this.r) * sa + float<-(background.r) * da * (1.0 - sa)
|
|
218
|
+
let g_out = float<-(this.g) * sa + float<-(background.g) * da * (1.0 - sa)
|
|
219
|
+
let b_out = float<-(this.b) * sa + float<-(background.b) * da * (1.0 - sa)
|
|
220
|
+
let a_out = sa + da * (1.0 - sa)
|
|
221
|
+
|
|
222
|
+
return Color(
|
|
223
|
+
r = ubyte<-(r_out),
|
|
224
|
+
g = ubyte<-(g_out),
|
|
225
|
+
b = ubyte<-(b_out),
|
|
226
|
+
a = ubyte<-(a_out * 255.0)
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
public function scale(factor: float) -> Color:
|
|
231
|
+
let r = fmin(fmax(float<-(this.r) * factor, 0.0), 255.0)
|
|
232
|
+
let g = fmin(fmax(float<-(this.g) * factor, 0.0), 255.0)
|
|
233
|
+
let b = fmin(fmax(float<-(this.b) * factor, 0.0), 255.0)
|
|
234
|
+
return Color(r = ubyte<-(r), g = ubyte<-(g), b = ubyte<-(b), a = this.a)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
public function multiply(other: Color) -> Color:
|
|
238
|
+
let r = ubyte<-(int<-((int<-(this.r) * int<-(other.r)) / 255))
|
|
239
|
+
let g = ubyte<-(int<-((int<-(this.g) * int<-(other.g)) / 255))
|
|
240
|
+
let b = ubyte<-(int<-((int<-(this.b) * int<-(other.b)) / 255))
|
|
241
|
+
return Color(r = r, g = g, b = b, a = this.a)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
public function with_alpha(a: ubyte) -> Color:
|
|
245
|
+
return Color(r = this.r, g = this.g, b = this.b, a = a)
|