1use crate::core::*;
2use crate::renderer::*;
3use std::sync::Arc;
4
5pub struct Skybox {
9 context: Context,
10 vertex_buffer: VertexBuffer<Vec3>,
11 material: SkyboxMaterial,
12}
13
14impl Skybox {
15 pub fn new(
20 context: &Context,
21 right: &CpuTexture,
22 left: &CpuTexture,
23 top: &CpuTexture,
24 bottom: &CpuTexture,
25 front: &CpuTexture,
26 back: &CpuTexture,
27 ) -> Self {
28 let convert = |cpu_texture: &CpuTexture| match &cpu_texture.data {
29 TextureData::RgbU8(_) | TextureData::RgbaU8(_) => {
30 let mut cpu_texture = cpu_texture.clone();
31 cpu_texture.data.to_linear_srgb();
32 Some(cpu_texture)
33 }
34 _ => None,
35 };
36 Self::new_with_texture(
37 context,
38 Arc::new(TextureCubeMap::new(
39 context,
40 convert(right).as_ref().unwrap_or(right),
41 convert(left).as_ref().unwrap_or(left),
42 convert(top).as_ref().unwrap_or(top),
43 convert(bottom).as_ref().unwrap_or(bottom),
44 convert(front).as_ref().unwrap_or(front),
45 convert(back).as_ref().unwrap_or(back),
46 )),
47 )
48 }
49
50 pub fn new_from_equirectangular(context: &Context, cpu_texture: &CpuTexture) -> Self {
54 let texture = match cpu_texture.data {
55 TextureData::RgbaU8(_) | TextureData::RgbU8(_) => {
56 let mut cpu_texture = cpu_texture.clone();
57 cpu_texture.data.to_linear_srgb();
58 TextureCubeMap::new_from_equirectangular::<u8>(context, &cpu_texture)
59 }
60 TextureData::RgU8(_) | TextureData::RU8(_) => {
61 TextureCubeMap::new_from_equirectangular::<u8>(context, cpu_texture)
62 }
63 TextureData::RgbaF16(_)
64 | TextureData::RgbF16(_)
65 | TextureData::RgF16(_)
66 | TextureData::RF16(_) => {
67 TextureCubeMap::new_from_equirectangular::<f16>(context, cpu_texture)
68 }
69 TextureData::RgbaF32(_)
70 | TextureData::RgbF32(_)
71 | TextureData::RgF32(_)
72 | TextureData::RF32(_) => {
73 TextureCubeMap::new_from_equirectangular::<f32>(context, cpu_texture)
74 }
75 };
76
77 Self::new_with_texture(context, Arc::new(texture))
78 }
79
80 pub fn new_with_texture(context: &Context, texture: Arc<TextureCubeMap>) -> Self {
85 let vertex_buffer = VertexBuffer::new_with_data(
86 context,
87 &[
88 vec3(1.0, 1.0, -1.0),
89 vec3(-1.0, 1.0, -1.0),
90 vec3(1.0, 1.0, 1.0),
91 vec3(-1.0, 1.0, 1.0),
92 vec3(1.0, 1.0, 1.0),
93 vec3(-1.0, 1.0, -1.0),
94 vec3(-1.0, -1.0, -1.0),
95 vec3(1.0, -1.0, -1.0),
96 vec3(1.0, -1.0, 1.0),
97 vec3(1.0, -1.0, 1.0),
98 vec3(-1.0, -1.0, 1.0),
99 vec3(-1.0, -1.0, -1.0),
100 vec3(1.0, -1.0, -1.0),
101 vec3(-1.0, -1.0, -1.0),
102 vec3(1.0, 1.0, -1.0),
103 vec3(-1.0, 1.0, -1.0),
104 vec3(1.0, 1.0, -1.0),
105 vec3(-1.0, -1.0, -1.0),
106 vec3(-1.0, -1.0, 1.0),
107 vec3(1.0, -1.0, 1.0),
108 vec3(1.0, 1.0, 1.0),
109 vec3(1.0, 1.0, 1.0),
110 vec3(-1.0, 1.0, 1.0),
111 vec3(-1.0, -1.0, 1.0),
112 vec3(1.0, -1.0, -1.0),
113 vec3(1.0, 1.0, -1.0),
114 vec3(1.0, 1.0, 1.0),
115 vec3(1.0, 1.0, 1.0),
116 vec3(1.0, -1.0, 1.0),
117 vec3(1.0, -1.0, -1.0),
118 vec3(-1.0, 1.0, -1.0),
119 vec3(-1.0, -1.0, -1.0),
120 vec3(-1.0, 1.0, 1.0),
121 vec3(-1.0, -1.0, 1.0),
122 vec3(-1.0, 1.0, 1.0),
123 vec3(-1.0, -1.0, -1.0),
124 ],
125 );
126
127 Skybox {
128 context: context.clone(),
129 vertex_buffer,
130 material: SkyboxMaterial { texture },
131 }
132 }
133
134 pub fn texture(&self) -> &Arc<TextureCubeMap> {
138 &self.material.texture
139 }
140}
141
142impl<'a> IntoIterator for &'a Skybox {
143 type Item = &'a dyn Object;
144 type IntoIter = std::iter::Once<&'a dyn Object>;
145
146 fn into_iter(self) -> Self::IntoIter {
147 std::iter::once(self)
148 }
149}
150
151impl Geometry for Skybox {
152 fn draw(&self, viewer: &dyn Viewer, program: &Program, render_states: RenderStates) {
153 program.use_uniform("view", viewer.view());
154 program.use_uniform("projection", viewer.projection());
155 program.use_vertex_attribute("position", &self.vertex_buffer);
156 program.draw_arrays(render_states, viewer.viewport(), 36);
157 }
158
159 fn vertex_shader_source(&self) -> String {
160 include_str!("shaders/skybox.vert").to_owned()
161 }
162
163 fn id(&self) -> GeometryId {
164 GeometryId::Skybox
165 }
166
167 fn aabb(&self) -> AxisAlignedBoundingBox {
168 AxisAlignedBoundingBox::INFINITE
169 }
170
171 fn render_with_material(
172 &self,
173 material: &dyn Material,
174 viewer: &dyn Viewer,
175 lights: &[&dyn Light],
176 ) {
177 render_with_material(&self.context, viewer, &self, material, lights)
178 }
179
180 fn render_with_effect(
181 &self,
182 material: &dyn Effect,
183 viewer: &dyn Viewer,
184 lights: &[&dyn Light],
185 color_texture: Option<ColorTexture>,
186 depth_texture: Option<DepthTexture>,
187 ) {
188 render_with_effect(
189 &self.context,
190 viewer,
191 self,
192 material,
193 lights,
194 color_texture,
195 depth_texture,
196 )
197 }
198}
199
200impl Object for Skybox {
201 fn render(&self, viewer: &dyn Viewer, lights: &[&dyn Light]) {
202 render_with_material(&self.context, viewer, self, &self.material, lights)
203 }
204
205 fn material_type(&self) -> MaterialType {
206 MaterialType::Opaque
207 }
208}