1use super::*;
2use crate::{
3 ColumnSample, Land,
4 site::{r#gen::PrimitiveTransform, util::gradient::WrapMode},
5 util::{RandomField, Sampler},
6};
7use common::terrain::{
8 Block, BlockKind, SpriteKind, Structure as PrefabStructure, sprite::RelativeNeighborPosition,
9};
10use rand::prelude::*;
11use vek::*;
12
13pub struct Barn {
14 pub door_tile: Vec2<i32>,
16 bounds: Aabr<i32>,
18 pub(crate) alt: i32,
20 is_desert: bool,
21 surface_color: Rgb<f32>,
22 sub_surface_color: Rgb<f32>,
23}
24
25impl Barn {
26 pub fn generate(
27 land: &Land,
28 index: IndexRef,
29 _rng: &mut impl Rng,
30 site: &Site,
31 door_tile: Vec2<i32>,
32 door_dir: Vec2<i32>,
33 tile_aabr: Aabr<i32>,
34 is_desert: bool,
35 ) -> Self {
36 let door_tile_pos = site.tile_center_wpos(door_tile);
37 let bounds = Aabr {
38 min: site.tile_wpos(tile_aabr.min),
39 max: site.tile_wpos(tile_aabr.max),
40 };
41 let (surface_color, sub_surface_color) =
42 if let Some(sample) = land.column_sample(bounds.center(), index) {
43 (sample.surface_color, sample.sub_surface_color)
44 } else {
45 (Rgb::new(161.0, 116.0, 86.0), Rgb::new(88.0, 64.0, 64.0))
46 };
47
48 Self {
49 door_tile: door_tile_pos,
50 bounds,
51 alt: land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32 + 2,
52 is_desert,
53 surface_color,
54 sub_surface_color,
55 }
56 }
57}
58
59impl Structure for Barn {
60 #[cfg(feature = "use-dyn-lib")]
61 const UPDATE_FN: &'static [u8] = b"render_barn\0";
62
63 #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "render_barn"))]
64 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
65 let base = self.alt;
66 let plot_center = self.bounds.center();
67
68 let surface_color = self.surface_color.map(|e| (e * 255.0) as u8);
71 let sub_surface_color = self.sub_surface_color.map(|e| (e * 255.0) as u8);
72 let gradient_center = Vec3::new(
73 plot_center.x as f32,
74 plot_center.y as f32,
75 (base - 1) as f32,
76 );
77 let gradient_var_1 = RandomField::new(0).get(plot_center.with_z(base - 1)) as i32 % 8;
78 let gradient_var_2 = RandomField::new(0).get(plot_center.with_z(base)) as i32 % 10;
79
80 let brick = Fill::Gradient(
81 util::gradient::Gradient::new(
82 gradient_center,
83 12.0 + gradient_var_1 as f32,
84 util::gradient::Shape::Point,
85 (surface_color, sub_surface_color),
86 )
87 .with_repeat(if gradient_var_2 > 5 {
88 WrapMode::Repeat
89 } else {
90 WrapMode::PingPong
91 }),
92 BlockKind::Rock,
93 );
94
95 let barn_path = "site_structures.plot_structures.barn";
96 let asset_handle = PrefabStructure::load_group(barn_path);
97 let barn_prefab_structure = asset_handle.read()[0].clone();
98 let barn_prefab_structure_bounds = barn_prefab_structure.get_bounds();
99 let barn_length = barn_prefab_structure_bounds.max.x - barn_prefab_structure_bounds.min.x;
100 let barn_half_length = barn_length / 2;
101 let barn_width = barn_prefab_structure_bounds.max.y - barn_prefab_structure_bounds.min.y;
102 let barn_half_width = barn_width / 2;
103 let barn_height = barn_prefab_structure_bounds.max.z - barn_prefab_structure_bounds.min.z;
104
105 painter
106 .aabb(Aabb {
107 min: Vec2::new(
108 plot_center.x - barn_half_length,
109 plot_center.y - barn_half_width,
110 )
111 .with_z(base - 10),
112 max: Vec2::new(
113 plot_center.x + barn_half_length,
114 plot_center.y + barn_half_width,
115 )
116 .with_z(base - 1),
117 })
118 .fill(brick.clone());
119
120 let air = Fill::Block(Block::new(BlockKind::Air, Rgb::new(255, 255, 255)));
122
123 painter
124 .aabb(Aabb {
125 min: Vec2::new(
126 plot_center.x - barn_half_length,
127 plot_center.y - barn_half_width,
128 )
129 .with_z(base),
130 max: Vec2::new(
131 plot_center.x + barn_half_length,
132 plot_center.y + barn_half_width,
133 )
134 .with_z(base + barn_height),
135 })
136 .fill(air);
137
138 let entrance_pos: Vec3<i32> = (plot_center.x, plot_center.y, self.alt).into();
140 let barn_site_pos: Vec3<i32> = entrance_pos + Vec3::new(0, 0, -1);
141
142 painter
144 .prim(Primitive::Prefab(Box::new(barn_prefab_structure.clone())))
145 .translate(barn_site_pos)
146 .fill(Fill::Prefab(
147 Box::new(barn_prefab_structure),
148 barn_site_pos,
149 0,
150 ));
151 }
152
153 fn terrain_surface_at<R: Rng>(
154 &self,
155 wpos: Vec2<i32>,
156 old: Block,
157 _rng: &mut R,
158 col: &ColumnSample,
159 z_off: i32,
160 _site: &Site,
161 ) -> Option<Block> {
162 let hit_min_x_bounds = wpos.x == self.bounds.min.x;
163 let hit_min_y_bounds = wpos.y == self.bounds.min.y;
164 let hit_max_x_bounds = wpos.x == self.bounds.max.x - 1;
165 let hit_max_y_bounds = wpos.y == self.bounds.max.y - 1;
166
167 let is_bounds =
168 hit_min_x_bounds || hit_min_y_bounds || hit_max_x_bounds || hit_max_y_bounds;
169
170 let is_corner = (hit_max_y_bounds || hit_min_y_bounds)
171 && (hit_max_x_bounds || hit_min_x_bounds)
172 && is_bounds;
173
174 if z_off == 0 {
175 Some(Block::new(
177 if self.is_desert {
178 BlockKind::Sand
179 } else {
180 BlockKind::Grass
181 },
182 (Lerp::lerp(
183 col.surface_color,
184 col.sub_surface_color * 0.5,
185 false as i32 as f32,
186 ) * 255.0)
187 .as_(),
188 ))
189 } else if z_off == 1 && is_bounds {
190 let adjacent_type = if is_corner {
192 RelativeNeighborPosition::L
193 } else {
194 RelativeNeighborPosition::I
195 };
196
197 let ori = if !is_corner {
198 if hit_min_x_bounds || hit_max_x_bounds {
201 2
202 } else {
203 0
204 }
205 } else {
206 if hit_min_x_bounds && hit_min_y_bounds {
209 4
210 } else if hit_max_x_bounds && hit_min_y_bounds {
211 6
212 } else if hit_min_x_bounds && hit_max_y_bounds {
213 2
214 } else {
215 0
216 }
217 };
218
219 Some(
220 old.into_vacant()
221 .with_sprite(SpriteKind::FenceWoodWoodland)
222 .with_ori(ori)
223 .unwrap()
224 .with_adjacent_type(adjacent_type)
225 .unwrap(),
226 )
227 } else {
228 None
229 }
230 }
231}