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	}
84
85	#[derive(Debug)]
86	struct Renderer {
87		pipeline: Rc<Pipeline<MyVertex, UnusedType>>,
88		shader: Rc<Shader>,
89		mesh: Rc<dyn GenericMeshWithMaterial>,
90	}
91
92	#[derive(Debug)]
93	struct AppInstance {
94		renderer: Option<Renderer>,
95		glcore: Rc<GLCore>,
96		events: GlfwReceiver<(f64, WindowEvent)>,
97		window: PWindow,
98		glfw: Glfw,
99	}
100
101	impl Renderer {
102		fn new(glcore: Rc<GLCore>) -> Self {
103			let vertices = [
104				MyVertex{position: Vec2::new(-1.0, -1.0)},
105				MyVertex{position: Vec2::new( 1.0, -1.0)},
106				MyVertex{position: Vec2::new(-1.0,  1.0)},
107				MyVertex{position: Vec2::new( 1.0,  1.0)},
108			];
109			let elements = [
110				0u8, 1u8, 2u8,
111				1u8, 3u8, 2u8,
112			];
113			let vertex_buffer = Buffer::new(glcore.clone(), BufferTarget::ArrayBuffer, size_of_val(&vertices), BufferUsage::StaticDraw, vertices.as_ptr() as *const c_void);
114			let mut vertex_buffer = BufferVecStatic::<MyVertex>::new(glcore.clone(), vertex_buffer);
115			vertex_buffer.resize(4, MyVertex::default());
116			let element_buffer = Buffer::new(glcore.clone(), BufferTarget::ElementArrayBuffer, size_of_val(&elements), BufferUsage::StaticDraw, elements.as_ptr() as *const c_void);
117			let mut element_buffer = BufferVecStatic::<u8>::new(glcore.clone(), element_buffer);
118			element_buffer.resize(6, 0u8);
119			let mesh = StaticMesh::<MyVertex, u8, UnusedType, UnusedType>::new(PrimitiveMode::Triangles, vertex_buffer, Some(element_buffer), None, None);
120			let mesh = Rc::new(MeshWithMaterial::new(mesh, Rc::new(MaterialLegacy::default())));
121			let mesh: Rc<dyn GenericMeshWithMaterial> = mesh;
122			let shader = Rc::new(Shader::new(glcore.clone(),
123				Some("
124#version 330\n
125
126in vec2 position;
127
128void main()
129{
130	gl_Position = vec4(position, 0.0, 1.0);
131}
132				"),
133				None,
134				Some( // **NOTE** The fragment shader below comes from "https://www.shadertoy.com/view/MsjSzz", The author is TDM.
135"#version 330\n
136
137#define LINEAR_ROTATION\n
138
139#define WEIGHT (3.0 / iResolution.x)\n
140const vec3 RED = vec3(1.0,0.0,0.0);
141const vec3 GREEN = vec3(0.0,1.0,0.0);
142const vec3 BLUE = vec3(0.0,0.8,1.0);
143const vec3 WHITE = vec3(1.0,1.0,0.97);
144const vec3 YELLOW = vec3(1.0,1.0,0.0);
145
146uniform vec3 iResolution;
147uniform float iTime;
148
149vec2 fragCoord = gl_FragCoord.xy;
150out vec4 Color;
151
152/* rasterize functions */
153float line(vec2 p, vec2 p0, vec2 p1, float w) {
154	vec2 d = p1 - p0;
155	float t = clamp(dot(d,p-p0) / dot(d,d), 0.0,1.0);
156	vec2 proj = p0 + d * t;
157	float dist = length(p - proj);
158	dist = 1.0/dist*WEIGHT*w;
159	return min(dist*dist,1.0);
160}
161float circle(vec2 p, vec2 c, float r, float w) {
162	float dist = abs(length(p - c)) + r;
163	dist = 1.0/dist*WEIGHT*w;
164	return min(dist*dist,1.0);
165}
166
167/* matrices */
168mat4 getRotMatrix(vec3 a) {
169	vec3 s = sin(a);
170	vec3 c = cos(a);
171	mat4 ret;
172	ret[0] = vec4(c.y*c.z,c.y*s.z,-s.y,0.0);
173	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);
174	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);
175	ret[3] = vec4(0.0,0.0,0.0,1.0);
176	return ret;
177}
178mat4 getPosMatrix(vec3 p) {
179	mat4 ret;
180	ret[0] = vec4(1.0,0.0,0.0,p.x);
181	ret[1] = vec4(0.0,1.0,0.0,p.y);
182	ret[2] = vec4(0.0,0.0,1.0,p.z);
183	ret[3] = vec4(0.0,0.0,0.0,1.0);
184	return ret;
185}
186
187/* utils */
188vec3 mix3(vec3 a, vec3 b, vec3 c, float t) {
189	if(t>0.5) return mix(b,c,t*2.0-1.0);
190	else return mix(a,b,t*2.0);
191}
192vec3 fragment(vec3 p) {
193	float t = sin(p.x*0.8+iTime*0.5)*0.5+0.5;
194	float fog = min(pow(p.z,3.0)*400.0,1.0);
195	return mix3(RED,GREEN,BLUE,t) * fog;
196}
197
198void main() {
199	vec2 uv = fragCoord.xy / iResolution.xy;
200	uv = uv * 2.0 - 1.0;
201	uv.x *= iResolution.x / iResolution.y;
202	/* uv = uv * (1.0 + pow(length(uv)*0.4,0.5)) * 0.6; */
203
204	float line_width = 0.4;
205	float time = iTime * 0.31415;
206	vec3 c = vec3(mix(vec3(0.19,0.13,0.1),vec3(1.0), 0.5*pow(length(uv)*0.5,2.0)));
207	mat4 cam = getPosMatrix(vec3(0.0,0.0,10.0));
208
209#ifdef LINEAR_ROTATION
210	mat4 rot = getRotMatrix(vec3(time,time*0.86,time*0.473));
211#else
212	float p = 0.08;
213	mat4 rot = getRotMatrix(vec3(time		+sin(time*30.0)*p,
214								 time*0.860	+sin(time*20.0)*p*1.24,
215								 time*0.473	+sin(time*10.0)*p));
216#endif
217
218	vec3 instances[18];
219	instances[0] = vec3( 0.0, 0.0,-1.0);
220	instances[1] = vec3(-1.0, 0.0,-1.0);
221	instances[2] = vec3( 1.0, 0.0,-1.0);
222	instances[3] = vec3( 0.0, 1.0,-1.0);
223	instances[4] = vec3( 0.0,-1.0,-1.0);
224	instances[5] = vec3(-1.0, 0.0, 0.0);
225	instances[6] = vec3( 1.0, 0.0, 0.0);
226	instances[7] = vec3( 0.0, 1.0, 0.0);
227	instances[8] = vec3( 0.0,-1.0, 0.0);
228	instances[9] = vec3(-1.0,-1.0, 0.0);
229	instances[10] = vec3( 1.0, 1.0, 0.0);
230	instances[11] = vec3(-1.0, 1.0, 0.0);
231	instances[12] = vec3( 1.0,-1.0, 0.0);
232	instances[13] = vec3( 0.0, 0.0, 1.0);
233	instances[14] = vec3(-1.0, 0.0, 1.0);
234	instances[15] = vec3( 1.0, 0.0, 1.0);
235	instances[16] = vec3( 0.0, 1.0, 1.0);
236	instances[17] = vec3( 0.0,-1.0, 1.0);
237
238	/* box pipeline */
239	for(int dip = 0; dip < 18; dip++) {
240
241		/* input assembly */
242		vec3 vert[8];
243		vert[0] = vec3(-1.0,-1.0, 1.0);
244		vert[1] = vec3(-1.0, 1.0, 1.0);
245		vert[2] = vec3( 1.0, 1.0, 1.0);
246		vert[3] = vec3( 1.0,-1.0, 1.0);
247		vert[4] = vec3(-1.0,-1.0,-1.0);
248		vert[5] = vec3(-1.0, 1.0,-1.0);
249		vert[6] = vec3( 1.0, 1.0,-1.0);
250		vert[7] = vec3( 1.0,-1.0,-1.0);
251
252		/* vertex processing */
253		mat4 pos = getPosMatrix(instances[dip] * 4.0);
254		mat4 mat = pos * rot * cam;
255
256		for(int i = 0; i < 8; i++) {
257
258			/* transform */
259			vert[i] = (vec4(vert[i],1.0) * mat).xyz;
260
261			/* perspective */
262			vert[i].z = 1.0 / vert[i].z;
263			vert[i].xy *= vert[i].z;
264		}
265
266		/* primitive assembly and rasterize */
267		float i;
268		i  = line(uv,vert[0].xy,vert[1].xy,line_width);
269		i += line(uv,vert[1].xy,vert[2].xy,line_width);
270		i += line(uv,vert[2].xy,vert[3].xy,line_width);
271		i += line(uv,vert[3].xy,vert[0].xy,line_width);
272		i += line(uv,vert[4].xy,vert[5].xy,line_width);
273		i += line(uv,vert[5].xy,vert[6].xy,line_width);
274		i += line(uv,vert[6].xy,vert[7].xy,line_width);
275		i += line(uv,vert[7].xy,vert[4].xy,line_width);
276		i += line(uv,vert[0].xy,vert[4].xy,line_width);
277		i += line(uv,vert[1].xy,vert[5].xy,line_width);
278		i += line(uv,vert[2].xy,vert[6].xy,line_width);
279		i += line(uv,vert[3].xy,vert[7].xy,line_width);
280		c += fragment(vert[0]) * min(i,1.0);
281	}
282
283	instances[0] = vec3(-1.0, 1.0,-1.0);
284	instances[1] = vec3( 1.0, 1.0,-1.0);
285	instances[2] = vec3(-1.0,-1.0,-1.0);
286	instances[3] = vec3( 1.0,-1.0,-1.0);
287	instances[4] = vec3(-1.0, 1.0, 1.0);
288	instances[5] = vec3( 1.0, 1.0, 1.0);
289	instances[6] = vec3(-1.0,-1.0, 1.0);
290	instances[7] = vec3( 1.0,-1.0, 1.0);
291
292	/* cicle pipeline */
293	for(int dip = 0; dip < 8; dip++) {
294
295		/* input assembly */
296		vec3 vert = vec3(0.0);
297
298		/* vertex processing */
299		mat4 pos = getPosMatrix(instances[dip] * 4.0);
300		mat4 mat = pos * rot * cam;
301
302		/* transform */
303		vert = (vec4(vert,1.0) * mat).xyz;
304
305		/* perspective */
306		vert.z = 1.0 / vert.z;
307		vert.xy *= vert.z;
308
309		/* rasterize */
310		c += fragment(vert) * circle(uv,vert.xy,-vert.z,line_width);
311	}
312
313	/* fragment */
314	Color = vec4(c, 1.0);
315}
316				")
317			).unwrap());
318			let pipeline = Rc::new(Pipeline::new(glcore.clone(), mesh.clone(), shader.clone()));
319			Self {
320				mesh,
321				shader,
322				pipeline,
323			}
324		}
325
326		fn render(&self, glcore: &GLCore, frame_time: f64, width: u32, height: u32) {
327			glcore.glViewport(0, 0, width as i32, height as i32);
328			glcore.glClearColor(0.0, 0.3, 0.5, 1.0);
329			glcore.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
330
331			let shader = self.shader.use_program();
332			let time = frame_time as f32;
333			let _ = shader.set_uniform("iResolution", &Vec3::new(width as f32, height as f32, 0.0));
334			let _ = shader.set_uniform("iTime", &time);
335			shader.unuse();
336
337			let p_bind = self.pipeline.bind();
338			p_bind.draw(None);
339			p_bind.unbind();
340		}
341	}
342
343	impl AppInstance {
344		pub fn new() -> Result<Self, AppError> {
345			let mut glfw = match glfw::init_no_callbacks() {
346				Ok(glfw) => glfw,
347				Err(_) => return Err(AppError::GLFWInitErr), // According to the spec, `glfw::init_no_callbacks()` won't return `glfw::InitError::AlreadyInitialized`
348			};
349			let (mut window, events) = glfw.create_window(1024, 768, "GLFW Window", glfw::WindowMode::Windowed).ok_or(AppError::GLFWCreateWindowFailed)?;
350			window.set_key_polling(true);
351			window.make_current();
352			glfw.set_swap_interval(SwapInterval::Adaptive);
353			let glcore = Rc::new(GLCore::new(|proc_name|window.get_proc_address(proc_name)));
354			let renderer = Some(Renderer::new(glcore.clone()));
355			Ok(Self {
356				renderer,
357				glcore,
358				events,
359				window,
360				glfw,
361			})
362		}
363
364		pub fn run(&mut self, timeout: Option<f64>) -> ExitCode {
365			let start_debug_time = self.glfw.get_time();
366			while !self.window.should_close() {
367				let time_cur_frame = self.glfw.get_time();
368
369				if let Some(renderer) = self.renderer.as_ref() {
370					let (width, height) = self.window.get_framebuffer_size();
371					renderer.render(&self.glcore, time_cur_frame, width as u32, height as u32);
372					self.window.swap_buffers();
373				}
374
375				self.glfw.poll_events();
376				for (_, event) in glfw::flush_messages(&self.events) {
377					match event {
378						glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
379							self.window.set_should_close(true)
380						}
381						_ => {}
382					}
383				}
384
385				if let Some(timeout) = timeout {
386					if time_cur_frame - start_debug_time >= timeout {
387						self.window.set_should_close(true)
388					}
389				}
390			}
391
392			ExitCode::from(0)
393		}
394	}
395
396	#[test]
397	fn test_glfw() -> ExitCode {
398		const DEBUG_TIME: f64 = 10.0;
399		let mut test_app = match AppInstance::new() {
400			Ok(app) => app,
401			Err(e) => {
402				eprintln!("GLFW App Initialize failed: {:?}", e);
403				return ExitCode::from(2)
404			}
405		};
406		test_app.run(Some(DEBUG_TIME))
407	}
408}