181 lines
5.5 KiB
Rust
181 lines
5.5 KiB
Rust
use super::background::BackgroundWidget;
|
|
use super::exterior::ExteriorWidget;
|
|
use super::foreground::ForegroundWidget;
|
|
use super::WindowCoord;
|
|
use crate::coords::proj::Mercator;
|
|
use crate::coords::Mapper;
|
|
use femtovg::{Color, FontId, Paint, Path, Transform2D};
|
|
use gtk::glib;
|
|
use gtk::prelude::WidgetExtManual;
|
|
use gtk::subclass::prelude::*;
|
|
use gtk::traits::{GLAreaExt, WidgetExt};
|
|
use ndarray::Array2;
|
|
use std::cell::RefCell;
|
|
use std::num::NonZeroU32;
|
|
|
|
#[derive(Debug, Default, Clone)]
|
|
pub struct RenderConfig {
|
|
pub dim1: Option<Array2<f64>>,
|
|
pub dim2: Option<Array2<f64>>,
|
|
pub scale: f32,
|
|
pub pointer_location: WindowCoord,
|
|
pub pointer_lon_lat: (f64, f64),
|
|
pub translate: WindowCoord,
|
|
pub updated_translate: WindowCoord,
|
|
}
|
|
|
|
struct Fonts {
|
|
sans: FontId,
|
|
bold: FontId,
|
|
light: FontId,
|
|
}
|
|
|
|
pub struct Render {
|
|
pub(super) background: RefCell<BackgroundWidget>,
|
|
pub(super) foreground: RefCell<ForegroundWidget>,
|
|
pub(super) exterior: RefCell<ExteriorWidget>,
|
|
pub config: RefCell<RenderConfig>,
|
|
pub mapper: RefCell<Mapper>,
|
|
pub(super) canvas: RefCell<Option<femtovg::Canvas<femtovg::renderer::OpenGl>>>,
|
|
}
|
|
|
|
impl Default for Render {
|
|
fn default() -> Self {
|
|
Self {
|
|
background: RefCell::new(BackgroundWidget::default()),
|
|
foreground: RefCell::new(ForegroundWidget::default()),
|
|
exterior: RefCell::new(ExteriorWidget::default()),
|
|
config: RefCell::new(RenderConfig::default()),
|
|
mapper: RefCell::new(Mercator::new().into()),
|
|
canvas: RefCell::new(None),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[glib::object_subclass]
|
|
impl ObjectSubclass for Render {
|
|
const NAME: &'static str = "MyRender";
|
|
type Type = super::Render;
|
|
type ParentType = gtk::GLArea;
|
|
}
|
|
|
|
// Trait shared by all GObjects
|
|
impl ObjectImpl for Render {
|
|
fn constructed(&self) {
|
|
self.parent_constructed();
|
|
let area = self.obj();
|
|
area.set_has_stencil_buffer(true);
|
|
|
|
// area.add_tick_callback(|area, _| {
|
|
// area.queue_render();
|
|
// glib::Continue(true)
|
|
// });
|
|
}
|
|
}
|
|
|
|
// Trait shared by all widgets
|
|
impl WidgetImpl for Render {}
|
|
|
|
impl GLAreaImpl for Render {
|
|
fn resize(&self, width: i32, height: i32) {
|
|
self.ensure_canvas();
|
|
let mut canvas = self.canvas.borrow_mut();
|
|
let canvas = canvas.as_mut().unwrap();
|
|
canvas.set_size(
|
|
width as u32,
|
|
height as u32,
|
|
self.obj().scale_factor() as f32,
|
|
);
|
|
}
|
|
|
|
fn render(&self, context: >k::gdk::GLContext) -> bool {
|
|
self.ensure_canvas();
|
|
let mut canvas = self.canvas.borrow_mut();
|
|
let canvas = canvas.as_mut().unwrap();
|
|
|
|
let dpi = self.obj().scale_factor();
|
|
let w = canvas.width();
|
|
let h = canvas.height();
|
|
let configs = self.config.borrow();
|
|
|
|
canvas.clear_rect(
|
|
0,
|
|
0,
|
|
(w as i32 * dpi) as u32,
|
|
(h as i32 * dpi) as u32,
|
|
Color::rgba(0, 0, 0, 255),
|
|
);
|
|
let mapper = self.mapper.borrow();
|
|
|
|
let (lon_range, lat_range) = mapper.range.clone();
|
|
// {
|
|
// let background_widget = self.background.borrow_mut();
|
|
// background_widget.set_lat_lines(lat_range.key_points(9));
|
|
// }
|
|
// {
|
|
// let background_widget = self.background.borrow_mut();
|
|
// background_widget.set_lon_lines(lon_range.key_points(20));
|
|
// }
|
|
let translate = self.translate();
|
|
|
|
self.exterior.borrow().draw(canvas,self.mapper.borrow());
|
|
// self.foreground
|
|
// .borrow()
|
|
// .draw(canvas, configs.scale, dpi, self.mapper.borrow());
|
|
|
|
// self.background.borrow().draw(
|
|
// canvas,
|
|
// configs.scale,
|
|
// dpi,
|
|
// translate,
|
|
// self.mapper.borrow(),
|
|
// (lon_range, lat_range),
|
|
// );
|
|
canvas.flush();
|
|
true
|
|
}
|
|
}
|
|
|
|
impl Render {
|
|
fn ensure_canvas(&self) {
|
|
use femtovg::{renderer, Canvas};
|
|
use glow::HasContext;
|
|
|
|
if self.canvas.borrow().is_some() {
|
|
return;
|
|
}
|
|
|
|
let widget = self.obj();
|
|
widget.attach_buffers();
|
|
|
|
static LOAD_FN: fn(&str) -> *const std::ffi::c_void =
|
|
|s| epoxy::get_proc_addr(s) as *const _;
|
|
// SAFETY: Need to get the framebuffer id that gtk expects us to draw into, so femtovg
|
|
// knows which framebuffer to bind. This is safe as long as we call attach_buffers
|
|
// beforehand. Also unbind it here just in case, since this can be called outside render.
|
|
let (mut renderer, fbo) = unsafe {
|
|
let renderer =
|
|
renderer::OpenGl::new_from_function(LOAD_FN).expect("Cannot create renderer");
|
|
let ctx = glow::Context::from_loader_function(LOAD_FN);
|
|
let id = NonZeroU32::new(ctx.get_parameter_i32(glow::DRAW_FRAMEBUFFER_BINDING) as u32)
|
|
.expect("No GTK provided framebuffer binding");
|
|
ctx.bind_framebuffer(glow::FRAMEBUFFER, None);
|
|
(renderer, glow::NativeFramebuffer(id))
|
|
};
|
|
renderer.set_screen_target(Some(fbo));
|
|
let mut canvas = Canvas::new(renderer).expect("Cannot create canvas");
|
|
canvas
|
|
.add_font_dir("/Users/tsuki/projects/radar-g/src/assets")
|
|
.unwrap();
|
|
self.canvas.replace(Some(canvas));
|
|
}
|
|
|
|
pub fn translate(&self) -> WindowCoord {
|
|
let cfg = self.config.borrow();
|
|
let (rx, ry) = cfg.translate;
|
|
let (ux, uy) = cfg.updated_translate;
|
|
|
|
return (rx + ux, ry + uy);
|
|
}
|
|
}
|