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 = "use-dyn-lib")]
48    const UPDATE_FN: &'static [u8] = b"render_glider_ring\0";
49
50    #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "render_glider_ring"))]
51    fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
52        let rotate_turns = match self.direction {
53            Dir2::X => 0,
54            Dir2::Y => 1,
55            Dir2::NegX => 2,
56            Dir2::NegY => 3,
57        };
58        let rotation_center = Vec3::new(self.center.x, self.center.y, self.base);
59
60        let red = Fill::Brick(BlockKind::Wood, Rgb::new(200, 0, 0), 24);
61        let green = Fill::Brick(BlockKind::Wood, Rgb::new(0, 200, 0), 24);
62        let white = Fill::Brick(BlockKind::GlowingRock, Rgb::new(200, 200, 200), 24);
63        let black = Fill::Brick(BlockKind::Wood, Rgb::new(0, 0, 0), 24);
64        let wood = Fill::Brick(BlockKind::Wood, Rgb::new(55, 25, 8), 24);
65
66        let ring_base = self.base + self.ring_height;
67        let ring_diameter = self.ring_radius * 2;
68        let ring_top = ring_base + ring_diameter;
69
70        // Base
71        let base = painter.aabb(Aabb {
72            min: Vec2::new(self.center.x - 1, self.center.y - 2).with_z(self.base - 30),
73            max: Vec2::new(self.center.x + 2, self.center.y + 2)
74                .with_z(self.base + self.ring_height + 1),
75        });
76        // Ring
77        let green_ring = painter.horizontal_cylinder(
78            Aabb {
79                min: Vec2::new(self.center.x - 1, self.center.y - self.ring_radius)
80                    .with_z(ring_base),
81                max: Vec2::new(self.center.x, self.center.y + self.ring_radius).with_z(ring_top),
82            },
83            Dir2::X,
84        );
85        let red_ring = painter.horizontal_cylinder(
86            Aabb {
87                min: Vec2::new(self.center.x, self.center.y - self.ring_radius).with_z(ring_base),
88                max: Vec2::new(self.center.x + 2, self.center.y + self.ring_radius)
89                    .with_z(ring_top),
90            },
91            Dir2::X,
92        );
93        let front_white_ring = painter.horizontal_cylinder(
94            Aabb {
95                min: Vec2::new(
96                    self.center.x - 1,
97                    self.center.y - self.ring_radius + self.ring_thickness - 1,
98                )
99                .with_z(ring_base + self.ring_thickness - 1),
100                max: Vec2::new(
101                    self.center.x,
102                    self.center.y + self.ring_radius - self.ring_thickness + 1,
103                )
104                .with_z(ring_top - self.ring_thickness + 1),
105            },
106            Dir2::X,
107        );
108        let back_white_ring = painter.horizontal_cylinder(
109            Aabb {
110                min: Vec2::new(
111                    self.center.x + 1,
112                    self.center.y - self.ring_radius + self.ring_thickness - 1,
113                )
114                .with_z(ring_base + self.ring_thickness - 1),
115                max: Vec2::new(
116                    self.center.x + 2,
117                    self.center.y + self.ring_radius - self.ring_thickness + 1,
118                )
119                .with_z(ring_top - self.ring_thickness + 1),
120            },
121            Dir2::X,
122        );
123        let mut black_fills = Vec::new();
124        for y in self.center.y - self.ring_radius + self.ring_thickness - 1
125            ..=self.center.y + self.ring_radius - self.ring_thickness + 1
126        {
127            if y % 4 == 0 {
128                let stripe = painter
129                    .aabb(Aabb {
130                        min: Vec2::new(self.center.x - 1, y + 1).with_z(ring_base),
131                        max: Vec2::new(self.center.x, y + 3).with_z(ring_top),
132                    })
133                    .intersect(front_white_ring);
134                black_fills.push(stripe);
135            }
136        }
137        for z in ring_base + self.ring_thickness + 3..=ring_top - self.ring_thickness - 9 {
138            if z % 4 == 0 {
139                let stripe = painter
140                    .aabb(Aabb {
141                        min: Vec2::new(
142                            self.center.x - 1,
143                            self.center.y - self.ring_radius + self.ring_thickness - 1,
144                        )
145                        .with_z(z + 1),
146                        max: Vec2::new(
147                            self.center.x,
148                            self.center.y + self.ring_radius - self.ring_thickness + 1,
149                        )
150                        .with_z(z + 3),
151                    })
152                    .intersect(front_white_ring);
153                black_fills.push(stripe);
154            }
155        }
156        let ring_clear = painter.horizontal_cylinder(
157            Aabb {
158                min: Vec2::new(
159                    self.center.x - 5,
160                    self.center.y - self.ring_radius + self.ring_thickness,
161                )
162                .with_z(ring_base + self.ring_thickness),
163                max: Vec2::new(
164                    self.center.x + 6,
165                    self.center.y + self.ring_radius - self.ring_thickness,
166                )
167                .with_z(ring_top - self.ring_thickness),
168            },
169            Dir2::X,
170        );
171        // Sign
172        let sign_base = ring_top - self.ring_thickness - 1;
173        let sign_height = 7;
174        let sign = painter.aabb(Aabb {
175            min: Vec2::new(self.center.x - 1, self.center.y - 3).with_z(sign_base),
176            max: Vec2::new(self.center.x + 1, self.center.y + 3).with_z(sign_base + sign_height),
177        });
178        // Sign number
179        let numeral_origin = Vec3::new(self.center.x, self.center.y - 2, sign_base + 1);
180        // need to rotate the numeral 180 degrees as the ring direction is the direction
181        // of travel. The "positive" direction is towards the back of the ring
182        let numeral = painter
183            .numeral(numeral_origin, self.number)
184            .rotate_z_90_about(2, rotation_center);
185
186        let wood_fills = [base];
187        let red_fills = [red_ring];
188        let green_fills = [green_ring];
189        let white_fills = [front_white_ring, back_white_ring];
190        let sign_fills = [numeral];
191        let black_sign_fills = [sign];
192        let clear_fills = [ring_clear];
193
194        let fills = [
195            (&wood_fills as &[_], Some(wood)),
196            (&red_fills, Some(red)),
197            (&green_fills, Some(green)),
198            (&white_fills, Some(white.clone())),
199            (&black_fills, Some(black.clone())),
200            (&clear_fills, None),
201            (&black_sign_fills, Some(black)),
202            (&sign_fills, Some(white)),
203        ];
204        for (primitives, fill_color_maybe) in fills {
205            for prim in primitives {
206                if let Some(fill_color) = &fill_color_maybe {
207                    prim.rotate_z_90_about(rotate_turns, rotation_center)
208                        .fill(fill_color.clone());
209                } else {
210                    prim.rotate_z_90_about(rotate_turns, rotation_center)
211                        .clear();
212                }
213            }
214        }
215    }
216}