start drawing gears
authoralfadur
Fri, 13 Nov 2020 20:54:00 +0300
changeset 15784 84c07aa94b61
parent 15783 e7eb0cd5b0e4
child 15785 f6af9d05b03c
start drawing gears
rust/hwphysics/src/lib.rs
rust/lib-hedgewars-engine/src/render/gear.rs
rust/lib-hedgewars-engine/src/render/gl.rs
rust/lib-hedgewars-engine/src/render/map.rs
rust/lib-hedgewars-engine/src/world.rs
--- a/rust/hwphysics/src/lib.rs	Fri Nov 13 02:52:15 2020 +0300
+++ b/rust/hwphysics/src/lib.rs	Fri Nov 13 20:54:00 2020 +0300
@@ -11,7 +11,7 @@
 use crate::{
     collision::CollisionProcessor,
     common::{GearAllocator, GearId, Millis},
-    data::GearDataManager,
+    data::{DataIterator, GearDataManager, TypeIter},
     physics::PhysicsProcessor,
     time::TimeProcessor,
 };
@@ -67,6 +67,11 @@
     pub fn add_gear_data<T: Clone + 'static>(&mut self, gear_id: GearId, data: &T) {
         self.data.add(gear_id, data);
     }
+
+    #[inline]
+    pub fn iter_data<T: TypeIter + 'static>(&mut self) -> DataIterator<T> {
+        self.data.iter()
+    }
 }
 
 #[cfg(test)]
--- a/rust/lib-hedgewars-engine/src/render/gear.rs	Fri Nov 13 02:52:15 2020 +0300
+++ b/rust/lib-hedgewars-engine/src/render/gear.rs	Fri Nov 13 20:54:00 2020 +0300
@@ -1,7 +1,10 @@
 use crate::render::{
     atlas::{AtlasCollection, SpriteIndex, SpriteLocation},
     camera::Camera,
-    gl::{Texture2D, TextureDataType, TextureFilter, TextureFormat, TextureInternalFormat},
+    gl::{
+        Buffer, BufferType, BufferUsage, InputElement, InputFormat, InputLayout, PipelineState,
+        Shader, Texture2D, TextureDataType, TextureFilter, TextureFormat, TextureInternalFormat,
+    },
 };
 
 use integral_geometry::{Rect, Size};
@@ -14,9 +17,38 @@
     fs::{read_dir, File},
     io,
     io::BufReader,
+    mem::size_of,
     path::{Path, PathBuf},
 };
 
+const VERTEX_SHADER: &'static str = r#"
+#version 330 core
+
+layout(location = 0) in vec2 position;
+
+uniform mat4 projection;
+
+void main() {
+	gl_Position = projection * vec4(position, 0.0, 1.0);
+}
+"#;
+
+const PIXEL_SHADER: &'static str = r#"
+#version 330 core
+
+out vec4 outColor;
+
+void main() {
+	 outColor = vec4(0.0, 1.0, 0.0, 1.0);
+}
+"#;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct Vertex {
+    pos: [f32; 2],
+}
+
 #[derive(PartialEq, Debug, Clone, Copy)]
 pub enum SpriteId {
     Mine = 0,
@@ -38,9 +70,26 @@
 
 const MAX_SPRITES: usize = SpriteId::MaxSprite as usize + 1;
 
+pub struct GearEntry {
+    position: [f32; 2],
+    size: Size,
+}
+
+impl GearEntry {
+    pub fn new(x: f32, y: f32, size: Size) -> Self {
+        Self {
+            position: [x, y],
+            size,
+        }
+    }
+}
+
 pub struct GearRenderer {
     atlas: AtlasCollection,
     allocation: Box<[SpriteLocation; MAX_SPRITES]>,
+    shader: Shader,
+    layout: InputLayout,
+    vertex_buffer: Buffer,
 }
 
 struct SpriteData {
@@ -85,11 +134,81 @@
             allocation[*sprite as usize] = (texture_index, rect);
         }
 
-        Self { atlas, allocation }
+        let shader = Shader::new(VERTEX_SHADER, Some(PIXEL_SHADER), &[]).unwrap();
+
+        let layout = InputLayout::new(vec![
+            // position
+            InputElement {
+                shader_slot: 0,
+                buffer_slot: 0,
+                format: InputFormat::Float(gl::FLOAT, false),
+                components: 2,
+                stride: size_of::<Vertex>() as u32,
+                offset: 0,
+            },
+        ]);
+
+        let vertex_buffer = Buffer::empty(BufferType::Array, BufferUsage::DynamicDraw);
+
+        Self {
+            atlas,
+            allocation,
+            shader,
+            layout,
+            vertex_buffer,
+        }
     }
 
