mirror of
https://github.com/IllusionMan1212/3dobs.git
synced 2026-10-24 10:12:35 +00:00
various QOL improvements and bug fixes
This commit is contained in:
Generated
+336
-383
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -22,5 +22,5 @@ version = "0.11.0"
|
|||||||
features = ["docking", "tables-api"]
|
features = ["docking", "tables-api"]
|
||||||
|
|
||||||
[dependencies.russimp]
|
[dependencies.russimp]
|
||||||
version = "2.0.5"
|
version = "2.0.6"
|
||||||
features = ["prebuilt"]
|
features = ["prebuilt"]
|
||||||
|
|||||||
@@ -12,3 +12,19 @@
|
|||||||
- [x] (BUG) Fix some meshes not rotating around their origin point (in actuality, they don't have an origin point and are only rotating around 0.0, 0.0, 0.0)
|
- [x] (BUG) Fix some meshes not rotating around their origin point (in actuality, they don't have an origin point and are only rotating around 0.0, 0.0, 0.0)
|
||||||
- First thing that comes to mind is just rotating them around the center_point of the mesh (which is the bounding box's center point)
|
- First thing that comes to mind is just rotating them around the center_point of the mesh (which is the bounding box's center point)
|
||||||
- [x] Default material
|
- [x] Default material
|
||||||
|
- [x] Toggle box for different zooms
|
||||||
|
- [x] Increase max zoom-out
|
||||||
|
- [x] Slider for model rotation speed
|
||||||
|
- [x] Smaller console area
|
||||||
|
- [ ] Better object rotation
|
||||||
|
- [ ] Ability to change rotation pivot point (needs raycasting and shit)
|
||||||
|
- [ ] There might be memory leaks somewhere (tracked it down to russimp, will have to write my own .obj and .stl readers)
|
||||||
|
- [x] Reset object rotation when changing active model
|
||||||
|
- [x] Drag'n'Drop models
|
||||||
|
- [ ] Config for consistent settings between restarts (home dir preferred)
|
||||||
|
- [x] (BUG) when removing a model that's not selected and the selected model is not the last, we select the last one
|
||||||
|
- only select the last one if we removed the selected model
|
||||||
|
- [x] Use filename for the root node
|
||||||
|
- [x] Ship shaders directly in the executable
|
||||||
|
|
||||||
|
- [ ] Bring back the regular camera movement (can maybe be a switch between them) (for later)
|
||||||
|
|||||||
+11
-13
@@ -29,22 +29,20 @@ impl Camera {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_mouse_scroll(&mut self, yoffset: f32, can_capture_cursor: bool) {
|
pub fn handle_mouse_scroll(&mut self, yoffset: f32, can_capture_cursor: bool, fov_zoom: bool) {
|
||||||
if !can_capture_cursor { return }
|
if !can_capture_cursor { return }
|
||||||
self.fov -= yoffset;
|
if fov_zoom {
|
||||||
|
self.fov -= yoffset;
|
||||||
|
|
||||||
if self.fov <= 0.5 {
|
if self.fov <= 0.5 {
|
||||||
self.fov = 0.5;
|
self.fov = 0.5;
|
||||||
|
}
|
||||||
|
if self.fov >= 85.0 {
|
||||||
|
self.fov = 85.0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.position = self.position + (self.front * self._speed) + glm::vec3(0.0, 0.0, -yoffset);
|
||||||
}
|
}
|
||||||
if self.fov >= 45.0 {
|
|
||||||
self.fov = 45.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if yoffset > 0.0 {
|
|
||||||
// self.position = self.position + (self.front * self._speed) + glm::vec3(0.0, 0.0, yoffset);
|
|
||||||
// } else {
|
|
||||||
// self.position = self.position - (self.front * self._speed) + glm::vec3(0.0, 0.0, yoffset);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_camera(&mut self, xoffset: f32, yoffset: f32) {
|
pub fn move_camera(&mut self, xoffset: f32, yoffset: f32) {
|
||||||
|
|||||||
+39
-6
@@ -2,7 +2,7 @@ use glfw::{Action, Context, Key, Modifiers};
|
|||||||
use glad_gl::gl;
|
use glad_gl::gl;
|
||||||
use anyhow;
|
use anyhow;
|
||||||
|
|
||||||
use threedobs::{shader, ui::ui};
|
use threedobs::{shader, ui::ui, utils};
|
||||||
|
|
||||||
fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
|
fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS)?;
|
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS)?;
|
||||||
@@ -23,9 +23,36 @@ fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
let (mut imgui, glfw_platform, renderer) = ui::init_imgui(&mut window);
|
let (mut imgui, glfw_platform, renderer) = ui::init_imgui(&mut window);
|
||||||
|
|
||||||
let mesh_shader = shader::Shader::new("shaders/vertex.glsl", "shaders/frag.glsl")?;
|
let mesh_shader = shader::Shader::new(
|
||||||
let light_shader = shader::Shader::new("shaders/vertex.glsl", "shaders/light_f.glsl")?;
|
&mut shader::ShaderSource{
|
||||||
let grid_shader = shader::Shader::new("shaders/grid_v.glsl", "shaders/grid_f.glsl")?;
|
name: "vertex.glsl".to_string(),
|
||||||
|
source: include_str!("../shaders/vertex.glsl").to_string(),
|
||||||
|
},
|
||||||
|
&mut shader::ShaderSource{
|
||||||
|
name: "frag.glsl".to_string(),
|
||||||
|
source: include_str!("../shaders/frag.glsl").to_string(),
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
let light_shader = shader::Shader::new(
|
||||||
|
&mut shader::ShaderSource{
|
||||||
|
name: "vertex.glsl".to_string(),
|
||||||
|
source: include_str!("../shaders/vertex.glsl").to_string(),
|
||||||
|
},
|
||||||
|
&mut shader::ShaderSource{
|
||||||
|
name: "light_f.glsl".to_string(),
|
||||||
|
source: include_str!("../shaders/light_f.glsl").to_string(),
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
let grid_shader = shader::Shader::new(
|
||||||
|
&mut shader::ShaderSource{
|
||||||
|
name: "grid_v.glsl".to_string(),
|
||||||
|
source: include_str!("../shaders/grid_v.glsl").to_string(),
|
||||||
|
},
|
||||||
|
&mut shader::ShaderSource{
|
||||||
|
name: "grid_f.glsl".to_string(),
|
||||||
|
source: include_str!("../shaders/grid_f.glsl").to_string(),
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
let vertices: [f32; 288] = [
|
let vertices: [f32; 288] = [
|
||||||
// positions // normals // texture coords
|
// positions // normals // texture coords
|
||||||
@@ -198,7 +225,10 @@ fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
|
|||||||
} else {
|
} else {
|
||||||
if let Some(active_model) = state.active_model {
|
if let Some(active_model) = state.active_model {
|
||||||
let model = state.objects.iter_mut().find(|m| m.id == active_model).unwrap();
|
let model = state.objects.iter_mut().find(|m| m.id == active_model).unwrap();
|
||||||
model.rotate(xoffset * state.camera.sensitivity, yoffset * state.camera.sensitivity);
|
// let x_rotation = glm::quat_angle_axis(xoffset * state.camera.sensitivity, &state.camera.up);
|
||||||
|
let x_rotation = xoffset * state.camera.sensitivity * state.rotation_speed;
|
||||||
|
let y_rotation = yoffset * state.camera.sensitivity * state.rotation_speed;
|
||||||
|
model.rotate(x_rotation, y_rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,7 +343,10 @@ fn handle_window_event(window: &mut glfw::Window, event: &glfw::WindowEvent, sta
|
|||||||
window.set_cursor_mode(glfw::CursorMode::Normal);
|
window.set_cursor_mode(glfw::CursorMode::Normal);
|
||||||
}
|
}
|
||||||
glfw::WindowEvent::Scroll(_, yoff) => {
|
glfw::WindowEvent::Scroll(_, yoff) => {
|
||||||
state.camera.handle_mouse_scroll(*yoff as f32, state.can_capture_cursor);
|
state.camera.handle_mouse_scroll(*yoff as f32, state.can_capture_cursor, state.fov_zoom);
|
||||||
|
}
|
||||||
|
glfw::WindowEvent::FileDrop(paths) => {
|
||||||
|
utils::import_models_from_paths(paths, state);
|
||||||
}
|
}
|
||||||
glfw::WindowEvent::FramebufferSize(w, h) => {
|
glfw::WindowEvent::FramebufferSize(w, h) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
+38
-20
@@ -84,6 +84,8 @@ pub struct Mesh {
|
|||||||
pub material: Material,
|
pub material: Material,
|
||||||
|
|
||||||
vao: u32,
|
vao: u32,
|
||||||
|
vbo: u32,
|
||||||
|
ebo: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mesh {
|
impl Mesh {
|
||||||
@@ -128,7 +130,9 @@ impl Mesh {
|
|||||||
indices,
|
indices,
|
||||||
textures,
|
textures,
|
||||||
material,
|
material,
|
||||||
|
vbo,
|
||||||
vao,
|
vao,
|
||||||
|
ebo,
|
||||||
position,
|
position,
|
||||||
rotation,
|
rotation,
|
||||||
scale,
|
scale,
|
||||||
@@ -137,8 +141,8 @@ impl Mesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, shader: &Shader, scale: f32, pivot: glm::Vec3) {
|
pub fn draw(&self, shader: &Shader, scale: f32, pivot: glm::Vec3) {
|
||||||
let mut diffuse = 1;
|
// let mut diffuse = 1;
|
||||||
let mut specular = 1;
|
// let mut specular = 1;
|
||||||
|
|
||||||
shader.use_shader();
|
shader.use_shader();
|
||||||
|
|
||||||
@@ -152,25 +156,25 @@ impl Mesh {
|
|||||||
shader.set_3fv("material.specular", self.material.specular);
|
shader.set_3fv("material.specular", self.material.specular);
|
||||||
shader.set_float("material.shininess", self.material.shininess);
|
shader.set_float("material.shininess", self.material.shininess);
|
||||||
|
|
||||||
for i in 0..self.textures.len() {
|
// for i in 0..self.textures.len() {
|
||||||
unsafe {
|
// unsafe {
|
||||||
gl::ActiveTexture(gl::TEXTURE0 + i as u32);
|
// gl::ActiveTexture(gl::TEXTURE0 + i as u32);
|
||||||
match self.textures[i].typ {
|
// match self.textures[i].typ {
|
||||||
russimp::material::TextureType::Diffuse => {
|
// russimp::material::TextureType::Diffuse => {
|
||||||
diffuse += 1;
|
// diffuse += 1;
|
||||||
shader.set_int(format!("material.texture_diffuse{}", diffuse).as_str(), i as i32);
|
// shader.set_int(format!("material.texture_diffuse{}", diffuse).as_str(), i as i32);
|
||||||
},
|
// },
|
||||||
russimp::material::TextureType::Specular => {
|
// russimp::material::TextureType::Specular => {
|
||||||
specular += 1;
|
// specular += 1;
|
||||||
shader.set_int(format!("material.texture_specular{}", specular).as_str(), i as i32);
|
// shader.set_int(format!("material.texture_specular{}", specular).as_str(), i as i32);
|
||||||
},
|
// },
|
||||||
_ => {}, // don't do anything because unsupported texture types are logged
|
// _ => {}, // don't do anything because unsupported texture types are logged
|
||||||
// when the model is loaded
|
// // when the model is loaded
|
||||||
}
|
// }
|
||||||
|
|
||||||
gl::BindTexture(gl::TEXTURE_2D, self.textures[i].id);
|
// gl::BindTexture(gl::TEXTURE_2D, self.textures[i].id);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// draw Mesh
|
// draw Mesh
|
||||||
@@ -186,8 +190,22 @@ impl Mesh {
|
|||||||
pub fn rotate(&mut self, rotation: glm::Vec3) {
|
pub fn rotate(&mut self, rotation: glm::Vec3) {
|
||||||
self.rotation = self.rotation + rotation;
|
self.rotation = self.rotation + rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset_rotation(&mut self) {
|
||||||
|
self.rotation = glm::vec3(0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for Mesh {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
gl::BindVertexArray(0);
|
||||||
|
gl::DeleteBuffers(1, &self.vbo);
|
||||||
|
gl::DeleteBuffers(1, &self.ebo);
|
||||||
|
gl::DeleteVertexArrays(1, &self.vao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[repr(packed(2))]
|
#[repr(packed(2))]
|
||||||
|
|||||||
+14
-6
@@ -137,11 +137,11 @@ fn process_mesh(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn process_material(mat: &russimp::material::Material) -> Material {
|
fn process_material(mat: &russimp::material::Material) -> Material {
|
||||||
let mut mat_name = String::from("Default_Mat");
|
let mat_name = String::from("Default_Mat");
|
||||||
let mut ambient = glm::vec3(0.2, 0.2, 0.2);
|
let ambient = glm::vec3(0.2, 0.2, 0.2);
|
||||||
let mut diffuse = glm::vec3(0.7, 0.7, 0.7);
|
let diffuse = glm::vec3(0.7, 0.7, 0.7);
|
||||||
let mut specular = glm::vec3(0.1, 0.1, 0.1);
|
let specular = glm::vec3(0.1, 0.1, 0.1);
|
||||||
let mut shininess = 32.0;
|
let shininess = 32.0;
|
||||||
|
|
||||||
// TODO: better way of mapping properties
|
// TODO: better way of mapping properties
|
||||||
// for property in mat.properties.iter() {
|
// for property in mat.properties.iter() {
|
||||||
@@ -316,10 +316,18 @@ impl Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate(&mut self, xoffset: f32, yoffset: f32) {
|
pub fn rotate(&mut self, xoffset: f32, yoffset: f32) -> &mut Self {
|
||||||
let rotation = glm::vec3(-yoffset, xoffset, 0.0);
|
let rotation = glm::vec3(-yoffset, xoffset, 0.0);
|
||||||
for mesh in &mut self.meshes {
|
for mesh in &mut self.meshes {
|
||||||
mesh.rotate(rotation);
|
mesh.rotate(rotation);
|
||||||
}
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_rotation(&mut self) -> &mut Self {
|
||||||
|
for mesh in &mut self.meshes {
|
||||||
|
mesh.reset_rotation();
|
||||||
|
}
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-10
@@ -1,19 +1,22 @@
|
|||||||
use glad_gl::gl;
|
use glad_gl::gl;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub struct ShaderSource {
|
||||||
|
pub name: String,
|
||||||
|
pub source: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Shader {
|
pub struct Shader {
|
||||||
pub program_id: gl::GLuint,
|
pub program_id: gl::GLuint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shader {
|
impl Shader {
|
||||||
pub fn new(vertex_path: &str, frag_path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
pub fn new(vertex_obj: &mut ShaderSource, frag_obj: &mut ShaderSource) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let mut vertex_shader_source = std::fs::read_to_string(vertex_path).with_context(|| format!("Failed to read vertex shader file: {}", vertex_path))?;
|
vertex_obj.source.push('\0');
|
||||||
vertex_shader_source.push('\0');
|
let vertex_shader_source = std::ffi::CStr::from_bytes_with_nul(vertex_obj.source.as_bytes())?;
|
||||||
let vertex_shader_source = std::ffi::CStr::from_bytes_with_nul(vertex_shader_source.as_bytes())?;
|
|
||||||
|
|
||||||
let mut frag_shader_source = std::fs::read_to_string(frag_path).with_context(|| format!("Failed to read frag shader file: {}", frag_path))?;
|
frag_obj.source.push('\0');
|
||||||
frag_shader_source.push('\0');
|
let frag_shader_source = std::ffi::CStr::from_bytes_with_nul(frag_obj.source.as_bytes())?;
|
||||||
let frag_shader_source = std::ffi::CStr::from_bytes_with_nul(frag_shader_source.as_bytes())?;
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
|
let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
|
||||||
@@ -22,13 +25,15 @@ impl Shader {
|
|||||||
gl::CompileShader(vertex_shader);
|
gl::CompileShader(vertex_shader);
|
||||||
let mut success1 = 0;
|
let mut success1 = 0;
|
||||||
gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success1);
|
gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success1);
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
println!("vertex shader {:?} compiled with status: {}",
|
println!("vertex shader {:?} compiled with status: {}",
|
||||||
std::path::Path::new(vertex_path).file_name().unwrap(),
|
vertex_obj.name,
|
||||||
success1
|
success1
|
||||||
);
|
);
|
||||||
if success1 == 0 {
|
if success1 == 0 {
|
||||||
let info_buf = [0u8; 512];
|
let info_buf = [0u8; 512];
|
||||||
gl::GetShaderInfoLog(vertex_shader as u32, 512, std::ptr::null_mut(), info_buf.as_ptr() as *mut i8);
|
gl::GetShaderInfoLog(vertex_shader as u32, 512, std::ptr::null_mut(), info_buf.as_ptr() as *mut i8);
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
println!("vertex shader info: {}", std::str::from_utf8(&info_buf).unwrap());
|
println!("vertex shader info: {}", std::str::from_utf8(&info_buf).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,13 +44,15 @@ impl Shader {
|
|||||||
|
|
||||||
let mut success2 = 0;
|
let mut success2 = 0;
|
||||||
gl::GetShaderiv(frag_shader, gl::COMPILE_STATUS, &mut success2);
|
gl::GetShaderiv(frag_shader, gl::COMPILE_STATUS, &mut success2);
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
println!("frag shader {:?} compiled with status: {}",
|
println!("frag shader {:?} compiled with status: {}",
|
||||||
std::path::Path::new(frag_path).file_name().unwrap(),
|
frag_obj.name,
|
||||||
success2
|
success2
|
||||||
);
|
);
|
||||||
if success2 == 0 {
|
if success2 == 0 {
|
||||||
let info_buf2 = [0u8; 512];
|
let info_buf2 = [0u8; 512];
|
||||||
gl::GetShaderInfoLog(frag_shader as u32, 512, std::ptr::null_mut(), info_buf2.as_ptr() as *mut i8);
|
gl::GetShaderInfoLog(frag_shader as u32, 512, std::ptr::null_mut(), info_buf2.as_ptr() as *mut i8);
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
println!("frag shader info: {}", std::str::from_utf8(&info_buf2).unwrap());
|
println!("frag shader info: {}", std::str::from_utf8(&info_buf2).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+38
-24
@@ -1,6 +1,6 @@
|
|||||||
use glad_gl::gl;
|
use glad_gl::gl;
|
||||||
|
|
||||||
use crate::{camera::Camera, model, imgui_glfw_support, imgui_opengl_renderer, mesh, ui, log};
|
use crate::{camera::Camera, model, imgui_glfw_support, imgui_opengl_renderer, mesh, ui, log, utils};
|
||||||
|
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
@@ -12,6 +12,8 @@ pub struct State {
|
|||||||
pub can_capture_cursor: bool,
|
pub can_capture_cursor: bool,
|
||||||
pub draw_grid: bool,
|
pub draw_grid: bool,
|
||||||
pub draw_aabb: bool,
|
pub draw_aabb: bool,
|
||||||
|
pub fov_zoom: bool,
|
||||||
|
pub rotation_speed: f32,
|
||||||
pub wireframe: bool,
|
pub wireframe: bool,
|
||||||
pub first_frame_drawn: bool,
|
pub first_frame_drawn: bool,
|
||||||
pub camera: Camera,
|
pub camera: Camera,
|
||||||
@@ -30,6 +32,8 @@ impl Default for State {
|
|||||||
can_capture_cursor: false,
|
can_capture_cursor: false,
|
||||||
draw_grid: false,
|
draw_grid: false,
|
||||||
draw_aabb: false,
|
draw_aabb: false,
|
||||||
|
fov_zoom: true,
|
||||||
|
rotation_speed: 1.0,
|
||||||
show_help_menu_about: false,
|
show_help_menu_about: false,
|
||||||
wireframe: false,
|
wireframe: false,
|
||||||
camera: Camera::new(),
|
camera: Camera::new(),
|
||||||
@@ -89,22 +93,7 @@ pub fn import_model(state: &mut State) {
|
|||||||
Some(m) => m,
|
Some(m) => m,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
for model_path in &models {
|
utils::import_models_from_paths(&models, state);
|
||||||
let model = model::Model::new(model_path.to_str().unwrap(), state);
|
|
||||||
match model {
|
|
||||||
Ok(m) => {
|
|
||||||
state.active_model = Some(m.id);
|
|
||||||
state.objects.push(m);
|
|
||||||
state.camera.update_position(state.active_model, &state.objects);
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
let error = format!("Error loading model \"{}\": {}", model_path.to_str().unwrap(), e);
|
|
||||||
println!("{}", error);
|
|
||||||
|
|
||||||
state.logger.log(&error, log::LogLevel::Error);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_main_menu_bar(ui: &imgui::Ui, state: &mut State, window: &mut glfw::Window, delta_time: f32) {
|
pub fn draw_main_menu_bar(ui: &imgui::Ui, state: &mut State, window: &mut glfw::Window, delta_time: f32) {
|
||||||
@@ -197,6 +186,7 @@ fn draw_object_hierarchy(ui: &imgui::Ui, state: &mut State, idx: usize) -> bool
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ui.checkbox("Selected", &mut (Some(state.objects[idx].id) == state.active_model)) {
|
if ui.checkbox("Selected", &mut (Some(state.objects[idx].id) == state.active_model)) {
|
||||||
|
state.objects[idx].reset_rotation();
|
||||||
state.active_model = Some(state.objects[idx].id);
|
state.active_model = Some(state.objects[idx].id);
|
||||||
state.camera.update_position(state.active_model, &state.objects);
|
state.camera.update_position(state.active_model, &state.objects);
|
||||||
}
|
}
|
||||||
@@ -213,9 +203,13 @@ fn draw_objects_window(ui: &imgui::Ui, state: &mut State) {
|
|||||||
|
|
||||||
while i < state.objects.len() {
|
while i < state.objects.len() {
|
||||||
if draw_object_hierarchy(ui, state, i) {
|
if draw_object_hierarchy(ui, state, i) {
|
||||||
|
let selected_obj_id = state.objects[i].id;
|
||||||
state.objects.remove(i);
|
state.objects.remove(i);
|
||||||
state.active_model = state.objects.last().and_then(|o| Some(o.id));
|
if state.active_model == Some(selected_obj_id) {
|
||||||
state.camera.update_position(state.active_model, &state.objects);
|
let model = state.objects.last_mut().map(|m| m.reset_rotation());
|
||||||
|
state.active_model = model.and_then(|o| Some(o.id));
|
||||||
|
state.camera.update_position(state.active_model, &state.objects);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,10 +271,18 @@ fn create_initial_docking(ui: &imgui::Ui, state: &mut State) {
|
|||||||
if !state.first_frame_drawn {
|
if !state.first_frame_drawn {
|
||||||
space.split(
|
space.split(
|
||||||
imgui::Direction::Right,
|
imgui::Direction::Right,
|
||||||
0.3,
|
300.0 / ui.io().display_size[0],
|
||||||
|right| {
|
|right| {
|
||||||
right.dock_window("Objects");
|
right.split(
|
||||||
right.dock_window("Console");
|
imgui::Direction::Up,
|
||||||
|
0.6,
|
||||||
|
|up| {
|
||||||
|
up.dock_window("Objects");
|
||||||
|
},
|
||||||
|
|down| {
|
||||||
|
down.dock_window("Console");
|
||||||
|
}
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|left| {
|
|left| {
|
||||||
left.dock_window("Viewer");
|
left.dock_window("Viewer");
|
||||||
@@ -297,6 +299,7 @@ fn draw_viewport(ui: &imgui::Ui, state: &mut State, texture: u32) {
|
|||||||
ui.window("Viewer")
|
ui.window("Viewer")
|
||||||
.size(ui.content_region_avail(), imgui::Condition::FirstUseEver)
|
.size(ui.content_region_avail(), imgui::Condition::FirstUseEver)
|
||||||
.no_decoration()
|
.no_decoration()
|
||||||
|
.scrollable(!state.can_capture_cursor)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.build(|| {
|
.build(|| {
|
||||||
let mut tex_size = ui.content_region_avail();
|
let mut tex_size = ui.content_region_avail();
|
||||||
@@ -360,12 +363,21 @@ fn draw_viewport(ui: &imgui::Ui, state: &mut State, texture: u32) {
|
|||||||
ui.same_line();
|
ui.same_line();
|
||||||
ui.checkbox("Bounding box", &mut state.draw_aabb);
|
ui.checkbox("Bounding box", &mut state.draw_aabb);
|
||||||
ui.same_line();
|
ui.same_line();
|
||||||
ui.set_next_item_width(200.0);
|
ui.checkbox("FOV zoom", &mut state.fov_zoom);
|
||||||
|
ui.same_line();
|
||||||
|
ui.set_next_item_width(150.0);
|
||||||
imgui::Drag::new("Camera Speed")
|
imgui::Drag::new("Camera Speed")
|
||||||
.range(1.0, 10000.0)
|
.range(1.0, 10000.0)
|
||||||
.speed(1.0)
|
.speed(1.0)
|
||||||
.display_format("%.3f")
|
.display_format("%.3f")
|
||||||
.build(ui, &mut state.camera.speed);
|
.build(ui, &mut state.camera.speed);
|
||||||
|
ui.same_line();
|
||||||
|
ui.set_next_item_width(150.0);
|
||||||
|
imgui::Drag::new("Rotation Speed")
|
||||||
|
.range(0.1, 100.0)
|
||||||
|
.speed(0.5)
|
||||||
|
.display_format("%.3f")
|
||||||
|
.build(ui, &mut state.rotation_speed);
|
||||||
imgui::Image::new(imgui::TextureId::new(texture.try_into().unwrap()), tex_size)
|
imgui::Image::new(imgui::TextureId::new(texture.try_into().unwrap()), tex_size)
|
||||||
// flip the image vertically
|
// flip the image vertically
|
||||||
.uv0([0.0, 1.0])
|
.uv0([0.0, 1.0])
|
||||||
@@ -398,6 +410,8 @@ pub fn draw_ui(
|
|||||||
if state.show_help_menu_about {
|
if state.show_help_menu_about {
|
||||||
ui.window("About")
|
ui.window("About")
|
||||||
.size([300.0, 150.0], imgui::Condition::FirstUseEver)
|
.size([300.0, 150.0], imgui::Condition::FirstUseEver)
|
||||||
|
.resizable(false)
|
||||||
|
.movable(false)
|
||||||
.opened(&mut state.show_help_menu_about)
|
.opened(&mut state.show_help_menu_about)
|
||||||
.position([display_size[0] / 2.0, display_size[1] / 2.0], imgui::Condition::Always)
|
.position([display_size[0] / 2.0, display_size[1] / 2.0], imgui::Condition::Always)
|
||||||
.position_pivot([0.5, 0.5])
|
.position_pivot([0.5, 0.5])
|
||||||
@@ -417,7 +431,7 @@ pub fn draw_ui(
|
|||||||
|
|
||||||
ui.end_frame_early();
|
ui.end_frame_early();
|
||||||
|
|
||||||
if !state.is_cursor_captured {
|
if !state.can_capture_cursor {
|
||||||
let cursor = ui.mouse_cursor();
|
let cursor = ui.mouse_cursor();
|
||||||
if *last_cursor != cursor {
|
if *last_cursor != cursor {
|
||||||
*last_cursor = cursor;
|
*last_cursor = cursor;
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use glad_gl::gl;
|
use glad_gl::gl;
|
||||||
use glm;
|
use glm;
|
||||||
use anyhow::{Result, Context};
|
use anyhow::{Result, Context};
|
||||||
|
|
||||||
|
use crate::{ui, log, model};
|
||||||
|
|
||||||
|
const SUPPORTED_FILE_EXTENSIONS: [&str; 2] = ["obj", "stl"];
|
||||||
|
|
||||||
pub fn load_texture(path: &str) -> Result<u32> {
|
pub fn load_texture(path: &str) -> Result<u32> {
|
||||||
let tex = image::io::Reader::open(path)
|
let tex = image::io::Reader::open(path)
|
||||||
.with_context(|| format!("Failed to open texture file: {}", path))?
|
.with_context(|| format!("Failed to open texture file: {}", path))?
|
||||||
@@ -43,3 +49,36 @@ pub fn mat_ident() -> glm::Mat4 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn import_models_from_paths(paths: &Vec<PathBuf>, state: &mut ui::ui::State) {
|
||||||
|
for model_path in paths {
|
||||||
|
let filename = model_path.file_name();
|
||||||
|
if model_path.is_dir() {
|
||||||
|
state.logger.log(&format!("Skipping directory \"{}\"", filename.unwrap().to_str().unwrap()), log::LogLevel::Info);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(ext) = model_path.extension() {
|
||||||
|
if !SUPPORTED_FILE_EXTENSIONS.contains(&ext.to_ascii_lowercase().to_str().unwrap()) {
|
||||||
|
state.logger.log(&format!("Skipping file \"{}\" because it is not an OBJ or STL file", filename.unwrap().to_str().unwrap()), log::LogLevel::Info);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let model = model::Model::new(model_path.to_str().unwrap(), state);
|
||||||
|
match model {
|
||||||
|
Ok(mut m) => {
|
||||||
|
state.active_model = Some(m.id);
|
||||||
|
if let Some(model_name) = filename {
|
||||||
|
state.logger.log(&format!("Loaded model \"{}\"", model_name.to_str().unwrap()), log::LogLevel::Info);
|
||||||
|
m.name = model_name.to_str().unwrap().to_string();
|
||||||
|
}
|
||||||
|
state.objects.push(m);
|
||||||
|
state.camera.update_position(state.active_model, &state.objects);
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
let error = format!("Error loading model \"{}\": {}", model_path.to_str().unwrap(), e);
|
||||||
|
println!("{}", error);
|
||||||
|
|
||||||
|
state.logger.log(&error, log::LogLevel::Error);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user