1use super::*;
2use std::collections::HashMap;
3use std::sync::Arc;
4use std::sync::RwLock;
5
6#[doc(hidden)]
7pub use crate::context::HasContext;
8
9#[derive(Clone)]
15pub struct Context {
16 context: Arc<crate::context::Context>,
17 pub(super) vao: crate::context::VertexArray,
18 pub programs: Arc<RwLock<HashMap<Vec<u8>, Program>>>,
20}
21
22impl Context {
23 pub fn from_gl_context(context: Arc<crate::context::Context>) -> Result<Self, CoreError> {
30 unsafe {
31 if !context.version().is_embedded {
32 context.enable(crate::context::TEXTURE_CUBE_MAP_SEAMLESS);
34 }
35 context.pixel_store_i32(crate::context::UNPACK_ALIGNMENT, 1);
36 context.pixel_store_i32(crate::context::PACK_ALIGNMENT, 1);
37 };
38 let c = unsafe {
39 let vao = context
41 .create_vertex_array()
42 .map_err(CoreError::ContextCreation)?;
43 Self {
44 context,
45 vao,
46 programs: Arc::new(RwLock::new(HashMap::new())),
47 }
48 };
49 Ok(c)
50 }
51
52 pub fn set_scissor(&self, scissor_box: ScissorBox) {
56 unsafe {
57 if scissor_box.width > 0 && scissor_box.height > 0 {
58 self.enable(crate::context::SCISSOR_TEST);
59 self.scissor(
60 scissor_box.x,
61 scissor_box.y,
62 scissor_box.width as i32,
63 scissor_box.height as i32,
64 );
65 } else {
66 self.disable(crate::context::SCISSOR_TEST);
67 }
68 }
69 }
70
71 pub fn set_viewport(&self, viewport: Viewport) {
75 unsafe {
76 self.viewport(
77 viewport.x,
78 viewport.y,
79 viewport.width as i32,
80 viewport.height as i32,
81 );
82 }
83 }
84
85 pub fn set_cull(&self, cull: Cull) {
89 unsafe {
90 match cull {
91 Cull::None => {
92 self.disable(crate::context::CULL_FACE);
93 }
94 Cull::Back => {
95 self.enable(crate::context::CULL_FACE);
96 self.cull_face(crate::context::BACK);
97 }
98 Cull::Front => {
99 self.enable(crate::context::CULL_FACE);
100 self.cull_face(crate::context::FRONT);
101 }
102 Cull::FrontAndBack => {
103 self.enable(crate::context::CULL_FACE);
104 self.cull_face(crate::context::FRONT_AND_BACK);
105 }
106 }
107 }
108 }
109
110 pub fn set_write_mask(&self, write_mask: WriteMask) {
114 unsafe {
115 self.color_mask(
116 write_mask.red,
117 write_mask.green,
118 write_mask.blue,
119 write_mask.alpha,
120 );
121 self.depth_mask(write_mask.depth);
122 }
123 }
124
125 pub fn set_depth_test(&self, depth_test: DepthTest) {
129 unsafe {
130 self.enable(crate::context::DEPTH_TEST);
131 match depth_test {
132 DepthTest::Never => {
133 self.depth_func(crate::context::NEVER);
134 }
135 DepthTest::Less => {
136 self.depth_func(crate::context::LESS);
137 }
138 DepthTest::Equal => {
139 self.depth_func(crate::context::EQUAL);
140 }
141 DepthTest::LessOrEqual => {
142 self.depth_func(crate::context::LEQUAL);
143 }
144 DepthTest::Greater => {
145 self.depth_func(crate::context::GREATER);
146 }
147 DepthTest::NotEqual => {
148 self.depth_func(crate::context::NOTEQUAL);
149 }
150 DepthTest::GreaterOrEqual => {
151 self.depth_func(crate::context::GEQUAL);
152 }
153 DepthTest::Always => {
154 self.depth_func(crate::context::ALWAYS);
155 }
156 }
157 }
158 }
159
160 pub fn set_blend(&self, blend: Blend) {
164 unsafe {
165 if let Blend::Enabled {
166 source_rgb_multiplier,
167 source_alpha_multiplier,
168 destination_rgb_multiplier,
169 destination_alpha_multiplier,
170 rgb_equation,
171 alpha_equation,
172 } = blend
173 {
174 self.enable(crate::context::BLEND);
175 self.blend_func_separate(
176 Self::blend_const_from_multiplier(source_rgb_multiplier),
177 Self::blend_const_from_multiplier(destination_rgb_multiplier),
178 Self::blend_const_from_multiplier(source_alpha_multiplier),
179 Self::blend_const_from_multiplier(destination_alpha_multiplier),
180 );
181 self.blend_equation_separate(
182 Self::blend_const_from_equation(rgb_equation),
183 Self::blend_const_from_equation(alpha_equation),
184 );
185 } else {
186 self.disable(crate::context::BLEND);
187 }
188 }
189 }
190
191 fn blend_const_from_multiplier(multiplier: BlendMultiplierType) -> u32 {
192 match multiplier {
193 BlendMultiplierType::Zero => crate::context::ZERO,
194 BlendMultiplierType::One => crate::context::ONE,
195 BlendMultiplierType::SrcColor => crate::context::SRC_COLOR,
196 BlendMultiplierType::OneMinusSrcColor => crate::context::ONE_MINUS_SRC_COLOR,
197 BlendMultiplierType::DstColor => crate::context::DST_COLOR,
198 BlendMultiplierType::OneMinusDstColor => crate::context::ONE_MINUS_DST_COLOR,
199 BlendMultiplierType::SrcAlpha => crate::context::SRC_ALPHA,
200 BlendMultiplierType::OneMinusSrcAlpha => crate::context::ONE_MINUS_SRC_ALPHA,
201 BlendMultiplierType::DstAlpha => crate::context::DST_ALPHA,
202 BlendMultiplierType::OneMinusDstAlpha => crate::context::ONE_MINUS_DST_ALPHA,
203 BlendMultiplierType::SrcAlphaSaturate => crate::context::SRC_ALPHA_SATURATE,
204 }
205 }
206 fn blend_const_from_equation(equation: BlendEquationType) -> u32 {
207 match equation {
208 BlendEquationType::Add => crate::context::FUNC_ADD,
209 BlendEquationType::Subtract => crate::context::FUNC_SUBTRACT,
210 BlendEquationType::ReverseSubtract => crate::context::FUNC_REVERSE_SUBTRACT,
211 BlendEquationType::Min => crate::context::MIN,
212 BlendEquationType::Max => crate::context::MAX,
213 }
214 }
215
216 pub fn set_render_states(&self, render_states: RenderStates) {
220 self.set_cull(render_states.cull);
221 self.set_write_mask(render_states.write_mask);
222 if !render_states.write_mask.depth && render_states.depth_test == DepthTest::Always {
223 unsafe { self.disable(crate::context::DEPTH_TEST) }
224 } else {
225 self.set_depth_test(render_states.depth_test);
226 }
227 self.set_blend(render_states.blend);
228 }
229
230 pub fn error_check(&self) -> Result<(), CoreError> {
235 self.framebuffer_check()?;
236 unsafe {
237 let e = self.get_error();
238 if e != crate::context::NO_ERROR {
239 Err(CoreError::ContextError(
240 match e {
241 crate::context::INVALID_ENUM => "Invalid enum",
242 crate::context::INVALID_VALUE => "Invalid value",
243 crate::context::INVALID_OPERATION => "Invalid operation",
244 crate::context::INVALID_FRAMEBUFFER_OPERATION => {
245 "Invalid framebuffer operation"
246 }
247 crate::context::OUT_OF_MEMORY => "Out of memory",
248 crate::context::STACK_OVERFLOW => "Stack overflow",
249 crate::context::STACK_UNDERFLOW => "Stack underflow",
250 _ => "Unknown",
251 }
252 .to_string(),
253 ))?;
254 }
255 }
256 Ok(())
257 }
258
259 fn framebuffer_check(&self) -> Result<(), CoreError> {
260 unsafe {
261 match self.check_framebuffer_status(crate::context::FRAMEBUFFER) {
262 crate::context::FRAMEBUFFER_COMPLETE => Ok(()),
263 crate::context::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => Err(CoreError::ContextError(
264 "FRAMEBUFFER_INCOMPLETE_ATTACHMENT".to_string(),
265 )),
266 crate::context::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => Err(CoreError::ContextError(
267 "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER".to_string(),
268 )),
269 crate::context::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
270 Err(CoreError::ContextError(
271 "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT".to_string(),
272 ))
273 }
274 crate::context::FRAMEBUFFER_UNSUPPORTED => Err(CoreError::ContextError(
275 "FRAMEBUFFER_UNSUPPORTED".to_string(),
276 )),
277 crate::context::FRAMEBUFFER_UNDEFINED => {
278 Err(CoreError::ContextError("FRAMEBUFFER_UNDEFINED".to_string()))
279 }
280 crate::context::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => Err(CoreError::ContextError(
281 "FRAMEBUFFER_INCOMPLETE_READ_BUFFER".to_string(),
282 )),
283 crate::context::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => Err(CoreError::ContextError(
284 "FRAMEBUFFER_INCOMPLETE_MULTISAMPLE".to_string(),
285 )),
286 crate::context::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS => Err(
287 CoreError::ContextError("FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS".to_string()),
288 ),
289 _ => Err(CoreError::ContextError(
290 "Unknown framebuffer error".to_string(),
291 )),
292 }?;
293 }
294 Ok(())
295 }
296}
297
298impl std::fmt::Debug for Context {
299 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300 let mut d = f.debug_struct("Context");
301 d.field("programs", &self.programs.read().unwrap().len());
302 d.finish()
303 }
304}
305
306impl std::ops::Deref for Context {
307 type Target = Arc<crate::context::Context>;
308 fn deref(&self) -> &Self::Target {
309 &self.context
310 }
311}