1use gl::types::{GLint, GLsizei, GLuint};
5use graphics::color::gamma_srgb_to_linear;
6use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;
7use graphics::{Context, DrawState, Graphics, Viewport};
8use shader_version::glsl::GLSL;
9use shader_version::{OpenGL, Shaders};
10use std::ffi::CString;
11
12use crate::draw_state;
14use crate::shader_utils::{compile_shader, DynamicAttribute};
15use crate::Texture;
16
17const CHUNKS: usize = 100;
21
22const USE_WEBGL: bool = cfg!(all(target_arch = "wasm32", target_os = "unknown"))
24 || cfg!(target_os = "emscripten")
25 || cfg!(feature = "webgl");
26
27pub struct Colored {
29 vao: GLuint,
30 vertex_shader: GLuint,
31 fragment_shader: GLuint,
32 program: GLuint,
33 pos: DynamicAttribute,
34 color: DynamicAttribute,
35 pos_buffer: Vec<[f32; 2]>,
36 color_buffer: Vec<[f32; 4]>,
37 offset: usize,
38}
39
40impl Drop for Colored {
41 fn drop(&mut self) {
42 unsafe {
43 gl::DeleteVertexArrays(1, &self.vao);
44 gl::DeleteProgram(self.program);
45 gl::DeleteShader(self.vertex_shader);
46 gl::DeleteShader(self.fragment_shader);
47 }
48 }
49}
50
51impl Colored {
52 pub fn new(glsl: GLSL) -> Self {
57 use shaders::colored;
58 let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };
59
60 let mut vertex_shaders = Shaders::new();
61 if USE_WEBGL {
62 vertex_shaders
63 .set(GLSL::V1_20, src(colored::VERTEX_GLSL_120_WEBGL))
64 .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE_WEBGL))
65 } else {
66 vertex_shaders
67 .set(GLSL::V1_20, src(colored::VERTEX_GLSL_120))
68 .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE))
69 };
70
71 let mut fragment_shaders = Shaders::new();
72 if USE_WEBGL {
73 fragment_shaders
74 .set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120_WEBGL))
75 .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE_WEBGL))
76 } else {
77 fragment_shaders
78 .set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120))
79 .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE))
80 };
81
82 Colored::from_vs_fs(glsl, &vertex_shaders, &fragment_shaders).unwrap()
83 }
84
85 pub fn from_vs_fs(
87 glsl: GLSL,
88 vertex_shaders: &Shaders<GLSL, str>,
89 fragment_shaders: &Shaders<GLSL, str>,
90 ) -> Result<Self, String> {
91 let v_shader = vertex_shaders
92 .get(glsl)
93 .ok_or("No compatible vertex shader")?;
94
95 let v_shader_compiled = compile_shader(gl::VERTEX_SHADER, v_shader)
96 .map_err(|s| format!("Error compiling vertex shader: {}", s))?;
97
98 let f_shader = fragment_shaders
99 .get(glsl)
100 .ok_or("No compatible fragment shader")?;
101
102 let f_shader_compiled = compile_shader(gl::FRAGMENT_SHADER, f_shader)
103 .map_err(|s| format!("Error compiling fragment shader: {}", s))?;
104
105 let program;
106 unsafe {
107 program = gl::CreateProgram();
108 gl::AttachShader(program, v_shader_compiled);
109 gl::AttachShader(program, f_shader_compiled);
110
111 let c_o_color = CString::new("o_Color").unwrap();
112 if !USE_WEBGL {
113 gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
114 }
115 drop(c_o_color);
116 }
117
118 let mut vao = 0;
119 unsafe {
120 gl::GenVertexArrays(1, &mut vao);
121 gl::LinkProgram(program);
122 }
123 let pos = DynamicAttribute::xy(program, "pos", vao).unwrap();
124 let color = DynamicAttribute::rgba(program, "color", vao).unwrap();
125 Ok(Colored {
126 vao,
127 vertex_shader: v_shader_compiled,
128 fragment_shader: f_shader_compiled,
129 program,
130 pos,
131 color,
132 pos_buffer: vec![[0.0; 2]; CHUNKS * BUFFER_SIZE],
133 color_buffer: vec![[0.0; 4]; CHUNKS * BUFFER_SIZE],
134 offset: 0,
135 })
136 }
137
138 fn flush(&mut self) {
139 unsafe {
140 gl::BindVertexArray(self.vao);
141 gl::Disable(gl::CULL_FACE);
144 self.color.set(&self.color_buffer[..self.offset]);
145 self.pos.set(&self.pos_buffer[..self.offset]);
146 gl::DrawArrays(gl::TRIANGLES, 0, self.offset as i32);
147 gl::BindVertexArray(0);
148 }
149
150 self.offset = 0;
151 }
152}
153
154pub struct Textured {
156 vertex_shader: GLuint,
157 fragment_shader: GLuint,
158 program: GLuint,
159 vao: GLuint,
160 color: GLint,
161 pos: DynamicAttribute,
162 uv: DynamicAttribute,
163 pos_buffer: Vec<[f32; 2]>,
164 uv_buffer: Vec<[f32; 2]>,
165 offset: usize,
166 last_texture_id: GLuint,
167 last_color: [f32; 4],
168}
169
170impl Drop for Textured {
171 fn drop(&mut self) {
172 unsafe {
173 gl::DeleteVertexArrays(1, &self.vao);
174 gl::DeleteProgram(self.program);
175 gl::DeleteShader(self.vertex_shader);
176 gl::DeleteShader(self.fragment_shader);
177 }
178 }
179}
180
181impl Textured {
182 pub fn new(glsl: GLSL) -> Self {
187 use shaders::textured;
188 let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };
189
190 let mut vertex_shaders = Shaders::new();
191 if USE_WEBGL {
192 vertex_shaders
193 .set(GLSL::V1_20, src(textured::VERTEX_GLSL_120_WEBGL))
194 .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE_WEBGL))
195 } else {
196 vertex_shaders
197 .set(GLSL::V1_20, src(textured::VERTEX_GLSL_120))
198 .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE))
199 };
200
201 let mut fragment_shaders = Shaders::new();
202 if USE_WEBGL {
203 fragment_shaders
204 .set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120_WEBGL))
205 .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE_WEBGL))
206 } else {
207 fragment_shaders
208 .set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120))
209 .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE))
210 };
211
212 Textured::from_vs_fs(glsl, &vertex_shaders, &fragment_shaders).unwrap()
213 }
214
215 pub fn from_vs_fs(
217 glsl: GLSL,
218 vertex_shaders: &Shaders<GLSL, str>,
219 fragment_shaders: &Shaders<GLSL, str>,
220 ) -> Result<Self, String> {
221 let v_shader = vertex_shaders
222 .get(glsl)
223 .ok_or("No compatible vertex shader")?;
224
225 let v_shader_compiled = compile_shader(gl::VERTEX_SHADER, v_shader)
226 .map_err(|s| format!("Error compiling vertex shader: {}", s))?;
227
228 let f_shader = fragment_shaders
229 .get(glsl)
230 .ok_or("No compatible fragment shader")?;
231
232 let f_shader_compiled = compile_shader(gl::FRAGMENT_SHADER, f_shader)
233 .map_err(|s| format!("Error compiling fragment shader: {}", s))?;
234
235 let program;
236 unsafe {
237 program = gl::CreateProgram();
238 gl::AttachShader(program, v_shader_compiled);
239 gl::AttachShader(program, f_shader_compiled);
240
241 let c_o_color = CString::new("o_Color").unwrap();
242 if !USE_WEBGL {
243 gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
244 }
245 drop(c_o_color);
246 }
247
248 let mut vao = 0;
249 unsafe {
250 gl::GenVertexArrays(1, &mut vao);
251 gl::LinkProgram(program);
252 }
253 let pos = DynamicAttribute::xy(program, "pos", vao).unwrap();
254 let c_color = CString::new("color").unwrap();
255 let color = unsafe { gl::GetUniformLocation(program, c_color.as_ptr()) };
256 drop(c_color);
257 if color == -1 {
258 panic!("Could not find uniform `color`");
259 }
260 let uv = DynamicAttribute::uv(program, "uv", vao).unwrap();
261 Ok(Textured {
262 vao,
263 vertex_shader: v_shader_compiled,
264 fragment_shader: f_shader_compiled,
265 program,
266 pos,
267 color,
268 uv,
269 pos_buffer: vec![[0.0; 2]; CHUNKS * BUFFER_SIZE],
270 uv_buffer: vec![[0.0; 2]; CHUNKS * BUFFER_SIZE],
271 offset: 0,
272 last_texture_id: 0,
273 last_color: [0.0; 4],
274 })
275 }
276
277 fn flush(&mut self) {
278 let texture_id = self.last_texture_id;
279 let color = self.last_color;
280 unsafe {
281 gl::BindVertexArray(self.vao);
282 gl::BindTexture(gl::TEXTURE_2D, texture_id);
283 gl::Uniform4f(self.color, color[0], color[1], color[2], color[3]);
284 gl::Disable(gl::CULL_FACE);
287 self.pos.set(&self.pos_buffer[..self.offset]);
288 self.uv.set(&self.uv_buffer[..self.offset]);
289 gl::DrawArrays(gl::TRIANGLES, 0, self.offset as i32);
290 gl::BindVertexArray(0);
291 }
292
293 self.offset = 0;
294 }
295}
296
297pub struct TexturedColor {
299 vertex_shader: GLuint,
300 fragment_shader: GLuint,
301 program: GLuint,
302 vao: GLuint,
303 pos: DynamicAttribute,
304 uv: DynamicAttribute,
305 color: DynamicAttribute,
306 pos_buffer: Vec<[f32; 2]>,
307 uv_buffer: Vec<[f32; 2]>,
308 color_buffer: Vec<[f32; 4]>,
309 offset: usize,
310 last_texture_id: GLuint,
311}
312
313impl Drop for TexturedColor {
314 fn drop(&mut self) {
315 unsafe {
316 gl::DeleteVertexArrays(1, &self.vao);
317 gl::DeleteProgram(self.program);
318 gl::DeleteShader(self.vertex_shader);
319 gl::DeleteShader(self.fragment_shader);
320 }
321 }
322}
323
324impl TexturedColor {
325 pub fn new(glsl: GLSL) -> Self {
330 use shaders::textured_color;
331 let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };
332
333 let mut vertex_shaders = Shaders::new();
334 if USE_WEBGL {
335 vertex_shaders
336 .set(GLSL::V1_20, src(textured_color::VERTEX_GLSL_120_WEBGL))
337 .set(GLSL::V1_50, src(textured_color::VERTEX_GLSL_150_CORE_WEBGL))
338 } else {
339 vertex_shaders
340 .set(GLSL::V1_20, src(textured_color::VERTEX_GLSL_120))
341 .set(GLSL::V1_50, src(textured_color::VERTEX_GLSL_150_CORE))
342 };
343
344 let mut fragment_shaders = Shaders::new();
345 if USE_WEBGL {
346 fragment_shaders
347 .set(GLSL::V1_20, src(textured_color::FRAGMENT_GLSL_120_WEBGL))
348 .set(
349 GLSL::V1_50,
350 src(textured_color::FRAGMENT_GLSL_150_CORE_WEBGL),
351 )
352 } else {
353 fragment_shaders
354 .set(GLSL::V1_20, src(textured_color::FRAGMENT_GLSL_120))
355 .set(GLSL::V1_50, src(textured_color::FRAGMENT_GLSL_150_CORE))
356 };
357
358 TexturedColor::from_vs_fs(glsl, &vertex_shaders, &fragment_shaders).unwrap()
359 }
360
361 pub fn from_vs_fs(
363 glsl: GLSL,
364 vertex_shaders: &Shaders<GLSL, str>,
365 fragment_shaders: &Shaders<GLSL, str>,
366 ) -> Result<Self, String> {
367 let v_shader = vertex_shaders
368 .get(glsl)
369 .ok_or("No compatible vertex shader")?;
370
371 let v_shader_compiled = compile_shader(gl::VERTEX_SHADER, v_shader)
372 .map_err(|s| format!("Error compiling vertex shader: {}", s))?;
373
374 let f_shader = fragment_shaders
375 .get(glsl)
376 .ok_or("No compatible fragment shader")?;
377
378 let f_shader_compiled = compile_shader(gl::FRAGMENT_SHADER, f_shader)
379 .map_err(|s| format!("Error compiling fragment shader: {}", s))?;
380
381 let program;
382 unsafe {
383 program = gl::CreateProgram();
384 gl::AttachShader(program, v_shader_compiled);
385 gl::AttachShader(program, f_shader_compiled);
386
387 let c_o_color = CString::new("o_Color").unwrap();
388 if !USE_WEBGL {
389 gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
390 }
391 drop(c_o_color);
392 }
393
394 let mut vao = 0;
395 unsafe {
396 gl::GenVertexArrays(1, &mut vao);
397 gl::LinkProgram(program);
398 }
399 let pos = DynamicAttribute::xy(program, "pos", vao).unwrap();
400 let color = DynamicAttribute::rgba(program, "color", vao).unwrap();
401 let uv = DynamicAttribute::uv(program, "uv", vao).unwrap();
402 Ok(TexturedColor {
403 vao,
404 vertex_shader: v_shader_compiled,
405 fragment_shader: f_shader_compiled,
406 program,
407 pos,
408 color,
409 uv,
410 pos_buffer: vec![[0.0; 2]; CHUNKS * BUFFER_SIZE],
411 uv_buffer: vec![[0.0; 2]; CHUNKS * BUFFER_SIZE],
412 color_buffer: vec![[0.0; 4]; CHUNKS * BUFFER_SIZE],
413 offset: 0,
414 last_texture_id: 0,
415 })
416 }
417
418 fn flush(&mut self) {
419 let texture_id = self.last_texture_id;
420 unsafe {
421 gl::BindVertexArray(self.vao);
422 gl::BindTexture(gl::TEXTURE_2D, texture_id);
423 gl::Disable(gl::CULL_FACE);
426 self.pos.set(&self.pos_buffer[..self.offset]);
427 self.uv.set(&self.uv_buffer[..self.offset]);
428 self.color.set(&self.color_buffer[..self.offset]);
429 gl::DrawArrays(gl::TRIANGLES, 0, self.offset as i32);
430 gl::BindVertexArray(0);
431 }
432
433 self.offset = 0;
434 }
435}
436
437const GL_FUNC_NOT_LOADED: &str = "
439 OpenGL function pointers must be loaded before creating the `Gl` backend!
440 For more info, see the following issue on GitHub:
441 https://github.com/PistonDevelopers/opengl_graphics/issues/103
442";
443
444pub struct GlGraphics {
446 colored: Colored,
447 textured: Textured,
448 textured_color: TexturedColor,
449 current_program: Option<GLuint>,
451 current_draw_state: Option<DrawState>,
453 current_viewport: Option<Viewport>,
455}
456
457impl GlGraphics {
458 pub fn new(opengl: OpenGL) -> Self {
464 assert!(gl::Enable::is_loaded(), "{}", GL_FUNC_NOT_LOADED);
465
466 let glsl = opengl.to_glsl();
467 GlGraphics {
469 colored: Colored::new(glsl),
470 textured: Textured::new(glsl),
471 textured_color: TexturedColor::new(glsl),
472 current_program: None,
473 current_draw_state: None,
474 current_viewport: None,
475 }
476 }
477
478 pub fn from_pieces(
485 colored: Colored,
486 textured: Textured,
487 textured_color: TexturedColor,
488 ) -> Self {
489 assert!(gl::Enable::is_loaded(), "{}", GL_FUNC_NOT_LOADED);
490
491 GlGraphics {
493 colored,
494 textured,
495 textured_color,
496 current_program: None,
497 current_draw_state: None,
498 current_viewport: None,
499 }
500 }
501
502 fn viewport(&mut self, x: i32, y: i32, w: i32, h: i32) {
504 unsafe {
505 gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
506 }
507 }
508
509 pub fn get_current_program(&self) -> Option<GLuint> {
511 self.current_program
512 }
513
514 pub fn use_program(&mut self, program: GLuint) {
516 match self.current_program {
517 None => {}
518 Some(current_program) => {
519 if program == current_program {
520 return;
521 }
522 }
523 }
524
525 unsafe {
526 gl::UseProgram(program);
527 }
528 self.current_program = Some(program);
529 }
530
531 pub fn clear_program(&mut self) {
535 self.current_program = None
536 }
537
538 pub fn use_draw_state(&mut self, draw_state: &DrawState) {
540 match self.current_draw_state {
541 None => {
542 draw_state::bind_scissor(draw_state.scissor, &self.current_viewport);
543 draw_state::bind_stencil(draw_state.stencil);
544 draw_state::bind_blend(draw_state.blend);
545 }
546 Some(ref old_state) => {
547 draw_state::bind_state(old_state, draw_state, &self.current_viewport);
548 }
549 }
550 self.current_draw_state = Some(*draw_state);
551 }
552
553 pub fn clear_draw_state(&mut self) {
557 self.current_draw_state = None;
558 }
559
560 pub fn draw_begin(&mut self, viewport: Viewport) -> Context {
562 let rect = viewport.rect;
563 let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
564 self.viewport(x, y, w, h);
565 self.current_viewport = Some(viewport);
566 self.clear_program();
567 unsafe {
568 gl::Enable(gl::FRAMEBUFFER_SRGB);
569 }
570 Context::new_viewport(viewport)
571 }
572
573 pub fn draw_end(&mut self) {
575 if self.colored.offset > 0 {
576 let program = self.colored.program;
577 self.use_program(program);
578 self.colored.flush();
579 }
580 if self.textured.offset > 0 {
581 let program = self.textured.program;
582 self.use_program(program);
583 self.textured.flush();
584 }
585 if self.textured_color.offset > 0 {
586 let program = self.textured_color.program;
587 self.use_program(program);
588 self.textured_color.flush();
589 }
590 }
591
592 pub fn draw<F, U>(&mut self, viewport: Viewport, f: F) -> U
597 where
598 F: FnOnce(Context, &mut Self) -> U,
599 {
600 let c = self.draw_begin(viewport);
601 let res = f(c, self);
602 self.draw_end();
603 res
604 }
605
606 pub fn has_texture_alpha(&self, _texture: &Texture) -> bool {
608 true
609 }
610}
611
612impl Graphics for GlGraphics {
613 type Texture = Texture;
614
615 fn clear_color(&mut self, color: [f32; 4]) {
616 let color = gamma_srgb_to_linear(color);
617 unsafe {
618 let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
619 gl::ClearColor(r, g, b, a);
620 gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
621 }
622 }
623
624 fn clear_stencil(&mut self, value: u8) {
625 unsafe {
626 gl::ClearStencil(value as i32);
627 gl::Clear(gl::STENCIL_BUFFER_BIT);
628 }
629 }
630
631 fn tri_list<F>(&mut self, draw_state: &DrawState, color: &[f32; 4], mut f: F)
632 where
633 F: FnMut(&mut dyn FnMut(&[[f32; 2]])),
634 {
635 let color = gamma_srgb_to_linear(*color);
636
637 if self.textured.offset > 0 {
638 let program = self.textured.program;
639 self.use_program(program);
640 self.textured.flush();
641 }
642 if self.textured_color.offset > 0 {
643 let program = self.textured_color.program;
644 self.use_program(program);
645 self.textured_color.flush();
646 }
647
648 if self.current_draw_state.is_none()
650 || self.current_draw_state.as_ref().unwrap() != draw_state
651 {
652 let program = self.colored.program;
653 self.use_program(program);
654 if self.current_draw_state.is_none() {
655 self.use_draw_state(&Default::default());
656 }
657 if self.colored.offset > 0 {
658 self.colored.flush();
659 }
660 self.use_draw_state(draw_state);
661 }
662
663 f(&mut |vertices: &[[f32; 2]]| {
664 let items = vertices.len();
665
666 if self.colored.offset + items > BUFFER_SIZE * CHUNKS {
668 let program = self.colored.program;
669 self.use_program(program);
670 self.colored.flush();
671 }
672
673 let shader = &mut self.colored;
674 for i in 0..items {
675 shader.color_buffer[shader.offset + i] = color;
676 }
677 shader.pos_buffer[shader.offset..shader.offset + items].copy_from_slice(vertices);
678 shader.offset += items;
679 });
680 }
681
682 fn tri_list_c<F>(&mut self, draw_state: &DrawState, mut f: F)
683 where
684 F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 4]])),
685 {
686 if self.textured.offset > 0 {
687 let program = self.textured.program;
688 self.use_program(program);
689 self.textured.flush();
690 }
691 if self.textured_color.offset > 0 {
692 let program = self.textured_color.program;
693 self.use_program(program);
694 self.textured_color.flush();
695 }
696
697 if self.current_draw_state.is_none()
699 || self.current_draw_state.as_ref().unwrap() != draw_state
700 {
701 let program = self.colored.program;
702 self.use_program(program);
703 if self.current_draw_state.is_none() {
704 self.use_draw_state(&Default::default());
705 }
706 if self.colored.offset > 0 {
707 self.colored.flush();
708 }
709 self.use_draw_state(draw_state);
710 }
711
712 f(&mut |vertices: &[[f32; 2]], colors: &[[f32; 4]]| {
713 let items = vertices.len();
714
715 if self.colored.offset + items > BUFFER_SIZE * CHUNKS {
717 let program = self.colored.program;
718 self.use_program(program);
719 self.colored.flush();
720 }
721
722 let shader = &mut self.colored;
723 for (i, color) in colors.iter().enumerate() {
724 shader.color_buffer[shader.offset + i] = gamma_srgb_to_linear(*color);
725 }
726 shader.pos_buffer[shader.offset..shader.offset + items].copy_from_slice(vertices);
727 shader.offset += items;
728 });
729 }
730
731 fn tri_list_uv<F>(
732 &mut self,
733 draw_state: &DrawState,
734 color: &[f32; 4],
735 texture: &Texture,
736 mut f: F,
737 ) where
738 F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]])),
739 {
740 let color = gamma_srgb_to_linear(*color);
741
742 if self.colored.offset > 0 {
743 let program = self.colored.program;
744 self.use_program(program);
745 self.colored.flush();
746 }
747 if self.textured_color.offset > 0 {
748 let program = self.textured_color.program;
749 self.use_program(program);
750 self.textured_color.flush();
751 }
752
753 if self.current_draw_state.is_none()
755 || self.current_draw_state.as_ref().unwrap() != draw_state
756 || self.textured.last_texture_id != texture.get_id()
757 || self.textured.last_color != color
758 {
759 let program = self.textured.program;
760 if self.current_draw_state.is_none() {
761 self.use_draw_state(&Default::default());
762 }
763 if self.textured.offset > 0 {
764 self.use_program(program);
765 self.textured.flush();
766 }
767 self.use_draw_state(draw_state);
768 }
769
770 self.textured.last_texture_id = texture.get_id();
771 self.textured.last_color = color;
772 f(&mut |vertices: &[[f32; 2]], texture_coords: &[[f32; 2]]| {
773 let items = vertices.len();
774
775 if self.textured.offset + items > BUFFER_SIZE * CHUNKS {
777 let shader_program = self.textured.program;
778 self.use_program(shader_program);
779 self.textured.flush();
780 }
781
782 let shader = &mut self.textured;
783 shader.pos_buffer[shader.offset..shader.offset + items].copy_from_slice(vertices);
784 shader.uv_buffer[shader.offset..shader.offset + items].copy_from_slice(texture_coords);
785 shader.offset += items;
786 });
787 }
788
789 fn tri_list_uv_c<F>(&mut self, draw_state: &DrawState, texture: &Texture, mut f: F)
790 where
791 F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]], &[[f32; 4]])),
792 {
793 if self.colored.offset > 0 {
794 let program = self.colored.program;
795 self.use_program(program);
796 self.colored.flush();
797 }
798 if self.textured.offset > 0 {
799 let program = self.textured.program;
800 self.use_program(program);
801 self.textured.flush();
802 }
803
804 if self.current_draw_state.is_none()
806 || self.current_draw_state.as_ref().unwrap() != draw_state
807 || self.textured_color.last_texture_id != texture.get_id()
808 {
809 let program = self.textured_color.program;
810 if self.current_draw_state.is_none() {
811 self.use_draw_state(&Default::default());
812 }
813 if self.textured_color.offset > 0 {
814 self.use_program(program);
815 self.textured_color.flush();
816 }
817 self.use_draw_state(draw_state);
818 }
819
820 self.textured_color.last_texture_id = texture.get_id();
821 f(
822 &mut |vertices: &[[f32; 2]], texture_coords: &[[f32; 2]], colors: &[[f32; 4]]| {
823 let items = vertices.len();
824
825 if self.textured_color.offset + items > BUFFER_SIZE * CHUNKS {
827 let shader_program = self.textured_color.program;
828 self.use_program(shader_program);
829 self.textured_color.flush();
830 }
831
832 let shader = &mut self.textured_color;
833 for (i, color) in colors.iter().enumerate() {
834 shader.color_buffer[shader.offset + i] = gamma_srgb_to_linear(*color);
835 }
836 shader.pos_buffer[shader.offset..shader.offset + items].copy_from_slice(vertices);
837 shader.uv_buffer[shader.offset..shader.offset + items]
838 .copy_from_slice(texture_coords);
839 shader.offset += items;
840 },
841 );
842 }
843}
844
845#[test]
847#[should_panic]
848fn test_gl_loaded() {
849 GlGraphics::new(OpenGL::V3_2);
850}