1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
use std::collections::HashMap; use std::error::Error; use std::io::{Cursor, Read}; use gfx; use gfx::format::*; use gfx::texture::Kind; use gfx_core; use image::{self, RgbaImage}; use zip::ZipArchive; use cache::WebAsset; const FACE_NAMES: [&'static str; 6] = ["east", "west", "up", "down", "north", "south"]; pub struct SkyboxAsset(String); impl Default for SkyboxAsset { fn default() -> Self { SkyboxAsset("clouds1.zip".to_owned()) } } impl WebAsset for SkyboxAsset { type Type = SkyboxRaw; fn url(&self) -> String { format!("https://opengameart.org/sites/default/files/{}", self.0) } fn filename(&self) -> String { format!("sky/{}", self.0) } fn parse(&self, data: Vec<u8>) -> Result<Self::Type, Box<Error>> { let mut zip = ZipArchive::new(Cursor::new(data))?; let mut faces = HashMap::new(); for i in 0..zip.len() { let mut file = zip.by_index(i)?; for face in FACE_NAMES.iter() { if file.name().contains(face) { let mut image_data = Vec::new(); file.read_to_end(&mut image_data)?; faces.insert( face.to_owned(), image::load_from_memory(&image_data)?.to_rgba(), ); break; } } } assert_eq!(faces.len(), 6); let width = faces.iter().next().unwrap().1.width(); let height = faces.iter().next().unwrap().1.height(); assert_eq!(width, height); for img in faces.values() { assert_eq!(img.width(), width); assert_eq!(img.height(), height); } Ok(SkyboxRaw { resolution: width as u16, faces, }) } } pub struct SkyboxRaw { resolution: u16, faces: HashMap<&'static str, RgbaImage>, } pub struct Skybox<R: gfx::Resources> { pub(crate) texture_view: gfx_core::handle::ShaderResourceView<R, [f32; 4]>, pub(crate) _texture: gfx_core::handle::Texture<R, gfx_core::format::R8_G8_B8_A8>, } impl<R: gfx::Resources> Skybox<R> { pub fn new<F: gfx::Factory<R>, C: gfx_core::command::Buffer<R>>( factory: &mut F, encoder: &mut gfx::Encoder<R, C>, ) -> Self { let mut raw = SkyboxAsset::default().load().unwrap(); let mut data = Vec::new(); let mut data_slices = Vec::new(); for face in FACE_NAMES.iter() { data.push(raw.faces.remove(face).unwrap().into_raw()); } for face in data.iter() { data_slices.push(gfx::memory::cast_slice(&face[..])); } let mipmaps = 1 + (raw.resolution.next_power_of_two() as f32).log2() as u8; let texture = factory .create_texture::<R8_G8_B8_A8>( Kind::Cube(raw.resolution), mipmaps, gfx::SHADER_RESOURCE, gfx::memory::Usage::Dynamic, Some(ChannelType::Srgb), ) .unwrap(); for (i, face) in gfx::texture::CUBE_FACES.iter().cloned().enumerate() { encoder .update_texture::<R8_G8_B8_A8, gfx::format::Srgba8>( &texture, Some(face), gfx_core::texture::NewImageInfo { xoffset: 0, yoffset: 0, zoffset: 0, width: raw.resolution, height: raw.resolution, depth: 1, format: (), mipmap: 0, }, &data_slices[i][..], ) .unwrap(); } let texture_view = factory .view_texture_as_shader_resource::<gfx::format::Srgba8>( &texture, (0, mipmaps), Swizzle::new(), ) .unwrap(); encoder.generate_mipmap(&texture_view); Self { texture_view, _texture: texture, } } }