Compare commits

..

15 Commits

Author SHA1 Message Date
Ghoul
f4dc4dfea9 Merge branch 'main' into 'devel'
Draft: Add custom image and gif support for G835L

See merge request asus-linux/asusctl!249
2026-01-22 19:09:27 +00:00
Ghoul
1238e090a5 chore: code clean up and remove planning comments 2026-01-23 00:06:53 +05:00
Ghoul
f92545b0bb chore: add separate template and image set for G835L anime matrix 2026-01-22 23:46:55 +05:00
Ghoul
bf0ea88f01 feat: add full custom image and gif support for G835L 2026-01-22 23:46:55 +05:00
Ghoul
4db901ce17 fix: G835L animatrix edge and gif tests fixed to work with last modified image and gif 2026-01-22 22:44:24 +05:00
Ghoul
e105e6bd86 fix(simulator): add better error message when virtual device creation fails 2026-01-22 22:44:23 +05:00
Ghoul
465f472c25 feat: dump untested G835L simulator map with todo to fix simulator
simulator doesn't seem to be working right now. fix later and test this
properly
2026-01-22 22:44:22 +05:00
Ghoul
b04fed9a6d fix(anime_cli): default gif loops to infinite 2026-01-22 22:44:22 +05:00
Ghoul
0311c74049 chore: test case for G835L GIF animation 2026-01-22 22:44:18 +05:00
Ghoul
c08355f5c2 feat: pixel-perfect image and gif support for G835L and proper test written 2026-01-22 22:44:17 +05:00
Ghoul
9ee154cd1c wip: support for G835L 2026-01-22 22:44:17 +05:00
Ghoul
14c4b0501d feat: add G835L diagonal test images 2026-01-22 22:44:13 +05:00
Ghoul
eab7e89fa3 feat: add anime-led-scan tool
Usage: cargo run --example anime-led-scan
2026-01-22 22:44:09 +05:00
Ghoul
2c61cd8da6 chore: fix comments documenting Scar 18 implementation plan
Removed comments mentioning monochrome/grayscale LEDs added under the
impression G14 and M16 used to have RGB LED lighting. This assumption
has been proved false.

Additionally added agent md files to gitignore and uncommented G635L
width as even a random value is likely necessary
2026-01-22 22:44:09 +05:00
Ghoul
c7de3fb0c8 chore: add implementation planning for G635L/G835L support 2026-01-22 22:44:08 +05:00
3 changed files with 27 additions and 12 deletions

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

View File

@@ -121,8 +121,6 @@ impl AnimeImage {
match anime_type {
AnimeType::GA401 => 0.8,
AnimeType::GU604 => 0.78,
// TODO: Measure physical display and calculate correct value
AnimeType::G835L => 0.77,
_ => 0.77,
}
}
@@ -139,12 +137,8 @@ impl AnimeImage {
fn scale_y(anime_type: AnimeType) -> f32 {
match anime_type {
AnimeType::GA401 => 0.3,
AnimeType::GU604 => 0.28,
// TODO: Calculate correct values for G635L and G835L.
// Known values for G835L diagonal W*H is 68*34
AnimeType::G635L => 0.28,
AnimeType::G835L => 0.28,
_ => 0.283,
AnimeType::GA402 => 0.283,
_ => 0.28,
}
}
@@ -167,7 +161,7 @@ impl AnimeImage {
/// \ |
/// |----|\ |
/// ^ ------+
/// first_x (grows as y increases)
/// first_x
/// ```
///
/// For G835L (inverted pattern - triangle grows then rectangle shifts):
@@ -276,8 +270,7 @@ impl AnimeImage {
// 33.0 = Longest row LED count (physical) plus half-pixel offset
AnimeType::GA401 => (33.0 + 0.5) * Self::scale_x(anime_type),
AnimeType::GU604 => (38.0 + 0.5) * Self::scale_x(anime_type),
// G835L: max 15 LEDs wide + rectangle shift (~20 pixels) + stagger
AnimeType::G835L => (35.0 + 0.5) * Self::scale_x(anime_type),
AnimeType::G835L => (33.0 + 0.5) * Self::scale_x(anime_type),
_ => (35.0 + 0.5) * Self::scale_x(anime_type),
}
}
@@ -448,13 +441,35 @@ impl AnimeImage {
let transform =
Mat3::from_scale_angle_translation(self.scale, self.angle, self.translation);
let pos_in_leds = Mat3::from_translation(Vec2::new(20.0, 20.0));
let pos_in_leds = Mat3::from_translation(self.led_center());
// Get LED-to-image coords
let led_from_px = pos_in_leds * led_from_cm * transform * cm_from_px * center;
led_from_px.inverse()
}
fn led_center(&self) -> Vec2 {
if self.anime_type != AnimeType::G835L {
return Vec2::new(20.0, 20.0);
}
let mut min = Vec2::splat(f32::INFINITY);
let mut max = Vec2::splat(f32::NEG_INFINITY);
for led in self.led_pos.iter().flatten() {
let pos = Vec2::new(led.x(), led.y());
min = min.min(pos);
max = max.max(pos);
}
if min.x.is_finite() {
let mut center = (min + max) * 0.5;
center.y += 1.0;
center
} else {
Vec2::new(20.0, 20.0)
}
}
/// Generate the base image from inputs. The result can be displayed as is
/// or updated via scale, position, or angle then displayed again after
/// `update()`.