mirror of
https://github.com/MiSTer-devel/GameAndWatch_MiSTer.git
synced 2026-05-24 03:03:25 +00:00
Experimental automatic bound calculation after removal of bad layers
This commit is contained in:
@@ -172,6 +172,7 @@ fn select_view(views: &mut HashMap<String, View>) -> Option<View> {
|
||||
"handheld layout",
|
||||
"external layout",
|
||||
"screen focus",
|
||||
"unit only",
|
||||
];
|
||||
|
||||
for name in desired_names {
|
||||
|
||||
@@ -29,7 +29,7 @@ enum FilterArg {
|
||||
Specific { name: String },
|
||||
/// Match the games that use a particular CPU
|
||||
CPU { name: CPUType },
|
||||
/// Match the specific CPU types supported by the core currently. These are the SM510 and SM5a CPUs
|
||||
/// Match the specific CPU types supported by the core currently. These are the SM510 (inc. Tiger) and SM5a CPUs
|
||||
Supported,
|
||||
/// All game types specified in the manifest.json
|
||||
All,
|
||||
@@ -185,7 +185,9 @@ fn main() {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(FilterArg::Supported) => filter_platforms(vec![CPUType::SM510, CPUType::SM5a]),
|
||||
Some(FilterArg::Supported) => {
|
||||
filter_platforms(vec![CPUType::SM510, CPUType::SM510Tiger, CPUType::SM5a])
|
||||
}
|
||||
Some(FilterArg::CPU { name }) => filter_platforms(vec![name.clone()]),
|
||||
Some(FilterArg::All) | None => Some(manifest.iter().map(|(n, p)| (n.clone(), p)).collect()),
|
||||
};
|
||||
|
||||
@@ -28,9 +28,16 @@ pub fn render(
|
||||
let mut elements: Vec<&Element> = vec![];
|
||||
let mut screens: Vec<&Screen> = vec![];
|
||||
|
||||
let mut filtered_items: Vec<&ViewElement> = vec![];
|
||||
|
||||
// Keep track of which refs have already been added to the image, as most layouts contain multiple duplicates
|
||||
let mut already_applied_refs: HashSet<&String> = HashSet::<&String>::new();
|
||||
|
||||
// Prefilter all items
|
||||
for item in &layout.items {
|
||||
match item {
|
||||
ViewElement::Bounds(bounds) => {
|
||||
// Filter out
|
||||
if view_bounds.is_some() {
|
||||
return Err(format!(
|
||||
"View {} in {platform_name} has multiple bounds. Skipping",
|
||||
@@ -39,54 +46,116 @@ pub fn render(
|
||||
}
|
||||
view_bounds = Some(bounds.to_xy());
|
||||
}
|
||||
ViewElement::Element(element) => elements.push(element),
|
||||
ViewElement::Screen(screen) => screens.push(screen),
|
||||
ViewElement::Element(element) => {
|
||||
if already_applied_refs.contains(&element.ref_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
already_applied_refs.insert(&element.ref_name);
|
||||
|
||||
match element.ref_name.to_lowercase().as_str() {
|
||||
"dust" | "bubbles" | "unit" | "backdrop" => {
|
||||
// Ignore these features
|
||||
println!("Ignoring element by name {}", element.ref_name);
|
||||
continue;
|
||||
}
|
||||
value => {
|
||||
// if value.starts_with("fix") || value.starts_with("gradient") {
|
||||
if value.starts_with("gradient") {
|
||||
println!("Ignoring element by name {}", element.ref_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filtered_items.push(item);
|
||||
elements.push(element);
|
||||
}
|
||||
ViewElement::Screen(screen) => {
|
||||
filtered_items.push(item);
|
||||
screens.push(screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let view_bounds = if let Some(view_bounds) = view_bounds {
|
||||
view_bounds
|
||||
} else {
|
||||
// Calculate actual bounds
|
||||
let mut min_x: Option<i32> = None;
|
||||
let mut min_y: Option<i32> = None;
|
||||
let mut max_width = 0;
|
||||
let mut max_height = 0;
|
||||
// Calculate actual bounds
|
||||
let mut min_x: Option<i32> = None;
|
||||
let mut min_y: Option<i32> = None;
|
||||
let mut max_width = 0;
|
||||
let mut max_height = 0;
|
||||
let mut max_common_x: Option<i32> = None;
|
||||
let mut max_common_y: Option<i32> = None;
|
||||
|
||||
for bounds in elements
|
||||
.iter()
|
||||
.map(|e| e.bounds.to_xy())
|
||||
.chain(screens.iter().map(|s| s.bounds.to_xy()))
|
||||
{
|
||||
if let Some(inner_min_x) = min_x {
|
||||
if inner_min_x > bounds.x {
|
||||
min_x = Some(bounds.x);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(inner_min_y) = min_y {
|
||||
if inner_min_y > bounds.y {
|
||||
min_y = Some(bounds.y);
|
||||
}
|
||||
}
|
||||
|
||||
if bounds.width + bounds.x > max_width {
|
||||
max_width = bounds.width + bounds.x;
|
||||
}
|
||||
|
||||
if bounds.height + bounds.y > max_height {
|
||||
max_height = bounds.height + bounds.y;
|
||||
for bounds in elements
|
||||
.iter()
|
||||
.map(|e| e.bounds.to_xy())
|
||||
.chain(screens.iter().map(|s| s.bounds.to_xy()))
|
||||
{
|
||||
if let Some(inner_min_x) = min_x {
|
||||
if inner_min_x > bounds.x {
|
||||
min_x = Some(bounds.x);
|
||||
}
|
||||
}
|
||||
|
||||
Bounds {
|
||||
x: min_x.map_or(0, |x| x),
|
||||
y: min_y.map_or(0, |y| y),
|
||||
width: max_width,
|
||||
height: max_height,
|
||||
if let Some(inner_min_y) = min_y {
|
||||
if inner_min_y > bounds.y {
|
||||
min_y = Some(bounds.y);
|
||||
}
|
||||
}
|
||||
|
||||
if bounds.width + bounds.x > max_width {
|
||||
max_width = bounds.width + bounds.x;
|
||||
}
|
||||
|
||||
if bounds.height + bounds.y > max_height {
|
||||
max_height = bounds.height + bounds.y;
|
||||
}
|
||||
|
||||
if let Some(common_x) = max_common_x {
|
||||
if common_x > bounds.x {
|
||||
// Shorten max common
|
||||
max_common_x = Some(bounds.x);
|
||||
}
|
||||
} else {
|
||||
// Set first value
|
||||
max_common_x = Some(bounds.x);
|
||||
}
|
||||
|
||||
if let Some(common_y) = max_common_y {
|
||||
if common_y > bounds.y {
|
||||
// Shorten max common
|
||||
max_common_y = Some(bounds.y);
|
||||
}
|
||||
} else {
|
||||
// Set first value
|
||||
max_common_y = Some(bounds.y);
|
||||
}
|
||||
|
||||
println!("{bounds:?}");
|
||||
}
|
||||
|
||||
let max_common_x = max_common_x.map_or(0, |x| x);
|
||||
let max_common_y = max_common_y.map_or(0, |y| y);
|
||||
|
||||
let calculated_bounds = Bounds {
|
||||
x: (min_x.map_or(0, |x| x) - max_common_x).max(0),
|
||||
y: (min_y.map_or(0, |y| y) - max_common_y).max(0),
|
||||
width: max_width - max_common_x,
|
||||
height: max_height - max_common_y,
|
||||
};
|
||||
|
||||
println!("{max_common_x} {max_common_y} {calculated_bounds:?} {view_bounds:?}");
|
||||
|
||||
let view_bounds = calculated_bounds;
|
||||
|
||||
// if let Some(set_bounds) = view_bounds {
|
||||
// if (set_bounds.width - calculated_bounds.width).abs() > calculated_bounds.width * 0.3
|
||||
// || (set_bounds.height - calculated_bounds.height).abs() > calculated_bounds.height * 0.3
|
||||
// {
|
||||
// println!("Listed bounds differ from actual bounds by > 30%. Using actual bounds")
|
||||
// }
|
||||
// }
|
||||
|
||||
let x_ratio = WIDTH as f32 / view_bounds.width as f32;
|
||||
let y_ratio = HEIGHT as f32 / view_bounds.height as f32;
|
||||
|
||||
@@ -105,8 +174,7 @@ pub fn render(
|
||||
(0, (HEIGHT as i32 - scaled_height.round() as i32) / 2)
|
||||
};
|
||||
|
||||
// Keep track of which refs have already been added to the image, as most layouts contain multiple duplicates
|
||||
let mut already_applied_refs = HashSet::<&String>::new();
|
||||
println!("{x_ratio} {y_ratio} {x_offset}, {y_offset}");
|
||||
|
||||
// Keep track of the set of pixels that make up each screen
|
||||
let mut pixels_to_mask_id: Vec<Option<u16>> = vec![None; WIDTH * HEIGHT];
|
||||
@@ -116,30 +184,9 @@ pub fn render(
|
||||
|
||||
// We currently ignore offsetting by X/Y at the parent view, so the child positions are subtracted
|
||||
// from the parent's offset
|
||||
for item in &layout.items {
|
||||
for item in &filtered_items {
|
||||
match item {
|
||||
ViewElement::Element(element) => {
|
||||
if already_applied_refs.contains(&element.ref_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
already_applied_refs.insert(&element.ref_name);
|
||||
|
||||
match element.ref_name.to_lowercase().as_str() {
|
||||
"dust" | "bubbles" => {
|
||||
// Ignore these features
|
||||
println!("Ignoring element by name {}", element.ref_name);
|
||||
continue;
|
||||
}
|
||||
value => {
|
||||
// if value.starts_with("fix") || value.starts_with("gradient") {
|
||||
if value.starts_with("gradient") {
|
||||
println!("Ignoring element by name {}", element.ref_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let file_path = asset_dir
|
||||
.join("foo")
|
||||
.with_file_name(format!("{}.png", element.ref_name));
|
||||
@@ -158,15 +205,25 @@ pub fn render(
|
||||
)
|
||||
.expect("Could not convert image data");
|
||||
|
||||
let dimensions = ImageDimensions::new(
|
||||
&view_bounds,
|
||||
&element.bounds.to_xy(),
|
||||
ratio,
|
||||
x_offset,
|
||||
y_offset,
|
||||
let element_bounds = element.bounds.to_xy();
|
||||
|
||||
let element_bounds = Bounds {
|
||||
x: (element_bounds.x - max_common_x).max(0),
|
||||
y: (element_bounds.y - max_common_y).max(0),
|
||||
width: element_bounds.width,
|
||||
height: element_bounds.height,
|
||||
};
|
||||
|
||||
let dimensions =
|
||||
ImageDimensions::new(&view_bounds, &element_bounds, ratio, x_offset, y_offset);
|
||||
|
||||
println!(
|
||||
"{element_bounds:?} {} {}, {dimensions:?}",
|
||||
image.width(),
|
||||
image.height()
|
||||
);
|
||||
|
||||
let image = DynamicImage::ImageRgba8(image).resize_exact(
|
||||
let image: DynamicImage = DynamicImage::ImageRgba8(image).resize_exact(
|
||||
dimensions.width,
|
||||
dimensions.height,
|
||||
FilterType::CatmullRom,
|
||||
@@ -227,6 +284,13 @@ pub fn render(
|
||||
|
||||
let bounds = screen.bounds.to_xy();
|
||||
|
||||
let bounds = Bounds {
|
||||
x: (bounds.x - max_common_x).max(0),
|
||||
y: (bounds.y - max_common_y).max(0),
|
||||
width: bounds.width,
|
||||
height: bounds.height,
|
||||
};
|
||||
|
||||
let dimensions =
|
||||
ImageDimensions::new(&view_bounds, &bounds, ratio, x_offset, y_offset);
|
||||
|
||||
@@ -270,6 +334,8 @@ pub fn render(
|
||||
None,
|
||||
);
|
||||
|
||||
println!("{} {}", output_mask.width(), output_mask.height());
|
||||
|
||||
if debug {
|
||||
let debug_path = asset_dir.join(format!("{platform_name}.png"));
|
||||
let debug_background_path = asset_dir.join(format!("{platform_name}_background.png"));
|
||||
@@ -322,13 +388,13 @@ fn alpha_blend_colors(
|
||||
|
||||
let foreground_alpha = foreground.alpha() as f32 / 255.0;
|
||||
|
||||
PremultipliedColorU8::from_rgba(
|
||||
combine_values(foreground.red(), background.red(), foreground_alpha),
|
||||
combine_values(foreground.green(), background.green(), foreground_alpha),
|
||||
combine_values(foreground.blue(), background.blue(), foreground_alpha),
|
||||
combine_values(foreground.alpha(), background.alpha(), foreground_alpha),
|
||||
)
|
||||
.unwrap()
|
||||
let red = combine_values(foreground.red(), background.red(), foreground_alpha);
|
||||
let green = combine_values(foreground.green(), background.green(), foreground_alpha);
|
||||
let blue = combine_values(foreground.blue(), background.blue(), foreground_alpha);
|
||||
let alpha = combine_values(foreground.alpha(), background.alpha(), foreground_alpha);
|
||||
|
||||
PremultipliedColorU8::from_rgba(red, green, blue, red.max(green).max(blue).max(alpha))
|
||||
.expect("Could not convert alpha blend color")
|
||||
}
|
||||
|
||||
fn screen_filename(index: usize, platform_name: &str, platform: &PresetDefinition) -> String {
|
||||
@@ -353,7 +419,7 @@ fn screen_filename(index: usize, platform_name: &str, platform: &PresetDefinitio
|
||||
format!("{platform_name}{suffix}.svg")
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ImageDimensions {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
|
||||
Reference in New Issue
Block a user