1use std::io::Cursor;
4use std::rc::Rc;
5use std::cell::RefCell;
6
7use glium::{Frame, Surface, Program, ProgramCreationError, IndexBuffer, VertexBuffer};
8use glium::texture::{RawImage2d, Texture2d, UncompressedFloatFormat};
9use glium::uniforms::{Sampler, MagnifySamplerFilter, MinifySamplerFilter, SamplerWrapFunction};
10use glium::program::ProgramCreationInput;
11use glium::backend::Facade;
12use crate::thirdparty::glium_sdl2::{DisplayBuild, SDL2Facade};
13
14use crate::datapack::{DataId, DataStore, PreparedStore, PreparedStoreError, DataPreparer};
15
16use crate::renderer::{DrawControl, DrawControlResult, DrawTransform, DrawSpriteRawInfo, DrawBackgroundColorInfo, RendererError, Sheet, Shader, ViewportMode, DrawSpriteInfo, Color};
17use crate::renderer::draw_control_private::{DrawControlBackend, RendererNewInfo};
18
19#[cfg(feature = "imgui_feature")] use imgui_glium_renderer;
20#[cfg(feature = "imgui_feature")] use glium::uniforms::SamplerBehavior;
21
22const INSTANCES_MAX : usize = 2048; const INSTANCE_BUFFER_MAX: usize = 4; const INSTANCE_RUN_COARSENESS : usize = 128; const UNBORKED_IDENTITY_TRANSFORM : [f32; 9] = [2.0, 0.0, 0.0, 0.0, -2.0, 0.0, -1.0, 1.0, 1.0];
28const UNBORKED_UPSCALE_TRANSFORM : [f32; 9] = [2.0, 0.0, 0.0, 0.0, 2.0, 0.0, -1.0, -1.0, 1.0];
29
30#[derive(Copy, Clone, Eq, PartialEq)]
31enum RendererOp
32{
33 #[allow(dead_code)]
34 BackgroundColor,
35 #[allow(dead_code)]
36 Sprite
37}
38
39impl Default for RendererOp
40{
41 fn default() -> Self
42 {
43 RendererOp::BackgroundColor
44 }
45}
46
47#[derive(Copy, Clone)]
48struct Vertex
49{
50 a_position : [f32; 2]
51}
52
53implement_vertex!(Vertex, a_position);
54
55#[derive(Copy, Clone, Default)]
56struct Instance
57{
58 a_transform_col1 : [f32; 2],
59 a_transform_col2 : [f32; 2],
60 a_transform_col3 : [f32; 2],
61 a_transform_offset : [f32; 2],
62 a_tex_coords : [f32; 4],
63 a_rgba : [f32; 4]
64}
65
66implement_vertex!(Instance, a_transform_col1, a_transform_col2, a_transform_col3,
67 a_transform_offset, a_tex_coords, a_rgba);
68
69const VERTEX_QUAD : [Vertex; 4] =
70[
71 Vertex { a_position: [ 0.0, 0.0 ] },
72 Vertex { a_position: [ 1.0, 0.0 ] },
73 Vertex { a_position: [ 1.0, 1.0 ] },
74 Vertex { a_position: [ 0.0, 1.0 ] }
75];
76const INDEX_QUAD : [u16; 6] = [ 0, 1, 2, 2, 3, 0 ];
77
78struct GpuSpriteSlice
79{
80 pub texture_x : f32,
81 pub texture_y : f32,
82 pub texture_w : f32,
83 pub texture_h : f32,
84 pub scale_x : f32,
85 pub scale_y : f32,
86 pub offset_x : f32,
87 pub offset_y : f32,
88}
89
90struct GpuSheetHandle
91{
92 texture : Rc<Texture2d>,
93 mag_filter : MagnifySamplerFilter,
94 min_filter : MinifySamplerFilter,
95 slices : Vec<GpuSpriteSlice>
96}
97
98struct GpuSheetPreparer
99{
100 display : Rc<RefCell<SDL2Facade>>,
101 #[allow(dead_code)]
102 default_texture : Rc<Texture2d>,
103 texture_filtering : bool,
104 #[cfg(feature = "imgui_feature")]
105 imgui_renderer : Rc<RefCell<Option<imgui_glium_renderer::Renderer>>>
106}
107
108impl GpuSheetPreparer
109{
110 fn texture_raw_from_data(data : &Vec<u8>, palette : &Option<Vec<Color>>) -> Vec<u8>
111 {
112 if let Some(palette) = palette
113 {
114 let mut expanded = Vec::with_capacity(data.len() * 4);
115
116 for i in 0..data.len()
117 {
118 let color = data[i] as usize;
119
120 if color < palette.len()
121 {
122 expanded.push(palette[color].r);
123 expanded.push(palette[color].g);
124 expanded.push(palette[color].b);
125 expanded.push(palette[color].a);
126 }
127 else
128 {
129 for _ in 0..4
130 {
131 expanded.push(0);
132 }
133 }
134 }
135
136 return expanded;
137 }
138
139 data.clone()
140 }
141
142 fn make_sheet_handle(&mut self, data: &mut Sheet) -> GpuSheetHandle
143 {
144 let texture;
145
146 {
147 let display_ref: &SDL2Facade = &self.display.borrow();
148 let image_raw = GpuSheetPreparer::texture_raw_from_data(&data.image_raw, &data.palette);
149
150 let image = RawImage2d::from_raw_rgba(image_raw, (data.width, data.height));
151 texture = Rc::new(Texture2d::new(display_ref, image).expect("Texture upload failed"));
152 }
153
154 self.make_sheet_handle_from_texture(data, texture)
155 }
156
157 fn make_sheet_handle_from_texture(&mut self, data: &mut Sheet, texture : Rc<Texture2d>) -> GpuSheetHandle
158 {
159 let (mag_filter, min_filter) = self.sample_filters(data);
160
161 let mut slices = Vec::new();
162
163 for slice in &data.metadata.slices
164 {
165 let texture_w = slice.texture_w / data.width as f32;
166 let texture_h = slice.texture_h / data.height as f32;
167
168 slices.push(GpuSpriteSlice
169 {
170 texture_x: slice.texture_x / data.width as f32,
171 texture_y: slice.texture_y / data.height as f32,
172 texture_w,
173 texture_h,
174 scale_x: slice.texture_w,
175 scale_y: slice.texture_h,
176 offset_x: -slice.origin_x / slice.texture_w,
177 offset_y: -slice.origin_y / slice.texture_h,
178 })
179 }
180
181 GpuSheetHandle
182 {
183 texture,
184 mag_filter,
185 min_filter,
186 slices
187 }
188 }
189
190 #[cfg(feature = "imgui_feature")]
191 fn update_imgui_texture(&mut self, id : DataId<Sheet>, handle : &mut GpuSheetHandle)
192 {
193 let mut imgui_borrow = self.imgui_renderer.borrow_mut();
194
195 if let Some(imgui_renderer) = imgui_borrow.as_mut()
196 {
197 imgui_renderer.textures().replace(imgui::TextureId::from(id.index()), imgui_glium_renderer::Texture
198 {
199 texture : handle.texture.clone(),
200 sampler : SamplerBehavior
201 {
202 wrap_function: (SamplerWrapFunction::Repeat, SamplerWrapFunction::Repeat, SamplerWrapFunction::Repeat),
203 minify_filter: handle.min_filter,
204 magnify_filter: handle.mag_filter,
205 .. Default::default()
206 }
207 });
208 }
209 }
210
211 fn sample_filters(&mut self, data : &mut Sheet) -> (MagnifySamplerFilter, MinifySamplerFilter)
212 {
213 let filtered;
214
215 if let Some(filter) = data.metadata.texture_filtering
216 {
217 filtered = filter;
218 }
219 else
220 {
221 filtered = self.texture_filtering;
222 }
223
224 let mag_filter = match filtered
225 {
226 true => MagnifySamplerFilter::Linear,
227 false => MagnifySamplerFilter::Nearest
228 };
229 let min_filter = match filtered
230 {
231 true => MinifySamplerFilter::Linear,
232 false => MinifySamplerFilter::Nearest
233 };
234
235 (mag_filter, min_filter)
236 }
237}
238
239impl DataPreparer<Sheet, GpuSheetHandle> for GpuSheetPreparer
240{
241 #[allow(unused_variables)]
242 fn prepare(&mut self, data : &mut Sheet, id : DataId<Sheet>) -> GpuSheetHandle
243 {
244 #[allow(unused_mut)]
245 let mut handle = self.make_sheet_handle(data);
246
247 data.texture_dirty = false;
248
249 #[cfg(feature = "imgui_feature")]
250 self.update_imgui_texture(id, &mut handle);
251
252 handle
253 }
254
255 #[allow(unused_variables)]
256 fn unprepare(&mut self, _prepared : &mut GpuSheetHandle, id : DataId<Sheet>)
257 {
258 #[cfg(feature = "imgui_feature")]
259 {
260 let mut imgui_borrow = self.imgui_renderer.borrow_mut();
261
262 if let Some(imgui_renderer) = imgui_borrow.as_mut()
263 {
264 imgui_renderer.textures().replace(imgui::TextureId::from(id.index()), imgui_glium_renderer::Texture
265 {
266 texture : self.default_texture.clone(),
267 sampler : SamplerBehavior
268 {
269 wrap_function: (SamplerWrapFunction::Repeat, SamplerWrapFunction::Repeat, SamplerWrapFunction::Repeat),
270 minify_filter: MinifySamplerFilter::Linear,
271 magnify_filter: MagnifySamplerFilter::Linear,
272 .. Default::default()
273 }
274 });
275 }
276 }
277 }
278
279 #[allow(unused_variables)]
280 fn reprepare(&mut self, data : &mut Sheet, prepared : &mut GpuSheetHandle, id : DataId<Sheet>)
281 {
282 if data.texture_dirty
283 {
284 *prepared = self.make_sheet_handle(data);
285 }
286 else
287 {
288 *prepared = self.make_sheet_handle_from_texture(data, prepared.texture.clone());
289 }
290
291 #[cfg(feature = "imgui_feature")]
292 self.update_imgui_texture(id, prepared);
293
294 data.texture_dirty = false;
295 }
296}
297
298#[allow(unused_mut)]
299fn modify_shader_header(mut shader_text : &str) -> String
300{
301 #[cfg(not(target_os = "emscripten"))]
302 {
303 shader_text.to_string()
304 }
305 #[cfg(target_os = "emscripten")]
306 {
307 shader_text.replace("#version 140", "#version 300 es\nprecision mediump float;")
308 }
309}
310
311struct GpuShaderHandle
312{
313 program : Program
314}
315
316struct GpuShaderPreparer
317{
318 display : Rc<RefCell<SDL2Facade>>
319}
320
321impl DataPreparer<Shader, GpuShaderHandle> for GpuShaderPreparer
322{
323 fn prepare(&mut self, data : &mut Shader, _id : DataId<Shader>) -> GpuShaderHandle
324 {
325 let program = make_program(&self.display.borrow(),
326 &modify_shader_header(include_str!("shader/vert_standard_140.glsl")),
327 &modify_shader_header(&data.program_source)).expect("Shader compilation failed");
328
329 GpuShaderHandle
330 {
331 program
332 }
333 }
334 fn unprepare(&mut self, _prepared : &mut GpuShaderHandle, _id : DataId<Shader>)
335 {
336
337 }
338}
339
340#[derive(Copy, Clone, Eq, PartialEq, Default)]
341struct InstanceBufferParam
342{
343 op : RendererOp,
344 sheet : DataId<Sheet>,
345 shader : DataId<Shader>
346}
347
348fn make_program(display : &SDL2Facade, vertex_shader : &str, fragment_shader : &str) -> Result<Program, ProgramCreationError>
349{
350 let source = ProgramCreationInput::SourceCode
351 {
352 vertex_shader,
353 fragment_shader,
354 geometry_shader : None,
355 tessellation_control_shader : None,
356 tessellation_evaluation_shader : None,
357 transform_feedback_varyings : None,
358 uses_point_size : false,
359 outputs_srgb : true
360 };
361
362 glium::Program::new(display, source)
363}
364
365fn upscale_instance_from_transform(transform : &DrawTransform) -> Instance
366{
367 Instance
368 {
369 a_transform_col1 : [ transform.mat.x.x, transform.mat.x.y ],
370 a_transform_col2 : [ transform.mat.y.x, transform.mat.y.y ],
371 a_transform_col3 : [ transform.mat.z.x, transform.mat.z.y ],
372 a_transform_offset : [ 0.0, 0.0 ],
373 a_tex_coords : [0.0, 0.0, 1.0, 1.0],
374 a_rgba : [1.0, 1.0, 1.0, 1.0],
375 }
376}
377
378#[derive(Copy, Clone, Default)]
379struct BatchRun
380{
381 start : usize,
382 len : usize,
383 param : InstanceBufferParam
384}
385
386pub(crate) struct GlDrawControl
387{
388 display : Rc<RefCell<SDL2Facade>>,
389 window : Rc<RefCell<sdl2::video::Window>>,
390 base_width : f32,
391 base_height : f32,
392 scale_width : f32,
393 scale_height : f32,
394 need_recalc_viewport : bool,
395 viewport_offset : (f32, f32),
396 viewport_mode : ViewportMode,
397 quad_buffer : VertexBuffer<Vertex>,
398 index_buffer : IndexBuffer<u16>,
399 instance_buffer_src : Box<[Instance ; INSTANCES_MAX]>,
400 instance_buffer : Vec<VertexBuffer<Instance>>,
401 instance_buffer_flip : usize,
402 default_texture : Rc<Texture2d>,
403 shader_list : Vec<Program>,
404 scissor : Option<glium::Rect>,
405 frame : Option<Frame>,
406 pixel_scale : u32,
407 last_pixel_scale : u32,
408 pixel_texture : Option<Texture2d>,
409 pixel_upscale_texture : Option<Texture2d>,
410 current_index : usize,
411 index_runs : Vec<BatchRun>,
412 current_run : BatchRun,
413 last_view_transform : DrawTransform,
414 gpu_sheet_store : PreparedStore<Sheet, GpuSheetHandle>,
415 gpu_shader_store : PreparedStore<Shader, GpuShaderHandle>,
416 #[cfg(feature = "imgui_feature")]
417 imgui_renderer : Rc<RefCell<Option<imgui_glium_renderer::Renderer>>>
418}
419
420impl GlDrawControl
421{
422 fn perform_draw_batch(&mut self)
423 {
424 if self.current_index <= 0
425 {
426 return;
427 }
428
429 self.index_runs.push(self.current_run);
430
431 self.instance_buffer[self.instance_buffer_flip].invalidate();
432 self.instance_buffer[self.instance_buffer_flip].write(&self.instance_buffer_src[..]);
433
434 let index_skip_list = self.index_runs.clone();
436
437 let mut do_draw = | first : usize, last : usize, param : &InstanceBufferParam |
438 {
439 if first >= last
440 {
441 return;
442 }
443
444 if let Some(frame) = &mut self.frame
445 {
446 let mut texture_ref = self.default_texture.as_ref();
447 let mut shader_ref = &self.shader_list[param.op as usize];
448 let mut mag_filter = MagnifySamplerFilter::Linear;
449 let mut min_filter = MinifySamplerFilter::Linear;
450
451 if let Some(gpu_sheet_info) = self.gpu_sheet_store.get(param.sheet)
452 {
453 texture_ref = gpu_sheet_info.texture.as_ref();
454 mag_filter = gpu_sheet_info.mag_filter;
455 min_filter = gpu_sheet_info.min_filter;
456 }
457 if let Some(gpu_shader_info) = self.gpu_shader_store.get(param.shader)
458 {
459 shader_ref = &gpu_shader_info.program;
460 }
461
462 let uniform = uniform!
463 {
464 t_texture : Sampler::new(texture_ref)
465 .magnify_filter(mag_filter).minify_filter(min_filter)
466 .wrap_function(SamplerWrapFunction::Repeat),
467 u_tex_size : [ texture_ref.width() as f32, texture_ref.height() as f32 ]
468 };
469
470 match self.viewport_mode
471 {
472 ViewportMode::Independent | ViewportMode::OneToOneDpiScaled | ViewportMode::OneToOneUnscaled =>
473 {
474 let params = glium::DrawParameters
475 {
476 blend : glium::draw_parameters::Blend::alpha_blending(),
477 scissor : self.scissor,
478 .. Default::default()
479 };
480
481 frame.draw((&self.quad_buffer,
482 self.instance_buffer[self.instance_buffer_flip].slice(first..last)
483 .expect("Failed to prepare instance buffer").per_instance()
484 .expect("Failed to prepare instance buffer")),
485 &self.index_buffer, shader_ref,
486 &uniform, ¶ms).expect("Draw operation failed");
487 },
488 ViewportMode::Pixel =>
489 {
490 let params = glium::DrawParameters
491 {
492 blend : glium::draw_parameters::Blend::alpha_blending(),
493 scissor : self.scissor,
494 multisampling : false,
495 dithering : false,
496 .. Default::default()
497 };
498
499 self.pixel_texture.as_ref().unwrap().as_surface().draw((&self.quad_buffer,
500 self.instance_buffer[self.instance_buffer_flip].slice(first..last)
501 .expect("Failed to prepare instance buffer").per_instance()
502 .expect("Failed to prepare instance buffer")),
503 &self.index_buffer, shader_ref,
504 &uniform, ¶ms).expect("Draw operation failed");
505 }
506 }
507 }
508 };
509
510 for run in &index_skip_list
511 {
512 do_draw(run.start, run.start + run.len, &run.param);
513 }
514
515 self.flip_instance_buffers();
516 }
517
518 fn check_batch_break(&mut self, param : InstanceBufferParam)
519 {
520 let skip_index = (self.current_index + INSTANCE_RUN_COARSENESS) / INSTANCE_RUN_COARSENESS * INSTANCE_RUN_COARSENESS;
521
522 if skip_index >= INSTANCES_MAX
523 {
524 self.perform_draw_batch();
525 }
526
527 if self.current_index == 0
528 {
529 self.current_run.param = param;
530 }
531 else if self.current_run.param != param
532 {
533 self.index_runs.push(self.current_run);
534 self.current_index = skip_index;
535 self.current_run = BatchRun { start : self.current_index, len : 0, param };
536 }
537 }
538
539 fn flip_instance_buffers(&mut self)
540 {
541 self.instance_buffer_flip = (self.instance_buffer_flip + 1) % self.instance_buffer.len();
542 self.current_index = 0;
543 self.current_run = BatchRun { start : 0, len : 0, param : InstanceBufferParam::default() };
544 self.index_runs.clear();
545
546 if self.instance_buffer_flip % (self.instance_buffer.len() / 2) == 0
547 {
548 self.display.borrow().get_context().flush();
549 }
550 }
551
552 fn update_pixel_upscale(&mut self)
553 {
554 if self.pixel_scale == self.last_pixel_scale
555 {
556 return;
557 }
558
559 self.last_pixel_scale = self.pixel_scale;
560 let display_ref : &SDL2Facade = &self.display.borrow();
561 let pixel_surface = self.pixel_texture.as_mut().unwrap().as_surface();
562 let (width, height) = pixel_surface.get_dimensions();
563
564 self.pixel_upscale_texture = Some(Texture2d::empty_with_format(
565 display_ref, UncompressedFloatFormat::U8U8U8U8, glium::texture::MipmapsOption::NoMipmap,
566 width * self.pixel_scale, height * self.pixel_scale).expect("Could not create upscale framebuffer"));
567 }
568}
569
570impl DrawControl for GlDrawControl
571{
572 fn screen_transform(&self) -> &DrawTransform
573 {
574 &self.last_view_transform
575 }
576
577 fn draw_sprite(&mut self, draw_info: &DrawSpriteInfo)
578 {
579 let mut transform = draw_info.transform.clone();
580 let mut transform_offset_x = -0.5;
581 let mut transform_offset_y = -0.5;
582 let mut texture_x = 0.0;
583 let mut texture_y = 0.0;
584 let mut texture_w = 1.0;
585 let mut texture_h = 1.0;
586 let mut sheet_id = DataId::new(0);
587
588 transform.translate(draw_info.x, draw_info.y);
589 if draw_info.angle != 0.0
590 {
591 transform.rotate(draw_info.angle);
592 }
593
594 let mut got_slice = false;
595
596 if let Some(gpu_sheet_info) = self.gpu_sheet_store.get(draw_info.sheet_id)
597 {
598 if draw_info.slice < gpu_sheet_info.slices.len()
599 {
600 let slice = &gpu_sheet_info.slices[draw_info.slice];
601
602 transform.scale(draw_info.scale_x * slice.scale_x, draw_info.scale_y * slice.scale_y);
603
604 sheet_id = draw_info.sheet_id;
605 transform_offset_x = slice.offset_x;
606 transform_offset_y = slice.offset_y;
607 texture_x = slice.texture_x;
608 texture_y = slice.texture_y;
609 texture_w = slice.texture_w;
610 texture_h = slice.texture_h;
611
612 got_slice = true;
613 }
614 }
615
616 if !got_slice
617 {
618 transform.scale(draw_info.scale_x * 32.0, draw_info.scale_y * 32.0);
619 }
620
621 self.draw_sprite_raw(&DrawSpriteRawInfo
622 {
623 sheet_id,
624 shader_id: draw_info.shader_id,
625 transform: transform,
626 transform_offset_x,
627 transform_offset_y,
628 texture_x,
629 texture_y,
630 texture_w,
631 texture_h,
632 r: draw_info.r,
633 g: draw_info.g,
634 b: draw_info.b,
635 alpha: draw_info.alpha
636 });
637 }
638
639 fn draw_sprite_raw(&mut self, draw_info : &DrawSpriteRawInfo)
640 {
641 let instance_param = InstanceBufferParam
642 {
643 op : RendererOp::Sprite,
644 sheet : draw_info.sheet_id,
645 shader : draw_info.shader_id
646 };
647
648 self.check_batch_break(instance_param);
649
650 let transform = &draw_info.transform;
651 let instance = Instance
652 {
653 a_transform_col1 : [ transform.mat.x.x, transform.mat.x.y ],
654 a_transform_col2 : [ transform.mat.y.x, transform.mat.y.y ],
655 a_transform_col3 : [ transform.mat.z.x, transform.mat.z.y ],
656 a_transform_offset : [ draw_info.transform_offset_x, draw_info.transform_offset_y ],
657 a_tex_coords : [ draw_info.texture_x, draw_info.texture_y, draw_info.texture_w, draw_info.texture_h ],
658 a_rgba : [ draw_info.r, draw_info.g, draw_info.b, draw_info.alpha ],
659 };
660 self.instance_buffer_src[self.current_index] = instance;
661
662 self.current_index += 1;
663 self.current_run.len += 1;
664 }
665
666 fn draw_background_color(&mut self, draw_info : &DrawBackgroundColorInfo )
667 {
668 let instance_param = InstanceBufferParam
669 {
670 op : RendererOp::BackgroundColor,
671 sheet : DataId::new(0),
672 shader : draw_info.shader_id
673 };
674
675 self.check_batch_break(instance_param);
676
677 let instance = Instance
678 {
679 a_transform_col1 : [ 2.0, 0.0 ],
680 a_transform_col2 : [ 0.0, -2.0 ],
681 a_transform_col3 : [ -1.0, 1.0 ],
682 a_transform_offset : [ 0.0, 0.0 ],
683 a_tex_coords : [ 0.0, 0.0, 1.0, 1.0 ],
684 a_rgba : [ draw_info.r, draw_info.g, draw_info.b, draw_info.alpha ],
685 };
686 self.instance_buffer_src[self.current_index] = instance;
687
688 self.current_index += 1;
689 self.current_run.len += 1;
690 }
691}
692
693impl DrawControlBackend for GlDrawControl
694{
695 fn new(renderer_new_info : &mut RendererNewInfo) -> DrawControlResult where Self : Sized
696 {
697 let video_subsystem = &renderer_new_info.video_subsystem;
698
699 let (width, height) = crate::renderer::calculate_window_size(renderer_new_info.width as f32,
700 renderer_new_info.height as f32,
701 renderer_new_info.default_window_scale,
702 video_subsystem);
703
704 let mut window_builder = video_subsystem.window("", width, height);
705
706 window_builder.hidden().position_centered().resizable().allow_highdpi();
707
708 #[cfg(not(target_os = "emscripten"))]
709 {
710 video_subsystem.gl_attr().set_context_profile(sdl2::video::GLProfile::Core);
711 video_subsystem.gl_attr().set_context_version(3, 2);
712 }
713 #[cfg(target_os = "emscripten")]
714 {
715 video_subsystem.gl_attr().set_context_profile(sdl2::video::GLProfile::GLES);
716 video_subsystem.gl_attr().set_context_version(3, 0);
717 }
718
719 let display_raw = window_builder.build_glium().map_err(
720 |error| RendererError::RendererInitFailed(format!("Could not create game window: {}", error)))?;
721
722 let mut pixel_texture = None;
723
724 match renderer_new_info.viewport_mode
725 {
726 ViewportMode::Independent | ViewportMode::OneToOneDpiScaled | ViewportMode::OneToOneUnscaled => (),
727 ViewportMode::Pixel =>
728 {
729 pixel_texture = Some(Texture2d::empty_with_format(
730 &display_raw, UncompressedFloatFormat::U8U8U8U8, glium::texture::MipmapsOption::NoMipmap, renderer_new_info.width, renderer_new_info.height).map_err(
731 |error| RendererError::RendererInitFailed(format!("Could not create framebuffer: {}", error)))?);
732 }
733 };
734
735 let quad_buffer = glium::VertexBuffer::new(&display_raw, &VERTEX_QUAD).map_err(
736 |error| RendererError::RendererInitFailed(format!("Could not create vertex buffer: {}", error)))?;
737 let index_buffer = glium::IndexBuffer::new(&display_raw,
738 glium::index::PrimitiveType::TrianglesList, &INDEX_QUAD).map_err(
739 |error| RendererError::RendererInitFailed(format!("Could not create index buffer: {}", error)))?;
740
741 let mut instance_buffer = Vec::new();
742
743 for _ in 0..INSTANCE_BUFFER_MAX
744 {
745 instance_buffer.push(glium::VertexBuffer::<Instance>::empty_dynamic(&display_raw, INSTANCES_MAX).map_err(
746 |error| RendererError::RendererInitFailed(format!("Could not create instance buffer: {}", error)))?);
747 }
748
749 let context = display_raw.get_context();
750 info!("Renderer: {} {}", context.get_opengl_vendor_string(), context.get_opengl_renderer_string());
751 info!("OpenGL version: {}", context.get_opengl_version_string());
752 if let Some(free_vram) = context.get_free_video_memory()
753 {
754 info!("VRAM: {} MiB free", free_vram / 1024 / 1024);
755 }
756
757 let shader_background = make_program(&display_raw,
758 &modify_shader_header(include_str!("shader/vert_standard_140.glsl")),
759 &modify_shader_header(include_str!("shader/frag_solidcolor_140.glsl"))).map_err(
760 |error| RendererError::RendererInitFailed(format!("Could not load shader: {}", error)))?;
761 let shader_sprite = make_program(&display_raw,
762 &modify_shader_header(include_str!("shader/vert_standard_140.glsl")),
763 &modify_shader_header(include_str!("shader/frag_sprite_140.glsl"))).map_err(
764 |error| RendererError::RendererInitFailed(format!("Could not load shader: {}", error)))?;
765
766 let shader_list = vec!(shader_background, shader_sprite);
767
768 let (default_texture, default_width, default_height) = crate::renderer::png_to_raw(
769 Cursor::new(include_bytes!("data/default.png").to_vec()))?;
770
771 let image = RawImage2d::from_raw_rgba(default_texture, (default_width, default_height));
772 let default_texture = Rc::new(Texture2d::new(&display_raw, image).map_err(
773 |error| RendererError::RendererInitFailed(format!("Could not upload texture: {}", error)))?);
774
775 let window = display_raw.window_clone();
776
777 let display = Rc::new(RefCell::new(display_raw));
778 #[cfg(feature = "imgui_feature")]
779 let imgui_renderer = Rc::new(RefCell::new(None));
780 let sheet_data_preparer = Box::new(GpuSheetPreparer
781 {
782 display : display.clone(),
783 default_texture: default_texture.clone(),
784 texture_filtering : renderer_new_info.texture_filtering,
785 #[cfg(feature = "imgui_feature")]
786 imgui_renderer: imgui_renderer.clone()
787 });
788 let shader_data_preparer = Box::new(GpuShaderPreparer
789 {
790 display : display.clone()
791 });
792
793 let gpu_sheet_store = PreparedStore::new(&mut renderer_new_info.resources.store_mut(),
794 sheet_data_preparer).map_err(
795 |error| RendererError::LoadResourceFailed(format!("Failed to create GPU sheet handle store: {}", error)))?;
796
797 let gpu_shader_store = PreparedStore::new(&mut renderer_new_info.resources.store_mut(),
798 shader_data_preparer).map_err(
799 |error| RendererError::LoadResourceFailed(format!("Failed to create GPU shader handle store: {}", error)))?;
800
801 Ok((Box::new(GlDrawControl
802 {
803 display,
804 window : window.clone(),
805 viewport_offset : (0.0, 0.0),
806 viewport_mode : renderer_new_info.viewport_mode,
807 base_width : renderer_new_info.width as f32,
808 base_height : renderer_new_info.height as f32,
809 scale_width : 0.0,
810 scale_height : 0.0,
811 need_recalc_viewport : false,
812 quad_buffer,
813 index_buffer,
814 instance_buffer_src : Box::new([Default::default() ; INSTANCES_MAX]),
815 instance_buffer,
816 instance_buffer_flip : 0,
817 default_texture,
818 shader_list,
819 scissor : None,
820 frame : None,
821 pixel_scale : 1,
822 last_pixel_scale : 0,
823 pixel_texture,
824 pixel_upscale_texture : None,
825 current_index : 0,
826 index_runs : Vec::new(),
827 current_run : BatchRun { start : 0, len : 0, param : InstanceBufferParam::default() },
828 last_view_transform : DrawTransform::identity(),
829 gpu_sheet_store,
830 gpu_shader_store,
831 #[cfg(feature = "imgui_feature")]
832 imgui_renderer,
833 }), window))
834 }
835
836 fn sync_sheet_store(&mut self, sheet_store : &mut DataStore<Sheet>) -> Result<(), PreparedStoreError>
837 {
838 self.gpu_sheet_store.sync(sheet_store)
839 }
840
841 fn sync_shader_store(&mut self, shader_store : &mut DataStore<Shader>) -> Result<(), PreparedStoreError>
842 {
843 self.gpu_shader_store.sync(shader_store)
844 }
845
846 #[cfg(feature = "imgui_feature")]
847 fn draw_imgui(&mut self, ui : imgui::Ui)
848 {
849 self.perform_draw_batch();
850
851 if let Some(frame) = &mut self.frame
852 {
853 let mut imgui_borrow = self.imgui_renderer.borrow_mut();
854
855 if let Some(imgui_renderer) = imgui_borrow.as_mut()
856 {
857 let draw_data = ui.render();
858 imgui_renderer.render(frame, &draw_data).expect("imgui render failed");
859 }
860 }
861 }
862
863 fn recalculate_viewport(&mut self, base_width : f32, base_height : f32)
864 {
865 self.base_width = base_width;
866 self.base_height = base_height;
867
868 if self.frame.is_some()
869 {
870 self.need_recalc_viewport = true;
871 return;
872 }
873
874 let (width, height) = self.window.borrow().size();
875 let info = crate::renderer::recalculate_viewport_common(base_width, base_height, width, height, self.viewport_mode);
876
877 self.scale_width = info.scale_width;
878 self.scale_height = info.scale_height;
879 self.viewport_offset = (info.scale_offset_x, info.scale_offset_y);
880 self.pixel_scale = info.pixel_scale;
881 self.scissor = match info.scissor
882 {
883 Some(scissor) =>
884 {
885 Some(glium::Rect
886 {
887 left : scissor.x,
888 bottom : scissor.y,
889 width : scissor.w,
890 height : scissor.h
891 })
892 },
893 None => None
894 }
895 }
896
897 fn start_drawing(&mut self)
898 {
899 if self.frame.is_some()
900 {
901 panic!("Cannot call draw() twice without a present()");
902 }
903
904 if self.need_recalc_viewport
905 {
906 self.recalculate_viewport(self.base_width, self.base_height);
907
908 self.need_recalc_viewport = false;
909 }
910
911 self.frame = Some(self.display.borrow().draw());
912
913 self.frame.as_mut().unwrap().clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
914
915 let mut view_transform = DrawTransform::from_array(&UNBORKED_IDENTITY_TRANSFORM);
916
917 match self.viewport_mode
918 {
919 ViewportMode::Independent | ViewportMode::OneToOneDpiScaled | ViewportMode::OneToOneUnscaled =>
920 {
921 let (x, y) = self.viewport_offset;
922
923 view_transform.scale(1.0 / self.scale_width, 1.0 / self.scale_height);
924 view_transform.translate(x, y);
925 },
926 ViewportMode::Pixel =>
927 {
928 let mut pixel_surface = self.pixel_texture.as_mut().unwrap().as_surface();
929 let (width, height) = pixel_surface.get_dimensions();
930
931 pixel_surface.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
932
933 view_transform.scale(1.0 / width as f32, 1.0 / height as f32);
934 }
935 }
936
937 self.last_view_transform = view_transform.clone();
938 self.flip_instance_buffers();
939 }
940
941 fn end_drawing(&mut self)
942 {
943 self.perform_draw_batch();
944
945 self.display.borrow().get_context().flush();
946 }
947
948 fn present(&mut self)
949 {
950 if self.frame.is_some()
951 {
952 match self.viewport_mode
953 {
954 ViewportMode::Independent | ViewportMode::OneToOneDpiScaled | ViewportMode::OneToOneUnscaled => (),
955 ViewportMode::Pixel =>
956 {
957 let mut transform = DrawTransform::from_array(&UNBORKED_UPSCALE_TRANSFORM);
960
961 let params = glium::DrawParameters::default();
962
963 self.instance_buffer_src[0] = upscale_instance_from_transform(&transform);
964 self.instance_buffer[self.instance_buffer_flip].invalidate();
965 self.instance_buffer[self.instance_buffer_flip].write(&self.instance_buffer_src[..]);
966
967 self.update_pixel_upscale();
968
969 let uniform = uniform!
970 {
971 t_texture : Sampler::new(self.pixel_texture.as_ref().unwrap())
972 .magnify_filter(MagnifySamplerFilter::Nearest)
973 .minify_filter(MinifySamplerFilter::Nearest)
974 .wrap_function(SamplerWrapFunction::Clamp)
975 };
976
977 self.pixel_upscale_texture.as_mut().unwrap().as_surface().draw((&self.quad_buffer,
978 self.instance_buffer[self.instance_buffer_flip].slice(0..1)
979 .expect("Failed to prepare instance buffer").per_instance()
980 .expect("Failed to prepare instance buffer")),
981 &self.index_buffer, &self.shader_list[RendererOp::Sprite as usize],
982 &uniform, ¶ms).expect("Draw operation failed");
983
984 let uniform = uniform!
987 {
988 t_texture : Sampler::new(self.pixel_upscale_texture.as_ref().unwrap())
989 .magnify_filter(MagnifySamplerFilter::Linear)
990 .minify_filter(MinifySamplerFilter::Linear)
991 .wrap_function(SamplerWrapFunction::Clamp)
992 };
993
994 let (x, y) = self.viewport_offset;
995 transform.scale(1.0 / self.scale_width, 1.0 / self.scale_height);
996 transform.translate(x, y);
997
998 self.instance_buffer_src[0] = upscale_instance_from_transform(&transform);
999 self.instance_buffer[self.instance_buffer_flip].invalidate();
1000 self.instance_buffer[self.instance_buffer_flip].write(&self.instance_buffer_src[..]);
1001
1002 self.frame.as_mut().unwrap().draw((&self.quad_buffer,
1003 self.instance_buffer[self.instance_buffer_flip].slice(0..1)
1004 .expect("Failed to prepare instance buffer").per_instance()
1005 .expect("Failed to prepare instance buffer")),
1006 &self.index_buffer, &self.shader_list[RendererOp::Sprite as usize],
1007 &uniform, ¶ms).expect("Draw operation failed");
1008 }
1009 }
1010
1011 let mut frame = None;
1012 std::mem::swap(&mut frame, &mut self.frame);
1013
1014 frame.unwrap().finish().expect("Draw finish failed");
1015 }
1016 }
1017
1018 #[cfg(feature = "imgui_feature")]
1019 fn init_imgui_renderer(&mut self, imgui : &mut imgui::Context) -> Result<(), RendererError>
1020 {
1021 let mut imgui_borrow = self.imgui_renderer.borrow_mut();
1022
1023 if imgui_borrow.is_some()
1024 {
1025 return Err(RendererError::ImguiRendererFailed("Already initialized".to_string()));
1026 }
1027
1028 let mut imgui_renderer = imgui_glium_renderer::Renderer::init(
1029 imgui, &*self.display.borrow()).map_err(
1030 |error| RendererError::ImguiRendererFailed(format!("Could not initialize imgui renderer: {}", error)))?;
1031
1032 imgui_renderer.textures().replace(imgui::TextureId::from(0), imgui_glium_renderer::Texture
1033 {
1034 texture : self.default_texture.clone(),
1035 sampler : SamplerBehavior
1036 {
1037 wrap_function: (SamplerWrapFunction::Repeat, SamplerWrapFunction::Repeat, SamplerWrapFunction::Repeat),
1038 minify_filter: MinifySamplerFilter::Linear,
1039 magnify_filter: MagnifySamplerFilter::Linear,
1040 .. Default::default()
1041 }
1042 });
1043
1044 *imgui_borrow = Some(imgui_renderer);
1045
1046 Ok(())
1047 }
1048
1049 #[cfg(feature = "imgui_feature")]
1050 fn update_imgui_renderer(&mut self, imgui : &mut imgui::Context)
1051 {
1052 let mut imgui_borrow = self.imgui_renderer.borrow_mut();
1053
1054 if let Some(imgui_renderer) = imgui_borrow.as_mut()
1055 {
1056 if !imgui.fonts().is_built()
1057 {
1058 imgui_renderer.reload_font_texture(imgui).expect("Font texture update failed");
1059 }
1060 }
1061 }
1062}