289 lines
10 KiB
Rust
289 lines
10 KiB
Rust
use crate::ifs::wl_buffer::WlBuffer;
|
|
use crate::ifs::wl_surface::WlSurface;
|
|
use crate::rect::Rect;
|
|
use crate::render::gl::frame_buffer::{with_scissor, GlFrameBuffer};
|
|
use crate::render::gl::sys::{
|
|
glActiveTexture, glBindTexture, glDisableVertexAttribArray, glDrawArrays,
|
|
glEnableVertexAttribArray, glTexParameteri, glUniform1i, glUniform4f, glUseProgram,
|
|
glVertexAttribPointer, GL_FALSE, GL_FLOAT, GL_LINEAR, GL_TEXTURE0, GL_TEXTURE_2D,
|
|
GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
|
};
|
|
use crate::render::renderer::context::RenderContext;
|
|
use crate::tree::{ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode, CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT, StackedNode};
|
|
use std::ops::Deref;
|
|
use std::rc::Rc;
|
|
use std::slice;
|
|
use crate::ifs::wl_surface::xdg_surface::XdgSurface;
|
|
|
|
const NON_COLOR: (f32, f32, f32) = (0.2, 0.2, 0.2);
|
|
const CHILD_COLOR: (f32, f32, f32) = (0.8, 0.8, 0.8);
|
|
const YES_COLOR: (f32, f32, f32) = (0.0, 0.0, 1.0);
|
|
|
|
fn focus_color(focus: ContainerFocus) -> (f32, f32, f32) {
|
|
match focus {
|
|
ContainerFocus::None => NON_COLOR,
|
|
ContainerFocus::Child => CHILD_COLOR,
|
|
ContainerFocus::Yes => YES_COLOR,
|
|
}
|
|
}
|
|
|
|
pub struct Renderer<'a> {
|
|
pub(super) renderer: &'a RenderContext,
|
|
pub(super) image: &'a GlFrameBuffer,
|
|
}
|
|
|
|
impl Renderer<'_> {
|
|
pub fn render_output(&mut self, output: &OutputNode, x: i32, y: i32) {
|
|
if let Some(ws) = output.workspace.get() {
|
|
self.render_workspace(&ws, x, y);
|
|
}
|
|
}
|
|
|
|
pub fn render_workspace(&mut self, workspace: &WorkspaceNode, x: i32, y: i32) {
|
|
if let Some(node) = workspace.container.get() {
|
|
self.render_container(&node, x, y)
|
|
}
|
|
for stacked in workspace.stacked.iter() {
|
|
match &*stacked {
|
|
StackedNode::Float(f) => {
|
|
let pos = f.position.get();
|
|
self.render_floating(f, pos.x1(), pos.y1());
|
|
}
|
|
StackedNode::Popup(p) => {
|
|
let pos = p.xdg.absolute_desired_extents.get();
|
|
self.render_xdg_surface(&p.xdg, pos.x1(), pos.y1());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn x_to_f(&self, x: i32) -> f32 {
|
|
2.0 * (x as f32 / self.image.width as f32) - 1.0
|
|
}
|
|
|
|
fn y_to_f(&self, y: i32) -> f32 {
|
|
2.0 * (y as f32 / self.image.height as f32) - 1.0
|
|
}
|
|
|
|
fn fill_boxes(&self, boxes: &[Rect], r: f32, g: f32, b: f32, a: f32) {
|
|
let mut pos = Vec::with_capacity(boxes.len() * 12);
|
|
for bx in boxes {
|
|
let x1 = self.x_to_f(bx.x1());
|
|
let y1 = self.y_to_f(bx.y1());
|
|
let x2 = self.x_to_f(bx.x2());
|
|
let y2 = self.y_to_f(bx.y2());
|
|
pos.extend_from_slice(&[
|
|
// triangle 1
|
|
x2, y1, // top right
|
|
x1, y1, // top left
|
|
x1, y2, // bottom left
|
|
// triangle 2
|
|
x2, y1, // top right
|
|
x1, y2, // bottom left
|
|
x2, y2, // bottom right
|
|
]);
|
|
}
|
|
unsafe {
|
|
glUseProgram(self.renderer.fill_prog.prog);
|
|
glUniform4f(self.renderer.fill_prog_color, r, g, b, a);
|
|
glVertexAttribPointer(
|
|
self.renderer.fill_prog_pos as _,
|
|
2,
|
|
GL_FLOAT,
|
|
GL_FALSE,
|
|
0,
|
|
pos.as_ptr() as _,
|
|
);
|
|
glEnableVertexAttribArray(self.renderer.fill_prog_pos as _);
|
|
glDrawArrays(GL_TRIANGLES, 0, (boxes.len() * 6) as _);
|
|
glDisableVertexAttribArray(self.renderer.fill_prog_pos as _);
|
|
}
|
|
}
|
|
|
|
pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) {
|
|
let cwidth = container.width.get();
|
|
let cheight = container.height.get();
|
|
let num_children = container.num_children();
|
|
let title_rect =
|
|
Rect::new_sized(x, y, container.width.get(), CONTAINER_TITLE_HEIGHT).unwrap();
|
|
if let Some(child) = container.mono_child.get() {
|
|
let space_per_child = cwidth / num_children as i32;
|
|
let mut rem = cwidth % num_children as i32;
|
|
let mut pos = x;
|
|
let (r, g, b) = focus_color(ContainerFocus::None);
|
|
self.fill_boxes(slice::from_ref(&title_rect), r, g, b, 1.0);
|
|
for child in container.children.iter() {
|
|
let focus = child.focus.get();
|
|
let (r, g, b) = focus_color(focus);
|
|
let mut width = space_per_child;
|
|
if rem > 0 {
|
|
rem -= 1;
|
|
width += 1;
|
|
}
|
|
if focus != ContainerFocus::None {
|
|
let rect = Rect::new_sized(pos, y, width, CONTAINER_TITLE_HEIGHT).unwrap();
|
|
self.fill_boxes(slice::from_ref(&rect), r, g, b, 1.0);
|
|
}
|
|
pos += width as i32;
|
|
}
|
|
unsafe {
|
|
with_scissor(&container.mono_body.get(), || {
|
|
let content = container.mono_content.get();
|
|
child.node.render(self, x + content.x1(), y + content.y1());
|
|
});
|
|
}
|
|
} else {
|
|
let split = container.split.get();
|
|
let mut rects = Vec::with_capacity(num_children);
|
|
rects.push(title_rect);
|
|
for (i, child) in container.children.iter().enumerate() {
|
|
let body = child.body.get();
|
|
if i + 1 < num_children {
|
|
let rect = if split == ContainerSplit::Horizontal {
|
|
Rect::new_sized(
|
|
x + body.x2(),
|
|
y + body.y1() - CONTAINER_TITLE_HEIGHT,
|
|
CONTAINER_BORDER,
|
|
container.height.get(),
|
|
)
|
|
.unwrap()
|
|
} else {
|
|
Rect::new_sized(
|
|
x + body.x1(),
|
|
y + body.y2(),
|
|
container.width.get(),
|
|
CONTAINER_BORDER,
|
|
)
|
|
.unwrap()
|
|
};
|
|
rects.push(rect);
|
|
}
|
|
}
|
|
let (r, g, b) = focus_color(ContainerFocus::None);
|
|
self.fill_boxes(&rects, r, g, b, 1.0);
|
|
for child in container.children.iter() {
|
|
let body = child.body.get();
|
|
if body.x1() >= cwidth || body.y1() >= cheight {
|
|
break;
|
|
}
|
|
unsafe {
|
|
with_scissor(&body, || {
|
|
let content = child.content.get();
|
|
child.node.render(self, x + content.x1(), y + content.y1());
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn render_xdg_surface(&mut self, xdg: &XdgSurface, mut x: i32, mut y: i32) {
|
|
let surface = &xdg.surface;
|
|
if let Some(geo) = xdg.geometry() {
|
|
let (xt, yt) = geo.translate(x, y);
|
|
x = xt;
|
|
y = yt;
|
|
}
|
|
self.render_surface(surface, x, y);
|
|
}
|
|
|
|
pub fn render_surface(&mut self, surface: &WlSurface, x: i32, y: i32) {
|
|
let children = surface.children.borrow();
|
|
let buffer = match surface.buffer.get() {
|
|
Some(b) => b,
|
|
_ => {
|
|
log::warn!("surface has no buffer attached");
|
|
return;
|
|
}
|
|
};
|
|
if let Some(children) = children.deref() {
|
|
macro_rules! render {
|
|
($children:expr) => {
|
|
for child in $children.rev_iter() {
|
|
if child.pending.get() {
|
|
continue;
|
|
}
|
|
let pos = child.sub_surface.position.get();
|
|
self.render_surface(&child.sub_surface.surface, x + pos.x1(), y + pos.y1());
|
|
}
|
|
};
|
|
}
|
|
render!(&children.below);
|
|
self.render_buffer(&buffer, x, y);
|
|
render!(&children.above);
|
|
} else {
|
|
self.render_buffer(&buffer, x, y);
|
|
}
|
|
let mut fr = surface.frame_requests.borrow_mut();
|
|
for cb in fr.drain(..) {
|
|
surface.client.dispatch_frame_requests.push(cb);
|
|
}
|
|
}
|
|
|
|
pub fn render_buffer(&mut self, buffer: &WlBuffer, x: i32, y: i32) {
|
|
let texture = match buffer.texture.get() {
|
|
Some(t) => t,
|
|
_ => return,
|
|
};
|
|
assert!(Rc::ptr_eq(&self.renderer.ctx, &texture.ctx.ctx));
|
|
unsafe {
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture.gl.tex);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glUseProgram(self.renderer.tex_prog.prog);
|
|
|
|
glUniform1i(self.renderer.tex_prog_tex, 0);
|
|
|
|
let texcoord: [f32; 8] = [1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0];
|
|
|
|
let f_width = self.image.width as f32;
|
|
let f_height = self.image.height as f32;
|
|
|
|
let x1 = 2.0 * (x as f32 / f_width) - 1.0;
|
|
let y1 = 2.0 * (y as f32 / f_height) - 1.0;
|
|
let x2 = 2.0 * ((x + texture.gl.width) as f32 / f_width) - 1.0;
|
|
let y2 = 2.0 * ((y + texture.gl.height) as f32 / f_height) - 1.0;
|
|
|
|
let pos: [f32; 8] = [
|
|
x2, y1, // top right
|
|
x1, y1, // top left
|
|
x2, y2, // bottom right
|
|
x1, y2, // bottom left
|
|
];
|
|
|
|
glVertexAttribPointer(
|
|
self.renderer.tex_prog_texcoord as _,
|
|
2,
|
|
GL_FLOAT,
|
|
GL_FALSE,
|
|
0,
|
|
texcoord.as_ptr() as _,
|
|
);
|
|
glVertexAttribPointer(
|
|
self.renderer.tex_prog_pos as _,
|
|
2,
|
|
GL_FLOAT,
|
|
GL_FALSE,
|
|
0,
|
|
pos.as_ptr() as _,
|
|
);
|
|
|
|
glEnableVertexAttribArray(self.renderer.tex_prog_texcoord as _);
|
|
glEnableVertexAttribArray(self.renderer.tex_prog_pos as _);
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
glDisableVertexAttribArray(self.renderer.tex_prog_texcoord as _);
|
|
glDisableVertexAttribArray(self.renderer.tex_prog_pos as _);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
}
|
|
|
|
pub fn render_floating(&mut self, floating: &FloatNode, x: i32, y: i32) {
|
|
if let Some(child) = floating.child.get() {
|
|
child.render(self, x, y)
|
|
}
|
|
}
|
|
}
|