Skip to content

Commit

Permalink
Draw textures, edit pixels in images
Browse files Browse the repository at this point in the history
  • Loading branch information
bvssvni committed Jan 29, 2018
1 parent 11a4781 commit 4f50dd9
Show file tree
Hide file tree
Showing 8 changed files with 292 additions and 12 deletions.
Binary file added interactive/assets/img.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 32 additions & 8 deletions interactive/examples/dyongame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use piston::input::Event;
use piston::window::WindowSettings;
use piston::event_loop::{Events, EventSettings};
use sdl2_window::Sdl2Window;
use opengl_graphics::{OpenGL, Filter, GlGraphics, GlyphCache, TextureSettings};
use opengl_graphics::{OpenGL, Filter, GlGraphics, GlyphCache, Texture, TextureSettings};

#[derive(Clone, Hash, PartialEq, Eq)]
enum Music {
Expand Down Expand Up @@ -65,20 +65,20 @@ fn main() {
};

let mut dyon_runtime = Runtime::new();
let mut factory = ();
let fira_sans = include_bytes!("../assets/FiraSans-Regular.ttf");
let hack = include_bytes!("../assets/Hack-Regular.ttf");
let font_texture_settings = TextureSettings::new().filter(Filter::Nearest);
let mut glyphs = vec![
GlyphCache::from_bytes(&fira_sans[..], factory.clone(), font_texture_settings.clone()).unwrap(),
GlyphCache::from_bytes(&hack[..], factory.clone(), font_texture_settings).unwrap()
GlyphCache::from_bytes(&fira_sans[..], (), font_texture_settings.clone()).unwrap(),
GlyphCache::from_bytes(&hack[..], (), font_texture_settings).unwrap()
];
let mut font_names = FontNames(vec![
Arc::new("FiraSans-Regular".to_owned()),
Arc::new("Hack-Regular".to_owned()),
]);
let mut images = vec![];
let mut image_names = ImageNames(vec![]);
let mut textures = vec![];
let mut gl = GlGraphics::new(opengl);
let mut events = Events::new(EventSettings::new());

Expand All @@ -90,7 +90,7 @@ fn main() {
let font_names_guard: CurrentGuard<FontNames> = CurrentGuard::new(&mut font_names);
let images_guard: CurrentGuard<Vec<RgbaImage>> = CurrentGuard::new(&mut images);
let image_names_guard: CurrentGuard<ImageNames> = CurrentGuard::new(&mut image_names);
let factory_guard: CurrentGuard<()> = CurrentGuard::new(&mut factory);
let textures_guard: CurrentGuard<Vec<Texture>> = CurrentGuard::new(&mut textures);
let gl_guard: CurrentGuard<GlGraphics> = CurrentGuard::new(&mut gl);
let events_guard: CurrentGuard<Events> = CurrentGuard::new(&mut events);

Expand All @@ -102,7 +102,7 @@ fn main() {

drop(events_guard);
drop(gl_guard);
drop(factory_guard);
drop(textures_guard);
drop(image_names_guard);
drop(images_guard);
drop(font_names_guard);
Expand Down Expand Up @@ -175,6 +175,13 @@ fn load_module(file: &str) -> Option<Module> {
tys: vec![Type::F64],
ret: Type::Void
});
module.add(Arc::new("create_texture".into()),
create_texture, Dfn {
lts: vec![Lt::Default],
tys: vec![Type::F64],
ret: Type::F64,
}
);

if error(dyon::load_str(
"render.dyon",
Expand All @@ -195,24 +202,26 @@ mod dyon_functions {
use sdl2_window::Sdl2Window;
use piston::input::{Event, RenderEvent};
use piston::event_loop::Events;
use opengl_graphics::{GlGraphics, GlyphCache};
use opengl_graphics::{GlGraphics, GlyphCache, Texture, TextureSettings};
use dyon::Runtime;
use dyon_interactive::{draw_2d, NO_EVENT};
use current::Current;
use std::sync::Arc;
use music;
use {Music, Sound};
use image::RgbaImage;

dyon_fn!{fn render_source() -> String {include_str!("../src/render.dyon").into()}}

pub fn draw(rt: &mut Runtime) -> Result<(), String> {
let e = unsafe { &*Current::<Option<Event>>::new() };
let gl = unsafe { &mut *Current::<GlGraphics>::new() };
let glyphs = unsafe { &mut *Current::<Vec<GlyphCache>>::new() };
let textures = unsafe { &mut *Current::<Vec<Texture>>::new() };
if let &Some(ref e) = e {
if let Some(args) = e.render_args() {
gl.draw(args.viewport(), |c, g| {
draw_2d(rt, glyphs, c, g)
draw_2d(rt, glyphs, textures, c, g)
})
} else {
Ok(())
Expand All @@ -222,6 +231,21 @@ mod dyon_functions {
}
}

pub fn create_texture(rt: &mut Runtime) -> Result<(), String> {
let images = unsafe { &*Current::<Vec<RgbaImage>>::new() };
let textures = unsafe { &mut *Current::<Vec<Texture>>::new() };
let id: usize = rt.pop()?;
let new_id = textures.len();
let image = if let Some(x) = images.get(id) {
x
} else {
return Err("Image id is out of bounds".into());
};
textures.push(Texture::from_image(image, &TextureSettings::new()));
rt.push(new_id);
Ok(())
}

pub fn next_event(rt: &mut Runtime) -> Result<(), String> {
let window = unsafe { &mut *Current::<Sdl2Window>::new() };
let events = unsafe { &mut *Current::<Events>::new() };
Expand Down
9 changes: 9 additions & 0 deletions interactive/examples/image.dyon
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fn main() {
img := create_image(name: "img", size: (16, 16))
size := image_size(img)
for x x(size), y y(size) {
pxl(image: img, pos: (x, y), color: #00ff00)
}
println(str(color: pxl(image: img, pos: (0, 0))))
_ := unwrap(save(image: img, file: "../assets/img.png"))
}
4 changes: 0 additions & 4 deletions interactive/examples/test.dyon

This file was deleted.

26 changes: 26 additions & 0 deletions interactive/examples/texture.dyon
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
fn main() {
_ := unwrap(load_image("../assets/test.png"))
test := create_texture(TEST())
println(test)
~ draw_list := []
loop {
if !next_event() {break}

if render() {
clear(color: #ffffff)
image(texture: test, pos: (80, 80), color: #ff0000)
image(texture: test, pos: (100, 100), color: #00ff00)
image(texture: test, pos: (120, 120), color: #0000ff)
image(texture: test, pos: (300, 100), alpha: 0.3)

offset := (10, 10)
for i 10 {
image(texture: test, pos: (200 + i * 20, 400) + offset, alpha: i/10,
srccorner: offset, srcsize: (20, 40))
}
draw(draw_list)
}
}
}

fn TEST() -> Image f64 {return 0}
20 changes: 20 additions & 0 deletions interactive/src/lib.dyon
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,23 @@ fn image_names() -> [str] { ... }

/// Loads image from file.
fn load_image(file: str) -> res[str] { ... }

/// Saves image to file.
fn save__image_file(image: f64, file: str) -> res[str] { ... }

/// Creates empty image.
fn create_image__name_size(name: str, size: vec4) -> f64 { ... }

/// Returns image size.
fn image_size(image: f64) -> vec4 { ... }

/// Sets pixel color in image.
fn pxl__image_pos_color(image: f64, pos: vec4, color: vec4) { ... }

/// Gets pixel color from image.
fn pxl__image_pos(image: f64, pos: vec4) -> vec4 { ... }

/// Creates texture from image.
///
/// Takes an image id and returns a texture id.
fn create_texture(image: f64) -> f64 { ... }
163 changes: 163 additions & 0 deletions interactive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,41 @@ pub fn add_functions<W, F, C>(module: &mut Module)
ret: Type::Result(Box::new(Type::Text))
}
);
module.add(Arc::new("create_image__name_size".into()),
create_image__name_size, Dfn {
lts: vec![Lt::Default; 2],
tys: vec![Type::Text, Type::Vec4],
ret: Type::F64
}
);
module.add(Arc::new("save__image_file".into()),
save__image_file, Dfn {
lts: vec![Lt::Default; 2],
tys: vec![Type::F64, Type::Text],
ret: Type::Result(Box::new(Type::Text))
}
);
module.add(Arc::new("image_size".into()),
image_size, Dfn {
lts: vec![Lt::Default],
tys: vec![Type::F64],
ret: Type::Vec4
}
);
module.add(Arc::new("pxl__image_pos_color".into()),
pxl__image_pos_color, Dfn {
lts: vec![Lt::Default; 3],
tys: vec![Type::F64, Type::Vec4, Type::Vec4],
ret: Type::Void
}
);
module.add(Arc::new("pxl__image_pos".into()),
pxl__image_pos, Dfn {
lts: vec![Lt::Default; 2],
tys: vec![Type::F64, Type::Vec4],
ret: Type::Vec4
}
);
}

pub fn window_size<W: Any + Window>(rt: &mut Runtime) -> Result<(), String> {
Expand Down Expand Up @@ -355,10 +390,114 @@ pub fn load_image(rt: &mut Runtime) -> Result<(), String> {
Ok(())
}

#[allow(non_snake_case)]
pub fn create_image__name_size(rt: &mut Runtime) -> Result<(), String> {
use image::RgbaImage;

let image_names = unsafe { &mut *Current::<ImageNames>::new() };
let images = unsafe { &mut *Current::<Vec<RgbaImage>>::new() };
let id = images.len();
let size: [f64; 2] = rt.pop_vec4()?;
let name: Arc<String> = rt.pop()?;
image_names.0.push(name);
images.push(RgbaImage::new(size[0] as u32, size[1] as u32));
rt.push(id);
Ok(())
}

#[allow(non_snake_case)]
pub fn save__image_file(rt: &mut Runtime) -> Result<(), String> {
use image::RgbaImage;

let images = unsafe { &mut *Current::<Vec<RgbaImage>>::new() };
let file: Arc<String> = rt.pop()?;
let id: usize = rt.pop()?;
match images[id].save(&**file) {
Ok(_) => {
rt.push(Ok::<Arc<String>, Arc<String>>(file));
},
Err(err) => {
rt.push(Err::<Arc<String>, Arc<String>>(Arc::new(format!("{}", err))));
}
}
Ok(())
}

pub fn image_size(rt: &mut Runtime) -> Result<(), String> {
use image::RgbaImage;

let images = unsafe { &*Current::<Vec<RgbaImage>>::new() };
let id: usize = rt.pop()?;
let (w, h) = images[id].dimensions();
rt.push_vec4([w as f64, h as f64]);
Ok(())
}

#[allow(non_snake_case)]
pub fn pxl__image_pos_color(rt: &mut Runtime) -> Result<(), String> {
use image::{Rgba, RgbaImage, GenericImage};

let images = unsafe { &mut *Current::<Vec<RgbaImage>>::new() };
let color: [f32; 4] = rt.pop_vec4()?;
let pos: [f64; 2] = rt.pop_vec4()?;
let id: usize = rt.pop()?;
let image = if let Some(x) = images.get_mut(id) {
x
} else {
return Err("Image id is out of bounds".into());
};
let x = pos[0] as u32;
let y = pos[1] as u32;
let (w, h) = image.dimensions();
if x >= w || y >= h {
return Err("Pixel is out of image bounds".into());
}
unsafe {
image.unsafe_put_pixel(x, y, Rgba {
data: [
(color[0] * 255.0) as u8,
(color[1] * 255.0) as u8,
(color[2] * 255.0) as u8,
(color[3] * 255.0) as u8
]
});
}
Ok(())
}

#[allow(non_snake_case)]
pub fn pxl__image_pos(rt: &mut Runtime) -> Result<(), String> {
use image::{GenericImage, RgbaImage};

let images = unsafe { &*Current::<Vec<RgbaImage>>::new() };
let pos: [f64; 2] = rt.pop_vec4()?;
let id: usize = rt.pop()?;
let image = if let Some(x) = images.get(id) {
x
} else {
return Err("Image id is out of bounds".into());
};
let x = pos[0] as u32;
let y = pos[1] as u32;
let (w, h) = image.dimensions();
if x >= w || y >= h {
return Err("Pixel is out of image bounds".into());
}
let color = unsafe { image.unsafe_get_pixel(x, y).data };
rt.push_vec4([
color[0] as f32 / 255.0,
color[1] as f32 / 255.0,
color[2] as f32 / 255.0,
color[3] as f32 / 255.0
]);
Ok(())
}

/// Helper method for drawing 2D in Dyon environment.
pub fn draw_2d<C: CharacterCache<Texture = G::Texture>, G: Graphics>(
rt: &mut Runtime,
glyphs: &mut Vec<C>,
textures: &mut Vec<G::Texture>,
c: Context,
g: &mut G
) -> Result<(), String> {
Expand Down Expand Up @@ -434,6 +573,30 @@ pub fn draw_2d<C: CharacterCache<Texture = G::Texture>, G: Graphics>(
transform.trans(pos[0], pos[1]), g
).map_err(|_| "Could not get glyph".to_owned())?;
}
"image__texture_pos_color" => {
let id: usize = rt.var(&it[1])?;
let pos: [f64; 2] = rt.var_vec4(&it[2])?;
let color: [f32; 4] = rt.var_vec4(&it[3])?;
Image::new_color(color).draw(
&textures[id],
&c.draw_state,
transform.trans(pos[0], pos[1]), g
);
}
"image__texture_pos_color_srccorner_srcsize" => {
let id: usize = rt.var(&it[1])?;
let pos: [f64; 2] = rt.var_vec4(&it[2])?;
let color: [f32; 4] = rt.var_vec4(&it[3])?;
let srccorner: [f64; 2] = rt.var_vec4(&it[4])?;
let srcsize: [f64; 2] = rt.var_vec4(&it[5])?;
Image::new_color(color)
.src_rect([srccorner[0], srccorner[1], srcsize[0], srcsize[1]])
.draw(
&textures[id],
&c.draw_state,
transform.trans(pos[0], pos[1]), g
);
}
_ => {}
}
}
Expand Down
Loading

0 comments on commit 4f50dd9

Please sign in to comment.