Compare commits

...

2 Commits

Author SHA1 Message Date
38544ed3f1
some adjustments on alpha by pixel
All checks were successful
Intrepid/Prometeu/Runtime/pipeline/head This commit looks good
2026-05-24 22:36:50 +01:00
ab0e577c6f
add color RGBA8888 VM intrinsics 2026-05-24 09:53:26 +01:00
3 changed files with 650 additions and 27 deletions

View File

@ -774,11 +774,11 @@ impl Gfx {
let fetch_x = if tile.entry.flip_x() { size - 1 - local_x } else { local_x };
let fetch_y = if tile.entry.flip_y() { size - 1 - local_y } else { local_y };
let px_index = tile.bank.get_pixel_index(tile.entry.glyph_id, fetch_x, fetch_y);
if px_index == 0 {
let color = tile.bank.resolve_color(tile.entry.palette_id, px_index);
if color.alpha() == 0 {
continue;
}
let color = tile.bank.resolve_color(tile.entry.palette_id, px_index);
target.back[world_y as usize * target.screen_w + world_x as usize] = color.raw();
}
}
@ -823,17 +823,12 @@ impl Gfx {
let fetch_x = if sprite.flip_x { size - 1 - local_x } else { local_x };
let fetch_y = if sprite.flip_y { size - 1 - local_y } else { local_y };
// 1. Get index
let px_index = bank.get_pixel_index(sprite.glyph.glyph_id, fetch_x, fetch_y);
// 2. Transparency
if px_index == 0 {
let color = bank.resolve_color(sprite.glyph.palette_id, px_index);
if color.alpha() == 0 {
continue;
}
// 3. Resolve color via palette (from the tile inside the sprite)
let color = bank.resolve_color(sprite.glyph.palette_id, px_index);
back[world_y as usize * screen_w + world_x as usize] = color.raw();
}
}
@ -999,16 +994,23 @@ mod tests {
use prometeu_hal::tile::Tile;
use prometeu_hal::tilemap::TileMap;
fn make_glyph_bank(tile_size: TileSize, palette_colors: &[(u8, Color)]) -> GlyphBank {
fn make_glyph_bank(tile_size: TileSize, palette_colors: &[(u8, u8, Color)]) -> GlyphBank {
let size = tile_size as usize;
let mut bank = GlyphBank::new(tile_size, size, size);
for (palette_id, color) in palette_colors {
bank.palettes[*palette_id as usize][1] = *color;
for (palette_id, color_index, color) in palette_colors {
bank.palettes[*palette_id as usize][*color_index as usize] = *color;
}
for y in 0..size {
for x in 0..size {
bank.pixel_indices[y * bank.width + x] = 1;
bank
}
fn make_filled_glyph_bank(
tile_size: TileSize,
pixel_index: u8,
palette_colors: &[(u8, u8, Color)],
) -> GlyphBank {
let mut bank = make_glyph_bank(tile_size, palette_colors);
for index in 0..bank.pixel_indices.len() {
bank.pixel_indices[index] = pixel_index;
}
bank
}
@ -1094,6 +1096,90 @@ mod tests {
assert_eq!(gfx.back[9 * 10 + 9], Color::WHITE.0);
}
#[test]
fn test_sprite_draws_opaque_color_index_zero() {
let bank = make_filled_glyph_bank(TileSize::Size8, 0, &[(0, 0, Color::GREEN)]);
let mut back = vec![Color::BLACK.raw(); 8 * 8];
let sprite = Sprite {
glyph: Glyph { glyph_id: 0, palette_id: 0 },
x: 0,
y: 0,
layer: 0,
flip_x: false,
flip_y: false,
bank_id: 0,
active: true,
priority: 0,
};
Gfx::draw_sprite_pixel_by_pixel(&mut back, 8, 8, &sprite, &bank);
assert_eq!(back[0], Color::GREEN.raw());
}
#[test]
fn test_sprite_skips_alpha_zero_color_index_zero() {
let bank = make_filled_glyph_bank(TileSize::Size8, 0, &[(0, 0, Color::TRANSPARENT)]);
let mut back = vec![Color::RED.raw(); 8 * 8];
let sprite = Sprite {
glyph: Glyph { glyph_id: 0, palette_id: 0 },
x: 0,
y: 0,
layer: 0,
flip_x: false,
flip_y: false,
bank_id: 0,
active: true,
priority: 0,
};
Gfx::draw_sprite_pixel_by_pixel(&mut back, 8, 8, &sprite, &bank);
assert_eq!(back[0], Color::RED.raw());
}
#[test]
fn test_cached_tile_draws_opaque_color_index_zero() {
let bank = make_filled_glyph_bank(TileSize::Size8, 0, &[(0, 0, Color::GREEN)]);
let mut back = vec![Color::BLACK.raw(); 8 * 8];
let mut target = RenderTarget { back: &mut back, screen_w: 8, screen_h: 8 };
let entry = CachedTileEntry {
active: true,
glyph_id: 0,
palette_id: 0,
flags: 0,
glyph_asset_id: 0,
};
Gfx::draw_cached_tile_pixels(
&mut target,
CachedTileDraw { x: 0, y: 0, entry, bank: &bank, tile_size: TileSize::Size8 },
);
assert_eq!(target.back[0], Color::GREEN.raw());
}
#[test]
fn test_cached_tile_skips_alpha_zero_color_index_zero() {
let bank = make_filled_glyph_bank(TileSize::Size8, 0, &[(0, 0, Color::TRANSPARENT)]);
let mut back = vec![Color::RED.raw(); 8 * 8];
let mut target = RenderTarget { back: &mut back, screen_w: 8, screen_h: 8 };
let entry = CachedTileEntry {
active: true,
glyph_id: 0,
palette_id: 0,
flags: 0,
glyph_asset_id: 0,
};
Gfx::draw_cached_tile_pixels(
&mut target,
CachedTileDraw { x: 0, y: 0, entry, bank: &bank, tile_size: TileSize::Size8 },
);
assert_eq!(target.back[0], Color::RED.raw());
}
#[test]
fn test_draw_rect() {
let banks = Arc::new(MemoryBanks::new());
@ -1127,7 +1213,11 @@ mod tests {
let banks = Arc::new(MemoryBanks::new());
banks.install_glyph_bank(
0,
Arc::new(make_glyph_bank(TileSize::Size8, &[(0, Color::RED), (1, Color::GREEN)])),
Arc::new(make_filled_glyph_bank(
TileSize::Size8,
1,
&[(0, 1, Color::RED), (1, 1, Color::GREEN)],
)),
);
let mut scene = make_scene([0, 0, 0, 0]);
@ -1152,9 +1242,15 @@ mod tests {
let banks = Arc::new(MemoryBanks::new());
banks.install_glyph_bank(
0,
Arc::new(make_glyph_bank(
Arc::new(make_filled_glyph_bank(
TileSize::Size8,
&[(0, Color::RED), (1, Color::GREEN), (2, Color::BLUE), (4, Color::WHITE)],
1,
&[
(0, 1, Color::RED),
(1, 1, Color::GREEN),
(2, 1, Color::BLUE),
(4, 1, Color::WHITE),
],
)),
);

View File

@ -1,5 +1,5 @@
use prometeu_bytecode::Value;
use prometeu_hal::HostContext;
use prometeu_hal::{HostContext, color::Color};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BuiltinTypeKey {
@ -56,6 +56,7 @@ pub enum BuiltinScalarType {
Int,
Float,
Bool,
Str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -362,12 +363,63 @@ const VEC2_ZERO_LAYOUT: [AbiType; 2] =
[AbiType::Scalar(BuiltinScalarType::Float), AbiType::Scalar(BuiltinScalarType::Float)];
const VEC2_ZERO_SLOTS: [BuiltinConstSlotValue; 2] =
[BuiltinConstSlotValue::Float(0.0), BuiltinConstSlotValue::Float(0.0)];
const BUILTIN_CONSTS: [BuiltinConstMeta; 1] = [BuiltinConstMeta {
const COLOR_BLACK_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::BLACK.raw() as i64)];
const COLOR_WHITE_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::WHITE.raw() as i64)];
const COLOR_RED_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::RED.raw() as i64)];
const COLOR_GREEN_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::GREEN.raw() as i64)];
const COLOR_BLUE_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::BLUE.raw() as i64)];
const COLOR_YELLOW_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::YELLOW.raw() as i64)];
const COLOR_ORANGE_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::ORANGE.raw() as i64)];
const COLOR_INDIGO_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::INDIGO.raw() as i64)];
const COLOR_GRAY_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::GRAY.raw() as i64)];
const COLOR_CYAN_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::CYAN.raw() as i64)];
const COLOR_MAGENTA_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::MAGENTA.raw() as i64)];
const COLOR_TRANSPARENT_SLOTS: [BuiltinConstSlotValue; 1] =
[BuiltinConstSlotValue::Int64(Color::TRANSPARENT.raw() as i64)];
const BUILTIN_CONSTS: [BuiltinConstMeta; 13] = [
BuiltinConstMeta {
key: BuiltinConstKey::new("vec2", "zero", 1),
flat_slot_layout: &VEC2_ZERO_LAYOUT,
flat_slot_width: 2,
materializer: BuiltinConstMaterializer::Direct(&VEC2_ZERO_SLOTS),
}];
},
color_const_meta("black", &COLOR_BLACK_SLOTS),
color_const_meta("white", &COLOR_WHITE_SLOTS),
color_const_meta("red", &COLOR_RED_SLOTS),
color_const_meta("green", &COLOR_GREEN_SLOTS),
color_const_meta("blue", &COLOR_BLUE_SLOTS),
color_const_meta("yellow", &COLOR_YELLOW_SLOTS),
color_const_meta("orange", &COLOR_ORANGE_SLOTS),
color_const_meta("indigo", &COLOR_INDIGO_SLOTS),
color_const_meta("gray", &COLOR_GRAY_SLOTS),
color_const_meta("cyan", &COLOR_CYAN_SLOTS),
color_const_meta("magenta", &COLOR_MAGENTA_SLOTS),
color_const_meta("transparent", &COLOR_TRANSPARENT_SLOTS),
];
const fn color_const_meta(
name: &'static str,
slots: &'static [BuiltinConstSlotValue],
) -> BuiltinConstMeta {
BuiltinConstMeta {
key: BuiltinConstKey::new("color", name, 1),
flat_slot_layout: &COLOR_LAYOUT,
flat_slot_width: 1,
materializer: BuiltinConstMaterializer::Direct(slots),
}
}
const VEC2_DOT_ARGS: [AbiType; 4] = [
AbiType::Scalar(BuiltinScalarType::Float),
@ -379,6 +431,20 @@ const SINGLE_FLOAT_RET: [AbiType; 1] = [AbiType::Scalar(BuiltinScalarType::Float
const VEC2_LENGTH_ARGS: [AbiType; 2] =
[AbiType::Scalar(BuiltinScalarType::Float), AbiType::Scalar(BuiltinScalarType::Float)];
const NO_ARGS: [AbiType; 0] = [];
const COLOR_ARGS: [AbiType; 1] = [AbiType::Builtin(COLOR)];
const COLOR_RET: [AbiType; 1] = [AbiType::Builtin(COLOR)];
const COLOR_RGB_ARGS: [AbiType; 3] = [
AbiType::Scalar(BuiltinScalarType::Int),
AbiType::Scalar(BuiltinScalarType::Int),
AbiType::Scalar(BuiltinScalarType::Int),
];
const COLOR_RGBA_ARGS: [AbiType; 4] = [
AbiType::Scalar(BuiltinScalarType::Int),
AbiType::Scalar(BuiltinScalarType::Int),
AbiType::Scalar(BuiltinScalarType::Int),
AbiType::Scalar(BuiltinScalarType::Int),
];
const COLOR_HTML_RGBA_ARGS: [AbiType; 1] = [AbiType::Scalar(BuiltinScalarType::Str)];
const PAD_RET: [AbiType; 1] = [AbiType::Builtin(INPUT_PAD)];
const TOUCH_RET: [AbiType; 1] = [AbiType::Builtin(INPUT_TOUCH)];
const BUTTON_RET: [AbiType; 1] = [AbiType::Builtin(INPUT_BUTTON)];
@ -388,7 +454,7 @@ const BUTTON_ARGS: [AbiType; 1] = [AbiType::Builtin(INPUT_BUTTON)];
const BOOL_RET: [AbiType; 1] = [AbiType::Scalar(BuiltinScalarType::Bool)];
const INT_RET: [AbiType; 1] = [AbiType::Scalar(BuiltinScalarType::Int)];
const INTRINSICS: [IntrinsicMeta; 23] = [
const INTRINSICS: [IntrinsicMeta; 42] = [
IntrinsicMeta {
id: 0x1000,
owner: "vec2",
@ -411,6 +477,215 @@ const INTRINSICS: [IntrinsicMeta; 23] = [
may_allocate: false,
implementation: vec2_length,
},
IntrinsicMeta {
id: 0x1100,
owner: "color",
name: "from_raw",
version: 1,
arg_layout: &INT_RET,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_from_raw,
},
IntrinsicMeta {
id: 0x1101,
owner: "color",
name: "rgb",
version: 1,
arg_layout: &COLOR_RGB_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_rgb,
},
IntrinsicMeta {
id: 0x1102,
owner: "color",
name: "rgba",
version: 1,
arg_layout: &COLOR_RGBA_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_rgba,
},
IntrinsicMeta {
id: 0x1103,
owner: "color",
name: "html_rgba",
version: 1,
arg_layout: &COLOR_HTML_RGBA_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_html_rgba,
},
IntrinsicMeta {
id: 0x1104,
owner: "color",
name: "gray_scale",
version: 1,
arg_layout: &INT_RET,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_gray_scale,
},
IntrinsicMeta {
id: 0x1105,
owner: "color",
name: "hex",
version: 1,
arg_layout: &COLOR_ARGS,
ret_layout: &INT_RET,
deterministic: true,
may_allocate: false,
implementation: color_hex,
},
IntrinsicMeta {
id: 0x1106,
owner: "color",
name: "alpha",
version: 1,
arg_layout: &COLOR_ARGS,
ret_layout: &INT_RET,
deterministic: true,
may_allocate: false,
implementation: color_alpha,
},
IntrinsicMeta {
id: 0x1120,
owner: "color",
name: "black",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_black,
},
IntrinsicMeta {
id: 0x1121,
owner: "color",
name: "white",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_white,
},
IntrinsicMeta {
id: 0x1122,
owner: "color",
name: "red",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_red,
},
IntrinsicMeta {
id: 0x1123,
owner: "color",
name: "green",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_green,
},
IntrinsicMeta {
id: 0x1124,
owner: "color",
name: "blue",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_blue,
},
IntrinsicMeta {
id: 0x1125,
owner: "color",
name: "yellow",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_yellow,
},
IntrinsicMeta {
id: 0x1126,
owner: "color",
name: "orange",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_orange,
},
IntrinsicMeta {
id: 0x1127,
owner: "color",
name: "indigo",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_indigo,
},
IntrinsicMeta {
id: 0x1128,
owner: "color",
name: "gray",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_gray,
},
IntrinsicMeta {
id: 0x1129,
owner: "color",
name: "cyan",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_cyan,
},
IntrinsicMeta {
id: 0x112A,
owner: "color",
name: "magenta",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_magenta,
},
IntrinsicMeta {
id: 0x112B,
owner: "color",
name: "transparent",
version: 1,
arg_layout: &NO_ARGS,
ret_layout: &COLOR_RET,
deterministic: true,
may_allocate: false,
implementation: color_transparent,
},
IntrinsicMeta {
id: 0x2000,
owner: "input",
@ -698,11 +973,35 @@ fn expect_float_arg(args: &[Value], index: usize) -> Result<f64, IntrinsicExecut
})
}
fn expect_int_arg(args: &[Value], index: usize) -> Result<i64, IntrinsicExecutionError> {
let value = args
.get(index)
.ok_or(IntrinsicExecutionError::ArityMismatch { expected: index + 1, got: args.len() })?;
value.as_integer().ok_or(IntrinsicExecutionError::TypeMismatch {
index,
expected: AbiType::Scalar(BuiltinScalarType::Int),
})
}
fn expect_string_arg(args: &[Value], index: usize) -> Result<&str, IntrinsicExecutionError> {
let value = args
.get(index)
.ok_or(IntrinsicExecutionError::ArityMismatch { expected: index + 1, got: args.len() })?;
match value {
Value::String(value) => Ok(value.as_ref()),
_ => Err(IntrinsicExecutionError::TypeMismatch {
index,
expected: AbiType::Scalar(BuiltinScalarType::Str),
}),
}
}
fn value_matches_abi_type(value: &Value, expected: AbiType) -> bool {
match expected {
AbiType::Scalar(BuiltinScalarType::Int) => value.as_integer().is_some(),
AbiType::Scalar(BuiltinScalarType::Float) => value.as_float().is_some(),
AbiType::Scalar(BuiltinScalarType::Bool) => matches!(value, Value::Boolean(_)),
AbiType::Scalar(BuiltinScalarType::Str) => matches!(value, Value::String(_)),
AbiType::Builtin(_) => value.as_integer().is_some(),
}
}
@ -755,6 +1054,179 @@ fn vec2_length(
Ok(vec![Value::Float((x * x + y * y).sqrt())])
}
fn color_value(color: Color) -> Vec<Value> {
vec![Value::Int64(color.raw() as i64)]
}
fn expect_color_arg(args: &[Value], index: usize) -> Result<Color, IntrinsicExecutionError> {
let raw = u32::try_from(expect_int_arg(args, index)?).map_err(|_| {
IntrinsicExecutionError::TypeMismatch { index, expected: AbiType::Builtin(COLOR) }
})?;
Ok(Color::from_raw(raw))
}
fn expect_channel(args: &[Value], index: usize) -> Result<u8, IntrinsicExecutionError> {
let value = expect_int_arg(args, index)?;
u8::try_from(value).map_err(|_| IntrinsicExecutionError::TypeMismatch {
index,
expected: AbiType::Scalar(BuiltinScalarType::Int),
})
}
fn parse_html_rgba(value: &str) -> Option<Color> {
let hex = value.strip_prefix('#').unwrap_or(value);
if hex.len() != 8 || !hex.as_bytes().iter().all(u8::is_ascii_hexdigit) {
return None;
}
Some(Color::from_raw(u32::from_str_radix(hex, 16).ok()?))
}
fn color_from_raw(
args: &[Value],
_ctx: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
let raw = u32::try_from(expect_int_arg(args, 0)?).map_err(|_| {
IntrinsicExecutionError::TypeMismatch {
index: 0,
expected: AbiType::Scalar(BuiltinScalarType::Int),
}
})?;
Ok(color_value(Color::from_raw(raw)))
}
fn color_rgb(
args: &[Value],
_ctx: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
Ok(color_value(Color::rgb(
expect_channel(args, 0)?,
expect_channel(args, 1)?,
expect_channel(args, 2)?,
)))
}
fn color_rgba(
args: &[Value],
_ctx: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
Ok(color_value(Color::rgba(
expect_channel(args, 0)?,
expect_channel(args, 1)?,
expect_channel(args, 2)?,
expect_channel(args, 3)?,
)))
}
fn color_html_rgba(
args: &[Value],
_ctx: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
let color = parse_html_rgba(expect_string_arg(args, 0)?).ok_or({
IntrinsicExecutionError::TypeMismatch {
index: 0,
expected: AbiType::Scalar(BuiltinScalarType::Str),
}
})?;
Ok(color_value(color))
}
fn color_gray_scale(
args: &[Value],
_ctx: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
Ok(color_value(Color::gray_scale(expect_channel(args, 0)?)))
}
fn color_hex(
args: &[Value],
_ctx: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
Ok(vec![Value::Int64(expect_color_arg(args, 0)?.hex() as i64)])
}
fn color_alpha(
args: &[Value],
_ctx: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
Ok(vec![Value::Int64(expect_color_arg(args, 0)?.alpha() as i64)])
}
fn color_const(color: Color) -> Result<Vec<Value>, IntrinsicExecutionError> {
Ok(color_value(color))
}
fn color_black(
_: &[Value],
_: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::BLACK)
}
fn color_white(
_: &[Value],
_: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::WHITE)
}
fn color_red(_: &[Value], _: &mut HostContext<'_>) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::RED)
}
fn color_green(
_: &[Value],
_: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::GREEN)
}
fn color_blue(_: &[Value], _: &mut HostContext<'_>) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::BLUE)
}
fn color_yellow(
_: &[Value],
_: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::YELLOW)
}
fn color_orange(
_: &[Value],
_: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::ORANGE)
}
fn color_indigo(
_: &[Value],
_: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::INDIGO)
}
fn color_gray(_: &[Value], _: &mut HostContext<'_>) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::GRAY)
}
fn color_cyan(_: &[Value], _: &mut HostContext<'_>) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::CYAN)
}
fn color_magenta(
_: &[Value],
_: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::MAGENTA)
}
fn color_transparent(
_: &[Value],
_: &mut HostContext<'_>,
) -> Result<Vec<Value>, IntrinsicExecutionError> {
color_const(Color::TRANSPARENT)
}
fn input_pad(
_args: &[Value],
_ctx: &mut HostContext<'_>,
@ -1067,6 +1539,19 @@ mod tests {
assert_eq!(looked_up, materialized);
}
#[test]
fn builtin_constant_materializes_color_values() {
let red = materialize_builtin_constant("color", "red", 1)
.expect("materialization lookup must succeed")
.expect("constant must exist");
assert_eq!(red, vec![Value::Int64(Color::RED.raw() as i64)]);
let transparent = materialize_builtin_constant("color", "transparent", 1)
.expect("materialization lookup must succeed")
.expect("constant must exist");
assert_eq!(transparent, vec![Value::Int64(Color::TRANSPARENT.raw() as i64)]);
}
#[test]
fn intrinsic_metadata_exposes_arg_and_return_layouts() {
let dot = lookup_intrinsic("vec2", "dot", 1).expect("vec2.dot must exist");
@ -1105,6 +1590,29 @@ mod tests {
assert_eq!(result, vec![Value::Float(5.0)]);
}
#[test]
fn color_intrinsics_construct_and_project_rgba8888() {
let mut ctx = HostContext::new(None);
let rgba = lookup_intrinsic("color", "rgba", 1).expect("color.rgba must exist");
let result = (rgba.implementation)(
&[Value::Int64(0x11), Value::Int64(0x22), Value::Int64(0x33), Value::Int64(0x44)],
&mut ctx,
)
.expect("rgba implementation must execute");
assert_eq!(result, vec![Value::Int64(0x11223344)]);
let html = lookup_intrinsic("color", "html_rgba", 1).expect("color.html_rgba must exist");
let result = (html.implementation)(&[Value::String("#AABBCCDD".into())], &mut ctx)
.expect("html_rgba implementation must execute");
assert_eq!(result, vec![Value::Int64(0xAABBCCDD)]);
let alpha = lookup_intrinsic("color", "alpha", 1).expect("color.alpha must exist");
let result = (alpha.implementation)(&[Value::Int64(0xAABBCCDD)], &mut ctx)
.expect("alpha implementation must execute");
assert_eq!(result, vec![Value::Int64(0xDD)]);
}
#[test]
fn input_intrinsic_requires_hardware_context() {
let mut ctx = HostContext::new(None);

View File

@ -1,6 +1,25 @@
final_id_hex,final_id_dec,canonical_name,canonical_version,owner,name,arg_slots,ret_slots,arg_layout,ret_layout,deterministic,may_allocate
0x1000,4096,vec2.dot,1,vec2,dot,4,1,float|float|float|float,float,true,false
0x1001,4097,vec2.length,1,vec2,length,2,1,float|float,float,true,false
0x1100,4352,color.from_raw,1,color,from_raw,1,1,int,builtin:color,true,false
0x1101,4353,color.rgb,1,color,rgb,3,1,int|int|int,builtin:color,true,false
0x1102,4354,color.rgba,1,color,rgba,4,1,int|int|int|int,builtin:color,true,false
0x1103,4355,color.html_rgba,1,color,html_rgba,1,1,str,builtin:color,true,false
0x1104,4356,color.gray_scale,1,color,gray_scale,1,1,int,builtin:color,true,false
0x1105,4357,color.hex,1,color,hex,1,1,builtin:color,int,true,false
0x1106,4358,color.alpha,1,color,alpha,1,1,builtin:color,int,true,false
0x1120,4384,color.black,1,color,black,0,1,,builtin:color,true,false
0x1121,4385,color.white,1,color,white,0,1,,builtin:color,true,false
0x1122,4386,color.red,1,color,red,0,1,,builtin:color,true,false
0x1123,4387,color.green,1,color,green,0,1,,builtin:color,true,false
0x1124,4388,color.blue,1,color,blue,0,1,,builtin:color,true,false
0x1125,4389,color.yellow,1,color,yellow,0,1,,builtin:color,true,false
0x1126,4390,color.orange,1,color,orange,0,1,,builtin:color,true,false
0x1127,4391,color.indigo,1,color,indigo,0,1,,builtin:color,true,false
0x1128,4392,color.gray,1,color,gray,0,1,,builtin:color,true,false
0x1129,4393,color.cyan,1,color,cyan,0,1,,builtin:color,true,false
0x112A,4394,color.magenta,1,color,magenta,0,1,,builtin:color,true,false
0x112B,4395,color.transparent,1,color,transparent,0,1,,builtin:color,true,false
0x2000,8192,input.pad,1,input,pad,0,1,,builtin:input.pad,true,false
0x2001,8193,input.touch,1,input,touch,0,1,,builtin:input.touch,true,false
0x2010,8208,input.pad.up,1,input.pad,up,1,1,builtin:input.pad,builtin:input.button,true,false

1 final_id_hex final_id_dec canonical_name canonical_version owner name arg_slots ret_slots arg_layout ret_layout deterministic may_allocate
2 0x1000 4096 vec2.dot 1 vec2 dot 4 1 float|float|float|float float true false
3 0x1001 4097 vec2.length 1 vec2 length 2 1 float|float float true false
4 0x1100 4352 color.from_raw 1 color from_raw 1 1 int builtin:color true false
5 0x1101 4353 color.rgb 1 color rgb 3 1 int|int|int builtin:color true false
6 0x1102 4354 color.rgba 1 color rgba 4 1 int|int|int|int builtin:color true false
7 0x1103 4355 color.html_rgba 1 color html_rgba 1 1 str builtin:color true false
8 0x1104 4356 color.gray_scale 1 color gray_scale 1 1 int builtin:color true false
9 0x1105 4357 color.hex 1 color hex 1 1 builtin:color int true false
10 0x1106 4358 color.alpha 1 color alpha 1 1 builtin:color int true false
11 0x1120 4384 color.black 1 color black 0 1 builtin:color true false
12 0x1121 4385 color.white 1 color white 0 1 builtin:color true false
13 0x1122 4386 color.red 1 color red 0 1 builtin:color true false
14 0x1123 4387 color.green 1 color green 0 1 builtin:color true false
15 0x1124 4388 color.blue 1 color blue 0 1 builtin:color true false
16 0x1125 4389 color.yellow 1 color yellow 0 1 builtin:color true false
17 0x1126 4390 color.orange 1 color orange 0 1 builtin:color true false
18 0x1127 4391 color.indigo 1 color indigo 0 1 builtin:color true false
19 0x1128 4392 color.gray 1 color gray 0 1 builtin:color true false
20 0x1129 4393 color.cyan 1 color cyan 0 1 builtin:color true false
21 0x112A 4394 color.magenta 1 color magenta 0 1 builtin:color true false
22 0x112B 4395 color.transparent 1 color transparent 0 1 builtin:color true false
23 0x2000 8192 input.pad 1 input pad 0 1 builtin:input.pad true false
24 0x2001 8193 input.touch 1 input touch 0 1 builtin:input.touch true false
25 0x2010 8208 input.pad.up 1 input.pad up 1 1 builtin:input.pad builtin:input.button true false