Skip to main content

veloren_world/site/plot/
glider_ring.rs

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