1use crate::cx::*;
2use crate::cx_xlib::*;
3use makepad_glx_sys as glx_sys;
4use makepad_x11_sys as X11_sys;
5use std::ffi::{CStr, CString};
6use std::os::raw::{c_ulong, c_void};
7use std::ptr;
8use std::mem;
9
10impl Cx {
11
12 pub fn render_view(
13 &mut self,
14 pass_id: usize,
15 view_id: usize,
16 scroll: Vec2,
17 clip: (Vec2, Vec2),
18 full_repaint: bool,
19 view_rect: &Rect,
20 opengl_cx: &OpenglCx,
21 zbias: &mut f32,
22 zbias_step: f32
23 ) {
24
25 let draw_calls_len = self.views[view_id].draw_calls_len;
27 if !full_repaint && !view_rect.intersects(self.views[view_id].get_scrolled_rect()) {
28 return
29 }
30 self.views[view_id].uniform_view_transform(&Mat4::identity());
31 self.views[view_id].parent_scroll = scroll;
32 let local_scroll = self.views[view_id].get_local_scroll();
33 let clip = self.views[view_id].intersect_clip(clip);
34 for draw_call_id in 0..draw_calls_len {
35 let sub_view_id = self.views[view_id].draw_calls[draw_call_id].sub_view_id;
36 if sub_view_id != 0 {
37 self.render_view(
38 pass_id,
39 sub_view_id,
40 Vec2 {x: local_scroll.x + scroll.x, y: local_scroll.y + scroll.y},
41 clip,
42 full_repaint,
43 view_rect,
44 opengl_cx,
45 zbias,
46 zbias_step
47 );
48 }
49 else {
50 let cxview = &mut self.views[view_id];
51 let draw_call = &mut cxview.draw_calls[draw_call_id];
53 let sh = &self.shaders[draw_call.shader_id];
54 let shp = sh.platform.as_ref().unwrap();
55
56 if draw_call.instance_dirty {
57 draw_call.instance_dirty = false;
58 draw_call.platform.inst_vbuf.update_with_f32_data(opengl_cx, &draw_call.instance);
59 }
60
61 draw_call.platform.check_vao(draw_call.shader_id, &shp);
62
63 draw_call.set_zbias(*zbias);
64 draw_call.set_local_scroll(scroll, local_scroll);
65 draw_call.set_clip(clip);
66 *zbias += zbias_step;
67
68 if draw_call.uniforms_dirty {
69 draw_call.uniforms_dirty = false;
70 }
71
72 unsafe {
73 gl::UseProgram(shp.program);
74 gl::BindVertexArray(draw_call.platform.vao.unwrap());
75 let instances = draw_call.instance.len() / sh.mapping.instance_slots;
76 let indices = sh.shader_gen.geometry_indices.len();
77
78 let pass_uniforms = self.passes[pass_id].pass_uniforms.as_slice();
79 let view_uniforms = cxview.view_uniforms.as_slice();
80 let draw_uniforms = draw_call.draw_uniforms.as_slice();
81
82 opengl_cx.set_uniform_buffer(&shp.pass_uniforms, pass_uniforms);
83 opengl_cx.set_uniform_buffer(&shp.view_uniforms, view_uniforms);
84 opengl_cx.set_uniform_buffer(&shp.draw_uniforms, draw_uniforms);
85 opengl_cx.set_uniform_buffer(&shp.uniforms, &draw_call.uniforms);
86
87 for (i, texture_id) in draw_call.textures_2d.iter().enumerate() {
89 let cxtexture = &mut self.textures[*texture_id as usize];
90 if cxtexture.update_image {
91 opengl_cx.update_platform_texture_image2d(cxtexture);
92 }
93 gl::ActiveTexture(gl::TEXTURE0 + i as u32);
95 if let Some(texture) = cxtexture.platform.gl_texture {
96 gl::BindTexture(gl::TEXTURE_2D, texture);
97 }
98 else {
99 gl::BindTexture(gl::TEXTURE_2D, 0);
100 }
101 }
102
103 gl::DrawElementsInstanced(
104 gl::TRIANGLES,
105 indices as i32,
106 gl::UNSIGNED_INT,
107 ptr::null(),
108 instances as i32
109 );
110 }
111 }
112 }
113 }
114
115 pub fn calc_dirty_bounds(&mut self, pass_id: usize, view_id: usize, view_bounds: &mut ViewBounds) {
116 let draw_calls_len = self.views[view_id].draw_calls_len;
117 for draw_call_id in 0..draw_calls_len {
118 let sub_view_id = self.views[view_id].draw_calls[draw_call_id].sub_view_id;
119 if sub_view_id != 0 {
120 self.calc_dirty_bounds(pass_id, sub_view_id, view_bounds)
121 }
122 else {
123 let cxview = &mut self.views[view_id];
124 let draw_call = &mut cxview.draw_calls[draw_call_id];
125 if draw_call.instance_dirty || draw_call.uniforms_dirty {
129 view_bounds.add_rect(&cxview.get_inverse_scrolled_rect());
130 }
131 }
132 }
133 }
134
135 pub fn set_default_depth_and_blend_mode() {
136 unsafe {
137 gl::Enable(gl::DEPTH_TEST);
138 gl::DepthFunc(gl::LEQUAL);
139 gl::BlendEquationSeparate(gl::FUNC_ADD, gl::FUNC_ADD);
140 gl::BlendFuncSeparate(gl::ONE, gl::ONE_MINUS_SRC_ALPHA, gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
141 gl::Enable(gl::BLEND);
142 }
143 }
144
145 pub fn draw_pass_to_window(
146 &mut self,
147 pass_id: usize,
148 dpi_factor: f32,
149 opengl_window: &mut OpenglWindow,
150 opengl_cx: &OpenglCx,
151 _force_full_repaint: bool,
152 ) -> bool {
153 let view_id = self.passes[pass_id].main_view_id.unwrap();
154
155 let mut view_bounds = ViewBounds::new();
156 let mut init_repaint = false;
157 self.calc_dirty_bounds(pass_id, view_id, &mut view_bounds);
158
159 let full_repaint = true;if opengl_window.opening_repaint_count < 10 { opengl_window.opening_repaint_count += 1;
164 init_repaint = true;
165 }
166 let window;
167 let view_rect;
168 if full_repaint {
169 opengl_window.xlib_window.hide_child_windows();
170
171 window = opengl_window.xlib_window.window.unwrap();
172
173 let pass_size = self.passes[pass_id].pass_size;
174 self.passes[pass_id].set_ortho_matrix(Vec2::default(), pass_size);
175
176 let pix_width = opengl_window.window_geom.inner_size.x * opengl_window.window_geom.dpi_factor;
177 let pix_height = opengl_window.window_geom.inner_size.y * opengl_window.window_geom.dpi_factor;
178
179 unsafe {
180 glx_sys::glXMakeCurrent(opengl_cx.display, window, opengl_cx.context);
181 gl::Viewport(0, 0, pix_width as i32, pix_height as i32);
182 }
183 view_rect = Rect::default();
184 }
185 else {
186 if view_bounds.max_x == std::f32::NEG_INFINITY
187 || view_bounds.max_y == std::f32::NEG_INFINITY
188 || view_bounds.min_x == std::f32::INFINITY
189 || view_bounds.min_x == std::f32::INFINITY
190 || view_bounds.min_x == view_bounds.max_x
191 || view_bounds.min_y == view_bounds.max_y {
192 return false
193 }
194 let pix_width = (view_bounds.max_x - view_bounds.min_x) * opengl_window.window_geom.dpi_factor;
209 let pix_height = (view_bounds.max_y - view_bounds.min_y) * opengl_window.window_geom.dpi_factor;
210
211 window = opengl_window.xlib_window.alloc_child_window(
212 (view_bounds.min_x * opengl_window.window_geom.dpi_factor) as i32,
213 (view_bounds.min_y * opengl_window.window_geom.dpi_factor) as i32,
214 pix_width as u32,
215 pix_height as u32
216 ).unwrap();
217
218 self.passes[pass_id].set_ortho_matrix(
220 Vec2 {x: view_bounds.min_x, y: view_bounds.min_y},
221 Vec2 {x: pix_width / opengl_window.window_geom.dpi_factor, y: pix_height / opengl_window.window_geom.dpi_factor}
222 );
223
224 unsafe {
225 glx_sys::glXMakeCurrent(opengl_cx.display, window, opengl_cx.context);
226 gl::Viewport(0, 0, pix_width as i32, pix_height as i32);
227 }
228 view_rect = Rect {x: view_bounds.min_x, y: view_bounds.min_y, w: view_bounds.max_x - view_bounds.min_x, h: view_bounds.max_y - view_bounds.min_y}
229 }
230
231 self.passes[pass_id].uniform_camera_view(&Mat4::identity());
232 self.passes[pass_id].set_dpi_factor(dpi_factor);
233 let clear_color = if self.passes[pass_id].color_textures.len() == 0 {
235 Color::default()
236 }
237 else {
238 match self.passes[pass_id].color_textures[0].clear_color {
239 ClearColor::InitWith(color) => color,
240 ClearColor::ClearWith(color) => color
241 }
242 };
243 let clear_depth = match self.passes[pass_id].clear_depth {
244 ClearDepth::InitWith(depth) => depth,
245 ClearDepth::ClearWith(depth) => depth
246 };
247
248 unsafe {
249 gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
250 gl::ClearDepth(clear_depth);
251 gl::ClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
252 gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
253 }
254 Self::set_default_depth_and_blend_mode();
255
256 let mut zbias = 0.0;
257 let zbias_step = self.passes[pass_id].zbias_step;
258
259 self.render_view(
260 pass_id,
261 view_id,
262 Vec2::default(),
263 (Vec2 {x: -50000., y: -50000.}, Vec2 {x: 50000., y: 50000.}),
264 full_repaint,
265 &view_rect,
266 &opengl_cx,
267 &mut zbias,
268 zbias_step
269 );
270
271 unsafe {
272 glx_sys::glXSwapBuffers(opengl_cx.display, window);
273 }
274 return init_repaint;
275 }
276
277 pub fn draw_pass_to_texture(
278 &mut self,
279 pass_id: usize,
280 inherit_dpi_factor: f32,
281 opengl_cx: &OpenglCx,
282 ) {
283
284 let pass_size = self.passes[pass_id].pass_size;
285 self.passes[pass_id].set_ortho_matrix(Vec2::default(), pass_size);
286 self.passes[pass_id].uniform_camera_view(&Mat4::identity());
287 self.passes[pass_id].paint_dirty = false;
288
289 let dpi_factor = if let Some(override_dpi_factor) = self.passes[pass_id].override_dpi_factor {
290 override_dpi_factor
291 }
292 else {
293 inherit_dpi_factor
294 };
295 self.passes[pass_id].set_dpi_factor(dpi_factor);
296
297 let mut clear_color = Color::default();
298 let mut clear_depth = 1.0;
299 let mut clear_flags = 0;
300
301 if self.passes[pass_id].platform.gl_framebuffer.is_none() {
303 unsafe {
304 let mut gl_framebuffer = std::mem::MaybeUninit::uninit();
305 gl::GenFramebuffers(1, gl_framebuffer.as_mut_ptr());
306 self.passes[pass_id].platform.gl_framebuffer = Some(gl_framebuffer.assume_init());
307 }
308 }
309
310 unsafe {
312 gl::BindFramebuffer(gl::FRAMEBUFFER, self.passes[pass_id].platform.gl_framebuffer.unwrap());
313 }
314
315 for (index, color_texture) in self.passes[pass_id].color_textures.iter().enumerate() {
316 match color_texture.clear_color {
317 ClearColor::InitWith(color) => {
318 if opengl_cx.update_platform_render_target(&mut self.textures[color_texture.texture_id], dpi_factor, pass_size, false) {
319 clear_color = color;
320 clear_flags = gl::COLOR_BUFFER_BIT;
321 }
322 },
323 ClearColor::ClearWith(color) => {
324 opengl_cx.update_platform_render_target(&mut self.textures[color_texture.texture_id], dpi_factor, pass_size, false);
325 clear_color = color;
326 clear_flags = gl::COLOR_BUFFER_BIT;
327 }
328 }
329 if let Some(gl_texture) = self.textures[color_texture.texture_id].platform.gl_texture {
330 unsafe {
331 gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + index as u32, gl::TEXTURE_2D, gl_texture, 0);
332 }
333 }
334 }
335
336 if let Some(depth_texture_id) = self.passes[pass_id].depth_texture {
338 match self.passes[pass_id].clear_depth {
339 ClearDepth::InitWith(depth_clear) => {
340 if opengl_cx.update_platform_render_target(&mut self.textures[depth_texture_id], dpi_factor, pass_size, true) {
341 clear_depth = depth_clear;
342 clear_flags = gl::DEPTH_BUFFER_BIT;
343 }
344 },
345 ClearDepth::ClearWith(depth_clear) => {
346 opengl_cx.update_platform_render_target(&mut self.textures[depth_texture_id], dpi_factor, pass_size, true);
347 clear_depth = depth_clear;
348 clear_flags = gl::COLOR_BUFFER_BIT;
349 }
350 }
351 if let Some(gl_texture) = self.textures[depth_texture_id].platform.gl_texture {
352 unsafe {
353 gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::DEPTH_STENCIL_ATTACHMENT, gl::TEXTURE_2D, gl_texture, 0);
354 }
355 }
356 }
357 unsafe {
358 gl::Viewport(0, 0, (pass_size.x * dpi_factor) as i32, (pass_size.y * dpi_factor) as i32);
359 }
360 if clear_flags != 0 {
361 unsafe {
362 gl::ClearDepth(clear_depth);
363 gl::ClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
364 gl::Clear(clear_flags);
365 }
366 }
367
368 Self::set_default_depth_and_blend_mode();
369
370 let mut zbias = 0.0;
371 let zbias_step = self.passes[pass_id].zbias_step;
372 let view_id = self.passes[pass_id].main_view_id.unwrap();
373
374 self.render_view(
375 pass_id,
376 view_id,
377 Vec2::default(),
378 (Vec2 {x: -50000., y: -50000.}, Vec2 {x: 50000., y: 50000.}),
379 true,
380 &Rect::default(),
381 &opengl_cx,
382 &mut zbias,
383 zbias_step
384 );
385
386 }
387
388 pub fn opengl_compile_all_shaders(&mut self, opengl_cx: &OpenglCx) {
419 unsafe {
420 glx_sys::glXMakeCurrent(opengl_cx.display, opengl_cx.hidden_window, opengl_cx.context);
421 }
422 for sh in &mut self.shaders {
423 let openglsh = Self::opengl_compile_shader(sh, opengl_cx);
424 if let Err(err) = openglsh {
425 panic!("Got opengl shader compile error:: {}", err.msg);
426 }
427 };
428 }
429
430 pub fn opengl_has_shader_error(compile: bool, shader: usize, source: &str) -> Option<String> {
431 unsafe {
433
434 let mut success = i32::from(gl::FALSE);
435
436 if compile {
437 gl::GetShaderiv(shader as u32, gl::COMPILE_STATUS, &mut success);
438 }
439 else {
440 gl::GetProgramiv(shader as u32, gl::LINK_STATUS, &mut success);
441 };
442
443 if success != i32::from(gl::TRUE) {
444 let mut length = 0;
445 if compile {
446 gl::GetShaderiv(shader as u32, gl::INFO_LOG_LENGTH, &mut length);
447 } else {
448 gl::GetProgramiv(shader as u32, gl::INFO_LOG_LENGTH, &mut length);
449 }
450 let mut log = Vec::with_capacity(length as usize);
451 if compile {
452 gl::GetShaderInfoLog(shader as u32, length, ptr::null_mut(), log.as_mut_ptr());
453 } else {
454 gl::GetProgramInfoLog(shader as u32, length, ptr::null_mut(), log.as_mut_ptr());
455 }
456 log.set_len(length as usize);
457 let mut r = "".to_string();
458 r.push_str(CStr::from_ptr(log.as_ptr()).to_str().unwrap());
459 r.push_str("\n");
460 let split = source.split("\n");
461 for (line, chunk) in split.enumerate() {
462 r.push_str(&(line + 1).to_string());
463 r.push_str(":");
464 r.push_str(chunk);
465 r.push_str("\n");
466 }
467 Some(r)
468 }
469 else {
470 None
471 }
472 }
473 }
474
475 pub fn opengl_get_attributes(program: u32, prefix: &str, slots: usize) -> Vec<OpenglAttribute> {
476 let mut attribs = Vec::new();
477
478 let stride = (slots * mem::size_of::<f32>()) as i32;
479 let num_attr = Self::ceil_div4(slots);
480 for i in 0..num_attr {
481 let mut name = prefix.to_string();
482 name.push_str(&i.to_string());
483 name.push_str("\0");
484
485 let mut size = ((slots - i * 4)) as i32;
486 if size > 4 {
487 size = 4;
488 }
489 unsafe {
490 attribs.push(
491 OpenglAttribute {
492 loc: gl::GetAttribLocation(program, name.as_ptr() as *const _) as u32,
493 offset: (i * 4 * mem::size_of::<f32>()) as usize,
494 size: size,
495 stride: stride
496 }
497 )
498 }
499 }
500 attribs
501 }
502
503 pub fn opengl_get_uniforms(program: u32, sg: &ShaderGen, unis: &Vec<ShVar>) -> Vec<OpenglUniform> {
504 let mut gl_uni = Vec::new();
505
506 for uni in unis {
507 let mut name0 = "".to_string();
508 name0.push_str(&uni.name);
509 name0.push_str("\0");
510 unsafe {
511 gl_uni.push(OpenglUniform {
512 loc: gl::GetUniformLocation(program, name0.as_ptr() as *const _),
513 name: uni.name.clone(),
514 size: sg.get_type_slots(&uni.ty)
515 })
516 }
517 }
518 gl_uni
519 }
520
521 pub fn opengl_get_texture_slots(program: u32, texture_slots: &Vec<ShVar>) -> Vec<OpenglUniform> {
522 let mut gl_texture_slots = Vec::new();
523
524 for slot in texture_slots {
525 let mut name0 = "".to_string();
526 name0.push_str(&slot.name);
527 name0.push_str("\0");
528 unsafe {
529 gl_texture_slots.push(OpenglUniform {
530 loc: gl::GetUniformLocation(program, name0.as_ptr() as *const _),
531 name: slot.name.clone(),
532 size: 0
533 })
535 }
536 }
537 gl_texture_slots
538 }
539
540 pub fn opengl_compile_shader(sh: &mut CxShader, opengl_cx: &OpenglCx) -> Result<(), SlErr> {
541
542 let (vertex, fragment, mapping) = Self::gl_assemble_shader(&sh.shader_gen, GLShaderType::OpenGL) ?;
543 unsafe {
546 let vs = gl::CreateShader(gl::VERTEX_SHADER);
547 gl::ShaderSource(vs, 1, [vertex.as_ptr() as *const _].as_ptr(), ptr::null());
548 gl::CompileShader(vs);
549 if let Some(error) = Self::opengl_has_shader_error(true, vs as usize, &vertex) {
550 return Err(SlErr {
551 msg: format!("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n{}", error)
552 })
553 }
554
555 let fs = gl::CreateShader(gl::FRAGMENT_SHADER);
556 gl::ShaderSource(fs, 1, [fragment.as_ptr() as *const _].as_ptr(), ptr::null());
557 gl::CompileShader(fs);
558 if let Some(error) = Self::opengl_has_shader_error(true, fs as usize, &fragment) {
559 return Err(SlErr {
560 msg: format!("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n{}", error)
561 })
562 }
563
564 let program = gl::CreateProgram();
565 gl::AttachShader(program, vs);
566 gl::AttachShader(program, fs);
567 gl::LinkProgram(program);
568 if let Some(error) = Self::opengl_has_shader_error(false, program as usize, "") {
569 return Err(SlErr {
570 msg: format!("ERROR::SHADER::LINK::COMPILATION_FAILED\n{}", error)
571 })
572 }
573 gl::DeleteShader(vs);
574 gl::DeleteShader(fs);
575
576 let geom_attribs = Self::opengl_get_attributes(program, "geomattr", mapping.geometry_slots);
577 let inst_attribs = Self::opengl_get_attributes(program, "instattr", mapping.instance_slots);
578
579 sh.platform = Some(CxPlatformShader {
581 program: program,
582 geom_ibuf: {
583 let mut buf = OpenglBuffer::default();
584 buf.update_with_u32_data(opengl_cx, &sh.shader_gen.geometry_indices);
585 buf
586 },
587 geom_vbuf: {
588 let mut buf = OpenglBuffer::default();
589 buf.update_with_f32_data(opengl_cx, &sh.shader_gen.geometry_vertices);
590 buf
591 },
592 geom_attribs,
593 inst_attribs,
594 pass_uniforms: Self::opengl_get_uniforms(program, &sh.shader_gen, &mapping.pass_uniforms),
595 view_uniforms: Self::opengl_get_uniforms(program, &sh.shader_gen, &mapping.view_uniforms),
596 draw_uniforms: Self::opengl_get_uniforms(program, &sh.shader_gen, &mapping.draw_uniforms),
597 uniforms: Self::opengl_get_uniforms(program, &sh.shader_gen, &mapping.uniforms),
598 });
599 sh.mapping = mapping;
600 return Ok(());
601 }
602 }
603}
604
605#[derive(Clone, PartialEq)]
606pub struct ViewBounds {
607 pub min_x: f32,
608 pub min_y: f32,
609 pub max_x: f32,
610 pub max_y: f32
611}
612
613impl ViewBounds {
614 fn new() -> ViewBounds {
615 ViewBounds {
616 min_x: std::f32::INFINITY,
617 min_y: std::f32::INFINITY,
618 max_x: std::f32::NEG_INFINITY,
619 max_y: std::f32::NEG_INFINITY,
620 }
621 }
622
623 fn add_rect(&mut self, rect: &Rect) {
624 if rect.x < self.min_x {
625 self.min_x = rect.x;
626 }
627 if rect.x + rect.w > self.max_x {
628 self.max_x = rect.x + rect.w;
629 }
630 if rect.y < self.min_y {
631 self.min_y = rect.y;
632 }
633 if rect.y + rect.h > self.max_y {
634 self.max_y = rect.y + rect.h;
635 }
636 }
637}
638pub struct OpenglCx {
639 pub display: *mut glx_sys::Display,
640 pub context: glx_sys::GLXContext,
641 pub visual_info: glx_sys::XVisualInfo,
642 pub hidden_window: glx_sys::Window,
643}
644
645impl OpenglCx {
646 pub fn new(display: *mut X11_sys::Display) -> OpenglCx {
647 unsafe {
648 let display = display as *mut glx_sys::Display;
649
650 let mut major = 0;
652 let mut minor = 0;
653 assert!(
654 glx_sys::glXQueryVersion(display, &mut major, &mut minor) >= 0,
655 "can't query GLX version"
656 );
657
658 assert!(
660 major > 1 || major == 1 && minor >= 4,
661 "GLX version must be 1.4 or higher, got {}.{}",
662 major,
663 minor,
664 );
665
666 let screen = glx_sys::XDefaultScreen(display);
667
668 let supported_extensions = glx_sys::glXQueryExtensionsString(display, screen);
670 assert!(
671 !supported_extensions.is_null(),
672 "can't query GLX extensions string"
673 );
674 let supported_extensions = CStr::from_ptr(supported_extensions).to_str().unwrap();
675
676 let required_extensions = &["GLX_ARB_get_proc_address", "GLX_ARB_create_context"];
678 for required_extension in required_extensions {
679 assert!(
680 supported_extensions.contains(required_extension),
681 "extension {} is required, but not supported",
682 required_extension,
683 );
684 }
685
686 #[allow(non_snake_case)]
688 let glXCreateContextAttribsARB = mem::transmute::<
689 _,
690 glx_sys::PFNGLXCREATECONTEXTATTRIBSARBPROC,
691 >(glx_sys::glXGetProcAddressARB(
692 CString::new("glXCreateContextAttribsARB")
693 .unwrap()
694 .to_bytes_with_nul()
695 .as_ptr(),
696 ))
697 .expect("can't load glXCreateContextAttribsARB function pointer");
698
699 gl::load_with(|symbol| {
701 glx_sys::glXGetProcAddressARB(
702 CString::new(symbol).unwrap().to_bytes_with_nul().as_ptr(),
703 )
704 .map_or(ptr::null(), |ptr| ptr as *const c_void)
705 });
706
707 let config_attribs = &[
709 glx_sys::GLX_DOUBLEBUFFER as i32,
710 glx_sys::True as i32,
711 glx_sys::GLX_RED_SIZE as i32,
712 8,
713 glx_sys::GLX_GREEN_SIZE as i32,
714 8,
715 glx_sys::GLX_BLUE_SIZE as i32,
716 8,
717 glx_sys::GLX_ALPHA_SIZE as i32,
718 8,
719 glx_sys::None as i32,
720 ];
721 let mut config_count = 0;
722 let configs = glx_sys::glXChooseFBConfig(
723 display,
724 glx_sys::XDefaultScreen(display),
725 config_attribs.as_ptr(),
726 &mut config_count,
727 );
728 if configs.is_null() {
729 panic!("can't choose framebuffer configuration");
730 }
731 let config = *configs;
732 glx_sys::XFree(configs as *mut c_void);
733
734 let context_attribs = &[
736 glx_sys::GLX_CONTEXT_MAJOR_VERSION_ARB as i32,
737 3,
738 glx_sys::GLX_CONTEXT_MINOR_VERSION_ARB as i32,
739 0,
740 glx_sys::GLX_CONTEXT_PROFILE_MASK_ARB as i32,
741 glx_sys::GLX_CONTEXT_ES_PROFILE_BIT_EXT as i32,
742 glx_sys::None as i32
743 ];
744 let context = glXCreateContextAttribsARB(
745 display,
746 config,
747 ptr::null_mut(),
748 glx_sys::True as i32,
749 context_attribs.as_ptr(),
750 );
751
752 let visual_info_ptr = glx_sys::glXGetVisualFromFBConfig(display, config);
754 assert!(
755 !visual_info_ptr.is_null(),
756 "can't get visual from framebuffer configuration"
757 );
758 let visual_info = *visual_info_ptr;
759 glx_sys::XFree(visual_info_ptr as *mut c_void);
760
761 let root_window = glx_sys::XRootWindow(display, screen);
762
763 let mut attributes = mem::zeroed::<glx_sys::XSetWindowAttributes>();
769
770 attributes.colormap = glx_sys::XCreateColormap(
773 display,
774 root_window,
775 visual_info.visual,
776 glx_sys::AllocNone as i32
777 );
778 let hidden_window = glx_sys::XCreateWindow(
779 display,
780 root_window,
781 0,
782 0,
783 16,
784 16,
785 0,
786 visual_info.depth,
787 glx_sys::InputOutput as u32,
788 visual_info.visual,
789 glx_sys::CWColormap as c_ulong,
790 &mut attributes,
791 );
792
793 OpenglCx {
796 display,
797 context,
798 visual_info,
799 hidden_window,
800 }
801 }
802 }
803
804 pub fn set_uniform_buffer(&self, locs: &Vec<OpenglUniform>, uni: &[f32]) {
805
806 let mut o = 0;
807 for loc in locs {
808 if o + loc.size > uni.len() {
809 return
810 }
811 if (o & 3) != 0 && (o & 3) + loc.size > 4 { o += 4 - (o & 3); }
814 if loc.loc >= 0 {
815 unsafe {
816
817 match loc.size {
818 1 => {
819 gl::Uniform1f(loc.loc as i32, uni[o]);
820 },
821 2 => gl::Uniform2f(loc.loc as i32, uni[o], uni[o + 1]),
822 3 => gl::Uniform3f(loc.loc as i32, uni[o], uni[o + 1], uni[o + 2]),
823 4 => {
824 gl::Uniform4f(loc.loc as i32, uni[o], uni[o + 1], uni[o + 2], uni[o + 3]);
825 },
826 16 => {
827 gl::UniformMatrix4fv(loc.loc as i32, 1, 0, uni.as_ptr().offset((o) as isize));
828 },
829 _ => ()
830 }
831 }
832 };
833 o = o + loc.size;
834 }
835
836 }
837
838 pub fn update_platform_texture_image2d(&self, cxtexture: &mut CxTexture) {
839
840 if cxtexture.desc.width.is_none() || cxtexture.desc.height.is_none() {
841 println!("update_platform_texture_image2d without width/height");
842 return;
843 }
844
845 let width = cxtexture.desc.width.unwrap();
846 let height = cxtexture.desc.height.unwrap();
847
848 if cxtexture.platform.alloc_desc != cxtexture.desc {
850
851 cxtexture.platform.alloc_desc = cxtexture.desc.clone();
852 cxtexture.platform.width = width as u64;
853 cxtexture.platform.height = height as u64;
854
855 let gl_texture = match cxtexture.platform.gl_texture {
856 None => {
857 unsafe {
858 let mut gl_texture = std::mem::MaybeUninit::uninit();
859 gl::GenTextures(1, gl_texture.as_mut_ptr());
860 let gl_texture = gl_texture.assume_init();
861 cxtexture.platform.gl_texture = Some(gl_texture);
862 gl_texture
863 }
864 }
865 Some(gl_texture_old) => {
866 gl_texture_old
867 }
868 };
869 unsafe {
870 gl::BindTexture(gl::TEXTURE_2D, gl_texture);
871 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
872 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
873 gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as i32, width as i32, height as i32, 0, gl::RGBA, gl::UNSIGNED_BYTE, cxtexture.image_u32.as_ptr() as *const _);
874 gl::BindTexture(gl::TEXTURE_2D, 0);
875 }
876 }
877
878 cxtexture.update_image = false;
879 }
880
881 pub fn update_platform_render_target(&self, cxtexture: &mut CxTexture, dpi_factor: f32, size: Vec2, is_depth: bool) -> bool {
882 let width = if let Some(width) = cxtexture.desc.width {width as u64} else {(size.x * dpi_factor) as u64};
883 let height = if let Some(height) = cxtexture.desc.height {height as u64} else {(size.y * dpi_factor) as u64};
884
885 if cxtexture.platform.width == width && cxtexture.platform.height == height && cxtexture.platform.alloc_desc == cxtexture.desc {
886 return false
887 }
888
889 unsafe {
890 if let Some(gl_texture) = cxtexture.platform.gl_texture {
891 gl::DeleteTextures(1, &gl_texture);
892 }
893
894 let mut gl_texture = std::mem::MaybeUninit::uninit();
895 gl::GenTextures(1, gl_texture.as_mut_ptr());
896 let gl_texture = gl_texture.assume_init();
897 gl::BindTexture(gl::TEXTURE_2D, gl_texture);
898 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
899 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
900
901 cxtexture.platform.alloc_desc = cxtexture.desc.clone();
902 cxtexture.platform.width = width;
903 cxtexture.platform.height = height;
904 cxtexture.platform.gl_texture = Some(gl_texture);
905
906 if !is_depth {
907 match cxtexture.desc.format {
908 TextureFormat::Default | TextureFormat::RenderBGRA => {
909 gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as i32, width as i32, height as i32, 0, gl::RGBA, gl::UNSIGNED_BYTE, ptr::null());
910 },
911 _ => {
912 println!("update_platform_render_target unsupported texture format");
913 return false;
914 }
915 }
916 }
917 else {
918 match cxtexture.desc.format {
919 TextureFormat::Default | TextureFormat::Depth32Stencil8 => {
920 println!("Depth stencil texture!");
921 },
922 _ => {
923 println!("update_platform_render_targete unsupported texture format");
924 return false;
925 }
926 }
927 }
928
929 }
930 return true;
931 }
932}
933
934#[derive(Clone)]
935pub struct CxPlatformShader {
936 pub program: u32,
937 pub geom_vbuf: OpenglBuffer,
938 pub geom_ibuf: OpenglBuffer,
939 pub geom_attribs: Vec<OpenglAttribute>,
940 pub inst_attribs: Vec<OpenglAttribute>,
941 pub pass_uniforms: Vec<OpenglUniform>,
942 pub view_uniforms: Vec<OpenglUniform>,
943 pub draw_uniforms: Vec<OpenglUniform>,
944 pub uniforms: Vec<OpenglUniform>
945}
946
947
948#[derive(Clone)]
949pub struct OpenglWindow {
950 pub first_draw: bool,
951 pub window_id: usize,
952 pub window_geom: WindowGeom,
953 pub opening_repaint_count: u32,
954 pub cal_size: Vec2,
955 pub xlib_window: XlibWindow,
956}
957
958impl OpenglWindow {
959 pub fn new(window_id: usize, opengl_cx: &OpenglCx, xlib_app: &mut XlibApp, inner_size: Vec2, position: Option<Vec2>, title: &str) -> OpenglWindow {
960
961 let mut xlib_window = XlibWindow::new(xlib_app, window_id);
962
963 let visual_info = unsafe { mem::transmute(opengl_cx.visual_info) };
964 xlib_window.init(title, inner_size, position, visual_info);
965
966 OpenglWindow {
967 first_draw: true,
968 window_id,
969 opening_repaint_count: 0,
970 cal_size: Vec2::default(),
971 window_geom: xlib_window.get_window_geom(),
972 xlib_window
973 }
974 }
975
976 pub fn resize_framebuffer(&mut self, _opengl_cx: &OpenglCx) -> bool {
977 let cal_size = Vec2 {
978 x: self.window_geom.inner_size.x * self.window_geom.dpi_factor,
979 y: self.window_geom.inner_size.y * self.window_geom.dpi_factor
980 };
981 if self.cal_size != cal_size {
982 self.cal_size = cal_size;
983 true
985 }
986 else {
987 false
988 }
989 }
990
991}
992
993#[derive(Default, Clone)]
994pub struct OpenglAttribute {
995 pub loc: u32,
996 pub size: i32,
997 pub offset: usize,
998 pub stride: i32
999}
1000
1001#[derive(Default, Clone)]
1002pub struct OpenglUniform {
1003 pub loc: i32,
1004 pub name: String,
1005 pub size: usize
1006}
1007#[derive(Clone, Default)]
1015pub struct CxPlatformView {
1016}
1017
1018#[derive(Default, Clone)]
1019pub struct CxPlatformDrawCall {
1020 pub inst_vbuf: OpenglBuffer,
1021 pub vao_shader_id: Option<usize>,
1022 pub vao: Option<u32>
1023}
1024
1025impl CxPlatformDrawCall {
1026
1027 pub fn check_vao(&mut self, shader_id: usize, shp: &CxPlatformShader) {
1028 if self.vao_shader_id.is_none() || self.vao_shader_id.unwrap() != shader_id {
1029 self.free_vao();
1030 unsafe {
1032 let mut vao = std::mem::MaybeUninit::uninit();
1033 gl::GenVertexArrays(1, vao.as_mut_ptr());
1034 let vao = vao.assume_init();
1035 gl::BindVertexArray(vao);
1036
1037 gl::BindBuffer(gl::ARRAY_BUFFER, shp.geom_vbuf.gl_buffer.unwrap());
1039 for attr in &shp.geom_attribs {
1040 gl::VertexAttribPointer(attr.loc, attr.size, gl::FLOAT, 0, attr.stride, attr.offset as *const () as *const _);
1041 gl::EnableVertexAttribArray(attr.loc);
1042 }
1043
1044 gl::BindBuffer(gl::ARRAY_BUFFER, self.inst_vbuf.gl_buffer.unwrap());
1045
1046 for attr in &shp.inst_attribs {
1047 gl::VertexAttribPointer(attr.loc, attr.size, gl::FLOAT, 0, attr.stride, attr.offset as *const () as *const _);
1048 gl::EnableVertexAttribArray(attr.loc);
1049 gl::VertexAttribDivisor(attr.loc, 1 as gl::types::GLuint);
1050 }
1051
1052 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, shp.geom_ibuf.gl_buffer.unwrap());
1054 gl::BindVertexArray(0);
1055
1056 self.vao_shader_id = Some(shader_id);
1057 self.vao = Some(vao);
1058 }
1059 }
1060 }
1061
1062 fn free_vao(&mut self) {
1063 unsafe {
1064 if let Some(mut vao) = self.vao {
1065 gl::DeleteVertexArrays(1, &mut vao);
1066 self.vao = None;
1067 }
1068 }
1069 }
1070}
1071
1072#[derive(Default, Clone)]
1073pub struct CxPlatformTexture {
1074 pub alloc_desc: TextureDesc,
1075 pub width: u64,
1076 pub height: u64,
1077 pub gl_texture: Option<u32>,
1078}
1079
1080#[derive(Default, Clone)]
1081pub struct CxPlatformPass {
1082 pub gl_framebuffer: Option<u32>
1083}
1084
1085#[derive(Default, Clone)]
1086pub struct OpenglBuffer {
1087 pub gl_buffer: Option<u32>
1088}
1089
1090impl OpenglBuffer {
1091
1092 pub fn alloc_gl_buffer(&mut self) {
1093 unsafe {
1094 let mut gl_buffer = std::mem::MaybeUninit::uninit();
1095 gl::GenBuffers(1, gl_buffer.as_mut_ptr());
1096 self.gl_buffer = Some(gl_buffer.assume_init());
1097 }
1098 }
1099
1100 pub fn update_with_f32_data(&mut self, _opengl_cx: &OpenglCx, data: &Vec<f32>) {
1101 if self.gl_buffer.is_none() {
1102 self.alloc_gl_buffer();
1103 }
1104 unsafe {
1105 gl::BindBuffer(gl::ARRAY_BUFFER, self.gl_buffer.unwrap());
1106 gl::BufferData(gl::ARRAY_BUFFER, (data.len() * mem::size_of::<f32>()) as gl::types::GLsizeiptr, data.as_ptr() as *const _, gl::STATIC_DRAW);
1107 }
1108 }
1109
1110 pub fn update_with_u32_data(&mut self, _opengl_cx: &OpenglCx, data: &Vec<u32>) {
1111 if self.gl_buffer.is_none() {
1112 self.alloc_gl_buffer();
1113 }
1114 unsafe {
1115 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.gl_buffer.unwrap());
1116 gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, (data.len() * mem::size_of::<u32>()) as gl::types::GLsizeiptr, data.as_ptr() as *const _, gl::STATIC_DRAW);
1117 }
1118 }
1119}