Optimize rendering by pre-loading resources #231
|
@ -14,7 +14,7 @@ GNU General Public License for more details.
|
|||
You should have received a copy of the GNU General Public License along with On the Grid. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use crate::CoreApi;
|
||||
use crate::{CoreApi, ResourceManager};
|
||||
use adw::prelude::*;
|
||||
|
||||
use otg_core::{
|
||||
|
@ -22,7 +22,7 @@ use otg_core::{
|
|||
CoreRequest, CoreResponse,
|
||||
};
|
||||
use sgf::GameRecord;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::{rc::Rc, sync::{Arc, RwLock}};
|
||||
|
||||
use crate::views::{GameReview, HomeView, SettingsView};
|
||||
|
||||
|
@ -58,10 +58,12 @@ pub struct AppWindow {
|
|||
// Not liking this, but I have to keep track of the settings view model separately from
|
||||
// anything else. I'll have to look into this later.
|
||||
settings_view_model: Arc<RwLock<Option<SettingsView>>>,
|
||||
|
||||
resources: Rc<ResourceManager>,
|
||||
}
|
||||
|
||||
impl AppWindow {
|
||||
pub fn new(app: &adw::Application, core: CoreApi) -> Self {
|
||||
pub fn new(app: &adw::Application, core: CoreApi, resources: ResourceManager) -> Self {
|
||||
let window = Self::setup_window(app);
|
||||
let overlay = Self::setup_overlay();
|
||||
let stack = adw::NavigationView::new();
|
||||
|
@ -77,6 +79,7 @@ impl AppWindow {
|
|||
overlay,
|
||||
core,
|
||||
settings_view_model: Default::default(),
|
||||
resources: Rc::new(resources),
|
||||
};
|
||||
|
||||
let home = s.setup_home();
|
||||
|
|
|
@ -21,10 +21,12 @@ pub use app_window::AppWindow;
|
|||
|
||||
mod views;
|
||||
|
||||
use async_std::task::{yield_now};
|
||||
use otg_core::{Core, Observable, CoreRequest, CoreResponse};
|
||||
use std::{rc::Rc};
|
||||
|
||||
use async_std::task::yield_now;
|
||||
use gio::resources_lookup_data;
|
||||
use gtk::gdk_pixbuf::{Colorspace, InterpType, Pixbuf};
|
||||
use image::{io::Reader as ImageReader, ImageError};
|
||||
use otg_core::{Core, CoreRequest, CoreResponse, Observable};
|
||||
use std::{cell::RefCell, collections::HashMap, io::Cursor, rc::Rc};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CoreApi {
|
||||
|
@ -37,6 +39,92 @@ impl CoreApi {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Resource {
|
||||
Image(Pixbuf),
|
||||
}
|
||||
|
||||
pub struct ResourceManager {
|
||||
resources: Rc<RefCell<HashMap<String, Resource>>>,
|
||||
}
|
||||
|
||||
impl ResourceManager {
|
||||
pub fn new() -> Self {
|
||||
let mut resources = HashMap::new();
|
||||
|
||||
for (path, xres, yres, transparency) in [
|
||||
(
|
||||
"/com/luminescent-dreams/otg-gtk/wood_texture.jpg",
|
||||
840,
|
||||
840,
|
||||
false,
|
||||
),
|
||||
(
|
||||
"/com/luminescent-dreams/otg-gtk/black_stone.png",
|
||||
40,
|
||||
40,
|
||||
true,
|
||||
),
|
||||
(
|
||||
"/com/luminescent-dreams/otg-gtk/white_stone.png",
|
||||
40,
|
||||
40,
|
||||
true,
|
||||
),
|
||||
] {
|
||||
match perftrace(&format!("loading {}", path), || {
|
||||
Self::load_image(path, transparency, xres, yres)
|
||||
}) {
|
||||
Ok(Some(image)) => {
|
||||
resources.insert(path.to_owned(), Resource::Image(image));
|
||||
}
|
||||
Ok(None) => println!("no image in resource bundle for {}", path),
|
||||
Err(err) => println!("failed to load image {}: {}", path, err),
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
resources: Rc::new(RefCell::new(resources)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resource(&self, path: &str) -> Option<Resource> {
|
||||
self.resources.borrow().get(path).cloned()
|
||||
}
|
||||
|
||||
fn load_image(
|
||||
path: &str,
|
||||
transparency: bool,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Result<Option<Pixbuf>, ImageError> {
|
||||
let image_bytes = resources_lookup_data(path, gio::ResourceLookupFlags::NONE).unwrap();
|
||||
|
||||
let image = ImageReader::new(Cursor::new(image_bytes))
|
||||
.with_guessed_format()
|
||||
.unwrap()
|
||||
.decode();
|
||||
image.map(|image| {
|
||||
let stride = if transparency {
|
||||
image.to_rgba8().sample_layout().height_stride
|
||||
} else {
|
||||
image.to_rgb8().sample_layout().height_stride
|
||||
};
|
||||
Pixbuf::from_bytes(
|
||||
&glib::Bytes::from(image.as_bytes()),
|
||||
Colorspace::Rgb,
|
||||
transparency,
|
||||
8,
|
||||
image.width() as i32,
|
||||
image.height() as i32,
|
||||
stride as i32,
|
||||
)
|
||||
.scale_simple(width, height, InterpType::Nearest)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn perftrace<F, A>(trace_name: &str, f: F) -> A
|
||||
where
|
||||
F: FnOnce() -> A,
|
||||
|
|
|
@ -4,8 +4,7 @@ use async_std::task::spawn;
|
|||
use gio::ActionEntry;
|
||||
use otg_core::{Config, ConfigOption, Core, CoreNotification, LibraryPath, Observable};
|
||||
use otg_gtk::{
|
||||
AppWindow,
|
||||
CoreApi,
|
||||
AppWindow, CoreApi, ResourceManager
|
||||
};
|
||||
|
||||
|
||||
|
@ -123,8 +122,9 @@ fn main() {
|
|||
|
||||
app.connect_activate({
|
||||
move |app| {
|
||||
let resources = ResourceManager::new();
|
||||
let core_api = CoreApi { core: core.clone() };
|
||||
let app_window = AppWindow::new(app, core_api);
|
||||
let app_window = AppWindow::new(app, core_api, resources);
|
||||
|
||||
setup_app_configuration_action(app, app_window.clone());
|
||||
|
||||
|
|
Loading…
Reference in New Issue