diff --git a/resources/shaders/plane/shader.frag b/resources/shaders/plane/shader.frag new file mode 100644 index 0000000..725c0cb --- /dev/null +++ b/resources/shaders/plane/shader.frag @@ -0,0 +1,16 @@ +#version 330 core + +in vec2 v_texcoord; + +out vec4 frag_color; + +uniform sampler2D tex; + +void main() +{ + // Sample the texture using the texture coordinates + vec4 tex_color = texture(tex, v_texcoord); + + // Output the final color + frag_color = tex_color; +} diff --git a/resources/shaders/plane/shader.vert b/resources/shaders/plane/shader.vert new file mode 100644 index 0000000..66ae781 --- /dev/null +++ b/resources/shaders/plane/shader.vert @@ -0,0 +1,24 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 1) in vec2 texcoord; + +out vec2 v_texcoord; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; +uniform float tile_size; +uniform float scroll_speed; + +uniform vec3 camera_position; +void main() +{ + // Apply the model, view, and projection matrices + gl_Position = projection * view * model * vec4(position, 1.0); + + // Calculate the texture coordinate offset based on the camera position + vec2 offset = (camera_position.xz - position.xz) / tile_size; + offset += scroll_speed * vec2(0, 1) * -(gl_Position.w / projection[1][1]); + v_texcoord = texcoord + offset; +} diff --git a/resources/texture.jpg b/resources/texture.jpg new file mode 100644 index 0000000..08dd41a Binary files /dev/null and b/resources/texture.jpg differ diff --git a/src/camera.rs b/src/camera.rs index 29f8310..10cb444 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -68,6 +68,10 @@ impl Camera { Matrix4::look_at(self.Position, self.Position + self.Front, self.Up) } + pub fn follow(&mut self, pos: Vector3) + { + self.Position = Point3::new(0.0, 0.55, 1.0) + pos; + } /// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems) pub fn ProcessKeyboard(&mut self, direction: Camera_Movement, deltaTime: f32) { let velocity = self.MovementSpeed * deltaTime; diff --git a/src/main.rs b/src/main.rs index 5f33f71..6e9656d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -88,7 +88,7 @@ fn main() { let mut State = gameState::Playing; - let mut scene = Scene::new(gl); + let mut scene = Scene::new(gl); println!("entering main loop"); diff --git a/src/model.rs b/src/model.rs index f24fdda..c4c9a7a 100644 --- a/src/model.rs +++ b/src/model.rs @@ -110,7 +110,7 @@ impl Model { } } -unsafe fn TextureFromFile(path: &str, directory: &str, gl: Arc) -> glow::NativeTexture { +pub unsafe fn TextureFromFile(path: &str, directory: &str, gl: Arc) -> glow::NativeTexture { let filename = format!("{}/{}", directory, path); let mut textureID = gl.create_texture().unwrap(); diff --git a/src/scene.rs b/src/scene.rs index cd97b3f..236bb63 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -40,7 +40,8 @@ pub struct Scene { shaders: Vec>, time: std::time::Instant, DebugMode: bool, - input: objects::Input + input: objects::Input, + plane: objects::plane } impl Scene{ @@ -49,6 +50,7 @@ impl Scene{ let Car = objects::Player::new(Arc::clone(&gl)); let shader = Rc::new(shader::new("model", Arc::clone(&gl))); + let planeShader = Rc::new(shader::new("plane", Arc::clone(&gl))); let time = std::time::Instant::now(); @@ -57,6 +59,7 @@ impl Scene{ Pitch: -20.0, ..Camera::default() }; + let plane = objects::plane::new(Arc::clone(&gl)); let debug = Debug::new(gl.clone()); Scene{ @@ -64,15 +67,20 @@ impl Scene{ Car, camera, debug, - shaders: vec![shader], + shaders: vec![shader, planeShader], time, DebugMode: false, - input: objects::Input::default() + input: objects::Input::default(), + plane } } pub fn update(&mut self ,events_loop: &mut sdl2::EventPump, window: &sdl2::video::Window) -> SceneEnum { + + + + let mut ret = SceneEnum::Resume; unsafe { @@ -81,6 +89,10 @@ impl Scene{ } + self.camera.follow(self.Car.Transform.Position); + self.plane.draw(&self.shaders[1], &self.camera); + self.Car.update(&self.input); + self.Car.Draw(&self.shaders[0], &self.camera); if self.DebugMode{ self.handleDebug(events_loop, window, &mut ret) } @@ -133,8 +145,6 @@ impl Scene{ } - self.Car.update(&self.input); - self.Car.Draw(&self.shaders[0], &self.camera); ret } diff --git a/src/scene/objects.rs b/src/scene/objects.rs index 2272d2b..95ebcaa 100644 --- a/src/scene/objects.rs +++ b/src/scene/objects.rs @@ -2,10 +2,11 @@ const SCR_WIDTH: u32 = 1600; const SCR_HEIGHT: u32 = 900; -use cgmath::{Vector3, Quaternion, Rotation3}; +use cgmath::{Vector3, Quaternion, Rotation3, Deg, perspective, Matrix4}; use cgmath::prelude::*; use crate::model::Model; use crate::camera::Camera; +use glow::HasContext; pub struct Input { pub Accel: bool, @@ -117,3 +118,92 @@ impl Player { self.Model.Draw(shader); } } + +pub struct plane { + pub texture: glow::NativeTexture, + pub VAO: glow::VertexArray, + + VBO: glow::Buffer, + EBO: glow::Buffer, +} + +impl plane { + pub fn new(gl: std::sync::Arc) -> plane + { + let vertices: [f32; 20] = [ + 10.5, 10.5, 0.0, 1.0, 1.0, + 10.5, -10.5, 0.0, 1.0, 0.0, + -10.5, -10.5, 0.0, 0.0, 0.0, + -10.5, 10.5, 0.0, 0.0, 1.0 + ]; + let indices: [u32; 6] = [ + 0, 1, 3, + 1, 2, 3 + ]; + unsafe { + let VAO = gl.create_vertex_array().unwrap(); + let VBO = gl.create_buffer().unwrap(); + let EBO = gl.create_buffer().unwrap(); + + gl.bind_vertex_array(Some(VAO)); + + gl.bind_buffer(glow::ARRAY_BUFFER, Some(VBO)); + let data = core::slice::from_raw_parts( + vertices.as_ptr() as *const u8, + vertices.len() * core::mem::size_of::(), + ); + gl.named_buffer_data_u8_slice(VBO, data, glow::STATIC_DRAW); + + gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(EBO)); + let data = core::slice::from_raw_parts( + indices.as_ptr() as *const u8, + indices.len() * core::mem::size_of::(), + ); + gl.named_buffer_data_u8_slice(EBO, data, glow::STATIC_DRAW); + + let stride = 5 * core::mem::size_of::() as i32; + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, stride, 0); + + gl.enable_vertex_attrib_array(1); + gl.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, stride, (3 * core::mem::size_of::()) as i32 ); + + gl.bind_vertex_array(None); + + plane { + texture: crate::model::TextureFromFile("texture.jpg", "resources", gl.clone()), + VAO, + VBO, + EBO + } + } + } + + pub fn draw(&self, shader: &crate::shader::shader, camera: &Camera) + { + unsafe { + shader.Use(); + + + let model = cgmath::Matrix4::from_angle_x(cgmath::Deg(-90.0)); + let projection = cgmath::perspective(cgmath::Deg(camera.Zoom), SCR_WIDTH as f32 /SCR_HEIGHT as f32, 0.1, 100.0); + let view = camera.GetViewMatrix(); + + shader.setMat4("model", &model); + shader.setMat4("view", &view); + shader.setMat4("projection", &projection); + shader.setFloat("tile_size", 0.5); + shader.setFloat("scroll_speed", 10.0); + let camera_direction = (camera.Position - cgmath::Point3::new(0.0, 0.0, 0.0)); + shader.setVector3("camera_position", camera_direction); + + shader.gl.bind_texture(glow::TEXTURE_2D, Some(self.texture)); + shader.gl.bind_vertex_array(Some(self.VAO)); + + shader.gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_INT, 0); + shader.gl.bind_vertex_array(None); + + shader.gl.active_texture(glow::TEXTURE0); + } + } +}