Skip to content

Commit

Permalink
feat: instancing now works, with example. fix #40
Browse files Browse the repository at this point in the history
  • Loading branch information
ElhamAryanpur committed Sep 2, 2023
1 parent 1dafadf commit 8e5e2db
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 139 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "blue_engine"
version = "0.4.29"
version = "0.4.30"
authors = ["Elham Aryanpur <elhamaryanpur5@gmail.com>"]
edition = "2021"
description = "General-Purpose, Easy-to-use, Fast, and Portable graphics engine"
Expand Down Expand Up @@ -63,6 +63,10 @@ path = "examples/camera/rotate_around.rs"
name = "resource_sharing"
path = "examples/utils/resource_sharing.rs"

[[example]]
name = "instancing"
path = "examples/utils/instancing.rs"

# Development ONLY
[[example]]
name = "dev"
Expand Down
166 changes: 44 additions & 122 deletions examples/dev/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ use blue_engine::{
primitive_shapes::{cube, square, triangle, uv_sphere},
uniform_type::Matrix,
utils::default_resources::DEFAULT_MATRIX_4,
Engine, ObjectSettings, PolygonMode, PowerPreference, RotateAxis, ShaderSettings, TextureData,
Vertex, WindowDescriptor,
Engine, Instance, ObjectSettings, PolygonMode, PowerPreference, RotateAxis, ShaderSettings,
TextureData, Vertex, WindowDescriptor,
};

