aboutsummaryrefslogtreecommitdiff
path: root/src/render.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/render.rs')
-rw-r--r--src/render.rs131
1 files changed, 96 insertions, 35 deletions
diff --git a/src/render.rs b/src/render.rs
index 9341848..d4f9c49 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -110,6 +110,7 @@ const TRAITS_PER_TIER: u32 = 3;
const TIER_COUNT: u32 = 3;
const TOTAL_COLUMN_COUNT: u32 = 2 * TIER_COUNT;
const MINOR_LINE_SPLIT: u32 = 4;
+const MIDDLE_COL: u32 = 1;
fn half<T: Num>(input: T) -> T {
let two = T::one() + T::one();
@@ -121,6 +122,7 @@ pub struct Renderer<'r> {
options: RenderOptions,
minor_mask: DynamicImage,
major_mask: DynamicImage,
+ grid: Grid,
}
impl<'r> Renderer<'r> {
@@ -132,11 +134,19 @@ impl<'r> Renderer<'r> {
let major_mask = image::load_from_memory(include_bytes!("major_trait_mask.png"))
.expect("Major mask image could not be loaded")
.resize(options.trait_size, options.trait_size, CatmullRom);
+ let grid = Grid {
+ x_offset: options.traitline_x_offset,
+ width: options.traitline_width - options.traitline_x_offset,
+ height: options.traitline_height,
+ rows: TRAITS_PER_TIER,
+ cols: TOTAL_COLUMN_COUNT,
+ };
Renderer {
api,
options,
minor_mask,
major_mask,
+ grid,
}
}
@@ -164,18 +174,22 @@ impl<'r> Renderer<'r> {
buffer: &mut RgbaImage,
minor: &Trait,
) -> Result<(), RenderError> {
- let minor_img = self.api.get_image(&minor.icon)?.resize(
- self.options.trait_size,
- self.options.trait_size,
- CatmullRom,
- );
+ let trait_size = self.options.trait_size;
+ let minor_img = self
+ .api
+ .get_image(&minor.icon)?
+ .resize(trait_size, trait_size, CatmullRom);
let minor_img = with_mask(&minor_img, &self.minor_mask);
- let y_pos = half(buffer.height() - minor_img.height());
- let x_slice = (buffer.width() - self.options.traitline_x_offset) / TOTAL_COLUMN_COUNT;
- let x_pos = 2 * (minor.tier - 1) * x_slice
- + half(x_slice - minor_img.width())
- + self.options.traitline_x_offset;
- imageops::overlay(buffer, &minor_img, x_pos, y_pos);
+ // Minor traits are always in the middle row, which should be 1.
+ // We also need to skip the major columns, therefore we need to multiply the column number
+ // by two.
+ let (x, y) = self.grid.pos(MIDDLE_COL, 2 * (minor.tier - 1));
+ imageops::overlay(
+ buffer,
+ &minor_img,
+ x - half(trait_size),
+ y - half(trait_size),
+ );
Ok(())
}
@@ -186,25 +200,24 @@ impl<'r> Renderer<'r> {
vertical_pos: u8,
chosen: bool,
) -> Result<(), RenderError> {
- let major_img = self.api.get_image(&major.icon)?.resize(
- self.options.trait_size,
- self.options.trait_size,
- CatmullRom,
- );
+ let trait_size = self.options.trait_size;
+ let major_img = self
+ .api
+ .get_image(&major.icon)?
+ .resize(trait_size, trait_size, CatmullRom);
let major_img = if !chosen {
with_mask(&major_img.grayscale(), &major_img)
} else {
major_img.to_rgba()
};
let major_img = with_mask(&major_img, &self.major_mask);
- let y_slice = buffer.height() / TRAITS_PER_TIER;
- let y_pos = vertical_pos as u32 * y_slice + half(y_slice - major_img.height());
- let x_slice = (buffer.width() - self.options.traitline_x_offset) / TOTAL_COLUMN_COUNT;
- let x_pos = 2 * (major.tier - 1) * x_slice
- + x_slice
- + half(x_slice - major_img.width())
- + self.options.traitline_x_offset;
- imageops::overlay(buffer, &major_img, x_pos, y_pos);
+ let (x, y) = self.grid.pos(vertical_pos as u32, 2 * (major.tier - 1) + 1);
+ imageops::overlay(
+ buffer,
+ &major_img,
+ x - half(trait_size),
+ y - half(trait_size),
+ );
Ok(())
}
@@ -218,15 +231,13 @@ impl<'r> Renderer<'r> {
return Ok(());
}
- let x_slice = (buffer.width() - self.options.traitline_x_offset) / TOTAL_COLUMN_COUNT;
- let start_x = 2 * tier as u32 * x_slice
- + half(x_slice + self.options.trait_size)
- + self.options.traitline_x_offset;
- let end_x = start_x + x_slice - self.options.trait_size;
- let start_y = half(buffer.height() - self.options.trait_size)
- + self.options.trait_size / MINOR_LINE_SPLIT * (choice as u32);
- let y_slice = buffer.height() / TRAITS_PER_TIER;
- let end_y = y_slice * (choice as u32 - 1) + half(y_slice);
+ let trait_size = self.options.trait_size;
+ let (start_x, start_y) = self.grid.pos(MIDDLE_COL, 2 * tier as u32);
+ let start_x = start_x + half(trait_size);
+ let start_y = start_y - half(trait_size) + trait_size / MINOR_LINE_SPLIT * (choice as u32);
+
+ let (end_x, end_y) = self.grid.pos(choice as u32 - 1, 2 * tier as u32 + 1);
+ let end_x = end_x - half(trait_size);
draw_thick_line(
buffer,
@@ -241,8 +252,8 @@ impl<'r> Renderer<'r> {
draw_thick_line(
buffer,
- (end_x + self.options.trait_size, end_y),
- (end_x + x_slice, start_y),
+ (end_x + trait_size, end_y),
+ (end_x + self.grid.x_slice(), start_y),
self.options.line_height,
self.options.line_color,
);
@@ -485,3 +496,53 @@ fn draw_thick_line<I>(
half_y - half(line_length),
);
}
+
+/// A helper structure representing a grid of squares.
+///
+/// This can be used to calculate the centers of the traits that should be placed on the
+/// traitlines.
+struct Grid {
+ x_offset: u32,
+ width: u32,
+ height: u32,
+ rows: u32,
+ cols: u32,
+}
+
+impl Grid {
+ /// Return the coordinates of the center of the given square.
+ #[inline(always)]
+ fn pos(&self, row: u32, col: u32) -> (u32, u32) {
+ assert!(
+ row < self.rows,
+ "row {} is outside the bounds ({})",
+ row,
+ self.rows
+ );
+ assert!(
+ col < self.cols,
+ "col {} is outside the bounds ({})",
+ col,
+ self.cols
+ );
+
+ let x_slice = self.x_slice();
+ let y_slice = self.y_slice();
+
+ let x_pos = x_slice * col + self.x_offset + half(x_slice);
+ let y_pos = y_slice * row + half(y_slice);
+ (x_pos, y_pos)
+ }
+
+ /// Returns the width of a x slice.
+ #[inline(always)]
+ fn x_slice(&self) -> u32 {
+ self.width / self.cols
+ }
+
+ /// Returns the height of an y slice.
+ #[inline(always)]
+ fn y_slice(&self) -> u32 {
+ self.height / self.rows
+ }
+}