Set up image resources for the app #230

Merged
savanni merged 3 commits from otg/graphics into main 2024-04-05 13:34:57 +00:00
6 changed files with 105 additions and 56 deletions

View File

@ -3,5 +3,7 @@
<gresource prefix="/com/luminescent-dreams/otg-gtk/"> <gresource prefix="/com/luminescent-dreams/otg-gtk/">
<file>wood_texture.jpg</file> <file>wood_texture.jpg</file>
<file>style.css</file> <file>style.css</file>
<file>black_stone.png</file>
<file>white_stone.png</file>
</gresource> </gresource>
</gresources> </gresources>

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 698 KiB

View File

@ -37,14 +37,16 @@ You should have received a copy of the GNU General Public License along with On
use crate::perftrace; use crate::perftrace;
use gio::resources_lookup_data;
use glib::Object; use glib::Object;
use gtk::{ use gtk::{
gdk_pixbuf::{Colorspace, InterpType, Pixbuf},
prelude::*, prelude::*,
subclass::prelude::*, subclass::prelude::*,
}; };
use image::{io::Reader as ImageReader, ImageError};
use otg_core::{Color, Coordinate}; use otg_core::{Color, Coordinate};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, io::Cursor, rc::Rc};
const WIDTH: i32 = 800; const WIDTH: i32 = 800;
const HEIGHT: i32 = 800; const HEIGHT: i32 = 800;
@ -105,29 +107,12 @@ impl Goban {
fn redraw(&self, ctx: &cairo::Context, width: i32, height: i32) { fn redraw(&self, ctx: &cairo::Context, width: i32, height: i32) {
println!("{} x {}", width, height); println!("{} x {}", width, height);
/* let background = load_pixbuf(
let wood_texture = resources_lookup_data(
"/com/luminescent-dreams/otg-gtk/wood_texture.jpg", "/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, false,
8, WIDTH + 40,
background.width() as i32, HEIGHT + 40,
background.height() as i32, );
background.to_rgb8().sample_layout().height_stride as i32,
)
.scale_simple(WIDTH, HEIGHT, InterpType::Nearest)
});
match background { match background {
Ok(Some(ref background)) => { Ok(Some(ref background)) => {
@ -136,10 +121,6 @@ impl Goban {
} }
Ok(None) | Err(_) => ctx.set_source_rgb(0.7, 0.7, 0.7), 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(); 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 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 vspace_between = ((height - 40) as f64) / ((board.size.height - 1) as f64);
let pen = Pen { let pen = Pen::new(MARGIN as f64, MARGIN as f64, hspace_between, vspace_between);
x_offset: MARGIN as f64,
y_offset: MARGIN as f64,
hspace_between,
vspace_between,
};
(0..board.size.width).for_each(|col| { (0..board.size.width).for_each(|col| {
ctx.move_to( ctx.move_to(
@ -189,7 +165,7 @@ impl Goban {
(0..board.size.height).for_each(|row| { (0..board.size.height).for_each(|row| {
(0..board.size.width).for_each(|column| { (0..board.size.width).for_each(|column| {
match board.stone(&Coordinate { row, column }) { match board.stone(&Coordinate { row, column }) {
None => {}, None => {}
Some(Color::White) => pen.stone(ctx, row, column, Color::White, None), Some(Color::White) => pen.stone(ctx, row, column, Color::White, None),
Some(Color::Black) => pen.stone(ctx, row, column, Color::Black, None), Some(Color::Black) => pen.stone(ctx, row, column, Color::Black, None),
} }
@ -203,9 +179,45 @@ struct Pen {
y_offset: f64, y_offset: f64,
hspace_between: f64, hspace_between: f64,
vspace_between: f64, vspace_between: f64,
black_stone: Pixbuf,
white_stone: Pixbuf,
} }
impl Pen { 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) { fn star_point(&self, context: &cairo::Context, row: u8, col: u8) {
context.arc( context.arc(
self.x_offset + (col as f64) * self.hspace_between, self.x_offset + (col as f64) * self.hspace_between,
@ -217,20 +229,22 @@ impl Pen {
let _ = context.fill(); let _ = context.fill();
} }
fn stone( fn stone(&self, ctx: &cairo::Context, row: u8, col: u8, color: Color, _liberties: Option<u8>) {
&self, let (x_loc, y_loc) = self.stone_location(row, col);
context: &cairo::Context,
row: u8,
col: u8,
color: Color,
liberties: Option<u8>,
) {
match color { match color {
Color::White => context.set_source_rgb(0.9, 0.9, 0.9), Color::White => ctx.set_source_pixbuf(&self.white_stone, x_loc, y_loc),
Color::Black => context.set_source_rgb(0.0, 0.0, 0.0), 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 { if let Some(liberties) = liberties {
let stone_location = self.stone_location(row, col); let stone_location = self.stone_location(row, col);
context.set_source_rgb(1., 0., 1.); context.set_source_rgb(1., 0., 1.);
@ -238,28 +252,61 @@ impl Pen {
context.move_to(stone_location.0 - 10., stone_location.1 + 10.); context.move_to(stone_location.0 - 10., stone_location.1 + 10.);
let _ = context.show_text(&format!("{}", liberties)); let _ = context.show_text(&format!("{}", liberties));
} }
*/
} }
#[allow(dead_code)] #[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 { match color {
Color::White => context.set_source_rgba(0.9, 0.9, 0.9, 0.5), Color::White => ctx.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::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 radius = self.hspace_between / 2. - 2.;
let (x_loc, y_loc) = self.stone_location(row, col); 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); ctx.arc(x_loc, y_loc, radius, 0.0, 2.0 * std::f64::consts::PI);
let _ = context.fill(); let _ = ctx.fill();
} }
fn stone_location(&self, row: u8, col: u8) -> (f64, f64) { 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.x_offset + (col as f64) * self.hspace_between - radius,
self.y_offset + (row as f64) * self.vspace_between, self.y_offset + (row as f64) * self.vspace_between - radius,
) )
} }
} }
fn load_pixbuf(
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)
})
}