diff --git a/README.md b/README.md
index 3222063..fffae6b 100644
--- a/README.md
+++ b/README.md
@@ -6,3 +6,9 @@ The Goal of this repo is to make a simple engine like program in Rust
It is mainly for learning purposes and should be the base for a later, more fleshed out Engine made in Rust (with the possibility to create logic in Julia)
+
+
+
+
+The engine uses a left-handed y-up coordinate system
+
diff --git a/opengl_beginnings/.idea/vcs.xml b/opengl_beginnings/.idea/vcs.xml
index 35eb1dd..62bd7a0 100644
--- a/opengl_beginnings/.idea/vcs.xml
+++ b/opengl_beginnings/.idea/vcs.xml
@@ -2,5 +2,6 @@
+
\ No newline at end of file
diff --git a/opengl_beginnings/src/custom.rs b/opengl_beginnings/src/custom.rs
new file mode 100644
index 0000000..ddf41e4
--- /dev/null
+++ b/opengl_beginnings/src/custom.rs
@@ -0,0 +1 @@
+pub mod sphere_generator;
\ No newline at end of file
diff --git a/opengl_beginnings/src/custom/sphere_generator.rs b/opengl_beginnings/src/custom/sphere_generator.rs
new file mode 100644
index 0000000..2405cf5
--- /dev/null
+++ b/opengl_beginnings/src/custom/sphere_generator.rs
@@ -0,0 +1,154 @@
+use crate::engine::mesh::Mesh;
+use nalgebra::Vector3;
+
+pub struct OctaSphere {
+ mesh: Option,
+ resolution: i32,
+ generator: OctaSphereGenerator,
+}
+
+impl OctaSphere {
+ pub fn new(resolution: i32) -> Result {
+ match resolution {
+ r if r >= 0 => Ok(Self
+ {
+ resolution,
+ generator: OctaSphereGenerator::new(resolution),
+ mesh: None,
+ }),
+ _ => Err(String::from("Resolution of an octa sphere must be positive"))
+ }
+ }
+
+ pub fn generate_sphere(&mut self) {
+ let (vertices, indices) = self.generator.generate_sphere();
+ self.mesh = Some(Mesh::new(vertices, indices))
+ }
+}
+
+struct OctaSphereGenerator {
+ resolution: i32,
+}
+
+impl OctaSphereGenerator {
+ fn new(resolution: i32) -> Self {
+ Self {
+ resolution,
+ }
+ }
+
+ // Thanks Sebastian Lague
+ fn generate_sphere(&self) -> (Vec>, Vec) {
+ // Indices of the vertex pairs that make up each of the initial 12 edges
+ let vertex_pairs = [0, 1, 0, 2, 0, 3, 0, 4, 1, 2, 2, 3, 3, 4, 4, 1, 5, 1, 5, 2, 5, 3, 5, 4];
+ // Indices of the edge triplets that make up the initial 8 faces
+ let edge_triplets = [0, 1, 4, 1, 2, 5, 2, 3, 6, 3, 0, 7, 8, 9, 4, 9, 10, 5, 10, 11, 6, 11, 8, 7];
+ // The six initial vertices up left back right forward down
+ let base_vertices = [Vector3::y_axis().into_inner(), -Vector3::x_axis().into_inner(), -Vector3::z_axis().into_inner(), Vector3::x_axis().into_inner(), Vector3::z_axis().into_inner(), -Vector3::y_axis().into_inner()];
+
+ let num_divisions = self.resolution;
+ let num_vertices_per_face = ((num_divisions + 3) * (num_divisions + 3) - (num_divisions + 3)) / 2;
+ let num_vertices = num_vertices_per_face * 8 - (num_divisions + 2) * 12 + 6;
+ let num_tris_per_face = (num_divisions + 1) * (num_divisions + 1);
+
+ let mut vertices = Vec::>::with_capacity(num_vertices as usize);
+ let mut indicies = Vec::::with_capacity((num_tris_per_face * 8 * 3) as usize);
+ vertices.copy_from_slice(&base_vertices);
+
+ // Create 12 edges, with n vertices added along them (n = numDivisions)
+ let mut edges = Vec::::with_capacity(12);
+ for i in (0..vertex_pairs.len()).step_by(2) {
+ let start_vertex = vertices[vertex_pairs[i]];
+ let end_vertex = vertices[vertex_pairs[i + 1]];
+
+ let mut edge_vertex_indices = Vec::::with_capacity((num_divisions + 2) as usize);
+ edge_vertex_indices[0] = vertex_pairs[i] as u32;
+
+ // Add vertices along edge
+ for division_index in 0..num_divisions {
+ let t = (division_index as f32 + 1.0) / (num_divisions as f32 + 1.0);
+ edge_vertex_indices[(division_index + 1) as usize] = vertices.len() as u32;
+ vertices.push(start_vertex.slerp(&end_vertex, t));
+ }
+
+ edge_vertex_indices[(num_divisions + 1) as usize] = vertex_pairs[i + 1] as u32;
+ let edge_index = i / 2;
+ edges[edge_index] = Edge::new(edge_vertex_indices)
+ }
+
+ // Create faces
+ for i in (0..edge_triplets.len()).step_by(3) {
+ let face_index = i / 3;
+ let reverse = face_index >= 4;
+ self.create_face(&edges[edge_triplets[i]], &edges[edge_triplets[i + 1]], &edges[edge_triplets[i + 2]], reverse, num_vertices_per_face, &mut vertices, &mut indicies);
+ }
+
+
+ (vertices, indicies)
+ }
+
+ fn create_face(&self, side_a: &Edge, side_b: &Edge, bottom: &Edge, reverse: bool, num_vertices_per_face: i32, vertices: &mut Vec>, indices: &mut Vec) {
+ let num_points_in_edge = side_a.vertex_indices.len();
+ let mut vertex_map = Vec::::with_capacity(num_vertices_per_face as usize);
+ vertex_map.push(side_a.vertex_indices[0]); // top of triangle
+
+ for i in 1..num_points_in_edge-1 {
+ // Side A vertex
+ vertex_map.push(side_a.vertex_indices[i]);
+
+ //add vertices between side a and b
+ let side_a_vertex = vertices[(side_a.vertex_indices[i]) as usize];
+ let side_b_vertex = vertices[(side_b.vertex_indices[i]) as usize];
+ let num_inner_points = i - 1;
+ for j in 0..num_inner_points {
+ let t = (j as f32 + 1.0) / (num_inner_points as f32 + 1.0);
+ vertex_map.push(vertices.len() as u32);
+ vertices.push(side_a_vertex.slerp(&side_b_vertex, t));
+ }
+
+ // Side B vertex
+ vertex_map.push(side_b.vertex_indices[i]);
+ }
+
+ // add bottom edge vertices
+ for i in 0..num_points_in_edge {
+ vertex_map.push(bottom.vertex_indices[i]);
+ }
+
+ // Triangulate
+ let num_rows = self.resolution + 1;
+ for row in 0..num_rows {
+ // vertices down left edge follow quadratic sequence: 0, 1, 3, 6, 10, 15...
+ // the nth term can be calculated with: (n^2 - n)/2
+ let top_vertex = (((row + 1) * (row + 1) - row - 1) / 2) as usize;
+ let bottom_vertex = (((row + 2) * (row + 2) + row - 2) / 2) as usize;
+
+ let num_triangles_in_row = 1 + 2 * row;
+ for column in 0..num_triangles_in_row {
+ let v0;
+ let v1;
+ let v2;
+
+ if column % 2 == 0 {
+ v0 = top_vertex;
+ v1 = bottom_vertex + 1;
+ v2 = bottom_vertex;
+ } else {
+ v0 = top_vertex;
+ v1 = bottom_vertex;
+ v2 = top_vertex + 1;
+ }
+
+ indices.push(vertex_map[v0]);
+ indices.push(vertex_map[if reverse {v2} else {v1}]);
+ indices.push(vertex_map[if reverse {v1} else {v2}]);
+ }
+ }
+ }
+}
+
+struct Edge {
+ vertex_indices: Vec,
+}
+
+impl Edge {fn new(vertex_indices: Vec) -> Self {Self{vertex_indices}}}
\ No newline at end of file
diff --git a/opengl_beginnings/src/engine.rs b/opengl_beginnings/src/engine.rs
index 7fc22f7..71e31a8 100644
--- a/opengl_beginnings/src/engine.rs
+++ b/opengl_beginnings/src/engine.rs
@@ -1,5 +1,5 @@
pub mod nebulix;
pub mod time;
pub mod input;
-mod shader;
-mod mesh;
+pub mod shader;
+pub mod mesh;
diff --git a/opengl_beginnings/src/engine/mesh.rs b/opengl_beginnings/src/engine/mesh.rs
index 39fdb54..86cd0c8 100644
--- a/opengl_beginnings/src/engine/mesh.rs
+++ b/opengl_beginnings/src/engine/mesh.rs
@@ -6,7 +6,7 @@ use nalgebra::Vector3;
// Down the line the MeshRenderer should have a material. The material then holds the data that is needed by the shader (so the actual texture or data for variables inside the shader)
// End Goal: Shader belongs to Material; Material belongs to MeshRenderer; Mesh belongs to MeshRenderer; MeshRenderer renders the mesh using the shader and data provided by the material
-struct Mesh {
+pub struct Mesh {
vertices: Vec>,
normals: Vec>,
indices: Vec,
diff --git a/opengl_beginnings/src/engine/nebulix.rs b/opengl_beginnings/src/engine/nebulix.rs
index f6cd092..2349467 100644
--- a/opengl_beginnings/src/engine/nebulix.rs
+++ b/opengl_beginnings/src/engine/nebulix.rs
@@ -136,11 +136,6 @@ impl ApplicationHandler for Nebulix {
}
// Custom code HERE
- // TODO: Next step is:
- // - dynamically generate a mesh
- // - use a shader to render it
- // - and fly around in the scene
- // After I confirmed that the above is working -> add textures
gl_surface.swap_buffers(&gl_context).unwrap();
self.window.as_ref().unwrap().request_redraw();
diff --git a/opengl_beginnings/src/main.rs b/opengl_beginnings/src/main.rs
index 6aaaa85..eef769f 100644
--- a/opengl_beginnings/src/main.rs
+++ b/opengl_beginnings/src/main.rs
@@ -4,7 +4,9 @@ use winit::event_loop::{ControlFlow, EventLoop};
mod camera;
mod engine;
+mod custom;
+// TODO: This should actually not be needed because of the Type "Unit" from nalgebra!
trait Extension {
fn normalize_checked(&self) -> Self;
fn normalize_checked_mut(&mut self);