mirror of https://github.com/emilk/egui.git
Emil Ernerfeldt
3 years ago
11 changed files with 277 additions and 57 deletions
@ -0,0 +1,190 @@ |
|||||
|
//! This demo shows how to embed 3D rendering using [`glow`](https://github.com/grovesNL/glow) in `epi`.
|
||||
|
//!
|
||||
|
//! This is very advanced usage, and you need to be careful.
|
||||
|
//!
|
||||
|
//! If you want an easier way to show 3D graphics with egui, take a look at:
|
||||
|
//! * [`bevy_egui`](https://github.com/mvlabat/bevy_egui)
|
||||
|
//! * [`three-d`](https://github.com/asny/three-d)
|
||||
|
|
||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
|
||||
|
use epi::{glow, Renderer as _}; |
||||
|
use parking_lot::Mutex; |
||||
|
use std::sync::Arc; |
||||
|
|
||||
|
pub struct Custom3dApp { |
||||
|
/// Behind an `Arc<Mutex<…>>` so we can pass it to [`egui::PaintCallback`] and paint later.
|
||||
|
rotating_triangle: Arc<Mutex<RotatingTriangle>>, |
||||
|
angle: f32, |
||||
|
} |
||||
|
|
||||
|
impl Custom3dApp { |
||||
|
pub fn new(cc: &epi::CreationContext<'_>) -> Self { |
||||
|
Self { |
||||
|
rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(&cc.gl))), |
||||
|
angle: 0.0, |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
impl epi::App for Custom3dApp { |
||||
|
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { |
||||
|
egui::CentralPanel::default().show(ctx, |ui| { |
||||
|
ui.vertical_centered(|ui| { |
||||
|
ui.add(crate::__egui_github_link_file!()); |
||||
|
}); |
||||
|
|
||||
|
ui.horizontal(|ui| { |
||||
|
ui.spacing_mut().item_spacing.x = 0.0; |
||||
|
ui.label("The triangle is being painted using "); |
||||
|
ui.hyperlink_to("glow", "https://github.com/grovesNL/glow"); |
||||
|
ui.label(" (OpenGL)."); |
||||
|
}); |
||||
|
|
||||
|
egui::ScrollArea::both().show(ui, |ui| { |
||||
|
egui::Frame::canvas(ui.style()).show(ui, |ui| { |
||||
|
self.custom_painting(ui); |
||||
|
}); |
||||
|
ui.label("Drag to rotate!"); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
impl Custom3dApp { |
||||
|
fn custom_painting(&mut self, ui: &mut egui::Ui) { |
||||
|
let (rect, response) = |
||||
|
ui.allocate_exact_size(egui::Vec2::splat(256.0), egui::Sense::drag()); |
||||
|
|
||||
|
self.angle += response.drag_delta().x * 0.01; |
||||
|
|
||||
|
let angle = self.angle; |
||||
|
let rotating_triangle = self.rotating_triangle.clone(); |
||||
|
|
||||
|
let callback = egui::epaint::PaintCallback { |
||||
|
rect, |
||||
|
callback: std::sync::Arc::new(move |render_ctx| { |
||||
|
if let Some(painter) = render_ctx.downcast_ref::<egui_glow::Painter>() { |
||||
|
rotating_triangle.lock().paint(painter.gl(), angle); |
||||
|
} else { |
||||
|
eprintln!("Can't do custom painting because we are not using a glow context"); |
||||
|
} |
||||
|
}), |
||||
|
}; |
||||
|
ui.painter().add(callback); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
struct RotatingTriangle { |
||||
|
program: glow::Program, |
||||
|
vertex_array: glow::VertexArray, |
||||
|
} |
||||
|
|
||||
|
impl RotatingTriangle { |
||||
|
fn new(gl: &glow::Context) -> Self { |
||||
|
use glow::HasContext as _; |
||||
|
|
||||
|
let shader_version = if cfg!(target_arch = "wasm32") { |
||||
|
"#version 300 es" |
||||
|
} else { |
||||
|
"#version 410" |
||||
|
}; |
||||
|
|
||||
|
unsafe { |
||||
|
let program = gl.create_program().expect("Cannot create program"); |
||||
|
|
||||
|
let (vertex_shader_source, fragment_shader_source) = ( |
||||
|
r#" |
||||
|
const vec2 verts[3] = vec2[3]( |
||||
|
vec2(0.0, 1.0), |
||||
|
vec2(-1.0, -1.0), |
||||
|
vec2(1.0, -1.0) |
||||
|
); |
||||
|
const vec4 colors[3] = vec4[3]( |
||||
|
vec4(1.0, 0.0, 0.0, 1.0), |
||||
|
vec4(0.0, 1.0, 0.0, 1.0), |
||||
|
vec4(0.0, 0.0, 1.0, 1.0) |
||||
|
); |
||||
|
out vec4 v_color; |
||||
|
uniform float u_angle; |
||||
|
void main() { |
||||
|
v_color = colors[gl_VertexID]; |
||||
|
gl_Position = vec4(verts[gl_VertexID], 0.0, 1.0); |
||||
|
gl_Position.x *= cos(u_angle); |
||||
|
} |
||||
|
"#, |
||||
|
r#" |
||||
|
precision mediump float; |
||||
|
in vec4 v_color; |
||||
|
out vec4 out_color; |
||||
|
void main() { |
||||
|
out_color = v_color; |
||||
|
} |
||||
|
"#, |
||||
|
); |
||||
|
|
||||
|
let shader_sources = [ |
||||
|
(glow::VERTEX_SHADER, vertex_shader_source), |
||||
|
(glow::FRAGMENT_SHADER, fragment_shader_source), |
||||
|
]; |
||||
|
|
||||
|
let shaders: Vec<_> = shader_sources |
||||
|
.iter() |
||||
|
.map(|(shader_type, shader_source)| { |
||||
|
let shader = gl |
||||
|
.create_shader(*shader_type) |
||||
|
.expect("Cannot create shader"); |
||||
|
gl.shader_source(shader, &format!("{}\n{}", shader_version, shader_source)); |
||||
|
gl.compile_shader(shader); |
||||
|
if !gl.get_shader_compile_status(shader) { |
||||
|
panic!("{}", gl.get_shader_info_log(shader)); |
||||
|
} |
||||
|
gl.attach_shader(program, shader); |
||||
|
shader |
||||
|
}) |
||||
|
.collect(); |
||||
|
|
||||
|
gl.link_program(program); |
||||
|
if !gl.get_program_link_status(program) { |
||||
|
panic!("{}", gl.get_program_info_log(program)); |
||||
|
} |
||||
|
|
||||
|
for shader in shaders { |
||||
|
gl.detach_shader(program, shader); |
||||
|
gl.delete_shader(shader); |
||||
|
} |
||||
|
|
||||
|
let vertex_array = gl |
||||
|
.create_vertex_array() |
||||
|
.expect("Cannot create vertex array"); |
||||
|
|
||||
|
Self { |
||||
|
program, |
||||
|
vertex_array, |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// TODO: figure out how to call this in a nice way
|
||||
|
#[allow(unused)] |
||||
|
fn destroy(self, gl: &glow::Context) { |
||||
|
use glow::HasContext as _; |
||||
|
unsafe { |
||||
|
gl.delete_program(self.program); |
||||
|
gl.delete_vertex_array(self.vertex_array); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
fn paint(&self, gl: &glow::Context, angle: f32) { |
||||
|
use glow::HasContext as _; |
||||
|
unsafe { |
||||
|
gl.use_program(Some(self.program)); |
||||
|
gl.uniform_1_f32( |
||||
|
gl.get_uniform_location(self.program, "u_angle").as_ref(), |
||||
|
angle, |
||||
|
); |
||||
|
gl.bind_vertex_array(Some(self.vertex_array)); |
||||
|
gl.draw_arrays(glow::TRIANGLES, 0, 3); |
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue