mirror of
https://github.com/IllusionMan1212/3dobs.git
synced 2026-10-24 10:12:35 +00:00
log: logging to file, console and stdout
This commit is contained in:
Generated
+92
@@ -255,6 +255,15 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deranged"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
|
||||||
|
dependencies = [
|
||||||
|
"powerfmt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "directories"
|
name = "directories"
|
||||||
version = "4.0.1"
|
version = "4.0.1"
|
||||||
@@ -677,6 +686,12 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jpeg-decoder"
|
name = "jpeg-decoder"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -892,6 +907,15 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc"
|
name = "objc"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@@ -1015,6 +1039,12 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "powerfmt"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.69"
|
version = "1.0.69"
|
||||||
@@ -1285,6 +1315,17 @@ version = "0.3.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simplelog"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acee08041c5de3d5048c8b3f6f13fafb3026b24ba43c6a695a0c76179b844369"
|
||||||
|
dependencies = [
|
||||||
|
"log 0.4.20",
|
||||||
|
"termcolor",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@@ -1349,6 +1390,15 @@ version = "0.12.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a"
|
checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.50"
|
version = "1.0.50"
|
||||||
@@ -1401,9 +1451,11 @@ dependencies = [
|
|||||||
"glm",
|
"glm",
|
||||||
"image",
|
"image",
|
||||||
"imgui",
|
"imgui",
|
||||||
|
"log 0.4.20",
|
||||||
"mint",
|
"mint",
|
||||||
"rfd",
|
"rfd",
|
||||||
"serde",
|
"serde",
|
||||||
|
"simplelog",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1417,6 +1469,37 @@ dependencies = [
|
|||||||
"weezl",
|
"weezl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
|
||||||
|
dependencies = [
|
||||||
|
"deranged",
|
||||||
|
"itoa",
|
||||||
|
"libc",
|
||||||
|
"num_threads",
|
||||||
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
|
"time-core",
|
||||||
|
"time-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
|
||||||
|
dependencies = [
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@@ -1591,6 +1674,15 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ anyhow = "1.0.71"
|
|||||||
rfd = "0.11.3"
|
rfd = "0.11.3"
|
||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
fs4 = "0.7.0"
|
fs4 = "0.7.0"
|
||||||
|
simplelog = "0.12.1"
|
||||||
|
log = "0.4.20"
|
||||||
|
|
||||||
[dependencies.imgui]
|
[dependencies.imgui]
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
3dobs TODOs:
|
3dobs TODOs:
|
||||||
- [x] Help menu
|
- [x] Help menu
|
||||||
- [x] About window
|
- [x] About window
|
||||||
- [ ] File logger
|
- [x] File logger
|
||||||
- [ ] Logger should log to file, console and stdout
|
- [x] Logger should log to file, console and stdout
|
||||||
- [x] Move console to be under objects
|
- [x] Move console to be under objects
|
||||||
- [x] Don't have the viewport window be scrollable
|
- [x] Don't have the viewport window be scrollable
|
||||||
- [x] Object rotation with left click + mouse movement (very rudimentary implementation, but works)
|
- [x] Object rotation with left click + mouse movement (very rudimentary implementation, but works)
|
||||||
|
|||||||
+6
-4
@@ -1,5 +1,7 @@
|
|||||||
use std::{io::{BufReader, BufRead}, collections::HashMap, path::PathBuf};
|
use std::{io::{BufReader, BufRead}, collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
|
use log::{error, warn, trace};
|
||||||
|
|
||||||
use crate::{mesh::Vertex, aabb::AABB, importer::ObjMesh, importer::Object, importer::Material};
|
use crate::{mesh::Vertex, aabb::AABB, importer::ObjMesh, importer::Object, importer::Material};
|
||||||
|
|
||||||
const BUF_CAP: usize = 1024 * 128; // 128 Kilobytes
|
const BUF_CAP: usize = 1024 * 128; // 128 Kilobytes
|
||||||
@@ -140,7 +142,7 @@ fn parse_mtl(path: &PathBuf) -> Result<HashMap<String, Material>, Box<dyn std::e
|
|||||||
Some(MtlToken::DiffuseTexture) => {
|
Some(MtlToken::DiffuseTexture) => {
|
||||||
// TODO: textures
|
// TODO: textures
|
||||||
}
|
}
|
||||||
_ => { println!("Unhandled material token: {}", token) },
|
_ => { warn!("Unhandled material token: {}", token) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -327,7 +329,7 @@ pub fn load_obj(obj_path: &PathBuf, file: std::fs::File) -> Result<Object, Box<d
|
|||||||
materials.extend(m);
|
materials.extend(m);
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to parse mtl file {:?}: {}", material_path, e);
|
error!("Failed to parse mtl file {:?}: {}", material_path, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,12 +362,12 @@ pub fn load_obj(obj_path: &PathBuf, file: std::fs::File) -> Result<Object, Box<d
|
|||||||
Some(ObjToken::Line) | Some(ObjToken::Point) => {
|
Some(ObjToken::Line) | Some(ObjToken::Point) => {
|
||||||
// we don't handle lines or points
|
// we don't handle lines or points
|
||||||
}
|
}
|
||||||
_ => { println!("Unhandled obj token: {}", token) },
|
_ => { warn!("Unhandled obj token: {}", token) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let elapsed = now.elapsed();
|
let elapsed = now.elapsed();
|
||||||
println!("Loaded in {}ms", elapsed.as_millis());
|
trace!("Loaded in {}ms", elapsed.as_millis());
|
||||||
|
|
||||||
let mesh_name = {
|
let mesh_name = {
|
||||||
if current_mesh_name.is_empty() && !object_name.is_empty() {
|
if current_mesh_name.is_empty() && !object_name.is_empty() {
|
||||||
|
|||||||
+3
-1
@@ -1,5 +1,7 @@
|
|||||||
use std::io::{Read, Seek, BufReader, BufRead};
|
use std::io::{Read, Seek, BufReader, BufRead};
|
||||||
|
|
||||||
|
use log::trace;
|
||||||
|
|
||||||
use crate::{importer::ObjMesh, importer::Object, importer::Material, aabb::AABB, mesh::Vertex};
|
use crate::{importer::ObjMesh, importer::Object, importer::Material, aabb::AABB, mesh::Vertex};
|
||||||
|
|
||||||
const STL_HEADER_SIZE: u64 = 80;
|
const STL_HEADER_SIZE: u64 = 80;
|
||||||
@@ -229,7 +231,7 @@ pub fn load_stl(mut file: std::fs::File) -> Result<Object, Box<dyn std::error::E
|
|||||||
parse_binary_stl(file)?
|
parse_binary_stl(file)?
|
||||||
};
|
};
|
||||||
let elapsed = now.elapsed();
|
let elapsed = now.elapsed();
|
||||||
println!("Loaded in {} ms", elapsed.as_millis());
|
trace!("Loaded in {} ms", elapsed.as_millis());
|
||||||
|
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
use std::{os::unix::net::{UnixListener, UnixStream}, path::PathBuf, io::{Write, Read}, fs::File, process::exit, thread, sync::mpsc::Receiver};
|
use std::{os::unix::net::{UnixListener, UnixStream}, path::PathBuf, io::{Write, Read}, fs::File, process::exit, thread, sync::mpsc::Receiver};
|
||||||
|
|
||||||
use fs4::FileExt;
|
use fs4::FileExt;
|
||||||
|
use log::error;
|
||||||
|
|
||||||
fn create_named_pipe(pipe_path: PathBuf) -> UnixListener {
|
fn create_named_pipe(pipe_path: PathBuf) -> UnixListener {
|
||||||
if pipe_path.exists() {
|
if pipe_path.exists() {
|
||||||
@@ -58,7 +59,7 @@ pub fn init(lock_file: &File, args_paths: Vec<PathBuf>, one_instance: bool) -> O
|
|||||||
ipc_tx.send(paths).unwrap();
|
ipc_tx.send(paths).unwrap();
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Error: {:?}", err);
|
error!("Error: {:?}", err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ pub mod utils;
|
|||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod log;
|
pub mod logger;
|
||||||
pub mod aabb;
|
pub mod aabb;
|
||||||
pub mod importer;
|
pub mod importer;
|
||||||
pub mod ipc;
|
pub mod ipc;
|
||||||
|
|||||||
-64
@@ -1,64 +0,0 @@
|
|||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum LogLevel {
|
|
||||||
Debug,
|
|
||||||
Info,
|
|
||||||
Warning,
|
|
||||||
Error,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<LogLevel> for mint::Vector4<f32> {
|
|
||||||
fn from(level: LogLevel) -> Self {
|
|
||||||
match level {
|
|
||||||
LogLevel::Debug => [0.5, 0.5, 1.0, 1.0].into(),
|
|
||||||
LogLevel::Info => [0.5, 0.5, 0.5, 1.0].into(),
|
|
||||||
LogLevel::Warning => [1.0, 0.64, 0.0, 1.0].into(),
|
|
||||||
LogLevel::Error => [1.0, 0.0, 0.0, 1.0].into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct LogMessage {
|
|
||||||
pub level: LogLevel,
|
|
||||||
pub message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LogMessage {
|
|
||||||
pub fn new(level: LogLevel, message: &str) -> Self {
|
|
||||||
let severity = match level {
|
|
||||||
LogLevel::Debug => "DEBUG",
|
|
||||||
LogLevel::Info => "INFO",
|
|
||||||
LogLevel::Warning => "WARNING",
|
|
||||||
LogLevel::Error => "ERROR",
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
|
||||||
level,
|
|
||||||
message: format!("[{}]: {}", severity, message),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Log {
|
|
||||||
pub history: Vec<LogMessage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Log {
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.history.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn log(&mut self, message: &str, level: LogLevel) {
|
|
||||||
// TODO: also write to a log file
|
|
||||||
self.history.push(LogMessage::new(level, message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Log {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
history: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
use std::{io::Write, sync::{Arc, RwLock}};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum LogLevel {
|
||||||
|
Error,
|
||||||
|
Warn,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LogLevel> for mint::Vector4<f32> {
|
||||||
|
fn from(level: LogLevel) -> Self {
|
||||||
|
match level {
|
||||||
|
LogLevel::Debug => [0.5, 0.5, 1.0, 1.0].into(),
|
||||||
|
LogLevel::Info => [0.5, 0.5, 0.5, 1.0].into(),
|
||||||
|
LogLevel::Warn => [1.0, 0.64, 0.0, 1.0].into(),
|
||||||
|
LogLevel::Error => [1.0, 0.0, 0.0, 1.0].into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<log::LevelFilter> for LogLevel {
|
||||||
|
fn from(level: log::LevelFilter) -> Self {
|
||||||
|
match level {
|
||||||
|
log::LevelFilter::Debug => LogLevel::Debug,
|
||||||
|
log::LevelFilter::Info => LogLevel::Info,
|
||||||
|
log::LevelFilter::Warn => LogLevel::Warn,
|
||||||
|
log::LevelFilter::Error => LogLevel::Error,
|
||||||
|
_ => LogLevel::Debug,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LogMessage {
|
||||||
|
pub level: LogLevel,
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LogMessage {
|
||||||
|
pub fn new(level: LogLevel, message: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
level,
|
||||||
|
message: format!("{}", message),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Log {
|
||||||
|
pub history: Vec<LogMessage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Log {
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.history.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log(&mut self, message: &str, level: LogLevel) {
|
||||||
|
self.history.push(LogMessage::new(level, message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct WritableLog {
|
||||||
|
pub arc: Arc<RwLock<Log>>,
|
||||||
|
buf: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WritableLog {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self{arc: Arc::new(RwLock::new(Log::default())), buf: String::with_capacity(1024)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for WritableLog {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
self.buf.push_str(std::str::from_utf8(buf).unwrap());
|
||||||
|
if buf.contains(&b'\n') {
|
||||||
|
self.flush()?;
|
||||||
|
}
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
// match the log level found at index 0 till space to LogLevel
|
||||||
|
let level = match &self.buf[0..self.buf.find(' ').unwrap()] {
|
||||||
|
"[ERROR]" => LogLevel::Error,
|
||||||
|
"[WARN]" => LogLevel::Warn,
|
||||||
|
"[INFO]" => LogLevel::Info,
|
||||||
|
"[DEBUG]" => LogLevel::Debug,
|
||||||
|
_ => LogLevel::Info,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut logger = self.arc.write().unwrap();
|
||||||
|
logger.log(&self.buf, level);
|
||||||
|
self.buf.clear();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
-3
@@ -1,13 +1,49 @@
|
|||||||
use glfw::{Action, Context, Key, Modifiers};
|
|
||||||
use glad_gl::gl;
|
|
||||||
use anyhow;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use glfw::{Action, Context, Key, Modifiers};
|
||||||
|
use glad_gl::gl;
|
||||||
|
use anyhow;
|
||||||
|
use simplelog::*;
|
||||||
|
|
||||||
use threedobs::{shader, ui::ui, utils, ipc};
|
use threedobs::{shader, ui::ui, utils, ipc};
|
||||||
|
|
||||||
fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
|
fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let logger = threedobs::logger::WritableLog::default();
|
||||||
|
|
||||||
|
let log_conf = ConfigBuilder::default()
|
||||||
|
.set_target_level(LevelFilter::Error)
|
||||||
|
.set_thread_level(LevelFilter::Off)
|
||||||
|
.set_level_color(Level::Error, Some(Color::Red))
|
||||||
|
.set_level_color(Level::Debug, Some(Color::Rgb(128, 128, 255)))
|
||||||
|
.set_level_color(Level::Warn, Some(Color::Rgb(255, 163, 0)))
|
||||||
|
.set_level_color(Level::Info, Some(Color::Rgb(128, 128, 128)))
|
||||||
|
.build();
|
||||||
|
let in_program_log_conf = ConfigBuilder::default()
|
||||||
|
.set_target_level(LevelFilter::Off)
|
||||||
|
.set_time_level(LevelFilter::Off)
|
||||||
|
.set_thread_level(LevelFilter::Off)
|
||||||
|
.set_level_color(Level::Error, Some(Color::Red))
|
||||||
|
.set_level_color(Level::Debug, Some(Color::Rgb(128, 128, 255)))
|
||||||
|
.set_level_color(Level::Warn, Some(Color::Rgb(255, 255, 0)))
|
||||||
|
.set_level_color(Level::Info, Some(Color::Rgb(128, 128, 128)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let log_level = if cfg!(debug_assertions) {
|
||||||
|
LevelFilter::Debug
|
||||||
|
} else {
|
||||||
|
LevelFilter::Info
|
||||||
|
};
|
||||||
|
|
||||||
|
CombinedLogger::init(
|
||||||
|
vec![
|
||||||
|
TermLogger::new(log_level, log_conf.clone(), TerminalMode::Mixed, ColorChoice::Auto),
|
||||||
|
WriteLogger::new(log_level, log_conf, File::create("3dobs.log")?),
|
||||||
|
WriteLogger::new(log_level, in_program_log_conf, logger.clone())
|
||||||
|
]
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
let settings: ui::Settings = confy::load("3dobs", "settings")?;
|
let settings: ui::Settings = confy::load("3dobs", "settings")?;
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
@@ -36,6 +72,7 @@ fn main() -> anyhow::Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
let mut state = ui::State{
|
let mut state = ui::State{
|
||||||
settings,
|
settings,
|
||||||
|
logger,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -1,5 +1,6 @@
|
|||||||
use glad_gl::gl;
|
use glad_gl::gl;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use log::{debug, error};
|
||||||
|
|
||||||
pub struct ShaderSource {
|
pub struct ShaderSource {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -26,7 +27,7 @@ impl 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)]
|
#[cfg(debug_assertions)]
|
||||||
println!("vertex shader {:?} compiled with status: {}",
|
debug!("vertex shader {:?} compiled with status: {}",
|
||||||
vertex_obj.name,
|
vertex_obj.name,
|
||||||
success1
|
success1
|
||||||
);
|
);
|
||||||
@@ -34,7 +35,7 @@ impl Shader {
|
|||||||
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)]
|
#[cfg(debug_assertions)]
|
||||||
println!("vertex shader info: {}", std::str::from_utf8(&info_buf).unwrap());
|
error!("vertex shader info: {}", std::str::from_utf8(&info_buf).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let frag_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
|
let frag_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
|
||||||
@@ -45,7 +46,7 @@ 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)]
|
#[cfg(debug_assertions)]
|
||||||
println!("frag shader {:?} compiled with status: {}",
|
debug!("frag shader {:?} compiled with status: {}",
|
||||||
frag_obj.name,
|
frag_obj.name,
|
||||||
success2
|
success2
|
||||||
);
|
);
|
||||||
@@ -53,7 +54,7 @@ impl Shader {
|
|||||||
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)]
|
#[cfg(debug_assertions)]
|
||||||
println!("frag shader info: {}", std::str::from_utf8(&info_buf2).unwrap());
|
error!("frag shader info: {}", std::str::from_utf8(&info_buf2).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let shader_program = gl::CreateProgram();
|
let shader_program = gl::CreateProgram();
|
||||||
|
|||||||
+16
-24
@@ -1,9 +1,10 @@
|
|||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use glad_gl::gl;
|
use glad_gl::gl;
|
||||||
|
use log::{info, debug};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use crate::{camera::Camera, model, imgui_glfw_support, imgui_opengl_renderer, mesh, ui, log, utils};
|
use crate::{camera::Camera, model, imgui_glfw_support, imgui_opengl_renderer, mesh, ui, logger, utils};
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
@@ -26,7 +27,7 @@ pub struct State {
|
|||||||
pub camera: Camera,
|
pub camera: Camera,
|
||||||
pub objects: Vec<model::Model>,
|
pub objects: Vec<model::Model>,
|
||||||
pub viewport_size: [f32; 2],
|
pub viewport_size: [f32; 2],
|
||||||
pub logger: log::Log,
|
pub logger: logger::WritableLog,
|
||||||
pub settings: Settings,
|
pub settings: Settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ impl Default for State {
|
|||||||
camera: Camera::new(),
|
camera: Camera::new(),
|
||||||
objects: vec![],
|
objects: vec![],
|
||||||
viewport_size: [0.0, 0.0],
|
viewport_size: [0.0, 0.0],
|
||||||
logger: log::Log::default(),
|
logger: logger::WritableLog::default(),
|
||||||
settings: Settings::default(),
|
settings: Settings::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,10 +211,7 @@ fn draw_object_hierarchy(ui: &imgui::Ui, state: &mut State, idx: usize) -> bool
|
|||||||
|
|
||||||
ui.table_next_column();
|
ui.table_next_column();
|
||||||
if ui.small_button(format!("X###{}-{}", object.name.as_str(), idx)) {
|
if ui.small_button(format!("X###{}-{}", object.name.as_str(), idx)) {
|
||||||
let output = format!("Removing object {}", object.name);
|
info!("Removing object {}", object.name);
|
||||||
println!("{}", output);
|
|
||||||
|
|
||||||
state.logger.log(&output, log::LogLevel::Info);
|
|
||||||
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)) {
|
||||||
@@ -256,8 +254,9 @@ fn draw_console(ui: &imgui::Ui, state: &mut State) {
|
|||||||
ui.child_window("###ConsoleHistory")
|
ui.child_window("###ConsoleHistory")
|
||||||
.size([0.0, -27.0])
|
.size([0.0, -27.0])
|
||||||
.build(|| {
|
.build(|| {
|
||||||
for line in state.logger.history.iter() {
|
for line in state.logger.arc.read().unwrap().history.iter() {
|
||||||
let style = ui.push_style_color(imgui::StyleColor::Text, line.level.clone());
|
let style = ui.push_style_color(imgui::StyleColor::Text, line.level);
|
||||||
|
|
||||||
ui.text_wrapped(line.message.clone());
|
ui.text_wrapped(line.message.clone());
|
||||||
style.pop();
|
style.pop();
|
||||||
}
|
}
|
||||||
@@ -268,7 +267,8 @@ fn draw_console(ui: &imgui::Ui, state: &mut State) {
|
|||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
if ui.button("Clear") {
|
if ui.button("Clear") {
|
||||||
state.logger.clear();
|
let mut logger = state.logger.arc.write().unwrap();
|
||||||
|
logger.clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -369,21 +369,13 @@ fn draw_viewport(ui: &imgui::Ui, state: &mut State, texture: u32) {
|
|||||||
let _ = capture.save(save_path);
|
let _ = capture.save(save_path);
|
||||||
let elapsed = now.elapsed();
|
let elapsed = now.elapsed();
|
||||||
|
|
||||||
state.logger.log(
|
info!("Scene capture saved to: {} successfully", save_path
|
||||||
format!("Scene capture saved to: {} successfully",
|
.canonicalize()
|
||||||
save_path
|
.expect("Capture path to be canonicalized")
|
||||||
.canonicalize()
|
.to_str()
|
||||||
.expect("Capture path to be canonicalized")
|
.expect("Capture path to be valid unicode"));
|
||||||
.to_str()
|
|
||||||
.expect("Capture path to be valid unicode"))
|
|
||||||
.as_str(),
|
|
||||||
log::LogLevel::Info);
|
|
||||||
|
|
||||||
state.logger.log(
|
debug!("Scene capture took: {}ms", elapsed.as_millis());
|
||||||
format!("Scene capture took: {}ms",
|
|
||||||
elapsed.as_millis())
|
|
||||||
.as_str(),
|
|
||||||
log::LogLevel::Debug);
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
|||||||
+7
-11
@@ -3,8 +3,9 @@ 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 ::log::{info, error};
|
||||||
|
|
||||||
use crate::{log, model, ui, importer};
|
use crate::{model, ui, importer};
|
||||||
|
|
||||||
pub enum SupportedFileExtensions {
|
pub enum SupportedFileExtensions {
|
||||||
OBJ,
|
OBJ,
|
||||||
@@ -66,18 +67,18 @@ pub fn import_models_from_paths(paths: &Vec<PathBuf>, state: &mut ui::ui::State)
|
|||||||
for model_path in paths {
|
for model_path in paths {
|
||||||
let filename = model_path.file_name();
|
let filename = model_path.file_name();
|
||||||
if model_path.is_dir() {
|
if model_path.is_dir() {
|
||||||
state.logger.log(&format!("Skipping directory \"{}\"", filename.unwrap().to_str().unwrap()), log::LogLevel::Info);
|
info!("Skipping directory \"{}\"", filename.unwrap().to_str().unwrap());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match model_path.extension() {
|
match model_path.extension() {
|
||||||
Some(ext) => {
|
Some(ext) => {
|
||||||
if SupportedFileExtensions::from_str(ext.to_str().unwrap()).is_none() {
|
if SupportedFileExtensions::from_str(ext.to_str().unwrap()).is_none() {
|
||||||
state.logger.log(&format!("Skipping file \"{}\" because it is not an OBJ or STL file", filename.unwrap().to_str().unwrap()), log::LogLevel::Info);
|
info!("Skipping file \"{}\" because it is not an OBJ or STL file", filename.unwrap().to_str().unwrap());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
state.logger.log(&format!("Skipping file \"{}\" because it has no extension", filename.unwrap().to_str().unwrap()), log::LogLevel::Info);
|
info!("Skipping file \"{}\" because it has no extension", filename.unwrap().to_str().unwrap());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,19 +89,14 @@ pub fn import_models_from_paths(paths: &Vec<PathBuf>, state: &mut ui::ui::State)
|
|||||||
|
|
||||||
state.active_model = Some(m.id);
|
state.active_model = Some(m.id);
|
||||||
if let Some(model_name) = filename {
|
if let Some(model_name) = filename {
|
||||||
let msg = format!("Loaded model \"{}\"", model_name.to_str().unwrap());
|
info!("Loaded model \"{}\"", model_name.to_str().unwrap());
|
||||||
println!("{}", msg);
|
|
||||||
state.logger.log(&msg, log::LogLevel::Info);
|
|
||||||
m.name = model_name.to_str().unwrap().to_string();
|
m.name = model_name.to_str().unwrap().to_string();
|
||||||
}
|
}
|
||||||
state.objects.push(m);
|
state.objects.push(m);
|
||||||
state.camera.focus_on_selected_model(state.active_model, &state.objects);
|
state.camera.focus_on_selected_model(state.active_model, &state.objects);
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let error = format!("Error loading model \"{}\": {}", model_path.to_str().unwrap(), e);
|
error!("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