Skip to main content

hdim_render/
view.rs

1//! Viewport definition and calculation logic.
2//!
3//! This module defines the [View] struct, which maps a source image region
4//! to a target terminal area, handling coordinate mapping and scaling calculations.
5
6/// Defines the mapping between a rectangular area of the source image
7/// and the target rendering area in the terminal.
8///
9/// The `View` struct is used to determine which pixels from the source image
10/// correspond to which character cells in the terminal output.
11#[derive(Debug, Clone, Copy)]
12pub struct View {
13    /// The top-left X coordinate of the view on the source image (in pixels).
14    pub source_x: u32,
15    /// The top-left Y coordinate of the view on the source image (in pixels).
16    pub source_y: u32,
17    /// The width of the view on the source image (in pixels).
18    pub source_width: u32,
19    /// The height of the view on the source image (in pixels).
20    pub source_height: u32,
21    /// The width of the target render area (in terminal columns).
22    pub target_width: u32,
23    /// The height of the target render area (in terminal rows).
24    pub target_height: u32,
25}
26
27impl View {
28    /// Calculates the scaling ratios between source and target dimensions.
29    ///
30    /// # Returns
31    ///
32    /// A tuple `(x_ratio, y_ratio)` representing source pixels per terminal cell.
33    pub fn calculate_scaling(&self) -> (f32, f32) {
34        let x_ratio = self.source_width as f32 / self.target_width as f32;
35        let y_ratio = self.source_height as f32 / self.target_height as f32;
36        (x_ratio, y_ratio)
37    }
38
39    /// Maps a terminal cell coordinate (x, y) to the corresponding source image coordinates.
40    ///
41    /// # Arguments
42    ///
43    /// * `x` - The terminal column index.
44    /// * `y` - The terminal row index.
45    /// * `x_ratio` - Source pixels per column.
46    /// * `y_ratio` - Source pixels per row.
47    ///
48    /// # Returns
49    ///
50    /// A tuple `(source_x, source_y_top, source_y_bottom)` representing the starting
51    /// pixel coordinates for the top and bottom halves of the character block.
52    pub fn map_to_source(&self, x: u32, y: u32, x_ratio: f32, y_ratio: f32) -> (u32, u32, u32) {
53        let source_pixel_x = self.source_x + (x as f32 * x_ratio) as u32;
54        let source_pixel_y_top = self.source_y + (y as f32 * y_ratio) as u32;
55        let source_pixel_y_bottom = source_pixel_y_top + (y_ratio / 2.0).round().max(1.0) as u32;
56        (source_pixel_x, source_pixel_y_top, source_pixel_y_bottom)
57    }
58
59    /// Calculates the block dimensions for averaging colors.
60    ///
61    /// # Arguments
62    ///
63    /// * `x_ratio` - Source pixels per column.
64    /// * `y_ratio` - Source pixels per row.
65    ///
66    /// # Returns
67    ///
68    /// A tuple `(block_width, block_height)` representing the size of the pixel block
69    /// to sample for each half-character.
70    pub fn calculate_block_size(&self, x_ratio: f32, y_ratio: f32) -> (u32, u32) {
71        let block_width = x_ratio.round().max(1.0) as u32;
72        let block_height = (y_ratio / 2.0).round().max(1.0) as u32;
73        (block_width, block_height)
74    }
75}