globject_rs/
lib.rs

1
2#![allow(dead_code)]
3
4/// The most basic OpenGL Buffer Object wrapping
5pub mod glbuffer;
6
7/// The most basic OpenGL Shader Program Object wrapping
8pub mod glshader;
9
10/// Definitions of `DrawArrayCommand`, `DrawElementsCommand` and `DispatchIndirectCommand`
11pub mod glcmdbuf;
12
13/// The most basic OpenGL Texture Object wrapping
14pub mod gltexture;
15
16/// The most basic OpenGL Framebuffer Object wrapping
17pub mod glframebuffer;
18
19/// An upper layer wrapping for `Buffer`, the `BufferVec` allows editing the buffer items easier than just to use the `Buffer`
20pub mod buffervec;
21
22/// An upper layer wrapping for `Mesh`, utilizing the trait `BufferVec` as the `Mesh` generic type of the vertex buffer, element buffer, instance buffer, and command buffer
23pub mod mesh;
24
25/// The material module provides `MaterialLegacy`, `MaterialPbr`, and the trait `Material`
26pub mod material;
27
28/// The most basic OpenGL Vertex Array Object that manages the pipeline from the data source in the array buffer to the shader attrib inputs
29pub mod pipeline;
30
31/// The mesh set for the complex mesh, each mesh subset has its name and material.
32pub mod meshset;
33
34/// The common module is to provide some miscellous utilities
35pub mod common;
36
37extern crate nalgebra_glm as glm;
38
39/// The prelude module provides all of the things you need to use
40pub mod prelude {
41	pub use crate::glbuffer::*;
42	pub use crate::glshader::*;
43	pub use crate::glcmdbuf::*;
44	pub use crate::gltexture::*;
45	pub use crate::glframebuffer::*;
46	pub use crate::buffervec::*;
47	pub use crate::mesh::*;
48	pub use crate::material::*;
49	pub use crate::pipeline::*;
50	pub use crate::meshset::*;
51	pub use crate::common::*;
52	pub use crate::derive_vertex_type;
53	pub use glm::*;
54	pub use struct_iterable::Iterable;
55	pub use glcore::*;
56	pub use half::f16;
57}
58
59pub use prelude::*;
60
61#[cfg(test)]
62mod tests {
63	use std::{
64		ffi::c_void,
65		mem::size_of_val,
66		process::ExitCode,
67		rc::Rc,
68	};
69	use super::prelude::*;
70	use glfw::*;
71
72	derive_vertex_type! {
73		pub struct MyVertex {
74			position: Vec2,
75		}
76	}
77
78	#[derive(Debug)]
79	enum AppError {
80		GLFWInitErr,
81		GLFWCreateWindowFailed,
82		GLFWErr(glfw::Error),
83		GLCoreError(GLCoreError),
84		ShaderError(ShaderError),
85		PipelineError(PipelineError),
86	}
87
88	#[derive(Debug)]
89	struct Renderer {
90		pipeline: Rc<Pipeline<MyVertex, UnusedType>>,
91		shader: Rc<Shader>,
92		mesh: Rc<dyn GenericMeshWithMaterial>,
93	}
94
95	#[derive(Debug)]
96	struct AppInstance {
97		renderer: Option<Renderer>,
98		glcore: Rc<GLCore>,
99		events: GlfwReceiver<(f64, WindowEvent)>,
100		window: PWindow,
101		glfw: Glfw,
102	}
103
104	impl From<GLCoreError> for AppError {
105		fn from(val: GLCoreError) -> Self {
106			Self::GLCoreError(val)
107		}
108	}
109
110	impl From<ShaderError> for AppError {
111		fn from(val: ShaderError) -> Self {
112			Self::ShaderError(val)
113		}
114	}
115
116	impl From<PipelineError> for AppError {
117		fn from(val: PipelineError) -> Self {
118			Self::PipelineError(val)
119		}
120	}
121
122	impl Renderer {
123		fn new(glcore: Rc<GLCore>) -> Result<Self, AppError> {
124			let vertices = [
125				MyVertex{position: Vec2::new(-1.0, -1.0)},
126				MyVertex{position: Vec2::new( 1.0, -1.0)},
127				MyVertex{position: Vec2::new(-1.0,  1.0)},
128				MyVertex{position: Vec2::new( 1.0,  1.0)},
129			];
130			let elements = [
131				0u8, 1u8, 2u8,
132				1u8, 3u8, 2u8,
133			];
134			let vertex_buffer = Buffer::new(glcore.clone(), BufferTarget::ArrayBuffer, size_of_val(&vertices), BufferUsage::StaticDraw, vertices.as_ptr() as *const c_void)?;
135			let mut vertex_buffer = BufferVecStatic::<MyVertex>::new(vertex_buffer);
136			vertex_buffer.resize(4, MyVertex::default())?;
137			let element_buffer = Buffer::new(glcore.clone(), BufferTarget::ElementArrayBuffer, size_of_val(&elements), BufferUsage::StaticDraw, elements.as_ptr() as *const c_void)?;
138			let mut element_buffer = BufferVecStatic::<u8>::new(element_buffer);
139			element_buffer.resize(6, 0u8)?;
140			let mesh = StaticMesh::<MyVertex, u8, UnusedType, UnusedType>::new(PrimitiveMode::Triangles, vertex_buffer, Some(element_buffer), None, None);
141			let mesh = Rc::new(MeshWithMaterial::new(mesh, Rc::new(MaterialLegacy::default())));
142			let mesh: Rc<dyn GenericMeshWithMaterial> = mesh;
143			let shader = Rc::new(Shader::new(glcore.clone(),
144				Some("
145#version 330\n
146
147in vec2 position;
148
149void main()
150{
151	gl_Position = vec4(position, 0.0, 1.0);
152}
153				"),
154				None,
155				Some( // **NOTE** The fragment shader below comes from "https://www.shadertoy.com/view/MsjSzz", The author is TDM.
156"#version 330\n
157
158#define LINEAR_ROTATION\n
159
160#define WEIGHT (3.0 / iResolution.x)\n
161const vec3 RED = vec3(1.0,0.0,0.0);
162const vec3 GREEN = vec3(0.0,1.0,0.0);
163const vec3 BLUE = vec3(0.0,0.8,1.0);
164const vec3 WHITE = vec3(1.0,1.0,0.97);
165const vec3 YELLOW = vec3(1.0,1.0,0.0);
166
167uniform vec3 iResolution;
168uniform float iTime;
169
170vec2 fragCoord = gl_FragCoord.xy;
171out vec4 Color;
172
173/* rasterize functions */
174float line(vec2 p, vec2 p0, vec2 p1, float w) {
175	vec2 d = p1 - p0;
176	float t = clamp(dot(d,p-p0) / dot(d,d), 0.0,1.0);
177	vec2 proj = p0 + d * t;
178	float dist = length(p - proj);
179	dist = 1.0/dist*WEIGHT*w;
180	return min(dist*dist,1.0);
181}
182float circle(vec2 p, vec2 c, float r, float w) {
183	float dist = abs(length(p - c)) + r;
184	dist = 1.0/dist*WEIGHT*w;
185	return min(dist*dist,1.0);
186}
187
188/* matrices */
189mat4 getRotMatrix(vec3 a) {
190	vec3 s = sin(a);
191	vec3 c = cos(a);
192	mat4 ret;
193	ret[0] = vec4(c.y*c.z,c.y*s.z,-s.y,0.0);
194	ret[1] = vec4(s.x*s.y*c.z-c.x*s.z,s.x*s.y*s.z+c.x*c.z,s.x*c.y,0.0);
195	ret[2] = vec4(c.x*s.y*c.z+s.x*s.z,c.x*s.y*s.z-s.x*c.z,c.x*c.y,0.0);
196	ret[3] = vec4(0.0,0.0,0.0,1.0);
197	return ret;
198}
199mat4 getPosMatrix(vec3 p) {
200	mat4 ret;
201	ret[0] = vec4(1.0,0.0,0.0,p.x);
202	ret[1] = vec4(0.0,1.0,0.0,p.y);
203	ret[2] = vec4(0.0,0.0,1.0,p.z);
204	ret[3] = vec4(0.0,0.0,0.0,1.0);
205	return ret;
206}
207
208/* utils */
209vec3 mix3(vec3 a, vec3 b, vec3 c, float t) {
210	if(t>0.5) return mix(b,c,t*2.0-1.0);
211	else return mix(a,b,t*2.0);
212}
213vec3 fragment(vec3 p) {
214	float t = sin(p.x*0.8+iTime*0.5)*0.5+0.5;
215	float fog = min(pow(p.z,3.0)*400.0,1.0);
216	return mix3(RED,GREEN,BLUE,t) * fog;
217}
218
219void main() {
220	vec2 uv = fragCoord.xy / iResolution.xy;
221	uv = uv * 2.0 - 1.0;
222	uv.x *= iResolution.x / iResolution.y;
223	/* uv = uv * (1.0 + pow(length(uv)*0.4,0.5)) * 0.6; */
224
225	float line_width = 0.4;
226	float time = iTime * 0.31415;
227	vec3 c = vec3(mix(vec3(0.19,0.13,0.1),vec3(1.0), 0.5*pow(length(uv)*0.5,2.0)));
228	mat4 cam = getPosMatrix(vec3(0.0,0.0,10.0));
229
230#ifdef LINEAR_ROTATION
231	mat4 rot = getRotMatrix(vec3(time,time*0.86,time*0.473));
232#else
233	float p = 0.08;
234	mat4 rot = getRotMatrix(vec3(time		+sin(time*30.0)*p,
235								 time*0.860	+sin(time*20.0)*p*1.24,
236								 time*0.473	+sin(time*10.0)*p));
237#endif
238
239	vec3 instances[18];
240	instances[0] = vec3( 0.0, 0.0,-1.0);
241	instances[1] = vec3(-1.0, 0.0,-1.0);
242	instances[2] = vec3( 1.0, 0.0,-1.0);
243	instances[3] = vec3( 0.0, 1.0,-1.0);
244	instances[4] = vec3( 0.0,-1.0,-1.0);
245	instances[5] = vec3(-1.0, 0.0, 0.0);
246	instances[6] = vec3( 1.0, 0.0, 0.0);
247	instances[7] = vec3( 0.0, 1.0, 0.0);
248	instances[8] = vec3( 0.0,-1.0, 0.0);
249	instances[9] = vec3(-1.0,-1.0, 0.0);
250	instances[10] = vec3( 1.0, 1.0, 0.0);
251	instances[11] = vec3(-1.0, 1.0, 0.0);
252	instances[12] = vec3( 1.0,-1.0, 0.0);
253	instances[13] = vec3( 0.0, 0.0, 1.0);
254	instances[14] = vec3(-1.0, 0.0, 1.0);
255	instances[15] = vec3( 1.0, 0.0, 1.0);
256	instances[16] = vec3( 0.0, 1.0, 1.0);
257	instances[17] = vec3( 0.0,-1.0, 1.0);
258
259	/* box pipeline */
260	for(int dip = 0; dip < 18; dip++) {
261
262		/* input assembly */
263		vec3 vert[8];
264		vert[0] = vec3(-1.0,-1.0, 1.0);
265		vert[1] = vec3(-1.0, 1.0, 1.0);
266		vert[2] = vec3( 1.0, 1.0, 1.0);
267		vert[3] = vec3( 1.0,-1.0, 1.0);
268		vert[4] = vec3(-1.0,-1.0,-1.0);
269		vert[5] = vec3(-1.0, 1.0,-1.0);
270		vert[6] = vec3( 1.0, 1.0,-1.0);
271		vert[7] = vec3( 1.0,-1.0,-1.0);
272
273		/* vertex processing */
274		mat4 pos = getPosMatrix(instances[dip] * 4.0);
275		mat4 mat = pos * rot * cam;
276
277		for(int i = 0; i < 8; i++) {
278
279			/* transform */
280			vert[i] = (vec4(vert[i],1.0) * mat).xyz;
281
282			/* perspective */
283			vert[i].z = 1.0 / vert[i].z;
284			vert[i].xy *= vert[i].z;
285		}
286
287		/* primitive assembly and rasterize */
288		float i;
289		i  = line(uv,vert[0].xy,vert[1].xy,line_width);
290		i += line(uv,vert[1].xy,vert[2].xy,line_width);
291		i += line(uv,vert[2].xy,vert[3].xy,line_width);
292		i += line(uv,vert[3].xy,vert[0].xy,line_width);
293		i += line(uv,vert[4].xy,vert[5].xy,line_width);
294		i += line(uv,vert[5].xy,vert[6].xy,line_width);
295		i += line(uv,vert[6].xy,vert[7].xy,line_width);
296		i += line(uv,vert[7].xy,vert[4].xy,line_width);
297		i += line(uv,vert[0].xy,vert[4].xy,line_width);
298		i += line(uv,vert[1].xy,vert[5].xy,line_width);
299		i += line(uv,vert[2].xy,vert[6].xy,line_width);
300		i += line(uv,vert[3].xy,vert[7].xy,line_width);
301		c += fragment(vert[0]) * min(i,1.0);
302	}
303
304	instances[0] = vec3(-1.0, 1.0,-1.0);
305	instances[1] = vec3( 1.0, 1.0,-1.0);
306	instances[2] = vec3(-1.0,-1.0,-1.0);
307	instances[3] = vec3( 1.0,-1.0,-1.0);
308	instances[4] = vec3(-1.0, 1.0, 1.0);
309	instances[5] = vec3( 1.0, 1.0, 1.0);
310	instances[6] = vec3(-1.0,-1.0, 1.0);
311	instances[7] = vec3( 1.0,-1.0, 1.0);
312
313	/* cicle pipeline */
314	for(int dip = 0; dip < 8; dip++) {
315
316		/* input assembly */
317		vec3 vert = vec3(0.0);
318
319		/* vertex processing */
320		mat4 pos = getPosMatrix(instances[dip] * 4.0);
321		mat4 mat = pos * rot * cam;
322
323		/* transform */
324		vert = (vec4(vert,1.0) * mat).xyz;
325
326		/* perspective */
327		vert.z = 1.0 / vert.z;
328		vert.xy *= vert.z;
329
330		/* rasterize */
331		c += fragment(vert) * circle(uv,vert.xy,-vert.z,line_width);
332	}
333
334	/* fragment */
335	Color = vec4(c, 1.0);
336}
337				")
338			)?);
339			let pipeline = Rc::new(Pipeline::new(glcore.clone(), mesh.clone(), shader.clone())?);
340			Ok(Self {
341				mesh,
342				shader,
343				pipeline,
344			})
345		}
346
347		fn render(&self, glcore: &GLCore, frame_time: f64, width: u32, height: u32) -> Result<(), AppError> {
348			glcore.glViewport(0, 0, width as i32, height as i32)?;
349			glcore.glClearColor(0.0, 0.3, 0.5, 1.0)?;
350			glcore.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)?;
351
352			let shader = self.shader.use_program()?;
353			let time = frame_time as f32;
354			let _ = shader.set_uniform("iResolution", &Vec3::new(width as f32, height as f32, 0.0));
355			let _ = shader.set_uniform("iTime", &time);
356			shader.unuse();
357
358			let p_bind = self.pipeline.bind()?;
359			p_bind.draw(None)?;
360			p_bind.unbind();
361			Ok(())
362		}
363	}
364
365	impl AppInstance {
366		pub fn new() -> Result<Self, AppError> {
367			let mut glfw = match glfw::init_no_callbacks() {
368				Ok(glfw) => glfw,
369				Err(_) => return Err(AppError::GLFWInitErr), // According to the spec, `glfw::init_no_callbacks()` won't return `glfw::InitError::AlreadyInitialized`
370			};
371			let (mut window, events) = glfw.create_window(1024, 768, "GLFW Window", glfw::WindowMode::Windowed).ok_or(AppError::GLFWCreateWindowFailed)?;
372			window.set_key_polling(true);
373			window.make_current();
374			glfw.set_swap_interval(SwapInterval::Adaptive);
375			let glcore = Rc::new(GLCore::new(|proc_name|window.get_proc_address(proc_name))?);
376			let renderer = Some(Renderer::new(glcore.clone())?);
377			Ok(Self {
378				renderer,
379				glcore,
380				events,
381				window,
382				glfw,
383			})
384		}
385
386		pub fn run(&mut self, timeout: Option<f64>) -> ExitCode {
387			let start_debug_time = self.glfw.get_time();
388			while !self.window.should_close() {
389				let time_cur_frame = self.glfw.get_time();
390
391				if let Some(renderer) = self.renderer.as_ref() {
392					let (width, height) = self.window.get_framebuffer_size();
393					renderer.render(&self.glcore, time_cur_frame, width as u32, height as u32).unwrap();
394					self.window.swap_buffers();
395				}
396
397				self.glfw.poll_events();
398				for (_, event) in glfw::flush_messages(&self.events) {
399					match event {
400						glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
401							self.window.set_should_close(true)
402						}
403						_ => {}
404					}
405				}
406
407				if let Some(timeout) = timeout {
408					if time_cur_frame - start_debug_time >= timeout {
409						self.window.set_should_close(true)
410					}
411				}
412			}
413
414			ExitCode::from(0)
415		}
416	}
417
418	#[test]
419	fn test_glfw() -> ExitCode {
420		const DEBUG_TIME: f64 = 10.0;
421		let mut test_app = match AppInstance::new() {
422			Ok(app) => app,
423			Err(e) => {
424				eprintln!("GLFW App Initialize failed: {:?}", e);
425				return ExitCode::from(2)
426			}
427		};
428		test_app.run(Some(DEBUG_TIME))
429	}
430}