1 use crate::render::{ |
1 use crate::render::{ |
2 atlas::{AtlasCollection, SpriteIndex, SpriteLocation}, |
2 atlas::{AtlasCollection, SpriteIndex, SpriteLocation}, |
3 camera::Camera, |
3 camera::Camera, |
4 gl::{Texture2D, TextureDataType, TextureFilter, TextureFormat, TextureInternalFormat}, |
4 gl::{ |
|
5 Buffer, BufferType, BufferUsage, InputElement, InputFormat, InputLayout, PipelineState, |
|
6 Shader, Texture2D, TextureDataType, TextureFilter, TextureFormat, TextureInternalFormat, |
|
7 }, |
5 }; |
8 }; |
6 |
9 |
7 use integral_geometry::{Rect, Size}; |
10 use integral_geometry::{Rect, Size}; |
8 |
11 |
9 use png::{ColorType, Decoder, DecodingError}; |
12 use png::{ColorType, Decoder, DecodingError}; |
12 collections::HashMap, |
15 collections::HashMap, |
13 ffi::OsString, |
16 ffi::OsString, |
14 fs::{read_dir, File}, |
17 fs::{read_dir, File}, |
15 io, |
18 io, |
16 io::BufReader, |
19 io::BufReader, |
|
20 mem::size_of, |
17 path::{Path, PathBuf}, |
21 path::{Path, PathBuf}, |
18 }; |
22 }; |
|
23 |
|
24 const VERTEX_SHADER: &'static str = r#" |
|
25 #version 330 core |
|
26 |
|
27 layout(location = 0) in vec2 position; |
|
28 |
|
29 uniform mat4 projection; |
|
30 |
|
31 void main() { |
|
32 gl_Position = projection * vec4(position, 0.0, 1.0); |
|
33 } |
|
34 "#; |
|
35 |
|
36 const PIXEL_SHADER: &'static str = r#" |
|
37 #version 330 core |
|
38 |
|
39 out vec4 outColor; |
|
40 |
|
41 void main() { |
|
42 outColor = vec4(0.0, 1.0, 0.0, 1.0); |
|
43 } |
|
44 "#; |
|
45 |
|
46 #[repr(C)] |
|
47 #[derive(Copy, Clone)] |
|
48 struct Vertex { |
|
49 pos: [f32; 2], |
|
50 } |
19 |
51 |
20 #[derive(PartialEq, Debug, Clone, Copy)] |
52 #[derive(PartialEq, Debug, Clone, Copy)] |
21 pub enum SpriteId { |
53 pub enum SpriteId { |
22 Mine = 0, |
54 Mine = 0, |
23 Grenade, |
55 Grenade, |
36 ), |
68 ), |
37 ]; |
69 ]; |
38 |
70 |
39 const MAX_SPRITES: usize = SpriteId::MaxSprite as usize + 1; |
71 const MAX_SPRITES: usize = SpriteId::MaxSprite as usize + 1; |
40 |
72 |
|
73 pub struct GearEntry { |
|
74 position: [f32; 2], |
|
75 size: Size, |
|
76 } |
|
77 |
|
78 impl GearEntry { |
|
79 pub fn new(x: f32, y: f32, size: Size) -> Self { |
|
80 Self { |
|
81 position: [x, y], |
|
82 size, |
|
83 } |
|
84 } |
|
85 } |
|
86 |
41 pub struct GearRenderer { |
87 pub struct GearRenderer { |
42 atlas: AtlasCollection, |
88 atlas: AtlasCollection, |
43 allocation: Box<[SpriteLocation; MAX_SPRITES]>, |
89 allocation: Box<[SpriteLocation; MAX_SPRITES]>, |
|
90 shader: Shader, |
|
91 layout: InputLayout, |
|
92 vertex_buffer: Buffer, |
44 } |
93 } |
45 |
94 |
46 struct SpriteData { |
95 struct SpriteData { |
47 size: Size, |
96 size: Size, |
48 filename: PathBuf, |
97 filename: PathBuf, |
83 ); |
132 ); |
84 |
133 |
85 allocation[*sprite as usize] = (texture_index, rect); |
134 allocation[*sprite as usize] = (texture_index, rect); |
86 } |
135 } |
87 |
136 |
88 Self { atlas, allocation } |
137 let shader = Shader::new(VERTEX_SHADER, Some(PIXEL_SHADER), &[]).unwrap(); |
89 } |
138 |
90 |
139 let layout = InputLayout::new(vec![ |
91 pub fn render(&mut self, camera: &Camera) { |
140 // position |
|
141 InputElement { |
|
142 shader_slot: 0, |
|
143 buffer_slot: 0, |
|
144 format: InputFormat::Float(gl::FLOAT, false), |
|
145 components: 2, |
|
146 stride: size_of::<Vertex>() as u32, |
|
147 offset: 0, |
|
148 }, |
|
149 ]); |
|
150 |
|
151 let vertex_buffer = Buffer::empty(BufferType::Array, BufferUsage::DynamicDraw); |
|
152 |
|
153 Self { |
|
154 atlas, |
|
155 allocation, |
|
156 shader, |
|
157 layout, |
|
158 vertex_buffer, |
|
159 } |
|
160 } |
|
161 |
|
162 pub fn render(&mut self, camera: &Camera, entries: &[GearEntry]) { |
92 let projection = camera.projection(); |
163 let projection = camera.projection(); |
|
164 self.shader.bind(); |
|
165 self.shader.set_matrix("projection", projection.as_ptr()); |
|
166 |
|
167 let mut data = Vec::with_capacity(entries.len() * 12); |
|
168 |
|
169 for entry in entries { |
|
170 let vertices = [ |
|
171 [ |
|
172 entry.position[0] - entry.size.width as f32 / 2.0, |
|
173 entry.position[1] + entry.size.height as f32 / 2.0, |
|
174 ], |
|
175 [ |
|
176 entry.position[0] + entry.size.width as f32 / 2.0, |
|
177 entry.position[1] + entry.size.height as f32 / 2.0, |
|
178 ], |
|
179 [ |
|
180 entry.position[0] - entry.size.width as f32 / 2.0, |
|
181 entry.position[1] - entry.size.height as f32 / 2.0, |
|
182 ], |
|
183 [ |
|
184 entry.position[0] + entry.size.width as f32 / 2.0, |
|
185 entry.position[1] - entry.size.height as f32 / 2.0, |
|
186 ], |
|
187 ]; |
|
188 |
|
189 data.extend_from_slice(&[ |
|
190 vertices[0][0], |
|
191 vertices[0][1], |
|
192 vertices[1][0], |
|
193 vertices[1][1], |
|
194 vertices[2][0], |
|
195 vertices[2][1], |
|
196 vertices[1][0], |
|
197 vertices[1][1], |
|
198 vertices[3][0], |
|
199 vertices[3][1], |
|
200 vertices[2][0], |
|
201 vertices[2][1], |
|
202 ]); |
|
203 } |
|
204 |
|
205 self.vertex_buffer.write_typed(&data); |
|
206 let _buffer_bind = self.layout.bind(&[(0, &self.vertex_buffer)], None); |
|
207 let _state = PipelineState::new().with_blend(); |
|
208 |
|
209 unsafe { |
|
210 gl::DrawArrays(gl::TRIANGLES, 0, entries.len() as i32 * 2); |
|
211 } |
93 } |
212 } |
94 } |
213 } |
95 |
214 |
96 fn load_sprite_pixels(path: &Path, buffer: &mut [u8]) -> io::Result<Size> { |
215 fn load_sprite_pixels(path: &Path, buffer: &mut [u8]) -> io::Result<Size> { |
97 let decoder = Decoder::new(BufReader::new(File::open(path)?)); |
216 let decoder = Decoder::new(BufReader::new(File::open(path)?)); |