diff --git a/otg/gtk/gresources.xml b/otg/gtk/gresources.xml index 9962834..f6b7a1c 100644 --- a/otg/gtk/gresources.xml +++ b/otg/gtk/gresources.xml @@ -3,5 +3,7 @@ wood_texture.jpg style.css + black_stone.png + white_stone.png diff --git a/otg/gtk/resources/black_stone.png b/otg/gtk/resources/black_stone.png new file mode 100644 index 0000000..a9650bc Binary files /dev/null and b/otg/gtk/resources/black_stone.png differ diff --git a/otg/gtk/resources/stones.kra b/otg/gtk/resources/stones.kra new file mode 100644 index 0000000..7e3f031 Binary files /dev/null and b/otg/gtk/resources/stones.kra differ diff --git a/otg/gtk/resources/white_stone.png b/otg/gtk/resources/white_stone.png new file mode 100644 index 0000000..def6226 Binary files /dev/null and b/otg/gtk/resources/white_stone.png differ diff --git a/otg/gtk/resources/wood_texture.jpg b/otg/gtk/resources/wood_texture.jpg index a586b16..88b8886 100644 Binary files a/otg/gtk/resources/wood_texture.jpg and b/otg/gtk/resources/wood_texture.jpg differ diff --git a/otg/gtk/src/components/goban.rs b/otg/gtk/src/components/goban.rs index 6105ee9..7d9958b 100644 --- a/otg/gtk/src/components/goban.rs +++ b/otg/gtk/src/components/goban.rs @@ -37,14 +37,16 @@ You should have received a copy of the GNU General Public License along with On use crate::perftrace; +use gio::resources_lookup_data; use glib::Object; use gtk::{ + gdk_pixbuf::{Colorspace, InterpType, Pixbuf}, prelude::*, subclass::prelude::*, }; - +use image::{io::Reader as ImageReader, ImageError}; use otg_core::{Color, Coordinate}; -use std::{cell::RefCell, rc::Rc}; +use std::{cell::RefCell, io::Cursor, rc::Rc}; const WIDTH: i32 = 800; const HEIGHT: i32 = 800; @@ -105,29 +107,12 @@ impl Goban { fn redraw(&self, ctx: &cairo::Context, width: i32, height: i32) { println!("{} x {}", width, height); - /* - let wood_texture = resources_lookup_data( + let background = load_pixbuf( "/com/luminescent-dreams/otg-gtk/wood_texture.jpg", - gio::ResourceLookupFlags::NONE, - ) - .unwrap(); - - let background = ImageReader::new(Cursor::new(wood_texture)) - .with_guessed_format() - .unwrap() - .decode(); - let background = background.map(|background| { - Pixbuf::from_bytes( - &glib::Bytes::from(background.as_bytes()), - gtk::gdk_pixbuf::Colorspace::Rgb, - false, - 8, - background.width() as i32, - background.height() as i32, - background.to_rgb8().sample_layout().height_stride as i32, - ) - .scale_simple(WIDTH, HEIGHT, InterpType::Nearest) - }); + false, + WIDTH + 40, + HEIGHT + 40, + ); match background { Ok(Some(ref background)) => { @@ -136,10 +121,6 @@ impl Goban { } Ok(None) | Err(_) => ctx.set_source_rgb(0.7, 0.7, 0.7), } - */ - - ctx.set_source_rgb(0.7, 0.7, 0.7); - let _ = ctx.paint(); let board = self.imp().board_state.borrow(); @@ -148,12 +129,7 @@ impl Goban { let hspace_between = ((width - 40) as f64) / ((board.size.width - 1) as f64); let vspace_between = ((height - 40) as f64) / ((board.size.height - 1) as f64); - let pen = Pen { - x_offset: MARGIN as f64, - y_offset: MARGIN as f64, - hspace_between, - vspace_between, - }; + let pen = Pen::new(MARGIN as f64, MARGIN as f64, hspace_between, vspace_between); (0..board.size.width).for_each(|col| { ctx.move_to( @@ -188,8 +164,8 @@ impl Goban { (0..board.size.height).for_each(|row| { (0..board.size.width).for_each(|column| { - match board.stone(&Coordinate{ row, column }) { - None => {}, + match board.stone(&Coordinate { row, column }) { + None => {} Some(Color::White) => pen.stone(ctx, row, column, Color::White, None), Some(Color::Black) => pen.stone(ctx, row, column, Color::Black, None), } @@ -203,9 +179,45 @@ struct Pen { y_offset: f64, hspace_between: f64, vspace_between: f64, + black_stone: Pixbuf, + white_stone: Pixbuf, } impl Pen { + fn new(x_offset: f64, y_offset: f64, hspace_between: f64, vspace_between: f64) -> Self { + let radius = (hspace_between / 2. - 2.) as i32; + let black_stone = load_pixbuf( + "/com/luminescent-dreams/otg-gtk/black_stone.png", + true, + 512, + 512, + ) + .unwrap() + .unwrap(); + let black_stone = black_stone + .scale_simple(radius * 2, radius * 2, InterpType::Nearest) + .unwrap(); + let white_stone = load_pixbuf( + "/com/luminescent-dreams/otg-gtk/white_stone.png", + true, + 512, + 512, + ) + .unwrap() + .unwrap(); + let white_stone = white_stone + .scale_simple(radius * 2, radius * 2, InterpType::Nearest) + .unwrap(); + Pen { + x_offset, + y_offset, + hspace_between, + vspace_between, + black_stone, + white_stone, + } + } + fn star_point(&self, context: &cairo::Context, row: u8, col: u8) { context.arc( self.x_offset + (col as f64) * self.hspace_between, @@ -217,20 +229,22 @@ impl Pen { let _ = context.fill(); } - fn stone( - &self, - context: &cairo::Context, - row: u8, - col: u8, - color: Color, - liberties: Option, - ) { + fn stone(&self, ctx: &cairo::Context, row: u8, col: u8, color: Color, _liberties: Option) { + let (x_loc, y_loc) = self.stone_location(row, col); match color { - Color::White => context.set_source_rgb(0.9, 0.9, 0.9), - Color::Black => context.set_source_rgb(0.0, 0.0, 0.0), + Color::White => ctx.set_source_pixbuf(&self.white_stone, x_loc, y_loc), + Color::Black => ctx.set_source_pixbuf(&self.black_stone, x_loc, y_loc), + } + ctx.paint().expect("paint should never fail"); + /* + match color { + Color::White => ctx.set_source_rgb(0.9, 0.9, 0.9), + Color::Black => ctx.set_source_rgb(0.0, 0.0, 0.0), }; - self.draw_stone(context, row, col); + self.draw_stone(ctx, row, col); + */ + /* if let Some(liberties) = liberties { let stone_location = self.stone_location(row, col); context.set_source_rgb(1., 0., 1.); @@ -238,28 +252,61 @@ impl Pen { context.move_to(stone_location.0 - 10., stone_location.1 + 10.); let _ = context.show_text(&format!("{}", liberties)); } + */ } #[allow(dead_code)] - fn ghost_stone(&self, context: &cairo::Context, row: u8, col: u8, color: Color) { + fn ghost_stone(&self, ctx: &cairo::Context, row: u8, col: u8, color: Color) { match color { - Color::White => context.set_source_rgba(0.9, 0.9, 0.9, 0.5), - Color::Black => context.set_source_rgba(0.0, 0.0, 0.0, 0.5), + Color::White => ctx.set_source_rgba(0.9, 0.9, 0.9, 0.5), + Color::Black => ctx.set_source_rgba(0.0, 0.0, 0.0, 0.5), }; - self.draw_stone(context, row, col); + self.draw_stone(ctx, row, col); } - fn draw_stone(&self, context: &cairo::Context, row: u8, col: u8) { + fn draw_stone(&self, ctx: &cairo::Context, row: u8, col: u8) { let radius = self.hspace_between / 2. - 2.; let (x_loc, y_loc) = self.stone_location(row, col); - context.arc(x_loc, y_loc, radius, 0.0, 2.0 * std::f64::consts::PI); - let _ = context.fill(); + ctx.arc(x_loc, y_loc, radius, 0.0, 2.0 * std::f64::consts::PI); + let _ = ctx.fill(); } fn stone_location(&self, row: u8, col: u8) -> (f64, f64) { + let radius = self.hspace_between / 2. - 2.; ( - self.x_offset + (col as f64) * self.hspace_between, - self.y_offset + (row as f64) * self.vspace_between, + self.x_offset + (col as f64) * self.hspace_between - radius, + self.y_offset + (row as f64) * self.vspace_between - radius, ) } } + +fn load_pixbuf( + path: &str, + transparency: bool, + width: i32, + height: i32, +) -> Result, 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) + }) +}