ruckus/
ruckus.rs

1use crate::opengl::gl_unbind_array_buffer;
2use crate::opengl::gl_draw_arrays;
3use crate::opengl::gl_unbind_element_buffer;
4use crate::opengl::gl_draw_elements;
5pub use nalgebra_glm as glm;
6
7pub mod sys;
8pub mod opengl;
9pub mod buffers;
10pub mod graphics;
11pub mod vertex;
12
13use sys::*;
14use buffers::*;
15use graphics::*;
16use vertex::*;
17use opengl::{opengl, gl};
18
19const CLIP_NEAR_DEFAULT: f32 = 0.1;
20const CLIP_FAR_DEFAULT: f32 = 1000.;
21
22// pub trait DrawSurface {
23
24//     fn swap_buffers(&self);
25
26//     fn clear(&self, color: &glm::Vec4) {
27//         unsafe {
28//             opengl().ClearColor(color.x, color.y, color.z, color.w);
29//             opengl().Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
30//         }
31//     }
32
33//     fn width(&self) -> f32;
34//     fn height(&self) -> f32;
35// }
36
37pub trait Renderable {  
38    fn draw(&self, renderer: &Renderer);
39}
40
41#[derive(Copy, Clone, Debug, Default)]
42struct ProjectionInfo {
43    width: f32, height: f32,
44    fov_deg: f32, clip_near: f32, clip_far: f32
45}
46
47impl ProjectionInfo {
48    pub fn aspect(&self) -> f32 { self.width / self.height }
49    pub fn fov_rad(&self) -> f32 { sys::radians(self.fov_deg) }
50
51    pub fn to_matrix(&self) -> glm::Mat4 {
52        glm::perspective(self.aspect(), self.fov_rad(), self.clip_near, self.clip_far)
53    }
54}
55
56pub struct Renderer {
57    pub camera: FlyCamera,
58
59    draw_vao: VAO,
60    quad_buffer: VertexBuffer,
61    instanced_mat_buffer: VertexBuffer,
62
63    shader: Shader,
64    instanced_shader: Shader,
65    
66    default_texture: Texture,
67    projection: glm::Mat4,
68    projection_info: ProjectionInfo,
69}
70
71// TODO :: Implement some type of builder pattern for renderer to pass flags on create,
72//         until then we have no way of modifying renderer defaults outside of cumbersome set_* calls
73// TODO :: Implement Instancing
74impl Renderer {
75
76    pub const DEFAULT_FOV: f32 = 45.;
77    pub const U_PROJECTION: &'static str = "u_projection";
78    pub const U_VIEW: &'static str = "u_view";
79    pub const U_MODEL: &'static str = "u_model";
80
81    pub fn new(width: u32, height: u32) -> Self {     
82        unsafe {
83            let gl = opengl();
84            gl.Viewport(0, 0, width as i32, height as i32);
85            gl.Enable(gl::DEPTH_TEST);
86            gl.Enable(gl::BLEND);
87            gl.BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
88        };
89        let projection_info = ProjectionInfo { 
90            width: width as f32, height: height as f32, 
91            fov_deg: Self::DEFAULT_FOV, clip_near: 0.1, clip_far: 100. 
92        };
93
94        let projection = projection_info.to_matrix();
95
96        let camera = { 
97            let mut c = FlyCamera::new();
98            c.position.z = -3.;
99            c.look_direction.z = 3.;
100            c
101        };
102
103        let shader = Shader::default();
104        let instanced_shader = Shader::default_instanced();
105        let default_texture = Texture::new_blank();
106
107        let quad_buffer = VertexBuffer::new(&sys::Quad::default_verts(), DrawUsage::Dynamic);
108        let instanced_mat_buffer = VertexBuffer::zeroed::<glm::Mat4>(2, DrawUsage::Dynamic, DrawPrimitive::Triangles);
109
110        let draw_vao = VAO::new();
111
112        Renderer { 
113            camera, draw_vao, quad_buffer,
114            instanced_mat_buffer, shader, 
115            instanced_shader,
116            default_texture, projection,
117            projection_info
118        }
119    }
120
121    pub fn set_viewport(&mut self, rect: &Rectf) {
122        self.projection_info.width = rect.w;
123        self.projection_info.height = rect.h;
124        self.projection = self.projection_info.to_matrix();
125        unsafe { opengl().Viewport(rect.x as i32, rect.y as i32, rect.w as i32, rect.h as i32) }
126    }
127
128    // NOTE :: Maybe add a way to set near and far clip here as well?
129    pub fn set_projection(&mut self, width: f32, height: f32, fov_deg: f32) {
130        self.projection_info = ProjectionInfo {
131            width, height, fov_deg, ..self.projection_info
132        };
133        self.projection = self.projection_info.to_matrix();
134    }
135    
136    pub fn begin_draw_texture(rt: &RenderTexture) {
137        FrameBuffer::apply(&rt.frame_buffer);
138    }
139    pub fn end_draw_texture() {
140        FrameBuffer::unbind();
141    }
142
143    pub fn draw<T>(&self, renderable: &T) where T: Renderable {
144        renderable.draw(self);
145    }
146
147    pub fn draw_mesh(&self, mesh: &Mesh) {
148        let shader = match mesh.shader.as_ref() {
149            Some(s) => s,
150            None => {
151                self.shader.set_uniform_matrix("u_projection", &self.projection);
152                self.shader.set_uniform_matrix("u_view", &self.camera.view());
153                self.shader.set_uniform_matrix("u_model", mesh.transform.model());
154                &self.shader
155            }
156        };
157
158        shader.apply();
159
160        self.draw_vao.set_buffer_layout(&mesh.buffer);
161
162        let texture = mesh.texture.as_ref().unwrap_or(&self.default_texture);
163        texture.apply();
164
165        if let Some(e) = mesh.indices.as_ref() {
166            self.draw_elements(&e, mesh.buffer.draw_prim);
167        } else {
168            self.draw_arrays(0, mesh.buffer.vert_count(), mesh.buffer.draw_prim);
169        }
170
171    }
172
173    pub fn draw_quad<'b, T>(&self, q: &Quad, texture: T) where T: Into<Option<&'b Texture>> {
174        let texture = texture.into().unwrap_or(&self.default_texture);
175        texture.apply();
176
177        self.draw_vao.set_buffer_layout(&self.quad_buffer);
178
179        self.quad_buffer.write(&q.verts, 0);
180
181        self.draw_arrays(0, self.quad_buffer.vert_count(), DrawPrimitive::TriangleStrip);
182    }
183
184    pub fn draw_buffer<'b, T>(&self, buffer: &VertexBuffer, first_vertex: u32, texture: T) where T: Into<Option<&'b Texture>> {
185        let texture = texture.into().unwrap_or(&self.default_texture);
186        texture.apply();
187
188        self.draw_vao.set_buffer_layout(&buffer);
189
190        self.draw_arrays(first_vertex, buffer.vert_count(), buffer.draw_prim);
191        // gl_unbind_array_buffer();
192    }
193
194    /** 
195     * Draws given buffer without any kind of vertex transformation
196    // */
197    // pub fn draw_buffer_static<'b, T>(&self, buffer: &VertexBuffer, first_vertex: u32, texture: T) where T: Into<Option<&'b Texture>> {
198    //     let texture = texture.into().unwrap_or(&self.default_texture);
199    //     texture.apply();
200
201    //     self.shader.set_uniform_matrix("u_projection", &glm::Mat4::identity());
202    //     self.shader.set_uniform_matrix("u_view", &glm::Mat4::identity());
203    //     self.shader.set_uniform_matrix("u_model", &glm::Mat4::identity());
204
205    //     self.draw_vao.set_buffer_layout(&buffer);
206
207    //     gl_draw_arrays(first_vertex, buffer.vert_count(), buffer.draw_prim);
208    //     // gl_unbind_array_buffer();
209    // }
210    /** 
211     * Draws given buffer without any kind of vertex transformation
212    */
213    pub fn draw_indexed_buffer<'b, T>(&self, buffer: &VertexBuffer, ebo: &ElementBuffer, texture: T) where T: Into<Option<&'b Texture>> {
214        let texture = texture.into().unwrap_or(&self.default_texture);
215        texture.apply();
216
217        self.draw_vao.set_buffer_layout(&buffer);
218
219        self.draw_elements(&ebo, buffer.draw_prim);
220    }
221    
222    pub fn clear_black(&self) {
223       self.clear(0., 0., 0., 1.);
224    }
225
226    pub fn use_default_shader<'b, T>(&self, xform: T) where T: Into<Option<&'b Transform>> {
227        if let Some(xform) = xform.into() {
228            self.shader.set_uniform_matrix("u_projection", &self.projection);
229            self.shader.set_uniform_matrix("u_view", &self.camera.view());
230            self.shader.set_uniform_matrix("u_model", xform.model());
231        } else {
232            self.shader.set_uniform_matrix("u_projection", &glm::Mat4::identity());
233            self.shader.set_uniform_matrix("u_view", &glm::Mat4::identity());
234            self.shader.set_uniform_matrix("u_model", &glm::Mat4::identity());
235        }
236
237        self.shader.apply(); // we dont need this apply() call... but why not for good measure lol
238
239    }
240
241    pub fn clear(&self, r: f32, g: f32, b: f32, a: f32) {
242        unsafe {
243            opengl().ClearColor(r, g, b, a);
244            opengl().Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
245        }
246    }
247
248    pub fn projection(&self) -> &glm::Mat4 { &self.projection }
249    pub fn view(&self) -> glm::Mat4 { self.camera.view() }
250    
251    /**
252     * Binds renderer's internal VAO
253    */
254    pub fn set_current(&self) {
255        self.draw_vao.apply();
256    }
257    
258    fn draw_arrays(&self, start: u32, vert_count: u32, prim: DrawPrimitive) {
259        self.draw_vao.apply();
260        gl_draw_arrays(start, vert_count, prim);        
261    }
262
263    fn draw_elements(&self, ebo: &ElementBuffer, prim: DrawPrimitive) {
264        self.draw_vao.apply();
265        ebo.apply();
266        gl_draw_elements(ebo.count, prim);
267        ebo.unbind();
268    }
269}
270
271
272pub struct FlyCamera {
273    pub position: glm::Vec3,
274    pub look_direction: glm::Vec3,
275    pub rotation: glm::Vec3,
276
277    pub speed: f32,
278    pub sensitivity: f32,
279}
280
281impl FlyCamera {
282
283    pub fn new() -> Self {
284        FlyCamera::default()
285    }
286
287    pub fn view(&self) -> glm::Mat4 {
288        glm::look_at(&self.position, &self.target(), &UP_VECTOR.into())
289    }
290
291    pub fn target(&self) -> glm::Vec3 {
292        self.position + self.look_direction
293    }
294
295    pub fn move_forward(&mut self, delta_time: f32) {
296        self.position += self.speed * self.look_direction * delta_time;
297    }
298
299    pub fn move_backward(&mut self, delta_time: f32) {
300        self.position -= self.speed * self.look_direction * delta_time;
301    }
302
303    pub fn move_left(&mut self, delta_time: f32) {
304        let v: glm::Vec3 = self.look_direction.cross(&UP_VECTOR.into());
305        self.position -= glm::normalize(&v) * self.speed * delta_time;
306    }
307
308    pub fn move_right(&mut self, delta_time: f32) {
309        let v = self.look_direction.cross(&UP_VECTOR.into());
310        self.position += glm::normalize(&v) * self.speed * delta_time;
311    }
312
313    pub fn look_towards(&mut self, offset: &glm::Vec3) {
314        let delta = offset * self.sensitivity;
315
316        self.rotation += glm::vec3(delta.x, delta.y, 0.);
317        self.rotation.y = sys::clamp_s(self.rotation.y, -89., 89.);
318        let frontx = f32::cos(radians(self.rotation.x)) * f32::cos(radians(self.rotation.y));
319        let fronty = f32::sin(radians(self.rotation.y));
320        let frontz = f32::sin(radians(self.rotation.x)) * f32::cos(radians(self.rotation.y));
321        
322        self.look_direction = glm::normalize(&glm::vec3(frontx, fronty, frontz));
323    }
324}
325
326impl Default for FlyCamera {
327    
328    fn default() -> Self { 
329        let zvec = glm::vec3(0., 0., 0.);
330        FlyCamera { 
331            position: zvec,
332            look_direction: zvec,
333            rotation: zvec,
334            speed: 0., sensitivity: 0.
335        }
336    }
337}