-    pub fn render(&mut self, camera: &Camera) {
+    pub fn render(&mut self, camera: &Camera, entries: &[GearEntry]) {
         let projection = camera.projection();
+        self.shader.bind();
+        self.shader.set_matrix("projection", projection.as_ptr());
+
+        let mut data = Vec::with_capacity(entries.len() * 12);
+
+        for entry in entries {
+            let vertices = [
+                [
+                    entry.position[0] - entry.size.width as f32 / 2.0,
+                    entry.position[1] + entry.size.height as f32 / 2.0,
+                ],
+                [
+                    entry.position[0] + entry.size.width as f32 / 2.0,
+                    entry.position[1] + entry.size.height as f32 / 2.0,
+                ],
+                [
+                    entry.position[0] - entry.size.width as f32 / 2.0,
+                    entry.position[1] - entry.size.height as f32 / 2.0,
+                ],
+                [
+                    entry.position[0] + entry.size.width as f32 / 2.0,
+                    entry.position[1] - entry.size.height as f32 / 2.0,
+                ],
+            ];
+
+            data.extend_from_slice(&[
+                vertices[0][0],
+                vertices[0][1],
+                vertices[1][0],
+                vertices[1][1],
+                vertices[2][0],
+                vertices[2][1],
+                vertices[1][0],
+                vertices[1][1],
+                vertices[3][0],
+                vertices[3][1],
+                vertices[2][0],
+                vertices[2][1],
+            ]);
+        }
+
+        self.vertex_buffer.write_typed(&data);
+        let _buffer_bind = self.layout.bind(&[(0, &self.vertex_buffer)], None);
+        let _state = PipelineState::new().with_blend();
+
+        unsafe {
+            gl::DrawArrays(gl::TRIANGLES, 0, entries.len() as i32 * 2);
+        }
     }
 }
 
--- a/rust/lib-hedgewars-engine/src/render/gl.rs	Fri Nov 13 02:52:15 2020 +0300
+++ b/rust/lib-hedgewars-engine/src/render/gl.rs	Fri Nov 13 20:54:00 2020 +0300
@@ -417,14 +417,8 @@
                 return Err(String::from_utf8_unchecked(log));
             }
 
-            //gl::DetachShader(program, vs);
-            if let Some(ps) = ps {
-                //gl::DetachShader(program, ps);
-            }
-
             gl::UseProgram(program);
 
-            // after linking we setup sampler bindings as specified in the shader
             for bind in bindings {
                 match bind {
                     VariableBinding::Uniform(name, id) => {
--- a/rust/lib-hedgewars-engine/src/render/map.rs	Fri Nov 13 02:52:15 2020 +0300
+++ b/rust/lib-hedgewars-engine/src/render/map.rs	Fri Nov 13 20:54:00 2020 +0300
@@ -13,7 +13,6 @@
 
 use std::num::NonZeroU32;
 
-// TODO: temp
 const VERTEX_SHADER: &'static str = r#"
 #version 150
 
@@ -48,7 +47,7 @@
 }
 "#;
 
-pub struct MapTile {
+struct MapTile {
     // either index into GL texture array or emulated [Texture; N]
     texture_index: u32,
 
@@ -58,13 +57,13 @@
 
 #[repr(C)]
 #[derive(Copy, Clone)]
-pub struct TileVertex {
+struct TileVertex {
     pos: [f32; 2],
     // doesn't hurt to include another float, just in case..
     uv: [f32; 3],
 }
 
-pub struct DrawTile {
+struct DrawTile {
     texture_index: u32,
     index_len: u32,
 }
--- a/rust/lib-hedgewars-engine/src/world.rs	Fri Nov 13 02:52:15 2020 +0300
+++ b/rust/lib-hedgewars-engine/src/world.rs	Fri Nov 13 20:54:00 2020 +0300
@@ -12,7 +12,7 @@
 };
 use lfprng::LaggedFibonacciPRNG;
 
-use crate::render::{camera::Camera, GearRenderer, MapRenderer};
+use crate::render::{camera::Camera, GearEntry, GearRenderer, MapRenderer};
 
 struct GameState {
     land: Land2D<u32>,
@@ -32,6 +32,7 @@
     map_renderer: Option<MapRenderer>,
     gear_renderer: Option<GearRenderer>,
     camera: Camera,
+    gear_entries: Vec<GearEntry>,
 }
 
 impl World {
@@ -43,6 +44,7 @@
             map_renderer: None,
             gear_renderer: None,
             camera: Camera::new(),
+            gear_entries: vec![],
         }
     }
 
@@ -125,9 +127,26 @@
 
             renderer.render(&self.camera);
         }
+
+        self.gear_entries.clear();
+        let mut gear_entries = std::mem::take(&mut self.gear_entries);
+
         if let Some(ref mut renderer) = self.gear_renderer {
-            renderer.render(&self.camera)
+            if let Some(ref mut state) = self.game_state {
+                state
+                    .physics
+                    .iter_data()
+                    .run(|(pos,): (&mut PositionData,)| {
+                        gear_entries.push(GearEntry::new(
+                            f64::from(pos.0.x()) as f32,
+                            f64::from(pos.0.y()) as f32,
+                            Size::square(128),
+                        ))
+                    });
+            }
+            renderer.render(&self.camera, &gear_entries);
         }
+        self.gear_entries = gear_entries;
     }
 
     fn create_gear(&mut self, position: Point) {