gdritter repos outlander / 0bab597
Some more abstraction + basic OBJ file Getty Ritter 6 years ago
7 changed file(s) with 301 addition(s) and 65 deletion(s). Collapse all Expand all
1 pub mod obj;
1 #[derive(Debug,PartialEq)]
2 pub struct OBJError(String);
3
4 #[derive(Debug,PartialEq)]
5 pub struct Vertex {
6 pub x: f32,
7 pub y: f32,
8 pub z: f32,
9 pub w: f32,
10 }
11
12 #[derive(Debug,PartialEq)]
13 pub struct UV {
14 pub u: f32,
15 pub v: f32,
16 }
17
18 #[derive(Debug,PartialEq)]
19 pub struct Normal {
20 pub x: f32,
21 pub y: f32,
22 pub z: f32,
23 }
24
25 #[derive(Debug,PartialEq)]
26 pub struct Point {
27 vertex: usize,
28 uv: Option<usize>,
29 normal: Option<usize>,
30 }
31
32 impl Point {
33 fn parse(s: &str) -> Result<Point, OBJError> {
34 let err = || OBJError(format!("Invalid point: {}", s));
35 let mut chunks = s.split("/");
36
37 let vertex = chunks.next().ok_or(err())?.parse().map_err(|_| err())?;
38 let uv = match chunks.next() {
39 Some("") => None,
40 Some(n) => Some(n.parse().map_err(|_| err())?),
41 None => None,
42 };
43
44 let normal = match chunks.next() {
45 Some("") => None,
46 Some(n) => Some(n.parse().map_err(|_| err())?),
47 None => None,
48 };
49
50 Ok(Point { vertex, uv, normal, })
51 }
52 }
53
54 #[derive(Debug,PartialEq)]
55 pub struct Face(Vec<Point>);
56
57 #[derive(Debug,PartialEq)]
58 pub struct OBJFile {
59 pub vertices: Vec<Vertex>,
60 pub texcoords: Vec<UV>,
61 pub normals: Vec<Normal>,
62 pub faces: Vec<Face>,
63 }
64
65 impl OBJFile {
66 pub fn parse(s: &str) -> Result<OBJFile, OBJError> {
67 let mut vertices = Vec::new();
68 let mut texcoords = Vec::new();
69 let mut normals = Vec::new();
70 let mut faces = Vec::new();
71
72 for line in s.lines() {
73 let err = || OBJError(format!("Invalid line: {}", line));
74 let mut chunks = line.split_whitespace();
75 match chunks.next() {
76 Some("v") => vertices.push(Vertex {
77 x: chunks.next().ok_or(err())?.parse().map_err(|_| err())?,
78 y: chunks.next().ok_or(err())?.parse().map_err(|_| err())?,
79 z: chunks.next().ok_or(err())?.parse().map_err(|_| err())?,
80 w: 1.0,
81 }),
82
83 Some("vt") => texcoords.push(UV {
84 u: chunks.next().ok_or(err())?.parse().map_err(|_| err())?,
85 v: chunks.next().ok_or(err())?.parse().map_err(|_| err())?,
86 }),
87
88 Some("vn") => normals.push(Normal {
89 x: chunks.next().ok_or(err())?.parse().map_err(|_| err())?,
90 y: chunks.next().ok_or(err())?.parse().map_err(|_| err())?,
91 z: chunks.next().ok_or(err())?.parse().map_err(|_| err())?,
92 }),
93
94 Some("f") =>
95 match chunks.map(Point::parse).collect() {
96 Ok(ps) => faces.push(Face(ps)),
97 Err(e) => return Err(e),
98 }
99
100 Some("") => (),
101 _ => return Err(err()),
102 }
103 }
104
105 Ok(OBJFile { vertices, texcoords, normals, faces })
106 }
107 }
108
109 #[cfg(test)]
110 mod test {
111 use super::*;
112
113 #[test]
114 fn just_a_vertex() {
115 assert_eq!(
116 OBJFile::parse("v 1.0 2.0 3.0\n").unwrap(),
117 OBJFile {
118 vertices: vec![ Vertex { x: 1.0, y: 2.0, z: 3.0, w: 1.0 } ],
119 texcoords: vec![],
120 normals: vec![],
121 faces: vec![],
122 },
123 );
124 }
125
126 #[test]
127 fn just_a_uv() {
128 assert_eq!(
129 OBJFile::parse("vt 1.0 0.5\n").unwrap(),
130 OBJFile {
131 vertices: vec![],
132 texcoords: vec![ UV { u: 1.0, v: 0.5 } ],
133 normals: vec![],
134 faces: vec![],
135 },
136 );
137 }
138
139 #[test]
140 fn simple_tri() {
141 assert_eq!(
142 OBJFile::parse("v 0 0 0
143 v 0 1 0
144 v 1 0 0
145 f 1 2 3").unwrap(),
146 OBJFile {
147 vertices: vec![
148 Vertex { x: 0.0, y: 0.0, z: 0.0, w: 1.0 },
149 Vertex { x: 0.0, y: 1.0, z: 0.0, w: 1.0 },
150 Vertex { x: 1.0, y: 0.0, z: 0.0, w: 1.0 },
151 ],
152 texcoords: vec![],
153 normals: vec![],
154 faces: vec![ Face(vec![
155 Point { vertex: 1, uv: None, normal: None },
156 Point { vertex: 2, uv: None, normal: None },
157 Point { vertex: 3, uv: None, normal: None },
158 ]) ],
159 },
160 );
161 }
162
163 #[test]
164 fn simple_tri_with_uvs() {
165 assert_eq!(
166 OBJFile::parse("v 0 0 0
167 v 0 1 0
168 v 1 0 0
169 vt 0 0
170 vt 1 1
171 vt 1 0
172 f 1/1 2/2 3/3\n").unwrap(),
173
174 OBJFile {
175 vertices: vec![
176 Vertex { x: 0.0, y: 0.0, z: 0.0, w: 1.0 },
177 Vertex { x: 0.0, y: 1.0, z: 0.0, w: 1.0 },
178 Vertex { x: 1.0, y: 0.0, z: 0.0, w: 1.0 },
179 ],
180 texcoords: vec![
181 UV { u: 0.0, v: 0.0 },
182 UV { u: 1.0, v: 1.0 },
183 UV { u: 1.0, v: 0.0 },
184 ],
185 normals: vec![],
186 faces: vec![ Face(vec![
187 Point { vertex: 1, uv: Some(1), normal: None },
188 Point { vertex: 2, uv: Some(2), normal: None },
189 Point { vertex: 3, uv: Some(3), normal: None },
190 ]) ],
191 },
192 );
193 }
194
195 }
1 use glutin;
2 use std::{convert, ffi, string};
3
4 #[derive(Debug)]
5 pub enum Error {
6 BadCString,
7 InvalidShaderLog,
8 CompileError(String),
9 LinkError(String),
10 GlutinCreation(glutin::CreationError),
11 GlutinContext(glutin::ContextError),
12 }
13
14 impl convert::From<glutin::CreationError> for Error {
15 fn from(err: glutin::CreationError) -> Error {
16 Error::GlutinCreation(err)
17 }
18 }
19
20 impl convert::From<glutin::ContextError> for Error {
21 fn from(err: glutin::ContextError) -> Error {
22 Error::GlutinContext(err)
23 }
24 }
25
26 impl convert::From<ffi::NulError> for Error {
27 fn from(_: ffi::NulError) -> Error {
28 Error::BadCString
29 }
30 }
31
32 impl convert::From<string::FromUtf8Error> for Error {
33 fn from(_: string::FromUtf8Error) -> Error {
34 Error::InvalidShaderLog
35 }
36 }
22 pub use gl::types::*;
33 pub use gl::*;
44 }
5 use std::{convert, ptr};
5 use std::ptr;
6
7 use errors::Error;
68 use graphics;
79
810 // Vertex data
911 static VERTEX_DATA: [gl::GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];
12 static ALT_VERTEX_DATA: [gl::GLfloat; 6] = [0.0, -0.5, -0.5, 0.5, 0.5, 0.5];
1013
1114 // Shader sources
1215 static VS_SRC: &'static str = "
2326 out_color = vec4(1.0, 1.0, 1.0, 1.0);
2427 }";
2528
26 #[derive(Debug)]
27 pub enum Error {
28 Graphics(graphics::GraphicsError),
29 }
30
31 impl convert::From<graphics::GraphicsError> for Error {
32 fn from(err: graphics::GraphicsError) -> Error {
33 Error::Graphics(err)
34 }
35 }
36
3729 pub fn main_loop() -> Result<(), Error> {
3830 let window = graphics::Window::create()?;
3931
4133 let fs = graphics::Shader::compile(graphics::ShaderType::Fragment, FS_SRC)?;
4234 let program = graphics::Program::link(vec![vs, fs])?;
4335
44 let _vao = graphics::VertexArray::new();
45 let _vbo = graphics::VertexBuffer::new_array_buffer(&VERTEX_DATA);
36 let vbo = graphics::VertexBuffer::new_array_buffer(
37 graphics::VertexArray::new(),
38 &VERTEX_DATA,
39 );
4640
4741 program.use_program();
4842 program.bind_frag_data_location(0, "out_color")?;
6054 );
6155 }
6256
57 vbo.unbind();
58
6359 window.run(|event| {
6460 use glutin::{ControlFlow, Event, WindowEvent, VirtualKeyCode};
6561
6662 match event {
6763 Event::WindowEvent { event: WindowEvent::Closed, .. } =>
6864 return ControlFlow::Break,
69 Event::WindowEvent { event: WindowEvent::KeyboardInput { input: k, .. }, .. } => {
65 Event::WindowEvent {
66 event: WindowEvent::KeyboardInput {
67 input: k,
68 ..
69 },
70 ..
71 } => {
7072 match k.virtual_keycode {
7173 Some(VirtualKeyCode::Q) =>
7274 return ControlFlow::Break,
8082 gl::ClearColor(0.3, 0.3, 0.3, 1.0);
8183 gl::Clear(gl::COLOR_BUFFER_BIT);
8284
85 vbo.bind();
86
8387 gl::DrawArrays(gl::TRIANGLES, 0, 3);
8488 }
8589
33 pub use gl::*;
44 }
55 use glutin;
6 use std::{convert,ffi,mem,ptr,string};
7
8 #[derive(Debug)]
9 pub enum GraphicsError {
10 BadCString,
11 InvalidShaderLog,
12 CompileError(String),
13 LinkError(String),
14 GlutinCreation(glutin::CreationError),
15 GlutinContext(glutin::ContextError),
16 }
17
18 impl convert::From<glutin::CreationError> for GraphicsError {
19 fn from(err: glutin::CreationError) -> GraphicsError {
20 GraphicsError::GlutinCreation(err)
21 }
22 }
23
24 impl convert::From<glutin::ContextError> for GraphicsError {
25 fn from(err: glutin::ContextError) -> GraphicsError {
26 GraphicsError::GlutinContext(err)
27 }
28 }
29
30 impl convert::From<ffi::NulError> for GraphicsError {
31 fn from(_: ffi::NulError) -> GraphicsError {
32 GraphicsError::BadCString
33 }
34 }
35
36 impl convert::From<string::FromUtf8Error> for GraphicsError {
37 fn from(_: string::FromUtf8Error) -> GraphicsError {
38 GraphicsError::InvalidShaderLog
39 }
40 }
6 use errors::Error;
7 use std::{ffi,mem,ptr};
418
429 //
4310
4714 }
4815
4916 impl Window {
50 pub fn create() -> Result<Window, GraphicsError> {
17 pub fn create() -> Result<Window, Error> {
5118 use glutin::GlContext;
5219 let events = glutin::EventsLoop::new();
5320 let window = glutin::WindowBuilder::new();
6128 Ok(Window { events, gl_window })
6229 }
6330
64 pub fn run<F>(self, mut cb: F) -> Result<(), GraphicsError>
31 pub fn run<F>(self, mut cb: F) -> Result<(), Error>
6532 where F: FnMut(glutin::Event) -> glutin::ControlFlow
6633 {
6734 use glutin::GlContext;
7441 match gl_window.swap_buffers() {
7542 Ok(()) => r,
7643 Err(ctx) => {
77 result = Err(GraphicsError::GlutinContext(ctx));
44 result = Err(Error::GlutinContext(ctx));
7845 glutin::ControlFlow::Break
7946 }
8047 }
11077 }
11178
11279 impl Shader {
113 pub fn compile(ty: ShaderType, src: &str) -> Result<Shader, GraphicsError> {
80 pub fn compile(ty: ShaderType, src: &str) -> Result<Shader, Error> {
11481 let shader;
11582 unsafe {
11683 shader = gl::CreateShader(ty.to_glenum());
13299 ptr::null_mut(),
133100 buf.as_mut_ptr() as *mut gl::GLchar
134101 );
135 return Err(GraphicsError::CompileError(String::from_utf8(buf)?));
102 return Err(Error::CompileError(String::from_utf8(buf)?));
136103 }
137104 }
138105 Ok(Shader { n: shader })
157124 }
158125
159126 impl Program {
160 pub fn link(shaders: Vec<Shader>) -> Result<Program, GraphicsError> {
127 pub fn link(shaders: Vec<Shader>) -> Result<Program, Error> {
161128 unsafe {
162129 let program = gl::CreateProgram();
163130 for s in shaders.iter() {
180147 ptr::null_mut(),
181148 buf.as_mut_ptr() as *mut gl::GLchar,
182149 );
183 return Err(GraphicsError::LinkError(String::from_utf8(buf)?));
150 return Err(Error::LinkError(String::from_utf8(buf)?));
184151 }
185152
186153 Ok(Program {
194161 unsafe { gl::UseProgram(self.p); }
195162 }
196163
197 pub fn bind_frag_data_location(&self, idx: u32, s: &str) -> Result<(), GraphicsError> {
164 pub fn bind_frag_data_location(&self, idx: u32, s: &str) -> Result<(), Error> {
198165 unsafe {
199166 gl::BindFragDataLocation(
200167 self.p,
201168 idx,
202 ffi::CString::new(s)?.as_ptr()
169 ffi::CString::new(s)?.as_ptr(),
203170 );
204171 }
205172 Ok(())
206173 }
207174
208 pub fn get_attrib_location(&self, s: &str) -> Result<i32, GraphicsError> {
175 pub fn get_attrib_location(&self, s: &str) -> Result<i32, Error> {
209176 Ok(unsafe {
210177 gl::GetAttribLocation(
211178 self.p,
212 ffi::CString::new(s)?.as_ptr()
179 ffi::CString::new(s)?.as_ptr(),
213180 )
214181 })
215182 }
229196
230197 pub struct VertexBuffer {
231198 idx: u32,
199 data: VertexArray,
232200 }
233201
234202 impl Drop for VertexBuffer {
247215
248216 VertexArray { idx }
249217 }
218
219 pub fn bind(&self) {
220 unsafe {
221 gl::BindVertexArray(self.idx);
222 }
223 }
224
225 pub fn unbind(&self) {
226 unsafe {
227 gl::BindVertexArray(0);
228 }
229 }
250230 }
251231
252232 impl VertexBuffer {
253 pub fn new_array_buffer(vertex_data: &[gl::GLfloat]) -> VertexBuffer {
233 pub fn new_array_buffer(
234 data: VertexArray,
235 vertex_data: &[gl::GLfloat],
236 ) -> VertexBuffer {
254237 let mut idx = 0;
255238 unsafe {
256239 gl::GenBuffers(1, &mut idx);
263246 );
264247 }
265248
266 VertexBuffer { idx }
267 }
268 }
249 VertexBuffer { idx, data }
250 }
251
252 pub fn bind(&self) {
253 unsafe {
254 self.data.bind();
255 gl::BindBuffer(gl::ARRAY_BUFFER, self.idx);
256 }
257 }
258
259 pub fn unbind(&self) {
260 unsafe {
261 gl::BindBuffer(gl::ARRAY_BUFFER, 0);
262 self.data.unbind();
263 }
264 }
265 }
11 extern crate gl;
22 extern crate glutin;
33
4 pub mod data;
45 pub mod cso;
6 pub mod errors;
57 pub mod game;
68 pub mod graphics;
79