rust/land2d/src/lib.rs
author sheepluva
Mon, 05 Aug 2019 00:20:45 +0200
changeset 15295 f382ec6dba11
parent 14702 29dbe9ce8b7d
child 15828 44b49f255e31
permissions -rw-r--r--
In hindsight my emscripten-ifdef (70d416a8f63f) is nonsense. As fpcrtl_glShaderSource() would not be defined and lead to compiling issues. So either it's 3 ifdefs (in pas2cRedo, pas2cSystem and misc.c), in order to toggle between fpcrtl_ and the native function, or alternatively have no ifdef for it at all. I'm going with none at all, which means emscripten will compile with the original (const) function prototype, being wrapped by the fpcrtl_ function, same as non-emscripten builds.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
14144
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
     1
use std::{
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
     2
    cmp,
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
     3
    ops::Index
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
     4
};
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
     5
14137
3119d665d3c6 collapse rectangle types back together with consistent usage of size
alfadur
parents: 14135
diff changeset
     6
use integral_geometry::{ArcPoints, EquidistantPoints, Line, Point, Rect, Size, SizeMask};
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13936
diff changeset
     7
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
     8
pub struct Land2D<T> {
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
     9
    pixels: vec2d::Vec2D<T>,
14137
3119d665d3c6 collapse rectangle types back together with consistent usage of size
alfadur
parents: 14135
diff changeset
    10
    play_box: Rect,
14078
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    11
    mask: SizeMask,
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    12
}
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    13
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    14
impl<T: Copy + PartialEq> Land2D<T> {
14052
alfadur
parents: 14050 14032
diff changeset
    15
    pub fn new(play_size: Size, fill_value: T) -> Self {
alfadur
parents: 14050 14032
diff changeset
    16
        let real_size = play_size.next_power_of_two();
14078
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    17
        let top_left = Point::new(
14101
ceda58e398e0 fix play area rect
alfadur
parents: 14078
diff changeset
    18
            ((real_size.width - play_size.width) / 2) as i32,
14078
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    19
            (real_size.height - play_size.height) as i32,
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    20
        );
14137
3119d665d3c6 collapse rectangle types back together with consistent usage of size
alfadur
parents: 14135
diff changeset
    21
        let play_box = Rect::from_size(top_left, play_size);
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    22
        Self {
14078
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    23
            play_box,
14052
alfadur
parents: 14050 14032
diff changeset
    24
            pixels: vec2d::Vec2D::new(real_size, fill_value),
14078
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    25
            mask: real_size.to_mask(),
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    26
        }
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    27
    }
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    28
14121
69db1d2e4cec land_dump app for testing templated landgen
unc0rr
parents: 14101
diff changeset
    29
    pub fn raw_pixels(&self) -> &[T] {
14160
c24a76f131d6 implement basic land texturing
alfadur
parents: 14150
diff changeset
    30
        &self.pixels.as_slice()
14121
69db1d2e4cec land_dump app for testing templated landgen
unc0rr
parents: 14101
diff changeset
    31
    }
69db1d2e4cec land_dump app for testing templated landgen
unc0rr
parents: 14101
diff changeset
    32
14702
29dbe9ce8b7d add basic map rendering with gl
fkaa
parents: 14207
diff changeset
    33
    pub fn raw_pixel_bytes(&self) -> &[u8] {
29dbe9ce8b7d add basic map rendering with gl
fkaa
parents: 14207
diff changeset
    34
        unsafe {
29dbe9ce8b7d add basic map rendering with gl
fkaa
parents: 14207
diff changeset
    35
            self.pixels.as_bytes()
29dbe9ce8b7d add basic map rendering with gl
fkaa
parents: 14207
diff changeset
    36
        }
29dbe9ce8b7d add basic map rendering with gl
fkaa
parents: 14207
diff changeset
    37
    }
29dbe9ce8b7d add basic map rendering with gl
fkaa
parents: 14207
diff changeset
    38
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    39
    #[inline]
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    40
    pub fn width(&self) -> usize {
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    41
        self.pixels.width()
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    42
    }
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    43
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    44
    #[inline]
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    45
    pub fn height(&self) -> usize {
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    46
        self.pixels.height()
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    47
    }
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    48
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    49
    #[inline]
14052
alfadur
parents: 14050 14032
diff changeset
    50
    pub fn size(&self) -> Size {
alfadur
parents: 14050 14032
diff changeset
    51
        self.pixels.size()
alfadur
parents: 14050 14032
diff changeset
    52
    }
alfadur
parents: 14050 14032
diff changeset
    53
alfadur
parents: 14050 14032
diff changeset
    54
    #[inline]
14050
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
    55
    pub fn play_width(&self) -> usize {
14135
7f5a591e1c43 separate rectangle types based on right/bottom edge inclusivity
alfadur
parents: 14121
diff changeset
    56
        self.play_box.width()
14050
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
    57
    }
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
    58
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
    59
    #[inline]
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
    60
    pub fn play_height(&self) -> usize {
14135
7f5a591e1c43 separate rectangle types based on right/bottom edge inclusivity
alfadur
parents: 14121
diff changeset
    61
        self.play_box.height()
14052
alfadur
parents: 14050 14032
diff changeset
    62
    }
alfadur
parents: 14050 14032
diff changeset
    63
alfadur
parents: 14050 14032
diff changeset
    64
    #[inline]
alfadur
parents: 14050 14032
diff changeset
    65
    pub fn play_size(&self) -> Size {
14135
7f5a591e1c43 separate rectangle types based on right/bottom edge inclusivity
alfadur
parents: 14121
diff changeset
    66
        self.play_box.size()
14050
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
    67
    }
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
    68
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
    69
    #[inline]
14137
3119d665d3c6 collapse rectangle types back together with consistent usage of size
alfadur
parents: 14135
diff changeset
    70
    pub fn play_box(&self) -> Rect {
14078
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    71
        self.play_box
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    72
    }
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    73
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
    74
    #[inline]
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    75
    pub fn is_valid_x(&self, x: i32) -> bool {
14032
2869c2ccb1b8 extract size struct for common usage
alfadur
parents: 14031
diff changeset
    76
        self.mask.contains_x(x as usize)
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    77
    }
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    78
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    79
    #[inline]
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    80
    pub fn is_valid_y(&self, y: i32) -> bool {
14032
2869c2ccb1b8 extract size struct for common usage
alfadur
parents: 14031
diff changeset
    81
        self.mask.contains_y(y as usize)
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    82
    }
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    83
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    84
    #[inline]
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
    85
    pub fn is_valid_coordinate(&self, x: i32, y: i32) -> bool {
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
    86
        self.is_valid_x(x) && self.is_valid_y(y)
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    87
    }
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    88
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    89
    #[inline]
14170
a4c1a2d0ac24 implement basic land bordering
alfadur
parents: 14160
diff changeset
    90
    pub fn rows(&self) -> impl DoubleEndedIterator<Item = &[T]> {
14030
2ebd505e62c1 make theme editor render some random map lines
alfadur
parents: 13951
diff changeset
    91
        self.pixels.rows()
2ebd505e62c1 make theme editor render some random map lines
alfadur
parents: 13951
diff changeset
    92
    }
2ebd505e62c1 make theme editor render some random map lines
alfadur
parents: 13951
diff changeset
    93
2ebd505e62c1 make theme editor render some random map lines
alfadur
parents: 13951
diff changeset
    94
    #[inline]
13940
1c30793b1cea put back land2d.map accidentally replaced by testing code
alfadur
parents: 13938
diff changeset
    95
    pub fn map<U: Default, F: FnOnce(&mut T) -> U>(&mut self, y: i32, x: i32, f: F) -> U {
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
    96
        if self.is_valid_coordinate(x, y) {
13934
9c112f2ae02d Raise levels of abstraction to implement draw_thick_line() avoiding code duplication
unc0rr
parents: 13931
diff changeset
    97
            unsafe {
9c112f2ae02d Raise levels of abstraction to implement draw_thick_line() avoiding code duplication
unc0rr
parents: 13931
diff changeset
    98
                // hey, I just checked that coordinates are valid!
13940
1c30793b1cea put back land2d.map accidentally replaced by testing code
alfadur
parents: 13938
diff changeset
    99
                f(self.pixels.get_unchecked_mut(y as usize, x as usize))
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   100
            }
13934
9c112f2ae02d Raise levels of abstraction to implement draw_thick_line() avoiding code duplication
unc0rr
parents: 13931
diff changeset
   101
        } else {
13940
1c30793b1cea put back land2d.map accidentally replaced by testing code
alfadur
parents: 13938
diff changeset
   102
            U::default()
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   103
        }
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   104
    }
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   105
13944
4162ea9ae333 Use integral-geometry iterators to implement Land2D::draw_thick_line, remove no longer unused functions from Land2D
unc0rr
parents: 13943
diff changeset
   106
    #[inline]
4162ea9ae333 Use integral-geometry iterators to implement Land2D::draw_thick_line, remove no longer unused functions from Land2D
unc0rr
parents: 13943
diff changeset
   107
    pub fn map_point<U: Default, F: FnOnce(&mut T) -> U>(&mut self, point: Point, f: F) -> U {
4162ea9ae333 Use integral-geometry iterators to implement Land2D::draw_thick_line, remove no longer unused functions from Land2D
unc0rr
parents: 13943
diff changeset
   108
        self.map(point.y, point.x, f)
13934
9c112f2ae02d Raise levels of abstraction to implement draw_thick_line() avoiding code duplication
unc0rr
parents: 13931
diff changeset
   109
    }
9c112f2ae02d Raise levels of abstraction to implement draw_thick_line() avoiding code duplication
unc0rr
parents: 13931
diff changeset
   110
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13936
diff changeset
   111
    pub fn fill_from_iter<I>(&mut self, i: I, value: T) -> usize
13943
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   112
    where
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   113
        I: std::iter::Iterator<Item = Point>,
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13936
diff changeset
   114
    {
13943
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   115
        i.map(|p| {
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   116
            self.map(p.y, p.x, |v| {
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   117
                *v = value;
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   118
                1
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   119
            })
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   120
        }).count()
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13936
diff changeset
   121
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13936
diff changeset
   122
14076
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   123
    pub fn draw_line(&mut self, line: Line, value: T) -> usize {
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   124
        self.fill_from_iter(line.into_iter(), value)
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   125
    }
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   126
13948
c6e1769ac9aa Change Land2D::fill() arguments a bit
unc0rr
parents: 13946
diff changeset
   127
    pub fn fill(&mut self, start_point: Point, border_value: T, fill_value: T) {
14150
6205a5230d23 make fill point asserts persistent
alfadur
parents: 14149
diff changeset
   128
        assert!(self.is_valid_coordinate(start_point.x - 1, start_point.y));
6205a5230d23 make fill point asserts persistent
alfadur
parents: 14149
diff changeset
   129
        assert!(self.is_valid_coordinate(start_point.x, start_point.y));
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   130
14148
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   131
        let mask = self.mask;
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   132
        let width = self.width();
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   133
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   134
        let mut stack: Vec<(usize, usize, usize, isize)> = Vec::new();
14148
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   135
        fn push(
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   136
            mask: SizeMask,
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   137
            stack: &mut Vec<(usize, usize, usize, isize)>,
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   138
            xl: usize,
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   139
            xr: usize,
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   140
            y: usize,
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   141
            dir: isize,
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   142
        ) {
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   143
            let yd = y as isize + dir;
14148
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   144
            if mask.contains_y(yd as usize) {
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   145
                stack.push((xl, xr, yd as usize, dir));
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   146
            }
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   147
        };
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   148
13948
c6e1769ac9aa Change Land2D::fill() arguments a bit
unc0rr
parents: 13946
diff changeset
   149
        let start_x_l = (start_point.x - 1) as usize;
c6e1769ac9aa Change Land2D::fill() arguments a bit
unc0rr
parents: 13946
diff changeset
   150
        let start_x_r = start_point.x as usize;
14148
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   151
        for dir in [-1, 1].iter().cloned() {
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   152
            push(mask, &mut stack, start_x_l, start_x_r, start_point.y as usize, dir);
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   153
        }
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   154
14148
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   155
        while let Some((mut xl, mut xr, y, dir)) = stack.pop() {
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   156
            let row = &mut self.pixels[y][..];
14149
8e2e98760003 a bit more simplification without an apparent performance gain
alfadur
parents: 14148
diff changeset
   157
            while xl > 0 && row[xl] != border_value && row[xl] != fill_value
13951
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   158
            {
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   159
                xl -= 1;
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   160
            }
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   161
14149
8e2e98760003 a bit more simplification without an apparent performance gain
alfadur
parents: 14148
diff changeset
   162
            while xr < width - 1 && row[xr] != border_value && row[xr] != fill_value
13951
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   163
            {
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   164
                xr += 1;
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   165
            }
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   166
13951
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   167
            while xl < xr {
14148
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   168
                while xl <= xr && (row[xl] == border_value || row[xl] == fill_value)
13951
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   169
                {
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   170
                    xl += 1;
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   171
                }
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   172
14148
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   173
                let x = xl;
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   174
14149
8e2e98760003 a bit more simplification without an apparent performance gain
alfadur
parents: 14148
diff changeset
   175
                while xl <= xr && row[xl] != border_value && row[xl] != fill_value
13951
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   176
                {
14148
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   177
                    row[xl] = fill_value;
13951
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   178
                    xl += 1;
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   179
                }
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   180
13951
03e41712eef8 Fix silly loop
unc0rr
parents: 13949
diff changeset
   181
                if x < xl {
14148
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   182
                    push(mask, &mut stack, x, xl - 1, y, dir);
d3c9025abd13 seems like about 25% speedup in land filling
alfadur
parents: 14144
diff changeset
   183
                    push(mask, &mut stack, x, xl - 1, y, -dir);
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   184
                }
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   185
            }
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   186
        }
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   187
    }
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   188
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   189
    #[inline]
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   190
    fn fill_circle_line<F: Fn(&mut T) -> usize>(
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   191
        &mut self,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   192
        y: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   193
        x_from: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   194
        x_to: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   195
        f: &F,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   196
    ) -> usize {
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   197
        let mut result = 0;
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   198
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   199
        if self.is_valid_y(y) {
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   200
            for i in cmp::min(x_from, 0) as usize..cmp::max(x_to as usize, self.width() - 1) {
13934
9c112f2ae02d Raise levels of abstraction to implement draw_thick_line() avoiding code duplication
unc0rr
parents: 13931
diff changeset
   201
                unsafe {
9c112f2ae02d Raise levels of abstraction to implement draw_thick_line() avoiding code duplication
unc0rr
parents: 13931
diff changeset
   202
                    // coordinates are valid at this point
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   203
                    result += f(self.pixels.get_unchecked_mut(y as usize, i));
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   204
                }
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   205
            }
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   206
        }
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   207
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   208
        result
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   209
    }
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   210
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   211
    #[inline]
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   212
    fn fill_circle_lines<F: Fn(&mut T) -> usize>(
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   213
        &mut self,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   214
        x: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   215
        y: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   216
        dx: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   217
        dy: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   218
        f: &F,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   219
    ) -> usize {
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   220
        self.fill_circle_line(y + dy, x - dx, x + dx, f)
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   221
            + self.fill_circle_line(y - dy, x - dx, x + dx, f)
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   222
            + self.fill_circle_line(y + dx, x - dy, x + dy, f)
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   223
            + self.fill_circle_line(y - dx, x - dy, x + dy, f)
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   224
    }
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   225
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   226
    pub fn change_round<F: Fn(&mut T) -> usize>(
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   227
        &mut self,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   228
        x: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   229
        y: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   230
        radius: i32,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   231
        f: F,
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   232
    ) -> usize {
13943
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   233
        ArcPoints::new(radius)
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   234
            .map(&mut |p: Point| self.fill_circle_lines(x, y, p.x, p.y, &f))
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   235
            .sum()
13934
9c112f2ae02d Raise levels of abstraction to implement draw_thick_line() avoiding code duplication
unc0rr
parents: 13931
diff changeset
   236
    }
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   237
14031
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   238
    fn fill_row(&mut self, center: Point, offset: Point, value: T) -> usize {
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   239
        let row_index = center.y + offset.y;
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   240
        if self.is_valid_y(row_index) {
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   241
            let from_x = cmp::max(0, center.x - offset.x) as usize;
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   242
            let to_x = cmp::min(self.width() - 1, (center.x + offset.x) as usize);
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   243
            self.pixels[row_index as usize][from_x..=to_x]
14078
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   244
                .iter_mut()
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   245
                .for_each(|v| *v = value);
14031
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   246
            to_x - from_x + 1
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   247
        } else {
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   248
            0
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   249
        }
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   250
    }
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   251
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   252
    pub fn fill_circle(&mut self, center: Point, radius: i32, value: T) -> usize {
14078
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   253
        let transforms = [[0, 1, 1, 0], [0, 1, -1, 0], [1, 0, 0, 1], [1, 0, 0, -1]];
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   254
        ArcPoints::new(radius)
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   255
            .map(|vector| {
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   256
                transforms
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   257
                    .iter()
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   258
                    .map(|m| self.fill_row(center, vector.transform(m), value))
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   259
                    .sum::<usize>()
bf40b5f938b0 - Add methods to work with Rect as box
unC0Rr
parents: 14076
diff changeset
   260
            }).sum()
14031
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   261
    }
c47283feafac add circle filling to land2d
alfadur
parents: 14030
diff changeset
   262
14076
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   263
    pub fn draw_thick_line(&mut self, line: Line, radius: i32, value: T) -> usize {
13944
4162ea9ae333 Use integral-geometry iterators to implement Land2D::draw_thick_line, remove no longer unused functions from Land2D
unc0rr
parents: 13943
diff changeset
   264
        let mut result = 0;
13931
9230aed8a32e Implement Land2D::change_round()
unc0rr
parents: 13924
diff changeset
   265
13949
a1895019bb94 change draw_thick_line iteration order to benchmark winner
alfadur
parents: 13948
diff changeset
   266
        for vector in ArcPoints::new(radius) {
a1895019bb94 change draw_thick_line iteration order to benchmark winner
alfadur
parents: 13948
diff changeset
   267
            for delta in EquidistantPoints::new(vector) {
14076
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   268
                for point in line.into_iter() {
13946
54e2a3698425 revert 2354264ab0b0
alfadur
parents: 13945
diff changeset
   269
                    self.map_point(point + delta, |p| {
54e2a3698425 revert 2354264ab0b0
alfadur
parents: 13945
diff changeset
   270
                        if *p != value {
54e2a3698425 revert 2354264ab0b0
alfadur
parents: 13945
diff changeset
   271
                            *p = value;
54e2a3698425 revert 2354264ab0b0
alfadur
parents: 13945
diff changeset
   272
                            result += 1;
54e2a3698425 revert 2354264ab0b0
alfadur
parents: 13945
diff changeset
   273
                        }
54e2a3698425 revert 2354264ab0b0
alfadur
parents: 13945
diff changeset
   274
                    })
13944
4162ea9ae333 Use integral-geometry iterators to implement Land2D::draw_thick_line, remove no longer unused functions from Land2D
unc0rr
parents: 13943
diff changeset
   275
                }
13943
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   276
            }
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   277
        }
a325ed57ebfe Don't generate unnecessary duplication in case of equal coordinates
unc0rr
parents: 13940
diff changeset
   278
13944
4162ea9ae333 Use integral-geometry iterators to implement Land2D::draw_thick_line, remove no longer unused functions from Land2D
unc0rr
parents: 13943
diff changeset
   279
        result
13934
9c112f2ae02d Raise levels of abstraction to implement draw_thick_line() avoiding code duplication
unc0rr
parents: 13931
diff changeset
   280
    }
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   281
}
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   282
14144
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
   283
impl<T> Index<usize> for Land2D<T> {
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
   284
    type Output = [T];
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
   285
    #[inline]
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
   286
    fn index(&self, row: usize) -> &[T] {
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
   287
        &self.pixels[row]
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
   288
    }
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
   289
}
165e43c3ed59 pull land into collision detector
alfadur
parents: 14140
diff changeset
   290
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   291
#[cfg(test)]
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   292
mod tests {
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   293
    use super::*;
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   294
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   295
    #[test]
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   296
    fn basics() {
14052
alfadur
parents: 14050 14032
diff changeset
   297
        let l: Land2D<u8> = Land2D::new(Size::new(30, 50), 0);
14050
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
   298
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
   299
        assert_eq!(l.play_width(), 30);
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
   300
        assert_eq!(l.play_height(), 50);
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
   301
        assert_eq!(l.width(), 32);
4b40bdd214df Use next_power_of_two() just like hedgewars engine does, expose original and real dimensions
unc0rr
parents: 13951
diff changeset
   302
        assert_eq!(l.height(), 64);
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   303
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   304
        assert!(l.is_valid_coordinate(0, 0));
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   305
        assert!(!l.is_valid_coordinate(-1, -1));
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   306
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   307
        assert!(l.is_valid_coordinate(31, 63));
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   308
        assert!(!l.is_valid_coordinate(32, 63));
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   309
        assert!(!l.is_valid_coordinate(31, 64));
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   310
    }
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   311
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   312
    #[test]
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   313
    fn fill() {
14032
2869c2ccb1b8 extract size struct for common usage
alfadur
parents: 14031
diff changeset
   314
        let mut l: Land2D<u8> = Land2D::new(Size::square(128), 0);
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   315
14076
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   316
        l.draw_line(Line::new(Point::new(0, 0), Point::new(32, 96)), 1);
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   317
        l.draw_line(Line::new(Point::new(32, 96), Point::new(64, 32)), 1);
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   318
        l.draw_line(Line::new(Point::new(64, 32), Point::new(96, 80)), 1);
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   319
        l.draw_line(Line::new(Point::new(96, 80), Point::new(128, 0)), 1);
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   320
14076
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   321
        l.draw_line(Line::new(Point::new(0, 128), Point::new(64, 96)), 1);
e5904ead4864 Introduce OutlineSegmentsIterator, some refactoring
unC0Rr
parents: 14052
diff changeset
   322
        l.draw_line(Line::new(Point::new(128, 128), Point::new(64, 96)), 1);
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   323
13948
c6e1769ac9aa Change Land2D::fill() arguments a bit
unc0rr
parents: 13946
diff changeset
   324
        l.fill(Point::new(32, 32), 1, 2);
c6e1769ac9aa Change Land2D::fill() arguments a bit
unc0rr
parents: 13946
diff changeset
   325
        l.fill(Point::new(16, 96), 1, 3);
c6e1769ac9aa Change Land2D::fill() arguments a bit
unc0rr
parents: 13946
diff changeset
   326
        l.fill(Point::new(60, 100), 1, 4);
13924
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   327
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   328
        assert_eq!(l.pixels[0][0], 1);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   329
        assert_eq!(l.pixels[96][64], 1);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   330
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   331
        assert_eq!(l.pixels[40][32], 2);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   332
        assert_eq!(l.pixels[40][96], 2);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   333
        assert_eq!(l.pixels[5][0], 3);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   334
        assert_eq!(l.pixels[120][0], 3);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   335
        assert_eq!(l.pixels[5][127], 3);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   336
        assert_eq!(l.pixels[120][127], 3);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   337
        assert_eq!(l.pixels[35][64], 3);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   338
        assert_eq!(l.pixels[120][20], 4);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   339
        assert_eq!(l.pixels[120][100], 4);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   340
        assert_eq!(l.pixels[100][64], 4);
a140f28decc4 Implement Land2D::fill() + tests
unc0rr
parents: 13917
diff changeset
   341
    }
13917
a83ba9ba1566 Start land2d library implementation: draw_line() method
unc0rr
parents:
diff changeset
   342
}