asi_opengl/
lib.rs

1// Copyright Jeron A. Lau 2018.
2// Dual-licensed under either the MIT License or the Boost Software License,
3// Version 1.0.  (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#[macro_use]
7extern crate dl_api;
8#[cfg(windows)]
9extern crate winapi;
10
11macro_rules! gl {
12	($o: expr, $a: stmt) => (
13		unsafe {
14			let a = { $a };
15			$o.error();
16			a
17		}
18	)
19}
20
21use std::os::raw::c_void;
22use std::rc::Rc;
23use std::cell::RefCell;
24
25mod loader;
26mod types;
27
28use types::*;
29
30mod texture;
31mod vertex_data;
32mod uniform_data;
33mod program;
34mod buffer;
35
36pub use vertex_data::VertexData;
37pub use uniform_data::UniformData;
38pub use program::Program;
39pub use buffer::Buffer;
40pub use texture::Texture;
41
42/// Features that can be enabled and disabled.
43#[repr(u32)]
44pub enum Feature {
45	Dither = 0x0BD0,
46	CullFace = 0x0B44,
47	Blend = 0x0BE2,
48	DepthTest = 0x0B71,
49	StencilTest = 0x0B90,
50}
51
52/// What the vertices represent
53#[repr(u32)]
54pub enum Topology {
55	Points = 0x0000,
56	Lines = 0x0001,
57	LineLoop = 0x0002,
58	LineStrip = 0x0003,
59	Triangles = 0x0004,
60	TriangleStrip = 0x0005,
61	TriangleFan = 0x0006,
62}
63
64/// The OpenGL context.
65#[derive(Clone)] pub struct OpenGL(Rc<RefCell<OpenGLContext>>);
66
67/// The OpenGL builder.
68pub struct OpenGLBuilder {
69	lib: loader::Lib,
70	display: loader::Display,
71}
72
73impl OpenGLBuilder {
74	/// Begin the building.
75	pub fn new() -> Option<(OpenGLBuilder, i32)> {
76		if let Ok(lib) = loader::Lib::new() {
77			let (mut display, visual_id) = lib.init();
78
79			Some((OpenGLBuilder {
80				lib,
81				display,
82			}, visual_id))
83		} else {
84			None
85		}
86	}
87
88	/// Complete the building
89	pub fn to_opengl(mut self, window: EGLNativeWindowType) -> OpenGL {
90		self.lib.init2(&mut self.display, window);
91
92		OpenGL(Rc::new(RefCell::new(OpenGLContext {
93			// FFI OpenGL Functions.
94			clear: self.lib.load(b"glClear\0"),
95			clear_color: self.lib.load(b"glClearColor\0"),
96			disable: self.lib.load(b"glDisable\0"),
97			enable: self.lib.load(b"glEnable\0"),
98			#[cfg(debug_assertions)]
99			get_error: self.lib.load(b"glGetError\0"),
100			blend_func_separate:
101				self.lib.load(b"glBlendFuncSeparate\0"),
102			create_shader: self.lib.load(b"glCreateShader\0"),
103			shader_source: self.lib.load(b"glShaderSource\0"),
104			compile_shader: self.lib.load(b"glCompileShader\0"),
105			create_program: self.lib.load(b"glCreateProgram\0"),
106			attach_shader: self.lib.load(b"glAttachShader\0"),
107			link_program: self.lib.load(b"glLinkProgram\0"),
108			uniform: self.lib.load(b"glGetUniformLocation\0"),
109			gen_buffers: self.lib.load(b"glGenBuffers\0"),
110			bind_buffer: self.lib.load(b"glBindBuffer\0"),
111			buffer_data: self.lib.load(b"glBufferData\0"),
112			vdata: self.lib.load(b"glGetAttribLocation\0"),
113			#[cfg(debug_assertions)]
114			get_shader: self.lib.load(b"glGetShaderiv\0"),
115			#[cfg(debug_assertions)]
116			info_log: self.lib.load(b"glGetShaderInfoLog\0"),
117			draw_arrays: self.lib.load(b"glDrawArrays\0"),
118			use_program: self.lib.load(b"glUseProgram\0"),
119			uniform_mat4: self.lib.load(b"glUniformMatrix4fv\0"),
120			uniform_int1: self.lib.load(b"glUniform1i\0"),
121			uniform_vec1: self.lib.load(b"glUniform1f\0"),
122			uniform_vec2: self.lib.load(b"glUniform2f\0"),
123			uniform_vec3: self.lib.load(b"glUniform3f\0"),
124			uniform_vec4: self.lib.load(b"glUniform4f\0"),
125			bind_texture: self.lib.load(b"glBindTexture\0"),
126			vertex_attrib: self.lib.load(b"glVertexAttribPointer\0"),
127			gen_textures: self.lib.load(b"glGenTextures\0"),
128			tex_params: self.lib.load(b"glTexParameteri\0"),
129			tex_image: self.lib.load(b"glTexImage2D\0"),
130			tex_subimage: self.lib.load(b"glTexSubImage2D\0"),
131			enable_vdata: self.lib.load(b"glEnableVertexAttribArray\0"),
132			viewport: self.lib.load(b"glViewport\0"),
133			gen_mipmap: self.lib.load(b"glGenerateMipmap\0"),
134			detach_shader: self.lib.load(b"glDetachShader\0"),
135			delete_program: self.lib.load(b"glDeleteProgram\0"),
136			delete_buffer: self.lib.load(b"glDeleteBuffers\0"),
137			delete_texture: self.lib.load(b"glDeleteTextures\0"),
138			stencil_op: self.lib.load(b"glStencilOp\0"),
139			stencil_func: self.lib.load(b"glStencilFunc\0"),
140			// Other
141			display: self.display,
142			lib: self.lib,
143		})))
144	}
145}
146
147/// The OpenGL context.
148struct OpenGLContext {
149	#[allow(unused)] // is used at drop.
150	lib: loader::Lib,
151	display: loader::Display,
152	clear: unsafe extern "system" fn(GLbitfield) -> (),
153	clear_color: unsafe extern "system" fn(GLfloat, GLfloat, GLfloat,
154		GLfloat) -> (),
155	disable: unsafe extern "system" fn(GLenum) -> (),
156	enable: unsafe extern "system" fn(GLenum) -> (),
157	#[cfg(debug_assertions)] get_error: unsafe extern "system" fn() -> GLenum,
158	blend_func_separate: unsafe extern "system" fn(GLenum, GLenum, GLenum,
159		GLenum) -> (),
160	create_shader: unsafe extern "system" fn(GLenum) -> GLuint,
161	shader_source: unsafe extern "system" fn(GLuint, GLsizei,
162		*const *const GLchar, *const GLint) -> (),
163	compile_shader: unsafe extern "system" fn(GLuint) -> (),
164	create_program: unsafe extern "system" fn() -> GLuint,
165	attach_shader: unsafe extern "system" fn(GLuint, GLuint) -> (),
166	link_program: unsafe extern "system" fn(GLuint) -> (),
167	uniform: unsafe extern "system" fn(GLuint, *const GLchar) -> GLint,
168	gen_buffers: unsafe extern "system" fn(GLsizei, *mut GLuint) -> (),
169	bind_buffer: unsafe extern "system" fn(GLenum, GLuint) -> (),
170	buffer_data: unsafe extern "system" fn(GLenum, GLsizeiptr,
171		*const c_void, GLenum) -> (),
172	vdata: unsafe extern "system" fn(GLuint, *const GLchar) -> GLint,
173	#[cfg(debug_assertions)]
174	get_shader: unsafe extern "system" fn(GLuint, GLenum, *mut GLint) -> (),
175	#[cfg(debug_assertions)]
176	info_log: unsafe extern "system" fn(GLuint, GLsizei, *mut GLsizei,
177		*mut GLchar) -> (),
178	draw_arrays: unsafe extern "system" fn(GLenum, GLint, GLsizei) -> (),
179	use_program: unsafe extern "system" fn(GLuint) -> (),
180	uniform_mat4: unsafe extern "system" fn(GLint, GLsizei, GLboolean,
181		*const GLfloat) -> (),
182	uniform_int1: unsafe extern "system" fn(GLint, GLint) -> (),
183	uniform_vec1: unsafe extern "system" fn(GLint, GLfloat) -> (),
184	uniform_vec2: unsafe extern "system" fn(GLint, GLfloat, GLfloat) -> (),
185	uniform_vec3: unsafe extern "system" fn(GLint, GLfloat, GLfloat, GLfloat)
186		-> (),
187	uniform_vec4: unsafe extern "system" fn(GLint, GLfloat, GLfloat, GLfloat,
188		GLfloat) -> (),
189	bind_texture: unsafe extern "system" fn(GLenum, GLuint) -> (),
190	vertex_attrib: unsafe extern "system" fn(GLuint, GLint, GLenum,
191		GLboolean, GLsizei, *const c_void) -> (),
192	gen_textures: unsafe extern "system" fn(GLsizei, *mut GLuint) -> (),
193	tex_params: unsafe extern "system" fn(GLenum, GLenum, GLint) -> (),
194	tex_image: unsafe extern "system" fn(GLenum, GLint, GLint, GLsizei,
195		GLsizei, GLint, GLenum, GLenum, *const c_void) -> (),
196	tex_subimage: unsafe extern "system" fn(GLenum, GLint, GLint, GLint, GLsizei,
197		GLsizei, GLenum, GLenum, *const c_void) -> (),
198	enable_vdata: unsafe extern "system" fn(GLuint) -> (),
199	viewport: unsafe extern "system" fn(GLint, GLint, GLsizei, GLsizei) -> (),
200	gen_mipmap: unsafe extern "system" fn(GLenum) -> (),
201	detach_shader: unsafe extern "system" fn(GLuint, GLuint) -> (),
202	delete_program: unsafe extern "system" fn(GLuint) -> (),
203	delete_buffer: unsafe extern "system" fn(GLsizei, *const GLuint) -> (),
204	delete_texture: unsafe extern "system" fn(GLsizei, *const GLuint) -> (),
205	stencil_op: unsafe extern "system" fn(GLenum, GLenum, GLenum) -> (),
206	stencil_func: unsafe extern "system" fn(GLenum, GLint, GLuint) -> (),
207}
208
209impl OpenGL {
210	/// Set the color for `clear`.
211	pub fn color(&self, r: f32, g: f32, b: f32) {
212		gl!(self, (self.get().clear_color)(r, g, b, 1.0));
213	}
214
215	/// Update the screen
216	pub fn update(&self) {
217		// Swap Display
218		self.get().display.swap(
219			#[cfg(not(target_os = "windows"))]
220			&self.get().lib
221		);
222		// Clear Color & Depth
223		gl!(self, (self.get().clear)(0x00000100 | 0x00004000));
224	}
225
226	/// Enable something
227	pub fn enable(&self, what: Feature) {
228		gl!(self, (self.get().enable)(what as u32))
229	}
230
231	/// Disable something
232	pub fn disable(&self, what: Feature) {
233		gl!(self, (self.get().disable)(what as u32))
234	}
235
236	/// Configure blending
237	pub fn blend(&self) {
238		const GL_SRC_ALPHA: u32 = 0x0302;
239		const GL_ONE_MINUS_SRC_ALPHA: u32 = 0x0303;
240		const GL_DST_ALPHA: u32 = 0x0304;
241
242		gl!(self, (self.get().blend_func_separate)(
243			GL_SRC_ALPHA,
244			GL_ONE_MINUS_SRC_ALPHA,
245			GL_SRC_ALPHA,
246			GL_DST_ALPHA
247		));
248	}
249
250	/// Configure stencil testing
251	pub fn stencil(&self) {
252		gl!(self, (self.get().stencil_op)(
253			0x150A, 0x150A, 0x150A // GL_INVERT
254		));
255
256		gl!(self, (self.get().stencil_func)(
257			0x0205, // GL_NOTEQUAL
258			0, // ≠ 0
259			0xffffffff // Mask
260		));
261	}
262
263	/// Create a new texture.
264	pub fn texture(&self) -> Texture {
265		Texture::new(self)
266	}
267
268	/// Update the viewport.
269	pub fn viewport(&self, w: u16, h: u16) {
270		gl!(self, (self.get().viewport)(0,0,w as GLsizei,h as GLsizei));
271	}
272
273	#[cfg(not(debug_assertions))]
274	unsafe fn error(&self) { /* Do nothing in release mode for speed. */ }
275
276	#[cfg(debug_assertions)]
277	unsafe fn error(&self) {
278		match (self.get().get_error)() {
279			0 => return, // NO_ERROR
280			0x0500 => panic!("OpenGL Error: Invalid enum"),
281			0x0501 => panic!("OpenGL Error: Invalid value"),
282			0x0502 => panic!("OpenGL Error: Invalid operation"),
283			0x0503 => panic!("OpenGL Error: Stack overflow"),
284			0x0504 => panic!("OpenGL Error: Stack underflow"),
285			0x0505 => panic!("OpenGL Error: Out of memory"),
286			_ => panic!("OpenGL Error: Unknown"),
287		}
288	}
289
290	fn get(&self) -> std::cell::Ref<OpenGLContext> {
291		self.0.borrow()
292	}
293}