veloren_world/site2/plot/
glider_ring.rs

1use super::*;
2use crate::{
3    Land,
4    site2::{gen::PrimitiveTransform, util::Dir},
5};
6use common::terrain::BlockKind;
7use rand::prelude::*;
8use vek::*;
9
10/// Represents glider ring data generated by the `generate()` method
11pub struct GliderRing {
12    /// Location of center of ring post
13    center: Vec2<i32>,
14    /// Represents the direction the ring is facing
15    direction: Dir,
16    /// The numeral on the ring sign
17    number: usize,
18    /// Starting altitude
19    base: i32,
20    /// The thickness of the ring from the inner to outer radius
21    ring_thickness: i32,
22    /// The height above the base altitude where the ring starts
23    ring_height: i32,
24    /// The inner radius of the ring
25    ring_radius: i32,
26}
27
28impl GliderRing {
29    pub fn generate(
30        land: &Land,
31        _rng: &mut impl Rng,
32        _site: &Site,
33        wpos: &Vec2<i32>,
34        number: usize,
35        direction: Dir,
36    ) -> Self {
37        Self {
38            center: *wpos,
39            direction,
40            number,
41            base: land.get_alt_approx(*wpos) as i32 + 1,
42            ring_thickness: 4,
43            ring_height: 35,
44            ring_radius: 16,
45        }
46    }
47}
48
49impl Structure for GliderRing {
50    #[cfg(feature = "use-dyn-lib")]
51    const UPDATE_FN: &'static [u8] = b"render_glider_ring\0";
52
53    #[cfg_attr(feature = "be-dyn-lib", export_name = "render_glider_ring")]
54    fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
55        let rotate_turns = match self.direction {
56            Dir::X => 0,
57            Dir::Y => 1,
58            Dir::NegX => 2,
59            Dir::NegY => 3,
60        };
61        let rotation_center = Vec3::new(self.center.x, self.center.y, self.base);
62
63        let red = Fill::Brick(BlockKind::Wood, Rgb::new(200, 0, 0), 24);
64        let green = Fill::Brick(BlockKind::Wood, Rgb::new(0, 200, 0), 24);
65        let white = Fill::Brick(BlockKind::GlowingRock, Rgb::new(200, 200, 200), 24);
66        let black = Fill::Brick(BlockKind::Wood, Rgb::new(0, 0, 0), 24);
67        let wood = Fill::Brick(BlockKind::Wood, Rgb::new(55, 25, 8), 24);
68
69        let ring_base = self.base + self.ring_height;
70        let ring_diameter = self.ring_radius * 2;
71        let ring_top = ring_base + ring_diameter;
72
73        // Base
74        let base = painter.aabb(Aabb {
75            min: Vec2::new(self.center.x - 1, self.center.y - 2).with_z(self.base - 30),
76            max: Vec2::new(self.center.x + 2, self.center.y + 2)
77                .with_z(self.base + self.ring_height + 1),
78        });
79        // Ring
80        let green_ring = painter.horizontal_cylinder(
81            Aabb {
82                min: Vec2::new(self.center.x - 1, self.center.y - self.ring_radius)
83                    .with_z(ring_base),
84                max: Vec2::new(self.center.x, self.center.y + self.ring_radius).with_z(ring_top),
85            },
86            Dir::X,
87        );
88        let red_ring = painter.horizontal_cylinder(
89            Aabb {
90                min: Vec2::new(self.center.x, self.center.y - self.ring_radius).with_z(ring_base),
91                max: Vec2::new(self.center.x + 2, self.center.y + self.ring_radius)
92                    .with_z(ring_top),
93            },
94            Dir::X,
95        );
96        let front_white_ring = painter.horizontal_cylinder(
97            Aabb {
98                min: Vec2::new(
99                    self.center.x - 1,
100                    self.center.y - self.ring_radius + self.ring_thickness - 1,
101                )
102                .with_z(ring_base + self.ring_thickness - 1),
103                max: Vec2::new(
104                    self.center.x,
105                    self.center.y + self.ring_radius - self.ring_thickness + 1,
106                )
107                .with_z(ring_top - self.ring_thickness + 1),
108            },
109            Dir::X,
110        );
111        let back_white_ring = painter.horizontal_cylinder(
112            Aabb {
113                min: Vec2::new(
114                    self.center.x + 1,
115                    self.center.y - self.ring_radius + self.ring_thickness - 1,
116                )
117                .with_z(ring_base + self.ring_thickness - 1),
118                max: Vec2::new(
119                    self.center.x + 2,
120                    self.center.y + self.ring_radius - self.ring_thickness + 1,
121                )
122                .with_z(ring_top - self.ring_thickness + 1),
123            },
124            Dir::X,
125        );
126        let mut black_fills = Vec::new();
127        for y in self.center.y - self.ring_radius + self.ring_thickness - 1
128            ..=self.center.y + self.ring_radius - self.ring_thickness + 1
129        {
130            if y % 4 == 0 {
131                let stripe = painter
132                    .aabb(Aabb {
133                        min: Vec2::new(self.center.x - 1, y + 1).with_z(ring_base),
134                        max: Vec2::new(self.center.x, y + 3).with_z(ring_top),
135                    })
136                    .intersect(front_white_ring);
137                black_fills.push(stripe);
138            }
139        }
140        for z in ring_base + self.ring_thickness + 3..=ring_top - self.ring_thickness - 9 {
141            if z % 4 == 0 {
142                let stripe = painter
143                    .aabb(Aabb {
144                        min: Vec2::new(
145                            self.center.x - 1,
146                            self.center.y - self.ring_radius + self.ring_thickness - 1,
147                        )
148                        .with_z(z + 1),
149                        max: Vec2::new(
150                            self.center.x,
151                            self.center.y + self.ring_radius - self.ring_thickness + 1,
152                        )
153                        .with_z(z + 3),
154                    })
155                    .intersect(front_white_ring);
156                black_fills.push(stripe);
157            }
158        }
159        let ring_clear = painter.horizontal_cylinder(
160            Aabb {
161                min: Vec2::new(
162                    self.center.x - 5,
163                    self.center.y - self.ring_radius + self.ring_thickness,
164                )
165                .with_z(ring_base + self.ring_thickness),
166                max: Vec2::new(
167                    self.center.x + 6,
168                    self.center.y + self.ring_radius - self.ring_thickness,
169                )
170                .with_z(ring_top - self.ring_thickness),
171            },
172            Dir::X,
173        );
174        // Sign
175        let sign_base = ring_top - self.ring_thickness - 1;
176        let sign_height = 7;
177        let sign = painter.aabb(Aabb {
178            min: Vec2::new(self.center.x - 1, self.center.y - 3).with_z(sign_base),
179            max: Vec2::new(self.center.x + 1, self.center.y + 3).with_z(sign_base + sign_height),
180        });
181        // Sign number
182        let numeral_origin = Vec3::new(self.center.x, self.center.y - 2, sign_base + 1);
183        // need to rotate the numeral 180 degrees as the ring direction is the direction
184        // of travel. The "positive" direction is towards the back of the ring
185        let numeral = painter
186            .numeral(numeral_origin, self.number)
187            .rotate_z_90_about(2, rotation_center);
188
189        let wood_fills = [base];
190        let red_fills = [red_ring];
191        let green_fills = [green_ring];
192        let white_fills = [front_white_ring, back_white_ring];
193        let sign_fills = [numeral];
194        let black_sign_fills = [sign];
195        let clear_fills = [ring_clear];
196
197        let fills = [
198            (&wood_fills as &[_], Some(wood)),
199            (&red_fills, Some(red)),
200            (&green_fills, Some(green)),
201            (&white_fills, Some(white.clone())),
202            (&black_fills, Some(black.clone())),
203            (&clear_fills, None),
204            (&black_sign_fills, Some(black)),
205            (&sign_fills, Some(white)),
206        ];
207        for (primitives, fill_color_maybe) in fills {
208            for prim in primitives {
209                if let Some(fill_color) = &fill_color_maybe {
210                    prim.rotate_z_90_about(rotate_turns, rotation_center)
211                        .fill(fill_color.clone());
212                } else {
213                    prim.rotate_z_90_about(rotate_turns, rotation_center)
214                        .clear();
215                }
216            }
217        }
218    }
219}