1
0
Fork 0
forked from wry/wry
wry/src/render/renderer/renderer.rs
2022-02-19 19:41:18 +01:00

364 lines
14 KiB
Rust

use crate::format::{Format, ARGB8888};
use crate::ifs::wl_buffer::WlBuffer;
use crate::ifs::wl_surface::xdg_surface::XdgSurface;
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::render::sys::{glDisable, glEnable, GL_BLEND};
use crate::render::Texture;
use crate::tree::{
ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode,
};
use crate::{State};
use std::ops::Deref;
use std::rc::Rc;
use std::slice;
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) ctx: &'a Rc<RenderContext>,
pub(super) fb: &'a GlFrameBuffer,
pub(super) state: &'a State,
}
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() {
let pos = stacked.absolute_position();
stacked.render(self, pos.x1(), pos.y1());
}
}
fn x_to_f(&self, x: i32) -> f32 {
2.0 * (x as f32 / self.fb.width as f32) - 1.0
}
fn y_to_f(&self, y: i32) -> f32 {
2.0 * (y as f32 / self.fb.height as f32) - 1.0
}
fn fill_boxes(&self, boxes: &[Rect], r: f32, g: f32, b: f32, a: f32) {
if boxes.is_empty() {
return;
}
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.ctx.fill_prog.prog);
glUniform4f(self.ctx.fill_prog_color, r, g, b, a);
glVertexAttribPointer(
self.ctx.fill_prog_pos as _,
2,
GL_FLOAT,
GL_FALSE,
0,
pos.as_ptr() as _,
);
glEnableVertexAttribArray(self.ctx.fill_prog_pos as _);
glDrawArrays(GL_TRIANGLES, 0, (boxes.len() * 6) as _);
glDisableVertexAttribArray(self.ctx.fill_prog_pos as _);
}
}
pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) {
let border_width = self.state.theme.border_width.get();
let title_height = self.state.theme.title_height.get();
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(), title_height).unwrap();
let underline_rect =
Rect::new_sized(x, y + title_height, container.width.get(), 1).unwrap();
let mut titles = vec![];
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);
let c = self.state.theme.border_color.get();
self.fill_boxes(slice::from_ref(&underline_rect), c.r, c.g, c.b, c.a);
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 let Some(title) = child.title_texture.get() {
titles.push((
pos,
0,
title,
));
}
if focus != ContainerFocus::None {
let rect = Rect::new_sized(pos, y, width, 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 num_title_rects = if split == ContainerSplit::Horizontal {
1
} else {
num_children
};
let mut title_rects = Vec::with_capacity(num_title_rects);
let mut underline_rects = Vec::with_capacity(num_title_rects);
let mut border_rects = Vec::with_capacity(num_children - 1);
let mut active_rects = Vec::new();
title_rects.push(title_rect);
underline_rects.push(underline_rect);
for (i, child) in container.children.iter().enumerate() {
let body = child.body.get();
if let Some(title) = child.title_texture.get() {
titles.push((
body.x1(),
body.y1() - title_height - 1,
title,
));
}
if child.active.get() {
active_rects.push(
Rect::new_sized(
x + body.x1(),
y + body.y1() - title_height - 1,
body.width(),
title_height,
)
.unwrap(),
);
}
if i + 1 < num_children {
let border_rect = if split == ContainerSplit::Horizontal {
Rect::new_sized(
x + body.x2(),
y + body.y1() - title_height - 1,
border_width,
container.height.get(),
)
.unwrap()
} else {
title_rects.push(
Rect::new_sized(
x,
y + body.y2() + border_width,
container.width.get(),
title_height,
)
.unwrap(),
);
underline_rects.push(
Rect::new_sized(
x,
y + body.y2() + border_width + title_height,
container.width.get(),
1,
)
.unwrap(),
);
Rect::new_sized(x, y + body.y2(), container.width.get(), border_width)
.unwrap()
};
border_rects.push(border_rect);
}
}
{
let c = self.state.theme.title_color.get();
self.fill_boxes(&title_rects, c.r, c.g, c.b, c.a);
let c = self.state.theme.active_title_color.get();
self.fill_boxes(&active_rects, c.r, c.g, c.b, c.a);
let c = self.state.theme.underline_color.get();
self.fill_boxes(&underline_rects, c.r, c.g, c.b, c.a);
let c = self.state.theme.border_color.get();
self.fill_boxes(&border_rects, c.r, c.g, c.b, c.a);
for (tx, ty, tex) in titles {
self.render_texture(&tex, x + tx, y + ty, ARGB8888);
}
}
for child in container.children.iter() {
let body = child.body.get();
if body.x1() >= cwidth || body.y1() >= cheight {
break;
}
let body = body.move_(container.abs_x1.get(), container.abs_y1.get());
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,
_ => {
if !surface.is_cursor() {
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) {
if let Some(tex) = buffer.texture.get() {
self.render_texture(&tex, x, y, buffer.format);
}
}
pub fn render_texture(&mut self, texture: &Texture, x: i32, y: i32, format: &Format) {
assert!(Rc::ptr_eq(&self.ctx.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);
let prog = match format.has_alpha {
true => {
glEnable(GL_BLEND);
&self.ctx.tex_alpha_prog
}
false => {
glDisable(GL_BLEND);
&self.ctx.tex_prog
}
};
glUseProgram(prog.prog.prog);
glUniform1i(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.fb.width as f32;
let f_height = self.fb.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(
prog.texcoord as _,
2,
GL_FLOAT,
GL_FALSE,
0,
texcoord.as_ptr() as _,
);
glVertexAttribPointer(prog.pos as _, 2, GL_FLOAT, GL_FALSE, 0, pos.as_ptr() as _);
glEnableVertexAttribArray(prog.texcoord as _);
glEnableVertexAttribArray(prog.pos as _);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(prog.texcoord as _);
glDisableVertexAttribArray(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)
}
}
}