extern crate good_web_game as ggez;
use ggez::event::EventHandler;
use ggez::graphics::{self, BlendMode, Color, DrawParam, Drawable};
use ggez::miniquad;
use ggez::{Context, GameResult};
use glam::Vec2;
use std::env;
use std::path;
struct MainState {
circle: graphics::Mesh,
canvas: graphics::Canvas,
font: graphics::Font,
}
impl MainState {
fn new(ctx: &mut Context, quad_ctx: &mut miniquad::GraphicsContext) -> GameResult<MainState> {
let circle = graphics::Mesh::new_circle(
ctx,
quad_ctx,
graphics::DrawMode::fill(),
Vec2::new(0.0, 0.0),
40.0,
0.5,
Color::WHITE,
)?;
let mut canvas = graphics::Canvas::with_window_size(ctx, quad_ctx)?;
canvas.set_blend_mode(Some(BlendMode::Alpha));
let font = graphics::Font::new(ctx, "/LiberationMono-Regular.ttf")?;
let s = Self {
circle,
canvas,
font,
};
Ok(s)
}
fn draw_venn(
&self,
ctx: &mut Context,
quad_ctx: &mut miniquad::GraphicsContext,
pos: Vec2,
name: &str,
) -> GameResult<()> {
const TRI_COLORS: [Color; 3] = [
Color::new(0.8, 0., 0., 0.5),
Color::new(0., 0.8, 0., 0.5),
Color::new(0., 0., 0.8, 0.5),
];
const OFFSET: f32 = 20.;
const REL_POSITIONS: [[f32; 2]; 3] = [
[-OFFSET, -OFFSET / 2.],
[OFFSET, -OFFSET / 2.],
[0., OFFSET],
];
for i in 0..3 {
self.circle.draw(
ctx,
quad_ctx,
DrawParam::default()
.dest(pos + Vec2::from(REL_POSITIONS[i]))
.color(TRI_COLORS[i]),
)?;
}
let text = graphics::Text::new((name, self.font, 20.0));
let text_offset = Vec2::new(0., -90.);
graphics::draw(
ctx,
quad_ctx,
&text,
graphics::DrawParam::new()
.dest(pos + text_offset)
.color(Color::WHITE)
.offset(Vec2::new(0.5, 0.5)),
)?;
Ok(())
}
fn draw_venn_diagrams(
&mut self,
ctx: &mut Context,
quad_ctx: &mut miniquad::GraphicsContext,
) -> GameResult<()> {
let (w, h) = graphics::drawable_size(quad_ctx);
let y = h / 4.;
const MODE_COUNT: usize = 5;
let x_step = w / (MODE_COUNT + 1) as f32;
self.circle.set_blend_mode(Some(BlendMode::Alpha));
self.draw_venn(ctx, quad_ctx, [x_step, y].into(), "Alpha")?;
self.circle.set_blend_mode(Some(BlendMode::Add));
self.draw_venn(ctx, quad_ctx, [x_step * 2., y].into(), "Add")?;
self.circle.set_blend_mode(Some(BlendMode::Subtract));
self.draw_venn(ctx, quad_ctx, [x_step * 3., y].into(), "Subtract")?;
self.circle.set_blend_mode(Some(BlendMode::Multiply));
self.draw_venn(ctx, quad_ctx, [x_step * 4., y].into(), "Multiply")?;
self.circle.set_blend_mode(Some(BlendMode::Replace));
self.draw_venn(ctx, quad_ctx, [x_step * 5., y].into(), "Replace")?;
Ok(())
}
}
impl EventHandler<ggez::GameError> for MainState {
fn update(
&mut self,
_: &mut Context,
_quad_ctx: &mut miniquad::GraphicsContext,
) -> GameResult<()> {
Ok(())
}
fn draw(
&mut self,
ctx: &mut Context,
quad_ctx: &mut miniquad::GraphicsContext,
) -> GameResult<()> {
graphics::set_canvas(ctx, Some(&self.canvas));
graphics::clear(ctx, quad_ctx, Color::new(0., 0., 0., 0.));
self.draw_venn_diagrams(ctx, quad_ctx)?;
graphics::set_canvas(ctx, None);
graphics::clear(ctx, quad_ctx, Color::new(0.3, 0.3, 0.3, 1.0));
self.draw_venn_diagrams(ctx, quad_ctx)?;
let (_, height) = graphics::drawable_size(quad_ctx);
self.canvas.draw(
ctx,
quad_ctx,
DrawParam::default().dest(mint::Point2 {
x: 0.,
y: height / 2.,
}),
)?;
let (_w, h) = graphics::drawable_size(quad_ctx);
let y = h / 2.;
let text = graphics::Text::new(("drawn directly:", self.font, 20.0));
graphics::draw(
ctx,
quad_ctx,
&text,
graphics::DrawParam::new()
.dest(Vec2::new(8., 4.))
.color(Color::WHITE),
)?;
let text =
graphics::Text::new(("drawn onto a (transparent black) canvas:", self.font, 20.0));
graphics::draw(
ctx,
quad_ctx,
&text,
graphics::DrawParam::new()
.dest(Vec2::new(8., 4. + y))
.color(Color::WHITE),
)?;
graphics::present(ctx, quad_ctx)?;
Ok(())
}
fn key_down_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut miniquad::GraphicsContext,
_keycode: ggez::event::KeyCode,
_keymod: ggez::event::KeyMods,
repeat: bool,
) {
if !repeat {
if let Some(BlendMode::Alpha) = self.canvas.blend_mode() {
self.canvas.set_blend_mode(Some(BlendMode::Premultiplied));
println!("Drawing canvas with premultiplied alpha mode");
} else {
self.canvas.set_blend_mode(Some(BlendMode::Alpha));
println!("Drawing canvas with default alpha mode");
}
}
}
}
pub fn main() -> GameResult {
let resource_dir = if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
let mut path = path::PathBuf::from(manifest_dir);
path.push("resources");
path
} else {
path::PathBuf::from("./resources")
};
ggez::start(
ggez::conf::Conf::default()
.cache(Some(include_bytes!("resources.tar")))
.physical_root_dir(Some(resource_dir)),
|mut context, quad_ctx| Box::new(MainState::new(&mut context, quad_ctx).unwrap()),
)
}