broken state - now its complicated
This commit is contained in:
parent
0cf7d5eb43
commit
1775cf90bc
@ -13,7 +13,7 @@ use winit::{event, window};
|
||||
|
||||
use crate::app::gl::{gl_config_picker, gl_create_context};
|
||||
use crate::app::renderer::Renderer;
|
||||
use crate::models::ModelData;
|
||||
use crate::models::Scene;
|
||||
|
||||
enum GlDisplayCreationState {
|
||||
Builder(Box<DisplayBuilder>),
|
||||
@ -32,13 +32,12 @@ pub struct App {
|
||||
|
||||
renderer: Option<Renderer>,
|
||||
current_scene: Option<String>,
|
||||
scene_data: ModelData,
|
||||
|
||||
state: Option<AppState>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new(scene_data: ModelData) -> Self {
|
||||
pub fn new() -> Self {
|
||||
let template = ConfigTemplateBuilder::new()
|
||||
.with_alpha_size(8)
|
||||
.with_transparency(cfg!(target_os = "macos"));
|
||||
@ -51,7 +50,6 @@ impl App {
|
||||
gl_context: None,
|
||||
renderer: None,
|
||||
state: None,
|
||||
scene_data,
|
||||
current_scene: None,
|
||||
}
|
||||
}
|
||||
@ -112,7 +110,7 @@ impl ApplicationHandler for App {
|
||||
if self.renderer.is_none() {
|
||||
let mut renderer = Renderer::new(&gl_context.display());
|
||||
|
||||
renderer.upload_scene_data(&self.scene_data);
|
||||
// renderer.upload_scene_data(&self.scene_data);
|
||||
|
||||
println!("Built Renderer");
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use glutin::prelude::GlDisplay;
|
||||
use crate::app::gl;
|
||||
use crate::models::{self, Model, ModelData, RenderObject, Scene, ShaderSource};
|
||||
use crate::models::{self, GpuMesh, Scene, ShaderSource};
|
||||
use crate::shaders::Shader;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::ffi::{ CStr, CString };
|
||||
@ -13,7 +14,7 @@ fn get_gl_string(gl: &gl::Gl, variant: gl::types::GLenum) -> Option<&'static CSt
|
||||
}
|
||||
|
||||
pub struct Renderer {
|
||||
gl: gl::Gl,
|
||||
gl: std::rc::Rc<gl::Gl>,
|
||||
shaders: HashMap<String, gl::types::GLuint>,
|
||||
scenes: HashMap<String, Scene>
|
||||
}
|
||||
@ -38,26 +39,13 @@ impl Renderer {
|
||||
}
|
||||
|
||||
Self {
|
||||
gl,
|
||||
gl: std::rc::Rc::new(gl),
|
||||
shaders: HashMap::new(),
|
||||
scenes: HashMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upload_scene_data(&mut self, scene_data: &ModelData) {
|
||||
let objects = scene_data.objects_data
|
||||
.iter()
|
||||
.map(|(mesh, shader_src)| {
|
||||
let shader = self.create_shader(shader_src);
|
||||
let render_object = self.upload_mesh(mesh);
|
||||
(render_object, shader)
|
||||
})
|
||||
.collect::<Vec<(RenderObject, u32)>>();
|
||||
println!("Uploading Scene {}", scene_data.name);
|
||||
self.scenes.insert(scene_data.name.clone(), Model { objects });
|
||||
}
|
||||
|
||||
pub fn upload_mesh(&self, mesh: &models::Mesh) -> RenderObject {
|
||||
pub fn upload_mesh(&self, mesh: &models::Mesh) -> GpuMesh {
|
||||
unsafe {
|
||||
let gl = &self.gl;
|
||||
|
||||
@ -71,7 +59,7 @@ impl Renderer {
|
||||
let vertex_data = mesh.vertices
|
||||
.iter()
|
||||
.map(|v| {
|
||||
[v.x, v.y, v.z, 1.0, 0.1, 0.1]
|
||||
[v.position.x, v.position.y, v.position.z, 1.0, 0.1, 0.1]
|
||||
})
|
||||
.collect::<Vec<[f32; 6]>>();
|
||||
|
||||
@ -106,7 +94,7 @@ impl Renderer {
|
||||
gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint);
|
||||
gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint);
|
||||
|
||||
RenderObject {
|
||||
GpuMesh {
|
||||
vao,
|
||||
vbo,
|
||||
_ebo: None,
|
||||
@ -125,7 +113,7 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_shader(&self, shader_src: &ShaderSource) -> gl::types::GLuint {
|
||||
pub fn create_shader(&self, shader_src: &ShaderSource) -> Shader {
|
||||
unsafe {
|
||||
let vertex_shader = Renderer::compile_shader(&self.gl, gl::VERTEX_SHADER, shader_src.vertex_src);
|
||||
let fragment_shader = Renderer::compile_shader(&self.gl, gl::FRAGMENT_SHADER, shader_src.fragment_src);
|
||||
@ -140,7 +128,10 @@ impl Renderer {
|
||||
self.gl.DeleteShader(vertex_shader);
|
||||
self.gl.DeleteShader(fragment_shader);
|
||||
|
||||
program
|
||||
Shader {
|
||||
program,
|
||||
gl: self.gl.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +155,7 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_object(&self, obj: &RenderObject, shader: gl::types::GLuint) {
|
||||
pub fn draw_object(&self, obj: &GpuMesh, shader: gl::types::GLuint) {
|
||||
unsafe {
|
||||
self.UseProgram(shader);
|
||||
|
||||
@ -182,9 +173,9 @@ impl Renderer {
|
||||
}
|
||||
|
||||
if let Some(scene) = self.scenes.get(current_scene) {
|
||||
for model in scene.models {
|
||||
scene.models.iter().for_each(|(obj, shader)| {
|
||||
self.draw_object(obj, *shader);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
eprintln!("Unknown Scene Requested: {}", current_scene);
|
||||
}
|
||||
|
||||
12
src/lib.rs
12
src/lib.rs
@ -13,6 +13,11 @@ pub mod models {
|
||||
|
||||
pub mod material;
|
||||
pub use material::*;
|
||||
|
||||
pub mod primitives;
|
||||
pub use primitives::*;
|
||||
|
||||
pub mod object;
|
||||
}
|
||||
|
||||
pub mod app {
|
||||
@ -22,6 +27,9 @@ pub mod app {
|
||||
}
|
||||
|
||||
pub mod shaders {
|
||||
pub mod shaders;
|
||||
pub use shaders::*;
|
||||
pub mod shader;
|
||||
pub use shader::*;
|
||||
|
||||
pub mod constants;
|
||||
pub use constants::*;
|
||||
}
|
||||
|
||||
27
src/main.rs
27
src/main.rs
@ -1,29 +1,34 @@
|
||||
use proj::{app::app::App, models::{Mesh, ModelData, ShaderSource}, shaders::{FRAGMENT_SHADER_SOURCE, VERTEX_SHADER_SOURCE}};
|
||||
use proj::{app::app::App, models::{ShaderSource, object::ObjData}, shaders::{FRAGMENT_SHADER_SOURCE, VERTEX_SHADER_SOURCE}};
|
||||
use winit::event_loop::EventLoop;
|
||||
|
||||
const TRIANGLE_OBJ_PATH: &str = "assets/models/small_house/model.obj";
|
||||
const HOUSE_OBJ_PATH: &str = "assets/models/small_house/model.obj";
|
||||
const HOUSE_MAT_PATH: &str = "assets/models/small_house/materials.mtl";
|
||||
|
||||
fn main() {
|
||||
dotenvy::dotenv().ok();
|
||||
let event_loop = EventLoop::new()
|
||||
.expect("Should be able to have Event Loop");
|
||||
|
||||
let mut mesh = Mesh::new();
|
||||
if let Err(e) = mesh.load_obj(TRIANGLE_OBJ_PATH) {
|
||||
panic!("{}", e);
|
||||
}
|
||||
|
||||
let shader_src = ShaderSource {
|
||||
vertex_src: VERTEX_SHADER_SOURCE,
|
||||
fragment_src: FRAGMENT_SHADER_SOURCE
|
||||
};
|
||||
|
||||
let scene_data = ModelData {
|
||||
name: "home".to_string(),
|
||||
objects_data: vec![(mesh, shader_src)]
|
||||
let obj_data = match ObjData::load_obj(HOUSE_OBJ_PATH) {
|
||||
Ok(o) => o,
|
||||
Err(e) => return eprintln!("Error: {}", e),
|
||||
};
|
||||
|
||||
let mut app = App::new(scene_data);
|
||||
println!("Done");
|
||||
|
||||
let materials = match ObjData::load_materials(HOUSE_MAT_PATH) {
|
||||
Ok(m) => m,
|
||||
Err(e) => return eprintln!("Error: {}", e),
|
||||
};
|
||||
|
||||
dbg!(&materials);
|
||||
|
||||
let mut app = App::new();
|
||||
|
||||
app.set_current_scene("home");
|
||||
|
||||
|
||||
@ -1,18 +1,26 @@
|
||||
#[derive(Debug)]
|
||||
use super::Vec3;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct TextureId(pub u32);
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Material {
|
||||
pub ambient: [f32; 3],
|
||||
pub diffuse: [f32; 3],
|
||||
pub specular: [f32; 3],
|
||||
pub shader_name: String,
|
||||
pub name: String,
|
||||
|
||||
pub ambient: Vec3,
|
||||
pub diffuse: Vec3,
|
||||
pub specular: Vec3,
|
||||
pub emissive: Vec3,
|
||||
pub shininess: f32,
|
||||
pub opacity: f32,
|
||||
|
||||
pub diffuse_texture: Option<TextureId>,
|
||||
pub normal_texture: Option<TextureId>,
|
||||
pub specular_texture: Option<TextureId>,
|
||||
}
|
||||
|
||||
impl Material {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
ambient: Default::default(),
|
||||
diffuse: Default::default(),
|
||||
specular: Default::default(),
|
||||
shader_name: String::new(),
|
||||
}
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,124 +1,44 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::models::Material;
|
||||
|
||||
use crate::models::{VertexIndex, object::{ObjData, ObjMesh}};
|
||||
|
||||
use super::Vertex;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Mesh {
|
||||
pub name: String,
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub material_name: String,
|
||||
}
|
||||
|
||||
const NEW_MATERIAL_DELIMITER: &str = "newmtl ";
|
||||
|
||||
fn parse_rgb(values: &str) -> Result<[f32; 3], Box<dyn std::error::Error>> {
|
||||
let mut rgb = [0.0; 3];
|
||||
let mut i = 0;
|
||||
|
||||
let values = values.split_whitespace();
|
||||
|
||||
for v in values {
|
||||
let parsed = v.parse::<f32>()?;
|
||||
rgb[i] = parsed;
|
||||
i += 1;
|
||||
if i > 2 {
|
||||
todo!("Implement custom error handling: too many values");
|
||||
}
|
||||
};
|
||||
|
||||
if i != 3 {
|
||||
todo!("Implement custom error handling: too few values");
|
||||
}
|
||||
|
||||
Ok(rgb)
|
||||
pub indices: Vec<u32>,
|
||||
pub material_name: Option<String>,
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
vertices: vec![],
|
||||
material_name: String::new(),
|
||||
}
|
||||
}
|
||||
pub fn new(obj: &ObjData, obj_mash: &ObjMesh) -> Self {
|
||||
let mut vertices: Vec<Vertex> = Vec::new();
|
||||
let mut indices: Vec<u32> = Vec::new();
|
||||
let mut vertex_map: HashMap<VertexIndex, u32> = HashMap::new();
|
||||
|
||||
pub fn load_obj(&mut self, path: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
|
||||
for line in content.lines() {
|
||||
if line.starts_with("v ") {
|
||||
let coords: Result<Vec<f32>, _> = line
|
||||
.split_whitespace()
|
||||
.skip(1)
|
||||
.take(3)
|
||||
.map(|s| s.parse::<f32>())
|
||||
.collect();
|
||||
|
||||
match coords {
|
||||
Ok(v) if v.len() == 3 => {
|
||||
self.vertices.push(Vertex { x: v[0], y: v[1], z: v[2] })
|
||||
},
|
||||
_ => eprintln!("Warning: Invalid vertex line: {}", line)
|
||||
for face in &obj_mash.faces {
|
||||
for i in 1..(face.indices.len() - 1) {
|
||||
for &idx in &[face.indices[0], face.indices[i], face.indices[i +1]] {
|
||||
let index = *vertex_map.entry(idx).or_insert_with(|| {
|
||||
let v = Vertex {
|
||||
position: obj.vertices[idx.position as usize],
|
||||
normal: idx.normal.map(|n| obj.normals[n as usize]).unwrap_or_default(),
|
||||
tex_coord: idx.tex_coord.map(|t| obj.tex_coords[t as usize]).unwrap_or_default(),
|
||||
};
|
||||
vertices.push(v);
|
||||
(vertices.len() - 1) as u32
|
||||
});
|
||||
indices.push(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("{:#?}", self.vertices);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_material(&mut self, path: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let mut lines = content.lines().peekable();
|
||||
|
||||
while let Some(line) = lines.next() {
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
continue ;
|
||||
}
|
||||
|
||||
if line.starts_with(NEW_MATERIAL_DELIMITER) {
|
||||
let mat_name = line.strip_prefix(NEW_MATERIAL_DELIMITER).unwrap();
|
||||
|
||||
while let Some(&next_line) = lines.peek() {
|
||||
let next = next_line.trim();
|
||||
|
||||
if next.starts_with(NEW_MATERIAL_DELIMITER) || next.is_empty() {
|
||||
lines.next();
|
||||
|
||||
let mut material = Material::new();
|
||||
if let Some((key, values)) = next.split_once(' ') {
|
||||
match key {
|
||||
"Ka" => {
|
||||
match parse_rgb(values) {
|
||||
Ok(v) => material.ka = v,
|
||||
Err(e) => eprintln!("Error parsing Ka values: {}", e.to_string())
|
||||
}
|
||||
},
|
||||
"Kd" => {
|
||||
match parse_rgb(values) {
|
||||
Ok(v) => material.kd = v,
|
||||
Err(e) => eprintln!("Error parsing Kd values: {}", e.to_string())
|
||||
}
|
||||
}
|
||||
"Ks" => {
|
||||
match parse_rgb(values) {
|
||||
Ok(v) => material.ks = v,
|
||||
Err(e) => eprintln!("Error parsing Ks values: {}", e.to_string())
|
||||
}
|
||||
}
|
||||
_ => { eprintln!("Unknown key: {key}") }
|
||||
}
|
||||
}
|
||||
|
||||
self.materials.insert(mat_name.to_string(), material);
|
||||
}
|
||||
}
|
||||
}
|
||||
Mesh {
|
||||
vertices,
|
||||
indices,
|
||||
name: obj_mash.name.clone(),
|
||||
material_name: obj_mash.material_name.clone(),
|
||||
}
|
||||
|
||||
println!("{:#?}", self.vertices);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::models::Mesh;
|
||||
use crate::models::{Material, Mesh};
|
||||
|
||||
pub struct ShaderSource {
|
||||
pub vertex_src: &'static [u8],
|
||||
@ -6,10 +6,11 @@ pub struct ShaderSource {
|
||||
}
|
||||
|
||||
pub struct Model {
|
||||
pub objects: Vec<RenderObject>
|
||||
pub objects: Vec<GpuMesh>,
|
||||
pub materials: Vec<Material>,
|
||||
}
|
||||
|
||||
pub struct RenderObject {
|
||||
pub struct GpuMesh {
|
||||
pub vao: gl::types::GLuint,
|
||||
pub vbo: gl::types::GLuint,
|
||||
pub _ebo: Option<gl::types::GLuint>,
|
||||
@ -19,5 +20,10 @@ pub struct RenderObject {
|
||||
|
||||
pub struct ModelData {
|
||||
pub name: String,
|
||||
pub meshes: Vec<Mesh>
|
||||
pub meshes: Vec<Mesh>,
|
||||
}
|
||||
|
||||
impl From<&ObjData> for Model {
|
||||
fn from(value: &ObjData) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
200
src/models/object.rs
Normal file
200
src/models/object.rs
Normal file
@ -0,0 +1,200 @@
|
||||
use crate::models::{Material, Vec2, VertexIndex, primitives::Vec3};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ObjData {
|
||||
pub normals: Vec<Vec3>,
|
||||
pub vertices: Vec<Vec3>,
|
||||
pub tex_coords: Vec<Vec2>,
|
||||
pub meshes: Vec<ObjMesh>,
|
||||
pub material_lib: Option<String>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ObjMesh {
|
||||
pub name: String,
|
||||
pub material_name: Option<String>,
|
||||
pub faces: Vec<ObjFace>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ObjFace {
|
||||
pub indices: Vec<VertexIndex>,
|
||||
}
|
||||
|
||||
const NEW_MATERIAL_DELIMITER: &str = "newmtl ";
|
||||
|
||||
fn parse_rgb(values: &str) -> Result<[f32; 3], Box<dyn std::error::Error>> {
|
||||
let mut rgb = [0.0; 3];
|
||||
let mut i = 0;
|
||||
|
||||
let values = values.split_whitespace();
|
||||
|
||||
for v in values {
|
||||
if i > 3 {
|
||||
todo!("Implement custom error handling: too many values");
|
||||
}
|
||||
let parsed = v.parse::<f32>()?;
|
||||
rgb[i] = parsed;
|
||||
i += 1;
|
||||
};
|
||||
|
||||
if i != 3 {
|
||||
todo!("Implement custom error handling: too few values");
|
||||
}
|
||||
|
||||
Ok(rgb)
|
||||
}
|
||||
|
||||
impl ObjData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
normals: vec![],
|
||||
vertices: vec![],
|
||||
tex_coords: vec![],
|
||||
meshes: vec![],
|
||||
material_lib: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_materials(path: &str) -> Result<Vec<Material>, Box<dyn std::error::Error>> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let mut lines = content.lines().peekable();
|
||||
let mut materials = vec![];
|
||||
|
||||
while let Some(line) = lines.next() {
|
||||
println!("{line}");
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
continue ;
|
||||
}
|
||||
|
||||
if line.starts_with(NEW_MATERIAL_DELIMITER) {
|
||||
let mat_name = line.strip_prefix(NEW_MATERIAL_DELIMITER).unwrap();
|
||||
println!("mat_name {mat_name}");
|
||||
|
||||
while let Some(&next_line) = lines.peek() {
|
||||
let next = next_line.trim();
|
||||
|
||||
println!("{next_line}");
|
||||
lines.next();
|
||||
|
||||
let mut material = Material::new();
|
||||
material.name = mat_name.to_string();
|
||||
|
||||
if let Some((key, values)) = next.split_once(' ') {
|
||||
match key {
|
||||
"Ka" => {
|
||||
match parse_rgb(values) {
|
||||
Ok(v) => material.ambient = Vec3 { x: v[0], y: v[1], z: v[2] },
|
||||
Err(e) => eprintln!("Error parsing Ka values: {}", e.to_string())
|
||||
}
|
||||
},
|
||||
"Kd" => {
|
||||
match parse_rgb(values) {
|
||||
Ok(v) => material.diffuse = Vec3 { x: v[0], y: v[1], z: v[2] },
|
||||
Err(e) => eprintln!("Error parsing Kd values: {}", e.to_string())
|
||||
}
|
||||
}
|
||||
"Ks" => {
|
||||
match parse_rgb(values) {
|
||||
Ok(v) => material.specular = Vec3 { x: v[0], y: v[1], z: v[2] },
|
||||
Err(e) => eprintln!("Error parsing Ks values: {}", e.to_string())
|
||||
}
|
||||
}
|
||||
_ => { eprintln!("Unknown key: {key}") }
|
||||
}
|
||||
}
|
||||
materials.push(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(materials)
|
||||
}
|
||||
|
||||
pub fn load_obj(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let mut obj_data = Self::new();
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let mut current_name = String::new();
|
||||
|
||||
let mut current_mash = ObjMesh {
|
||||
name: String::new(),
|
||||
material_name: None,
|
||||
faces: vec![]
|
||||
};
|
||||
|
||||
for line in content.lines() {
|
||||
let line = line.trim();
|
||||
let mut line_split = line.split_whitespace();
|
||||
|
||||
while let Some(split) = line_split.next() {
|
||||
match split {
|
||||
"v" => {
|
||||
let x = line_split.next().unwrap().parse::<f32>()?;
|
||||
let y = line_split.next().unwrap().parse::<f32>()?;
|
||||
let z = line_split.next().unwrap().parse::<f32>()?;
|
||||
|
||||
obj_data.vertices.push(Vec3 { x, y, z });
|
||||
},
|
||||
"vt" => {
|
||||
let x = line_split.next().unwrap().parse::<f32>()?;
|
||||
let y = line_split.next().unwrap().parse::<f32>()?;
|
||||
|
||||
obj_data.tex_coords.push(Vec2 { x, y })
|
||||
},
|
||||
"vn" => {
|
||||
let x = line_split.next().unwrap().parse::<f32>()?;
|
||||
let y = line_split.next().unwrap().parse::<f32>()?;
|
||||
let z = line_split.next().unwrap().parse::<f32>()?;
|
||||
|
||||
obj_data.normals.push(Vec3 { x, y, z });
|
||||
},
|
||||
"o" | "g" => {
|
||||
current_name = line_split.next().unwrap_or("").to_string();
|
||||
current_mash.name = current_name.clone();
|
||||
}
|
||||
"usemtl" => {
|
||||
if !current_mash.faces.is_empty() {
|
||||
obj_data.meshes.push(current_mash);
|
||||
}
|
||||
|
||||
let material_name = line_split.next().and_then(|l| Some(l.to_string()));
|
||||
current_mash = ObjMesh {
|
||||
name: current_name.clone(),
|
||||
material_name,
|
||||
faces: vec![]
|
||||
};
|
||||
},
|
||||
"f" => {
|
||||
let mut current_face = ObjFace { indices: vec![] };
|
||||
|
||||
while let Some(val) = line_split.next() {
|
||||
let values_split = val.split('/');
|
||||
let mut face_index: [u32; 3] = [0; 3];
|
||||
|
||||
for (i, value) in values_split.enumerate() {
|
||||
if !value.is_empty() {
|
||||
face_index[i] = value.parse::<u32>()?;
|
||||
}
|
||||
}
|
||||
|
||||
let vertex_index = VertexIndex {
|
||||
position: face_index[0],
|
||||
tex_coord: if face_index[1] != 0 { Some(face_index[1]) } else { None },
|
||||
normal: if face_index[2] != 0 { Some(face_index[2]) } else { None },
|
||||
};
|
||||
|
||||
current_face.indices.push(vertex_index);
|
||||
}
|
||||
current_mash.faces.push(current_face);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !current_mash.faces.is_empty() {
|
||||
obj_data.meshes.push(current_mash);
|
||||
}
|
||||
Ok(obj_data)
|
||||
}
|
||||
}
|
||||
194
src/models/primitives.rs
Normal file
194
src/models/primitives.rs
Normal file
@ -0,0 +1,194 @@
|
||||
use std::ops::Sub;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct Vec2 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct Vec3 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
}
|
||||
|
||||
impl Sub for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
z: self.z - rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Vec3 {
|
||||
pub fn length(&self) -> f32 {
|
||||
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
|
||||
}
|
||||
|
||||
pub fn normalize(&mut self) -> Self {
|
||||
let len = self.length();
|
||||
|
||||
if len == 0.0 {
|
||||
return *self;
|
||||
}
|
||||
Self {
|
||||
x: self.x / len,
|
||||
y: self.y / len,
|
||||
z: self.z / len,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dot(&self, other: Vec3) -> f32 {
|
||||
self.x * other.x + self.y * other.y + self.z * other.z
|
||||
}
|
||||
|
||||
pub fn cross(&self, other: Self) -> Self {
|
||||
Self {
|
||||
x: self.y * other.z - self.z * other.y,
|
||||
y: self.z * other.x - self.x * other.z,
|
||||
z: self.x * other.y - self.y * other.x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct Vec4 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
pub w: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mat4 {
|
||||
pub data: [f32; 16],
|
||||
}
|
||||
|
||||
impl Mat4 {
|
||||
pub fn identity() -> Self {
|
||||
Self {
|
||||
data: [
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translation(x: f32, y: f32, z: f32) -> Self {
|
||||
Self {
|
||||
data: [
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
x, y, z, 1.0,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale(x: f32, y: f32, z: f32) -> Self {
|
||||
Self {
|
||||
data: [
|
||||
x, 0.0, 0.0, 0.0,
|
||||
0.0, y, 0.0, 0.0,
|
||||
0.0, 0.0, z, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rotation_x(angle: f32) -> Self {
|
||||
let c = angle.cos();
|
||||
let s = angle.sin();
|
||||
Self {
|
||||
data: [
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, c, s, 0.0,
|
||||
0.0, -s, c, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rotation_y(angle: f32) -> Self {
|
||||
let c = angle.cos();
|
||||
let s = angle.sin();
|
||||
Self {
|
||||
data: [
|
||||
c, 0.0, -s, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
s, 0.0, c, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rotation_z(angle: f32) -> Self {
|
||||
let c = angle.cos();
|
||||
let s = angle.sin();
|
||||
Self {
|
||||
data: [
|
||||
c, s, 0.0, 0.0,
|
||||
-s, c, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn perspective(fov: f32, aspect: f32, near: f32, far: f32) -> Self {
|
||||
let f = 1.0 / (fov / 2.0).tan();
|
||||
let nf = 1.0 / (near - far);
|
||||
Self {
|
||||
data: [
|
||||
f / aspect, 0.0, 0.0, 0.0,
|
||||
0.0, f, 0.0, 0.0,
|
||||
0.0, 0.0, (far + near) * nf, -1.0,
|
||||
0.0, 0.0, 2.0 * far * near * nf, 0.0,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn look_at(eye: Vec3, target: Vec3, up: Vec3) -> Self {
|
||||
let f = (target - eye).normalize();
|
||||
let r = f.cross(up).normalize();
|
||||
let u = r.cross(f);
|
||||
Self {
|
||||
data: [
|
||||
r.x, u.x, -f.x, 0.0,
|
||||
r.y, u.y, -f.y, 0.0,
|
||||
r.z, u.z, -f.z, 0.0,
|
||||
-r.dot(eye), -u.dot(eye), f.dot(eye), 1.0,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const f32 {
|
||||
self.data.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul for Mat4 {
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: Self) -> Self {
|
||||
let mut result = [0.0f32; 16];
|
||||
for row in 0..4 {
|
||||
for col in 0..4 {
|
||||
for k in 0..4 {
|
||||
result[col * 4 + row] += self.data[k * 4 + row] * rhs.data[col * 4 + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
Self { data: result }
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,15 @@
|
||||
use crate::models::{ Vec2, Vec3 };
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Vertex {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
pub position: Vec3,
|
||||
pub normal: Vec3,
|
||||
pub tex_coord: Vec2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct VertexIndex {
|
||||
pub position: u32,
|
||||
pub tex_coord: Option<u32>,
|
||||
pub normal: Option<u32>
|
||||
}
|
||||
|
||||
43
src/shaders/shader.rs
Normal file
43
src/shaders/shader.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use crate::{app::gl, models::{Mat4, Vec3}};
|
||||
|
||||
pub struct Shader {
|
||||
pub program: gl::types::GLuint,
|
||||
pub gl: std::rc::Rc<gl::Gl>,
|
||||
}
|
||||
|
||||
impl Shader {
|
||||
pub fn use_program(&self) {
|
||||
unsafe { self.gl.UseProgram(self.program) };
|
||||
}
|
||||
|
||||
pub fn set_uniform_mat4(&self, name: &str, mat: &Mat4) {
|
||||
unsafe {
|
||||
let loc = self.gl.GetUniformLocation(
|
||||
self.program,
|
||||
name.as_ptr() as *const i8
|
||||
);
|
||||
self.gl.UniformMatrix4fv(loc, 1, gl::FALSE, mat.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_uniform_vec3(&self, name: &str, v: &Vec3) {
|
||||
unsafe {
|
||||
let loc = self.gl.GetUniformLocation(self.program, name.as_ptr() as *const i8);
|
||||
self.gl.Uniform3f(loc, v.x, v.y, v.z);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_uniform_f32(&self, name: &str, v: f32) {
|
||||
unsafe {
|
||||
let loc = self.gl.GetUniformLocation(self.program, name.as_ptr() as *const i8);
|
||||
self.gl.Uniform1f(loc, v);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_uniform_i32(&self, name: &str, v: i32) {
|
||||
unsafe {
|
||||
let loc = self.gl.GetUniformLocation(self.program, name.as_ptr() as *const i8);
|
||||
self.gl.Uniform1i(loc, v); // used for texture slots
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user