dyon_interactive/
lib.rs

1#![doc = include_str!("../README.md")]
2
3extern crate piston;
4extern crate dyon;
5extern crate current;
6extern crate graphics;
7extern crate texture;
8extern crate image;
9
10use std::any::Any;
11use std::sync::Arc;
12use self::dyon::*;
13use self::dyon::embed::to_rust_object;
14use self::current::Current;
15use self::piston::input::*;
16use self::piston::window::*;
17use self::graphics::{Context, Graphics};
18use self::graphics::character::CharacterCache;
19use texture::{CreateTexture, UpdateTexture};
20
21pub const NO_EVENT: &'static str = "No event";
22pub const CNGG: &'static str = "Could not get glyph";
23pub const CNOLOM: &'static str = "Could not obtain lock on Mutex";
24pub const EXPECTED_RGBA_IMAGE: &'static str = "Expected RgbaImage";
25pub const EXPECTED_TEXTURE: &'static str = "Expected Texture";
26pub const EXPECTED_FONT: &'static str = "Expected Font";
27pub const IMAGE_ID_IS_OFB: &'static str = "Image id is out of bounds";
28pub const FONT_ID_IS_OFB: &'static str = "Font index out of bounds";
29pub const PIXEL_IS_OFB: &'static str = "Pixel is out of image bounds";
30pub const EXPECTED_IMAGE_ID_OR_OBJECT: &'static str =
31    "Expected `f64` (image id) or `any` (rust object)";
32pub const EXPECTED_FONT_ID_OR_OBJECT: &'static str =
33    "Expected `f64` (font id) or `any` (rust object)";
34
35/// Adds functions to module, using a generic backend.
36///
37/// `W` is window.
38/// `F` is factory (to create textures).
39/// `C` is character cache.
40pub fn add_functions<W, F, C>(module: &mut Module)
41    where W: Any + AdvancedWindow,
42          F: 'static + Clone,
43          C::Texture: CreateTexture<F> + UpdateTexture<F>,
44          C: Any + CharacterCache,
45{
46    module.ns("piston::interactive");
47    // `render_source` has been renamed to `graphics2d_source`.
48    // This function might be removed in future versions.
49    module.add(Arc::new("render_source".into()), graphics2d_source, Dfn::nl(vec![], Type::Str));
50    module.add(Arc::new("graphics2d_source".into()), graphics2d_source, Dfn::nl(vec![], Type::Str));
51    module.add(Arc::new("window_size".into()), window_size::<W>,
52        Dfn::nl(vec![], Type::Vec4));
53    module.add(Arc::new("set_window__size".into()), set_window__size::<W>,
54        Dfn::nl(vec![Type::Vec4], Type::Void));
55    module.add(Arc::new("window_draw_size".into()), window_draw_size::<W>,
56        Dfn::nl(vec![], Type::Vec4));
57    module.add(Arc::new("window_position".into()), window_position::<W>,
58        Dfn::nl(vec![], Type::Vec4));
59    module.add(Arc::new("set_window__position".into()), set_window__position::<W>,
60        Dfn::nl(vec![Type::Vec4], Type::Void));
61    module.add(Arc::new("render".into()), render, Dfn::nl(vec![], Type::Bool));
62    module.add(Arc::new("after_render".into()), after_render, Dfn::nl(vec![], Type::Bool));
63    module.add(Arc::new("update".into()), update, Dfn::nl(vec![], Type::Bool));
64    module.add(Arc::new("idle".into()), idle, Dfn::nl(vec![], Type::Bool));
65    module.add(Arc::new("press".into()), press, Dfn::nl(vec![], Type::Bool));
66    module.add(Arc::new("release".into()), release, Dfn::nl(vec![], Type::Bool));
67    module.add(Arc::new("resize".into()), resize, Dfn::nl(vec![], Type::Bool));
68    module.add(Arc::new("focus".into()), focus, Dfn::nl(vec![], Type::Bool));
69    module.add(Arc::new("cursor".into()), cursor, Dfn::nl(vec![], Type::Bool));
70    module.add(Arc::new("text".into()), text, Dfn::nl(vec![], Type::Bool));
71    module.add(Arc::new("mouse_cursor".into()), mouse_cursor,
72        Dfn::nl(vec![], Type::Bool));
73    module.add(Arc::new("focus_arg".into()), focus_arg,
74        Dfn::nl(vec![], Type::Option(Box::new(Type::Bool))));
75    module.add(Arc::new("cursor_arg".into()), cursor_arg,
76        Dfn::nl(vec![], Type::Option(Box::new(Type::Bool))));
77    module.add(Arc::new("mouse_cursor_pos".into()), mouse_cursor_pos,
78        Dfn::nl(vec![], Type::Option(Box::new(Type::Vec4))));
79    module.add(Arc::new("window_title".into()),
80        window_title::<W>, Dfn::nl(vec![], Type::Str));
81    module.add(Arc::new("set_window__title".into()),
82        set_window__title::<W>, Dfn::nl(vec![Type::Str], Type::Void));
83    module.add(Arc::new("event_loop_ups".into()),
84        event_loop_ups, Dfn::nl(vec![], Type::F64));
85    module.add(Arc::new("set_event_loop__ups".into()),
86        set_event_loop__ups, Dfn::nl(vec![Type::F64], Type::Void));
87    module.add(Arc::new("event_loop_upsreset".into()),
88        event_loop_upsreset, Dfn::nl(vec![], Type::F64));
89    module.add(Arc::new("set_event_loop__upsreset".into()),
90        set_event_loop__upsreset, Dfn::nl(vec![Type::F64], Type::Void));
91    module.add(Arc::new("event_loop_maxfps".into()),
92        event_loop_maxfps, Dfn::nl(vec![], Type::F64));
93    module.add(Arc::new("set_event_loop__maxfps".into()),
94        set_event_loop__maxfps, Dfn::nl(vec![Type::F64], Type::Void));
95    module.add(Arc::new("event_loop_swapbuffers".into()),
96        event_loop_swapbuffers, Dfn::nl(vec![], Type::Bool));
97    module.add(Arc::new("set_event_loop__swapbuffers".into()),
98        set_event_loop__swapbuffers, Dfn::nl(vec![Type::Bool], Type::Void));
99    module.add(Arc::new("swap_buffers".into()),
100        swap_buffers::<W>, Dfn::nl(vec![], Type::Void));
101    module.add(Arc::new("event_loop_benchmode".into()),
102        event_loop_benchmode, Dfn::nl(vec![], Type::Bool));
103    module.add(Arc::new("set_event_loop__benchmode".into()),
104        set_event_loop__benchmode, Dfn::nl(vec![Type::Bool], Type::Void));
105    module.add(Arc::new("event_loop_lazy".into()),
106        event_loop_lazy, Dfn::nl(vec![], Type::Bool));
107    module.add(Arc::new("set_event_loop__lazy".into()),
108        set_event_loop__lazy, Dfn::nl(vec![Type::Bool], Type::Void));
109    module.add(Arc::new("render_ext_dt".into()),
110        render_ext_dt, Dfn::nl(vec![], Type::Option(Box::new(Type::F64))));
111    module.add(Arc::new("update_dt".into()),
112        update_dt, Dfn::nl(vec![], Type::Option(Box::new(Type::F64))));
113    module.add(Arc::new("idle_dt".into()),
114        idle_dt, Dfn::nl(vec![], Type::Option(Box::new(Type::F64))));
115    module.add(Arc::new("press_keyboard_key".into()),
116        press_keyboard_key, Dfn::nl(vec![], Type::Option(Box::new(Type::F64))));
117    module.add(Arc::new("release_keyboard_key".into()),
118        release_keyboard_key, Dfn::nl(vec![], Type::Option(Box::new(Type::F64))));
119    module.add(Arc::new("press_mouse_button".into()),
120        press_mouse_button, Dfn::nl(vec![], Type::Option(Box::new(Type::F64))));
121    module.add(Arc::new("release_mouse_button".into()),
122        release_mouse_button, Dfn::nl(vec![], Type::Option(Box::new(Type::F64))));
123    module.add(Arc::new("text_arg".into()),
124        text_arg, Dfn::nl(vec![], Type::Option(Box::new(Type::Str))));
125    module.add(Arc::new("width__font_size_string".into()),
126        width__font_size_string::<C>, Dfn::nl(vec![Type::F64, Type::F64, Type::Str], Type::F64));
127    module.add(Arc::new("font_names".into()),
128        font_names, Dfn::nl(vec![], Type::Array(Box::new(Type::Str)))
129    );
130    module.add(Arc::new("image_names".into()),
131        image_names, Dfn::nl(vec![], Type::Array(Box::new(Type::Str)))
132    );
133    module.add(Arc::new("load_image".into()),
134        load_image, Dfn::nl(vec![Type::Str], Type::Result(Box::new(Type::F64)))
135    );
136    module.add(Arc::new("load_image_obj".into()),
137        load_image_obj, Dfn::nl(vec![Type::Str], Type::Result(Box::new(Type::Any)))
138    );
139    module.add(Arc::new("create_image__name_size".into()),
140        create_image__name_size, Dfn::nl(vec![Type::Str, Type::Vec4], Type::F64)
141    );
142    module.add(Arc::new("create_image__size".into()),
143        create_image__size, Dfn::nl(vec![Type::Vec4], Type::Any)
144    );
145    module.add(Arc::new("save__image_file".into()),
146        save__image_file, Dfn::nl(vec![Type::F64, Type::Str], Type::Result(Box::new(Type::Str)))
147    );
148    module.add(Arc::new("image_size".into()),
149        image_size, Dfn::nl(vec![Type::Any], Type::Vec4)
150    );
151    module.add(Arc::new("pxl__image_pos_color".into()),
152        pxl__image_pos_color, Dfn::nl(vec![Type::Any, Type::Vec4, Type::Vec4], Type::Void)
153    );
154    module.add(Arc::new("pxl__image_pos".into()),
155        pxl__image_pos, Dfn::nl(vec![Type::Any, Type::Vec4], Type::Vec4)
156    );
157}
158
159dyon_fn!{fn render_source() -> String {
160    eprintln!("WARNING: `render_source` has been renamed to `graphics2d_source`.");
161    include_str!("../src/graphics2d.dyon").into()
162}}
163
164dyon_fn!{fn graphics2d_source() -> String {include_str!("../src/graphics2d.dyon").into()}}
165
166pub fn window_size<W: Any + Window>(_rt: &mut Runtime) -> Result<Variable, String> {
167    let size = unsafe { Current::<W>::new() }.size();
168    Ok(Variable::Vec4([size.width as f32, size.height as f32, 0.0, 0.0]))
169}
170
171pub fn window_draw_size<W: Any + Window>(_rt: &mut Runtime) -> Result<Variable, String> {
172    let draw_size = unsafe { Current::<W>::new() }.draw_size();
173    Ok(Variable::Vec4([draw_size.width as f32, draw_size.height as f32, 0.0, 0.0]))
174}
175
176#[allow(non_snake_case)]
177pub fn set_window__size<W: Any + AdvancedWindow>(rt: &mut Runtime) -> Result<(), String> {
178    let size: [f32; 2] = rt.pop_vec4()?;
179    let size: [u32; 2] = [size[0] as u32, size[1] as u32];
180    unsafe { Current::<W>::new() }.set_size(size);
181    Ok(())
182}
183
184pub fn window_position<W: Any + AdvancedWindow>(_rt: &mut Runtime) -> Result<Variable, String> {
185    Ok(Variable::Vec4(if let Some(pos) = unsafe { Current::<W>::new() }.get_position() {
186        [pos.x as f32, pos.y as f32, 0.0, 0.0]
187    } else {
188        [0.0 as f32; 4]
189    }))
190}
191
192#[allow(non_snake_case)]
193pub fn set_window__position<W: Any + AdvancedWindow>(rt: &mut Runtime) -> Result<(), String> {
194    let pos: [f32; 2] = rt.pop_vec4()?;
195    let pos: [i32; 2] = [pos[0] as i32, pos[1] as i32];
196    unsafe { Current::<W>::new() }.set_position(pos);
197    Ok(())
198}
199
200dyon_fn!{fn event_loop_ups() -> f64 {
201    use piston::event_loop::{EventLoop, Events};
202
203    unsafe { Current::<Events>::new() }.get_event_settings().ups as f64
204}}
205
206dyon_fn!{fn set_event_loop__ups(ups: f64) {
207    use piston::event_loop::{EventLoop, Events};
208
209    unsafe { Current::<Events>::new() }.set_ups(ups as u64);
210}}
211
212dyon_fn!{fn event_loop_upsreset() -> f64 {
213    use piston::event_loop::{EventLoop, Events};
214
215    unsafe { Current::<Events>::new() }.get_event_settings().ups_reset as f64
216}}
217
218dyon_fn!{fn set_event_loop__upsreset(ups_reset: f64) {
219    use piston::event_loop::{EventLoop, Events};
220
221    unsafe { Current::<Events>::new() }.set_ups_reset(ups_reset as u64);
222}}
223
224dyon_fn!{fn event_loop_maxfps() -> f64 {
225    use piston::event_loop::{EventLoop, Events};
226
227    unsafe { Current::<Events>::new() }.get_event_settings().max_fps as f64
228}}
229
230dyon_fn!{fn set_event_loop__maxfps(max_fps: f64) {
231    use piston::event_loop::{EventLoop, Events};
232
233    unsafe { Current::<Events>::new() }.set_max_fps(max_fps as u64);
234}}
235
236dyon_fn!{fn event_loop_swapbuffers() -> bool {
237    use piston::event_loop::{EventLoop, Events};
238
239    unsafe { Current::<Events>::new() }.get_event_settings().swap_buffers
240}}
241
242dyon_fn!{fn set_event_loop__swapbuffers(swap_buffers: bool) {
243    use piston::event_loop::{EventLoop, Events};
244
245    unsafe { Current::<Events>::new() }.set_swap_buffers(swap_buffers);
246}}
247
248pub fn swap_buffers<W: Any + Window>(_rt: &mut Runtime) -> Result<(), String> {
249    unsafe { Current::<W>::new() }.swap_buffers();
250    Ok(())
251}
252
253dyon_fn!{fn event_loop_benchmode() -> bool {
254    use piston::event_loop::{EventLoop, Events};
255
256    unsafe { Current::<Events>::new() }.get_event_settings().bench_mode
257}}
258
259dyon_fn!{fn set_event_loop__benchmode(bench_mode: bool) {
260    use piston::event_loop::{EventLoop, Events};
261
262    unsafe { Current::<Events>::new() }.set_bench_mode(bench_mode);
263}}
264
265dyon_fn!{fn event_loop_lazy() -> bool {
266    use piston::event_loop::{EventLoop, Events};
267
268    unsafe { Current::<Events>::new() }.get_event_settings().lazy
269}}
270
271dyon_fn!{fn set_event_loop__lazy(lazy: bool) {
272    use piston::event_loop::{EventLoop, Events};
273
274    unsafe { Current::<Events>::new() }.set_lazy(lazy);
275}}
276
277dyon_fn!{fn render() -> bool {
278    unsafe { Current::<Option<Event>>::new()
279        .as_ref().expect(NO_EVENT).render_args().is_some() }
280}}
281
282dyon_fn!{fn after_render() -> bool {
283    unsafe { Current::<Option<Event>>::new()
284        .as_ref().expect(NO_EVENT).after_render_args().is_some() }
285}}
286
287dyon_fn!{fn update() -> bool {
288    unsafe { Current::<Option<Event>>::new()
289        .as_ref().expect(NO_EVENT).update_args().is_some() }
290}}
291
292dyon_fn!{fn idle() -> bool {
293    unsafe { Current::<Option<Event>>::new()
294        .as_ref().expect(NO_EVENT).idle_args().is_some() }
295}}
296
297dyon_fn!{fn press() -> bool {
298    unsafe { Current::<Option<Event>>::new()
299        .as_ref().expect(NO_EVENT).press_args().is_some() }
300}}
301
302dyon_fn!{fn release() -> bool {
303    unsafe { Current::<Option<Event>>::new()
304        .as_ref().expect(NO_EVENT).release_args().is_some() }
305}}
306
307dyon_fn!{fn resize() -> bool {
308    unsafe { Current::<Option<Event>>::new()
309        .as_ref().expect(NO_EVENT).resize_args().is_some() }
310}}
311
312dyon_fn!{fn focus() -> bool {
313    unsafe { Current::<Option<Event>>::new()
314        .as_ref().expect(NO_EVENT).focus_args().is_some() }
315}}
316
317dyon_fn!{fn cursor() -> bool {
318    unsafe { Current::<Option<Event>>::new()
319        .as_ref().expect(NO_EVENT).cursor_args().is_some() }
320}}
321
322dyon_fn!{fn text() -> bool {
323    unsafe { Current::<Option<Event>>::new()
324        .as_ref().expect(NO_EVENT).text(|_| ()).is_some() }
325}}
326
327dyon_fn!{fn mouse_cursor() -> bool {
328    unsafe { Current::<Option<Event>>::new()
329        .as_ref().expect(NO_EVENT).mouse_cursor_args().is_some() }
330}}
331
332dyon_fn!{fn focus_arg() -> Option<bool> {
333    unsafe { Current::<Option<Event>>::new()
334        .as_ref().expect(NO_EVENT).focus_args() }
335}}
336
337dyon_fn!{fn cursor_arg() -> Option<bool> {
338    unsafe { Current::<Option<Event>>::new()
339        .as_ref().expect(NO_EVENT).cursor_args() }
340}}
341
342dyon_fn!{fn render_ext_dt() -> Option<f64> {
343    unsafe { Current::<Option<Event>>::new()
344        .as_ref().expect(NO_EVENT).render_args().map(|args| args.ext_dt) }
345}}
346
347dyon_fn!{fn update_dt() -> Option<f64> {
348    unsafe { Current::<Option<Event>>::new()
349        .as_ref().expect(NO_EVENT).update_args().map(|args| args.dt) }
350}}
351
352dyon_fn!{fn idle_dt() -> Option<f64> {
353    unsafe { Current::<Option<Event>>::new()
354        .as_ref().expect(NO_EVENT).idle_args().map(|args| args.dt) }
355}}
356
357dyon_fn!{fn mouse_cursor_pos() -> Option<Vec4> {
358    unsafe { Current::<Option<Event>>::new()
359        .as_ref().expect(NO_EVENT).mouse_cursor_args().map(|pos| pos.into()) }
360}}
361
362pub fn press_keyboard_key(_rt: &mut Runtime) -> Result<Variable, String> {
363    use dyon::embed::PushVariable;
364
365    let e = unsafe { &*Current::<Option<Event>>::new() };
366    if let &Some(ref e) = e {
367        Ok(if let Some(Button::Keyboard(key)) = e.press_args() {
368            Some(key as u64 as f64)
369        } else {
370            Option::<f64>::None
371        }.push_var())
372    } else {
373        Err(NO_EVENT.into())
374    }
375}
376
377pub fn release_keyboard_key(_rt: &mut Runtime) -> Result<Variable, String> {
378    use dyon::embed::PushVariable;
379
380    let e = unsafe { &*Current::<Option<Event>>::new() };
381    if let &Some(ref e) = e {
382        Ok(if let Some(Button::Keyboard(key)) = e.release_args() {
383            Some(key as u64 as f64)
384        } else {
385            Option::<f64>::None
386        }.push_var())
387    } else {
388        Err(NO_EVENT.into())
389    }
390}
391
392pub fn press_mouse_button(_rt: &mut Runtime) -> Result<Variable, String> {
393    use dyon::embed::PushVariable;
394
395    let e = unsafe { &*Current::<Option<Event>>::new() };
396    if let &Some(ref e) = e {
397        Ok(if let Some(Button::Mouse(button)) = e.press_args() {
398            Some(button as u64 as f64)
399        } else {
400            Option::<f64>::None
401        }.push_var())
402    } else {
403        Err(NO_EVENT.into())
404    }
405}
406
407pub fn release_mouse_button(_rt: &mut Runtime) -> Result<Variable, String> {
408    use dyon::embed::PushVariable;
409
410    let e = unsafe { &*Current::<Option<Event>>::new() };
411    if let &Some(ref e) = e {
412        Ok(if let Some(Button::Mouse(button)) = e.release_args() {
413            Some(button as u64 as f64)
414        } else {
415            Option::<f64>::None
416        }.push_var())
417    } else {
418        Err(NO_EVENT.into())
419    }
420}
421
422pub fn text_arg(_rt: &mut Runtime) -> Result<Variable, String> {
423    use dyon::embed::PushVariable;
424
425    let e = unsafe { &*Current::<Option<Event>>::new() };
426    if let &Some(ref e) = e {
427        Ok(if let Some(text) = e.text_args() {
428            Some(text)
429        } else {
430            Option::<String>::None
431        }.push_var())
432    } else {
433        Err(NO_EVENT.into())
434    }
435}
436
437pub fn window_title<W: Any + AdvancedWindow>(_rt: &mut Runtime) -> Result<Variable, String> {
438    let window = unsafe { &mut *Current::<W>::new() };
439    Ok(Variable::Str(Arc::new(window.get_title())))
440}
441
442#[allow(non_snake_case)]
443pub fn set_window__title<W: Any + AdvancedWindow>(rt: &mut Runtime) -> Result<(), String> {
444    let window = unsafe { &mut *Current::<W>::new() };
445    let title: Arc<String> = rt.pop()?;
446    window.set_title((*title).clone());
447    Ok(())
448}
449
450#[allow(non_snake_case)]
451pub fn width__font_size_string<C: Any + CharacterCache>(rt: &mut Runtime) -> Result<Variable, String> {
452    let glyphs = unsafe { &mut *Current::<Vec<C>>::new() };
453    let s: Arc<String> = rt.pop()?;
454    let size: u32 = rt.pop()?;
455    let font: usize = rt.pop()?;
456    Ok(Variable::f64(glyphs.get_mut(font).ok_or_else(|| FONT_ID_IS_OFB.to_owned())?
457        .width(size, &s).map_err(|_| CNGG.to_owned())?))
458}
459
460/// Wraps font names as a current object.
461pub struct FontNames(pub Vec<Arc<String>>);
462
463/// Wraps image names as a current object.
464pub struct ImageNames(pub Vec<Arc<String>>);
465
466dyon_fn!{fn font_names() -> Vec<Arc<String>> {
467    let font_names = unsafe { &*Current::<FontNames>::new() };
468    font_names.0.clone()
469}}
470
471dyon_fn!{fn image_names() -> Vec<Arc<String>> {
472    let image_names = unsafe { &*Current::<ImageNames>::new() };
473    image_names.0.clone()
474}}
475
476dyon_fn!{fn load_image(file: Arc<String>) -> Result<usize, Arc<String>> {
477    use image::{open, RgbaImage};
478
479    let images = unsafe { &mut *Current::<Vec<RgbaImage>>::new() };
480    let image_names = unsafe { &mut *Current::<ImageNames>::new() };
481    match open(&**file) {
482        Ok(x) => {
483            let id = images.len();
484            images.push(x.to_rgba8());
485            image_names.0.push(file.clone());
486            Ok(id)
487        }
488        Err(err) => {
489            Err(Arc::new(format!("{}", err)))
490        }
491    }
492}}
493
494dyon_fn!{fn load_image_obj(file: Arc<String>) -> Result<RustObject, Arc<String>> {
495    use image::open;
496
497    match open(&**file) {
498        Ok(x) => Ok(to_rust_object(x.to_rgba8())),
499        Err(err) => {
500            Err(Arc::new(format!("{}", err)))
501        }
502    }
503}}
504
505dyon_fn!{fn create_image__name_size(name: Arc<String>, size: Vec4) -> usize {
506    use image::RgbaImage;
507
508    let image_names = unsafe { &mut *Current::<ImageNames>::new() };
509    let images = unsafe { &mut *Current::<Vec<RgbaImage>>::new() };
510    let id = images.len();
511    let size: [f64; 2] = size.into();
512    image_names.0.push(name);
513    images.push(RgbaImage::new(size[0] as u32, size[1] as u32));
514    id
515}}
516
517dyon_fn!{fn create_image__size(size: Vec4) -> RustObject {
518    use image::RgbaImage;
519
520    let size: [f64; 2] = size.into();
521    to_rust_object(RgbaImage::new(size[0] as u32, size[1] as u32))
522}}
523
524dyon_fn!{fn save__image_file(id: usize, file: Arc<String>) -> Result<Arc<String>, Arc<String>> {
525    use image::RgbaImage;
526
527    let images = unsafe { &mut *Current::<Vec<RgbaImage>>::new() };
528    match images[id].save(&**file) {
529        Ok(_) => Ok(file),
530        Err(err) => Err(Arc::new(format!("{}", err))),
531    }
532}}
533
534pub fn image_size(rt: &mut Runtime) -> Result<Variable, String> {
535    use image::RgbaImage;
536
537    let var = rt.pop()?;
538    match var {
539        Variable::F64(id, _) => {
540            let images = unsafe { &*Current::<Vec<RgbaImage>>::new() };
541            let (w, h) = images.get(id as usize)
542                .ok_or_else(|| IMAGE_ID_IS_OFB.to_string())?.dimensions();
543            Ok(Variable::Vec4([w as f32, h as f32, 0.0, 0.0].into()))
544        }
545        Variable::RustObject(obj) => {
546            let guard = obj.lock().map_err(|_| CNOLOM.to_string())?;
547            let img: &RgbaImage = guard.downcast_ref()
548                .ok_or_else(|| EXPECTED_RGBA_IMAGE.to_string())?;
549            let (w, h) = img.dimensions();
550            Ok(Variable::Vec4([w as f32, h as f32, 0.0, 0.0].into()))
551        }
552        _ => Err(EXPECTED_IMAGE_ID_OR_OBJECT.to_string()),
553    }
554}
555
556#[allow(non_snake_case)]
557pub fn pxl__image_pos_color(rt: &mut Runtime) -> Result<(), String> {
558    use image::{Rgba, RgbaImage};
559
560    let color: [f32; 4] = rt.pop_vec4()?;
561    let pos: Vec4 = rt.pop()?;
562    let image: Variable = rt.pop()?;
563
564    let [x, y]: [u32; 2] = pos.into();
565
566    match image {
567        Variable::F64(id, _) => {
568            let images = unsafe { &mut *Current::<Vec<RgbaImage>>::new() };
569            let image: &mut RgbaImage = if let Some(x) = images.get_mut(id as usize) {x}
570                        else {return Err(IMAGE_ID_IS_OFB.into())};
571            let (w, h) = image.dimensions();
572            if x >= w || y >= h {return Err(PIXEL_IS_OFB.into())};
573
574            image.put_pixel(x, y, Rgba([
575                (color[0] * 255.0) as u8,
576                (color[1] * 255.0) as u8,
577                (color[2] * 255.0) as u8,
578                (color[3] * 255.0) as u8
579            ]));
580            Ok(())
581        }
582        Variable::RustObject(obj) => {
583            let mut guard = obj.lock().map_err(|_| CNOLOM.to_string())?;
584            let image: &mut RgbaImage = guard.downcast_mut()
585                .ok_or_else(|| EXPECTED_RGBA_IMAGE.to_string())?;
586            let (w, h) = image.dimensions();
587            if x >= w || y >= h {return Err(PIXEL_IS_OFB.into())};
588
589            image.put_pixel(x, y, Rgba([
590                (color[0] * 255.0) as u8,
591                (color[1] * 255.0) as u8,
592                (color[2] * 255.0) as u8,
593                (color[3] * 255.0) as u8
594            ]));
595            Ok(())
596        }
597        _ => Err(EXPECTED_IMAGE_ID_OR_OBJECT.to_string()),
598    }
599}
600
601dyon_fn!{fn pxl__image_pos(image: Variable, pos: Vec4) -> Result<Vec4, String> {
602    use image::RgbaImage;
603
604    let [x, y] = pos.into();
605    let color = match image {
606        Variable::F64(id, _) => {
607            let images = unsafe { &mut *Current::<Vec<RgbaImage>>::new() };
608            let image: &mut RgbaImage = if let Some(x) = images.get_mut(id as usize) {x}
609                        else {return Err(IMAGE_ID_IS_OFB.into())};
610            let (w, h) = image.dimensions();
611            if x >= w || y >= h {return Err(PIXEL_IS_OFB.into())};
612
613            image.get_pixel(x, y).0
614        }
615        Variable::RustObject(obj) => {
616            let mut guard = obj.lock().map_err(|_| CNOLOM.to_string())?;
617            let image: &mut RgbaImage = guard.downcast_mut()
618                .ok_or_else(|| EXPECTED_RGBA_IMAGE.to_string())?;
619            let (w, h) = image.dimensions();
620            if x >= w || y >= h {return Err(PIXEL_IS_OFB.into())};
621
622            image.get_pixel(x, y).0
623        }
624        _ => return Err(EXPECTED_IMAGE_ID_OR_OBJECT.to_string()),
625    };
626    Ok([
627        color[0] as f32 / 255.0,
628        color[1] as f32 / 255.0,
629        color[2] as f32 / 255.0,
630        color[3] as f32 / 255.0
631    ].into())
632}}
633
634/// Helper method for drawing 2D in Dyon environment.
635pub fn draw_2d<C: CharacterCache<Texture = G::Texture> + 'static, G: Graphics>(
636    rt: &mut Runtime,
637    glyphs: &mut Vec<C>,
638    textures: &mut Vec<G::Texture>,
639    mut c: Context,
640    g: &mut G
641) -> Result<(), String>
642    where G::Texture: 'static,
643{
644    use self::graphics::*;
645    use self::graphics::types::Matrix2d;
646    use self::graphics::draw_state::{Blend, Stencil};
647
648    let draw_list = rt.stack.pop().expect(TINVOTS);
649    let arr = rt.get(&draw_list);
650    let mut transform = c.transform;
651    if let &Variable::Array(ref arr) = arr {
652        for it in &**arr {
653            let it = rt.get(it);
654            if let &Variable::Array(ref it) = it {
655                let ty: Arc<String> = rt.var(&it[0])?;
656                match &**ty {
657                    "clear" => {
658                        let color: [f32; 4] = rt.var_vec4(&it[1])?;
659                        clear(color, g);
660                    }
661                    "clear__stencil" => {
662                        let v: f64 = rt.var(&it[1])?;
663                        g.clear_stencil(v as u8);
664                    }
665                    "clear__colorbuf" => {
666                        let color: [f32; 4] = rt.var_vec4(&it[1])?;
667                        g.clear_color(color);
668                    }
669                    "transform__rx_ry" => {
670                        // Changes transform matrix.
671                        let rx: [f32; 4] = rt.var_vec4(&it[1])?;
672                        let ry: [f32; 4] = rt.var_vec4(&it[2])?;
673                        let t: Matrix2d = [
674                            [rx[0] as f64, rx[1] as f64, rx[2] as f64],
675                            [ry[0] as f64, ry[1] as f64, ry[2] as f64]
676                        ];
677                        transform = math::multiply(c.transform, t);
678                    }
679                    "rel_transform__rx_ry" => {
680                        // Changes transform matrix.
681                        let rx: [f32; 4] = rt.var_vec4(&it[1])?;
682                        let ry: [f32; 4] = rt.var_vec4(&it[2])?;
683                        let t: Matrix2d = [
684                            [rx[0] as f64, rx[1] as f64, rx[2] as f64],
685                            [ry[0] as f64, ry[1] as f64, ry[2] as f64]
686                        ];
687                        transform = math::multiply(transform, t);
688                    }
689                    "line__color_radius_from_to" => {
690                        let color: [f32; 4] = rt.var_vec4(&it[1])?;
691                        let radius: f64 = rt.var(&it[2])?;
692                        let from: [f64; 2] = rt.var_vec4(&it[3])?;
693                        let to: [f64; 2] = rt.var_vec4(&it[4])?;
694                        Line::new(color, radius)
695                            .draw([from[0], from[1], to[0], to[1]],
696                                  &c.draw_state, transform, g);
697                    }
698                    "rectangle__color_corner_size" => {
699                        let color: [f32; 4] = rt.var_vec4(&it[1])?;
700                        let corner: [f64; 2] = rt.var_vec4(&it[2])?;
701                        let size: [f64; 2] = rt.var_vec4(&it[3])?;
702                        Rectangle::new(color)
703                            .draw([corner[0], corner[1], size[0], size[1]],
704                                  &c.draw_state, transform, g);
705                    }
706                    "rectangle__border_color_corner_size" => {
707                        let radius: f64 = rt.var(&it[1])?;
708                        let color: [f32; 4] = rt.var_vec4(&it[2])?;
709                        let corner: [f64; 2] = rt.var_vec4(&it[3])?;
710                        let size: [f64; 2] = rt.var_vec4(&it[4])?;
711                        Rectangle::new_border(color, radius)
712                            .draw([corner[0], corner[1], size[0], size[1]],
713                                  &c.draw_state, transform, g);
714                    }
715                    "ellipse__color_corner_size_resolution" => {
716                        let color: [f32; 4] = rt.var_vec4(&it[1])?;
717                        let corner: [f64; 2] = rt.var_vec4(&it[2])?;
718                        let size: [f64; 2] = rt.var_vec4(&it[3])?;
719                        let resolution: u32 = rt.var(&it[4])?;
720                        Ellipse::new(color)
721                        .resolution(resolution as u32)
722                        .draw([corner[0], corner[1], size[0], size[1]], &c.draw_state, transform, g);
723                    }
724                    "ellipse__border_color_corner_size_resolution" => {
725                        let border: f64 = rt.var(&it[1])?;
726                        let color: [f32; 4] = rt.var_vec4(&it[2])?;
727                        let corner: [f64; 2] = rt.var_vec4(&it[3])?;
728                        let size: [f64; 2] = rt.var_vec4(&it[4])?;
729                        let resolution: u32 = rt.var(&it[5])?;
730                        Ellipse::new_border(color, border)
731                        .resolution(resolution as u32)
732                        .draw([corner[0], corner[1], size[0], size[1]], &c.draw_state, transform, g);
733                    }
734                    "polygon__color_points" => {
735                        let color: [f32; 4] = rt.var_vec4(&it[1])?;
736                        let it_points = rt.get(&it[2]);
737                        if let &Variable::Array(ref it_points) = it_points {
738                            let mut polygon = it_points.iter()
739                                .map(|v| rt.get(v))
740                                .filter(|v| if let Variable::Vec4(_) = v {true} else {false})
741                                .map(|v| if let Variable::Vec4(p) = v {[p[0] as f64, p[1] as f64]}
742                                         else {unreachable!()});
743                            g.tri_list(&c.draw_state, &color, |f| {
744                                triangulation::stream_polygon_tri_list(
745                                    transform, &mut polygon, |vertices| f(vertices))
746                            });
747                        }
748                    }
749                    "text__font_color_size_pos_string" => {
750                        let font: Variable = rt.var(&it[1])?;
751                        let color: [f32; 4] = rt.var_vec4(&it[2])?;
752                        let size: u32 = rt.var(&it[3])?;
753                        let pos: [f64; 2] = rt.var_vec4(&it[4])?;
754                        let text: Arc<String> = rt.var(&it[5])?;
755                        match font {
756                            Variable::F64(id, _) => {
757                                text::Text::new_color(color, size).draw(
758                                    &text,
759                                    glyphs.get_mut(id as usize)
760                                        .ok_or_else(|| FONT_ID_IS_OFB.to_owned())?,
761                                    &c.draw_state,
762                                    transform.trans(pos[0], pos[1]), g
763                                ).map_err(|_| CNGG.to_owned())?;
764                            }
765                            Variable::RustObject(obj) => {
766                                let mut guard = obj.lock().map_err(|_| CNOLOM.to_string())?;
767                                let font: &mut C = guard.downcast_mut()
768                                    .ok_or_else(|| EXPECTED_FONT.to_string())?;
769                                text::Text::new_color(color, size).draw(
770                                    &text,
771                                    font,
772                                    &c.draw_state,
773                                    transform.trans(pos[0], pos[1]), g
774                                ).map_err(|_| CNGG.to_owned())?;
775                            }
776                            _ => return Err(EXPECTED_FONT_ID_OR_OBJECT.to_string()),
777                        }
778                    }
779                    "image__texture_pos_color" => {
780                        let image = rt.var(&it[1])?;
781                        let pos: [f64; 2] = rt.var_vec4(&it[2])?;
782                        let color: [f32; 4] = rt.var_vec4(&it[3])?;
783                        match image {
784                            Variable::F64(id, _) => {
785                                Image::new_color(color).draw(
786                                    &textures[id as usize],
787                                    &c.draw_state,
788                                    transform.trans(pos[0], pos[1]), g
789                                );
790                            }
791                            Variable::RustObject(obj) => {
792                                let guard = obj.lock().map_err(|_| CNOLOM.to_string())?;
793                                let texture: &G::Texture = guard.downcast_ref()
794                                    .ok_or_else(|| EXPECTED_TEXTURE.to_string())?;
795                                Image::new_color(color).draw(
796                                    texture,
797                                    &c.draw_state,
798                                    transform.trans(pos[0], pos[1]), g
799                                );
800                            }
801                            _ => return Err(EXPECTED_IMAGE_ID_OR_OBJECT.to_string()),
802                        }
803                    }
804                    "image__texture_pos_color_srccorner_srcsize" => {
805                        let image = rt.var(&it[1])?;
806                        let pos: [f64; 2] = rt.var_vec4(&it[2])?;
807                        let color: [f32; 4] = rt.var_vec4(&it[3])?;
808                        let srccorner: [f64; 2] = rt.var_vec4(&it[4])?;
809                        let srcsize: [f64; 2] = rt.var_vec4(&it[5])?;
810                        let im = Image::new_color(color)
811                            .src_rect([srccorner[0], srccorner[1], srcsize[0], srcsize[1]]);
812                        match image {
813                            Variable::F64(id, _) => {
814                                im.draw(
815                                    &textures[id as usize],
816                                    &c.draw_state,
817                                    transform.trans(pos[0], pos[1]), g
818                                );
819                            }
820                            Variable::RustObject(obj) => {
821                                let guard = obj.lock().map_err(|_| CNOLOM.to_string())?;
822                                let texture: &G::Texture = guard.downcast_ref()
823                                    .ok_or_else(|| EXPECTED_TEXTURE.to_string())?;
824                                im.draw(
825                                    texture,
826                                    &c.draw_state,
827                                    transform.trans(pos[0], pos[1]), g
828                                );
829                            }
830                            _ => return Err(EXPECTED_IMAGE_ID_OR_OBJECT.to_string()),
831                        }
832                    }
833                    "draw_state_alpha" => {
834                        c.draw_state = DrawState::new_alpha();
835                    }
836                    "draw_state_clip" => {
837                        c.draw_state = DrawState::new_clip();
838                    }
839                    "draw_state_increment" => {
840                        c.draw_state = DrawState::new_increment();
841                    }
842                    "draw_state_inside" => {
843                        c.draw_state = DrawState::new_inside();
844                    }
845                    "draw_state_outside" => {
846                        c.draw_state = DrawState::new_outside();
847                    }
848                    "blend_alpha" => {
849                        c.draw_state.blend = Some(Blend::Alpha);
850                    }
851                    "blend_add" => {
852                        c.draw_state.blend = Some(Blend::Add);
853                    }
854                    "blend_lighter" => {
855                        c.draw_state.blend = Some(Blend::Lighter);
856                    }
857                    "blend_multiply" => {
858                        c.draw_state.blend = Some(Blend::Multiply);
859                    }
860                    "blend_invert" => {
861                        c.draw_state.blend = Some(Blend::Invert);
862                    }
863                    "scissor__corner_size" => {
864                        let corner: [f64; 2] = rt.var_vec4(&it[1])?;
865                        let size: [f64; 2] = rt.var_vec4(&it[2])?;
866                        c.draw_state.scissor = Some([
867                            corner[0] as u32,
868                            corner[1] as u32,
869                            size[0] as u32,
870                            size[1] as u32
871                        ]);
872                    }
873                    "stencil__clip" => {
874                        let v: f64 = rt.var(&it[1])?;
875                        c.draw_state.stencil = Some(Stencil::Clip(v as u8));
876                    }
877                    "stencil__inside" => {
878                        let v: f64 = rt.var(&it[1])?;
879                        c.draw_state.stencil = Some(Stencil::Inside(v as u8));
880                    }
881                    "stencil__outside" => {
882                        let v: f64 = rt.var(&it[1])?;
883                        c.draw_state.stencil = Some(Stencil::Outside(v as u8));
884                    }
885                    "stencil_increment" => {
886                        c.draw_state.stencil = Some(Stencil::Increment);
887                    }
888                    _ => {}
889                }
890            }
891        }
892    }
893    return Ok(())
894}