use {
crate::{TextureCreateError, TextureMap, UserTexSource},
egui::{epaint::Primitive, ImageData, TextureId},
sfml::graphics::{
blend_mode::Factor, BlendMode, Color, PrimitiveType, RenderStates, RenderTarget as _,
RenderWindow, Texture, Vertex,
},
};
pub(super) fn update_tex_from_delta(
tex: &mut Texture,
delta: &egui::epaint::ImageDelta,
) -> Result<(), TextureCreateError> {
let [w, h] = delta.image.size();
let [x, y] = delta.pos.map_or([0, 0], |[x, y]| [x as u32, y as u32]);
match &delta.image {
ImageData::Color(color) => {
let srgba: Vec<u8> = color.pixels.iter().flat_map(|c32| c32.to_array()).collect();
if w > tex.size().x as usize || h > tex.size().y as usize {
let ok = tex.create(w as u32, h as u32).is_ok();
if !ok {
return Err(TextureCreateError {
width: w,
height: h,
});
}
}
tex.update_from_pixels(&srgba, w as u32, h as u32, x, y);
}
}
Ok(())
}
pub(super) fn draw(
window: &mut RenderWindow,
egui_ctx: &egui::Context,
shapes: Vec<egui::epaint::ClippedShape>,
user_tex_source: &mut dyn UserTexSource,
textures: &TextureMap,
pixels_per_point: f32,
) {
let _ = window.set_active(true);
unsafe {
glu_sys::glEnable(glu_sys::GL_SCISSOR_TEST);
}
let mut vertices = Vec::new();
for egui::ClippedPrimitive {
clip_rect,
primitive,
} in egui_ctx.tessellate(shapes, pixels_per_point)
{
let mesh = match primitive {
Primitive::Mesh(mesh) => mesh,
_ => continue,
};
let (tw, th, tex) = match mesh.texture_id {
TextureId::Managed(id) => {
let tex = &*textures[&TextureId::Managed(id)];
let (egui_tex_w, egui_tex_h) = (tex.size().x as f32, tex.size().y as f32);
(egui_tex_w, egui_tex_h, tex)
}
TextureId::User(id) => user_tex_source.get_texture(id),
};
for idx in mesh.indices {
let v = mesh.vertices[idx as usize];
let sf_v = Vertex::new(
(v.pos.x, v.pos.y).into(),
Color::rgba(v.color.r(), v.color.g(), v.color.b(), v.color.a()),
(v.uv.x * tw, v.uv.y * th).into(),
);
vertices.push(sf_v);
}
let pixels_per_point = 1.;
let win_size = window.size();
let width_in_pixels = win_size.x;
let height_in_pixels = win_size.y;
let clip_min_x = pixels_per_point * clip_rect.min.x;
let clip_min_y = pixels_per_point * clip_rect.min.y;
let clip_max_x = pixels_per_point * clip_rect.max.x;
let clip_max_y = pixels_per_point * clip_rect.max.y;
let clip_min_x = clip_min_x.clamp(0.0, width_in_pixels as f32);
let clip_min_y = clip_min_y.clamp(0.0, height_in_pixels as f32);
let clip_max_x = clip_max_x.clamp(clip_min_x, width_in_pixels as f32);
let clip_max_y = clip_max_y.clamp(clip_min_y, height_in_pixels as f32);
let clip_min_x = clip_min_x.round() as u32;
let clip_min_y = clip_min_y.round() as u32;
let clip_max_x = clip_max_x.round() as u32;
let clip_max_y = clip_max_y.round() as u32;
unsafe {
glu_sys::glScissor(
clip_min_x as _,
(height_in_pixels - clip_max_y) as _,
(clip_max_x - clip_min_x) as _,
(clip_max_y - clip_min_y) as _,
);
}
let rs = RenderStates {
blend_mode: BlendMode {
color_src_factor: Factor::One,
color_dst_factor: Factor::OneMinusSrcAlpha,
alpha_src_factor: Factor::OneMinusDstAlpha,
alpha_dst_factor: Factor::One,
..Default::default()
},
texture: Some(tex),
..Default::default()
};
window.draw_primitives(&vertices, PrimitiveType::TRIANGLES, &rs);
vertices.clear();
}
unsafe {
glu_sys::glDisable(glu_sys::GL_SCISSOR_TEST);
}
let _ = window.set_active(false);
}