Files
Ferrous-Solitaire/solitaire_engine/examples/icon_generator.rs
T
funman300 6e407a3ea7
Build and Deploy / build-and-push (push) Successful in 3m54s
fix(engine,server): safe area clamp, analytics batch, achievement save order, daily rollover, replay validation, leaderboard opt-in (#56, #60, #61, #62, #66, #68)
- #66: Clamp safe-area insets to 25% of window height with warn!() on excess
- #68: Move fire_flush outside per-event loop in analytics (batch flush once)
- #56: Persist progress before marking reward_granted to prevent XP loss on crash
- #60: Add DateRolloverTimer + check_date_rollover system for midnight seed refresh
- #62: Add validate_header() in replay upload with mode/draw_mode allowlists
- #61: Restore two-query leaderboard opt-in check (SELECT then UPDATE); original
       queries already in .sqlx cache; EXISTS variant would require sqlx prepare

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-28 13:07:22 -07:00

68 lines
2.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Application-icon generator — rasterises the project's icon SVG
//! into `assets/icon/icon_<size>.png` at every size in
//! `card_face_svg::ICON_SIZES` (16, 24, 32, 48, 64, 128, 256, 512,
//! 1024). Sufficient to cover Linux hicolor, Windows `.ico`, and
//! macOS `.icns` packaging targets — and the runtime `Window::icon`
//! wiring picks the 256 px slot.
//!
//! Run with:
//!
//! ```sh
//! cargo run --example icon_generator --release
//! ```
//!
//! Same shape as `card_face_generator`: SVG builder lives in
//! `solitaire_engine::assets::icon_svg` so the `icon_svg_pin`
//! integration test can call it. Rasterisation runs through
//! `assets::rasterize_svg` (the `usvg` + `resvg` + `tiny_skia`
//! pipeline already used by every other generated asset).
use bevy::math::UVec2;
use solitaire_engine::assets::icon_svg::{ICON_SIZES, icon_svg};
use solitaire_engine::assets::rasterize_svg;
use std::path::PathBuf;
use tiny_skia::{IntSize, Pixmap};
fn main() {
let icon_dir = workspace_assets_dir().join("icon");
std::fs::create_dir_all(&icon_dir).expect("create icon dir");
let svg = icon_svg();
for &size in ICON_SIZES {
let target = UVec2::new(size, size);
let pixmap = rasterize_to_pixmap(&svg, target);
let path = icon_dir.join(format!("icon_{size}.png"));
pixmap
.save_png(&path)
.unwrap_or_else(|e| panic!("write {}: {e}", path.display()));
}
println!(
"Wrote {} PNGs ({}{} px) to {}",
ICON_SIZES.len(),
ICON_SIZES.iter().min().copied().unwrap_or(0),
ICON_SIZES.iter().max().copied().unwrap_or(0),
icon_dir.display(),
);
}
fn rasterize_to_pixmap(svg: &str, target: UVec2) -> Pixmap {
let image = rasterize_svg(svg.as_bytes(), target).expect("rasterise icon SVG");
let bytes = image.data.expect("rasterised image carries pixel data");
debug_assert_eq!(
bytes.len(),
(target.x * target.y * 4) as usize,
"rasterised buffer must match width × height × 4 RGBA bytes",
);
let size = IntSize::from_wh(target.x, target.y).expect("non-zero target size");
Pixmap::from_vec(bytes, size).expect("RGBA buffer forms a valid Pixmap")
}
fn workspace_assets_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("solitaire_engine crate has a workspace-root parent")
.join("assets")
}