A 3D math playground visualizing on a canvas trait which the user needs to implement e.g. using XCB or a HTML5 Canvas for drawing as WebAssembly application. (Both exists in separate projects.)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
7.4 KiB

extern crate xcb;
use std::iter::{Iterator};
use std::{thread, time};
use std::sync::Arc;
use std::ptr::{null, null_mut};
use std::slice::from_raw_parts_mut;
pub fn getshm<'a>(size :usize) -> (i32, &'a mut [u32]) {
unsafe {
let id = libc::shmget( libc::IPC_PRIVATE
, size * 4
, libc::IPC_CREAT | 0o744 );
let ptr = libc::shmat(id, null(), 0);
(id as i32, from_raw_parts_mut(ptr as *mut u32, size))
}
}
fn main() {
let points: &[xcb::Point] = &[ xcb::Point::new(10, 10)
, xcb::Point::new(10, 20)
, xcb::Point::new(20, 10)
, xcb::Point::new(20, 20) ];
let polyline: &[xcb::Point] = &[ xcb::Point::new(50, 10 )
// rest of points are relative
, xcb::Point::new( 5, 20 )
, xcb::Point::new(25, -20)
, xcb::Point::new(10, 10 ) ];
let segments: &[xcb::Segment] = &[ xcb::Segment::new(100, 10, 140, 30)
, xcb::Segment::new(110, 25, 130, 60) ];
let rectangles: &[xcb::Rectangle]
= &[ xcb::Rectangle::new(10, 50, 40, 20)
, xcb::Rectangle::new(80, 50, 10, 40) ];
let arcs: &[xcb::Arc] = &[ xcb::Arc::new(10, 100, 60, 40, 0, 90 << 6)
, xcb::Arc::new(90, 100, 55, 40, 0, 270 << 6) ];
let (conn, screen_num) = {
let (conn, screen_num) = xcb::Connection::connect(None).unwrap();
(Arc::new(conn), screen_num)
};
let setup = conn.get_setup();
let screen = setup.roots().nth(screen_num as usize).unwrap();
let (shmid, shm) = getshm(150 * 150);
let shmseg = conn.generate_id();
xcb::shm::attach(&conn, shmseg, shmid as u32, false);
unsafe { libc::shmctl(shmid, libc::IPC_RMID, null_mut()); }
let foreground = conn.generate_id();
let pix = conn.generate_id();
xcb::create_gc( &conn
, foreground
, screen.root()
, &[ (xcb::GC_FOREGROUND, screen.black_pixel())
, (xcb::GC_GRAPHICS_EXPOSURES, 0) ] );
let window = conn.generate_id();
let values = [ ( xcb::CW_BACK_PIXEL, screen.white_pixel() )
, ( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE
| xcb::EVENT_MASK_KEY_PRESS
| xcb::EVENT_MASK_STRUCTURE_NOTIFY
| xcb::EVENT_MASK_PROPERTY_CHANGE ) ];
xcb::create_window( &conn
, xcb::COPY_FROM_PARENT as u8
, window
, screen.root()
, 0, 0, 150, 150, 0
, xcb::WINDOW_CLASS_INPUT_OUTPUT as u16
, screen.root_visual()
, &values);
xcb::shm::create_pixmap( &conn
, pix
, window
, 150, 150
, screen.root_depth()
, shmseg
, 0 );
xcb::map_window(&conn, window);
{
let conn = conn.clone();
thread::spawn(move || {
let mut blink = false;
let mut i = 0;
loop {
let title = if blink {
"Basic Threaded Window ;-)"
} else {
"Basic Threaded Window :-)"
};
shm[i] = 0xFFFFFF;
i = (i + 1) % (150 * 150);
let c = xcb::change_property_checked(
&conn
, xcb::PROP_MODE_REPLACE as u8
, window
, xcb::ATOM_WM_NAME
, xcb::ATOM_STRING
, 8
, title.as_bytes() );
xcb::copy_area( &conn
, pix
, window
, foreground
, 0, 0, 0, 0
, 150, 150);
if conn.has_error().is_err() || c.request_check().is_err() {
break;
}
blink = !blink;
thread::sleep(time::Duration::from_millis(500));
}
});
}
conn.flush();
loop {
let event = conn.wait_for_event();
match event {
None => break,
Some(event) => {
match event.response_type() & !0x80 {
xcb::PROPERTY_NOTIFY => {
let prop_notify: &xcb::PropertyNotifyEvent = unsafe {
xcb::cast_event(&event)
};
if prop_notify.atom() == xcb::ATOM_WM_NAME {
// retrieving title
let cookie = xcb::get_property( &conn
, false
, window
, xcb::ATOM_WM_NAME
, xcb::ATOM_STRING
, 0, 1024);
if let Ok(reply) = cookie.get_reply() {
let r = reply.value();
let r = std::str::from_utf8(r).unwrap();
println!( "title changed to \"{}\"", r);
}
}
},
xcb::EXPOSE => {
xcb::poly_point( &conn
, xcb::COORD_MODE_ORIGIN as u8
, window
, foreground
, &points );
xcb::poly_line( &conn
, xcb::COORD_MODE_PREVIOUS as u8
, window
, foreground
, &polyline );
xcb::poly_segment( &conn
, window
, foreground
, &segments );
xcb::poly_rectangle( &conn
, window
, foreground
, &rectangles );
xcb::poly_arc( &conn
, window
, foreground
, &arcs );
conn.flush();
},
xcb::KEY_PRESS => {
let key_press: &xcb::KeyPressEvent = unsafe {
xcb::cast_event(&event)
};
println!("Key '{}' pressed", key_press.detail());
if key_press.detail() == 0x18 { // Q (on qwerty)
break;
}
},
_ => {},
}
}
}
}
}