fn main() {
let mut engine = Engine::new().expect("win");

//let test_instance = Instance::default();
//println!("{:?}", test_instance.to_raw());

let texture = engine
.renderer
.build_texture(
Expand All @@ -17,8 +20,16 @@ fn main() {
blue_engine::TextureMode::Clamp,
)
.unwrap();
let texture2 = engine
.renderer
.build_texture(
"background",
TextureData::Path("resources/SimpleJacob.png"),
blue_engine::TextureMode::Clamp,
)
.unwrap();

let first = square(
square(
"main",
ObjectSettings::default(),
&mut engine.renderer,
Expand All @@ -32,159 +43,70 @@ fn main() {
.unwrap()
.set_position(-1f32, 0f32, 0f32);

let second = square(
square(
"alt",
ObjectSettings::default(),
&mut engine.renderer,
&mut engine.objects,
);

engine.objects.get_mut("alt").unwrap().set_texture(texture2);
engine
.objects
.get_mut("alt")
.unwrap()
.reference_texture("main");
engine
.objects
.get_mut("alt")
.unwrap()
.set_position(1f32, 0f32, 0f32);

// ===============================
/*
//let triangle_id = triangle(Some("Triangleee"), &mut engine, camera).unwrap();
let window_size = engine.window.inner_size();
uv_sphere(
"cube",
(18, 36, 1f32),
&mut engine.renderer,
&mut engine.objects,
)
.unwrap();
// engine.objects.get_mut("cube").unwrap().scale(0.6, 0.6, 0.6);
engine
.objects
.get_mut("cube")
.unwrap()
.set_color(1f32, 0f32, 0f32, 1f32);
//cube.scale(0.3, 0.3, 0.3);
.set_position(0.2f32, 0f32, 0.001f32);

engine
.objects
.get_mut("monke")
.unwrap()
.set_color(0.051f32, 0.533f32, 0.898f32, 1f32);
//engine.objects[test].rotate(90f32, RotateAxis::Y);
/*let sphere_1 = uv_sphere(Some("SPHERE1"), &mut engine, (18, 36, 1f32)).unwrap();
engine.objects[sphere_1].scale(2f32, 2f32, 2f32);
engine.objects[sphere_1].set_color(0.051f32, 0.533f32, 0.898f32, 1f32);
let sphere_1 = uv_sphere(Some("SPHERE1"), &mut engine, (18, 36, 1f32)).unwrap();
engine.objects[sphere_1].position(2f32, 1f32, 0f32);
engine.objects[sphere_1].set_color(1.0f32, 0.5f32, 0.31f32, 1f32);
let sphere_2 = uv_sphere(Some("SPHERE2"), &mut engine, (18, 36, 1f32)).unwrap();
engine.objects[sphere_2].position(-2f32, 1f32, 0f32);
engine.objects[sphere_2].set_color(1.0f32, 0.5f32, 0.31f32, 1f32);
let sphere_3 = uv_sphere(Some("SPHERE3"), &mut engine, (18, 36, 1f32)).unwrap();
engine.objects[sphere_3].position(2f32, -1f32, 0f32);
engine.objects[sphere_3].set_color(1.0f32, 0.5f32, 0.31f32, 1f32);
let sphere_4 = uv_sphere(Some("SPHERE4"), &mut engine, (18, 36, 1f32)).unwrap();
engine.objects[sphere_4].position(-2f32, -1f32, 0f32);
engine.objects[sphere_4].set_color(1.0f32, 0.5f32, 0.31f32, 1f32); */
//let window_size = engine.window.inner_size();
/*let change_texture = engine
.renderer
.build_and_append_texture(
"name",
TextureData::Bytes(include_bytes!("resource/BlueLogoDiscord.png").to_vec()),
blue_engine::header::TextureMode::Clamp,
//blue_engine::header::TextureFormat::PNG,
)
.unwrap();*/
//let square = engine.get_object(square_id).unwrap();
//square.change_color(0.0, 0.0, 1.0, 0.7).unwrap();
//square.change_texture(change_texture);
//square.resize(100.0, 100.0, 0.0, window_size);
//let square = engine.objects.get_mut(square_id).unwrap();
//square.no_stretch_update(&mut engine.renderer, engine.window.inner_size()).unwrap();
//font.draw("Hello_World", (-100, 50), &mut engine).unwrap();
let radius = 10f32;
let start = std::time::SystemTime::now();
let mut rotation = 0f32;
let speed = -0.05;
let mut has_border = false;
let mut val = 0f32;
*/
let speed = -0.05;
engine
.update_loop(move |renderer, _window, objects, input, camera, plugins| {
/*let o =
renderer.build_object("haha", Vec::new(), Vec::new(), ObjectSettings::default());
let camx = start.elapsed().unwrap().as_secs_f32().sin() * radius;
let camy = start.elapsed().unwrap().as_secs_f32().sin() * radius;
let camz = start.elapsed().unwrap().as_secs_f32().cos() * radius;
objects.get_mut("cube").unwrap().position(camx, camy, camz);
//cube.translate(1f32, 1f32, 1f32);
let sprite = objects.get_mut("cube").unwrap();
let sprite = objects.get_mut("alt").unwrap();

if input.key_held(blue_engine::VirtualKeyCode::Up) {
sprite.position(
sprite.position.0,
sprite.position.1 + speed,
sprite.position.2,
sprite.set_position(
sprite.position.x,
sprite.position.y - speed,
sprite.position.z,
);
//lm.ambient_color.data = [1f32, 1f32, 1f32, 1f32];
}
if input.key_held(blue_engine::VirtualKeyCode::Down) {
sprite.position(
sprite.position.0,
sprite.position.1 - speed,
sprite.position.2,
sprite.set_position(
sprite.position.x,
sprite.position.y + speed,
sprite.position.z,
);
//lm.ambient_color.data = [0.1f32, 0.1f32, 0.1f32, 1f32];
}

if input.key_held(blue_engine::VirtualKeyCode::Left) {
sprite.position(
sprite.position.0 - speed,
sprite.position.1,
sprite.position.2,
sprite.set_position(
sprite.position.x + speed,
sprite.position.y,
sprite.position.z,
);
}
if input.key_held(blue_engine::VirtualKeyCode::Right) {
sprite.position(
sprite.position.0 + speed,
sprite.position.1,
sprite.position.2,
sprite.set_position(
sprite.position.x - speed,
sprite.position.y,
sprite.position.z,
);
}

if input.key_held(blue_engine::VirtualKeyCode::E) {
sprite.position(
sprite.position.0,
sprite.position.1,
sprite.position.2 - speed,
sprite.set_position(
sprite.position.x,
sprite.position.y,
sprite.position.z + speed,
);
}
if input.key_held(blue_engine::VirtualKeyCode::Q) {
sprite.position(
sprite.position.0,
sprite.position.1,
sprite.position.2 + speed,
sprite.set_position(
sprite.position.x,
sprite.position.y,
sprite.position.z - speed,
);
} */
}
})
.expect("Error during update loop");
}
63 changes: 63 additions & 0 deletions examples/utils/instancing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Blue Engine by Elham Aryanpur
*
* Triangle example using pre-defined shapes
*
* The license is same as the one on the root.
*/

use blue_engine::{
header::{Engine, ObjectSettings},
primitive_shapes::triangle,
Instance,
};

pub fn main() {
// start the engine
let mut engine = Engine::new().expect("window not created");

// create a triangle
triangle(
"Triangle",
ObjectSettings::default(),
&mut engine.renderer,
&mut engine.objects,
)
.unwrap();

// update the triangle
engine.objects.update_object("Triangle", |object| {
// set the position of the main triangle
object.set_position(0f32, 0f32, -3f32);

// a function to make instance creation easier
let create_instance = |x: f32, y: f32, z: f32| {
Instance::new(
[x, y, z].into(),
[0f32, 0f32, 0f32].into(),
[1f32, 1f32, 1f32].into(),
)
};

// add an instance
object.add_instance(create_instance(2f32, 1f32, -2f32));
object.add_instance(create_instance(2f32, -1f32, -2f32));
object.add_instance(create_instance(-2f32, 1f32, -2f32));
object.add_instance(create_instance(-2f32, -1f32, -2f32));
});

// we manually update the instance buffer before the next frame starts
// this is due to the object updates happening after every frame, hence
// for the first frame, we need to update it ourselves.
engine
.objects
.get_mut("Triangle")
.expect("Couldn't get the triangle")
.update_instance_buffer(&mut engine.renderer)
.expect("Couldn't update instance buffer");

// run the loop as normal
engine
.update_loop(move |_, _, _, _, _, _| {})
.expect("Error during update loop");
}
Binary file added resources/SimpleJacob.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 16 additions & 4 deletions src/definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
use image::GenericImageView;
use wgpu::{util::DeviceExt, BindGroupLayout, Sampler, Texture, TextureView};

use crate::header::{
Pipeline, PipelineData, ShaderSettings, Shaders, StringBuffer, TextureData, TextureMode,
Textures, UniformBuffers, Vertex, VertexBuffers,
use crate::{
header::{
Pipeline, PipelineData, ShaderSettings, Shaders, StringBuffer, TextureData, TextureMode,
Textures, UniformBuffers, Vertex, VertexBuffers,
},
InstanceRaw,
};

impl crate::header::Renderer {
Expand Down Expand Up @@ -68,7 +71,7 @@ impl crate::header::Renderer {
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[Vertex::desc()],
buffers: &[Vertex::desc(), InstanceRaw::desc()],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
Expand Down Expand Up @@ -326,4 +329,13 @@ impl crate::header::Renderer {
length: indicies.len() as u32,
})
}

pub fn build_instance(&self, instance_data: Vec<InstanceRaw>) -> wgpu::Buffer {
self.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Instance Buffer"),
contents: bytemuck::cast_slice(&instance_data),
usage: wgpu::BufferUsages::VERTEX,
})
}
}
10 changes: 9 additions & 1 deletion src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ pub struct Object {
pub uniform_layout: wgpu::BindGroupLayout,
/// Pipeline holds all the data that is sent to GPU, including shaders and textures
pub pipeline: Pipeline,
/// List of instances of this object
pub instances: Vec<Instance>,
/// instance buffer
pub instance_buffer: wgpu::Buffer,
/// Dictates the size of your object in pixels
pub size: glm::Vec3,
pub scale: glm::Vec3,
Expand All @@ -94,7 +98,11 @@ pub struct Object {
/// Transformation matricies helps to apply changes to your object, including position, orientation, ...
/// Best choice is to let the Object system handle it
pub position_matrix: nalgebra_glm::Mat4,
/// Transformation matricies helps to apply changes to your object, including position, orientation, ...
/// Best choice is to let the Object system handle it
pub scale_matrix: nalgebra_glm::Mat4,
/// Transformation matricies helps to apply changes to your object, including position, orientation, ...
/// Best choice is to let the Object system handle it
pub rotation_matrix: nalgebra_glm::Mat4,
/// Transformation matrix, but inversed
pub inverse_transformation_matrix: crate::uniform_type::Matrix,
Expand Down Expand Up @@ -369,7 +377,7 @@ unsafe impl Sync for ShaderSettings {}
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct InstanceRaw {
pub model: uniform_type::Matrix,
pub model: [[f32; 4]; 4],
}

/// Instance buffer data storage
Expand Down
Loading

0 comments on commit 8e5e2db

Please sign in to comment.