Browse Source

Add first simple triable animation based on fractionals

master
Georg Hopp 6 years ago
parent
commit
f06b625998
Signed by: ghopp GPG Key ID: 4C5D226768784538
  1. 4
      fractional/Cargo.toml
  2. 10
      fractional/src/easel.rs
  3. 1
      fractional/src/lib.rs
  4. 56
      fractional/src/main.rs
  5. 232
      fractional/src/xcb.rs

4
fractional/Cargo.toml

@ -6,3 +6,7 @@ edition = "2018"
[dependencies]
lazy_static = "1.4.0"
libc = "0.2"
gl = "0.5.2"
x11 = { version = "2.3", features = ["glx"] }
xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] }

10
fractional/src/easel.rs

@ -20,13 +20,19 @@
//
use std::cmp;
use std::fmt::{Formatter, Display, Result};
use std::sync::mpsc;
pub trait Easel {
fn canvas(self) -> dyn Canvas;
//fn canvas(&mut self, width :u16, height :u16) -> Option<&dyn Canvas>;
}
pub trait Canvas {
fn draw(self, c :&dyn Drawable, ofs :Coordinate);
fn init_events(&self);
fn start_events(&self, tx :mpsc::Sender<i32>);
fn clear(&mut self);
fn draw(&mut self, c :&dyn Drawable, ofs :Coordinate);
fn show(&self);
}
pub trait Drawable {

1
fractional/src/lib.rs

@ -28,6 +28,7 @@ pub mod fractional;
pub mod transform;
pub mod trigonometry;
pub mod vector;
pub mod xcb;
use fractional::Fractional;
use vector::Vector;

56
fractional/src/main.rs

@ -23,6 +23,9 @@ use std::f64::consts::PI as FPI;
use std::fmt::Display;
use std::num::TryFromIntError;
use std::ops::{Add,Sub,Neg,Mul,Div};
use std::sync::mpsc;
use std::time;
use std::thread;
use fractional::continuous::Continuous;
use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline
@ -32,6 +35,9 @@ use fractional::trigonometry::Trig;
use fractional::vector::{Vector};
use fractional::transform::{TMatrix, translate, rotate_x, rotate_y, rotate_z, rotate_v};
use fractional::xcb::XcbEasel;
use fractional::easel::Canvas;
fn mean(v: &Vec<i64>) -> Result<Fractional, TryFromIntError> {
let r = v.iter().fold(0, |acc, x| acc + x);
let l = i64::try_from(v.len())?;
@ -325,4 +331,54 @@ fn main() {
_transform2();
println!();
_line();
let xcb = XcbEasel::new().unwrap();
let mut canvas = xcb.canvas(151, 151).unwrap();
canvas.set_title("Something...");
canvas.init_events();
let (tx, rx) = mpsc::channel();
let tx1 = mpsc::Sender::clone(&tx);
canvas.start_events(tx);
let i = Vector(Fractional( 0,1), Fractional(-35,1), Fractional(0,1));
let j = Vector(Fractional( 30,1), Fractional( 17,1), Fractional(0,1));
let k = Vector(Fractional(-30,1), Fractional( 17,1), Fractional(0,1));
fn to_i32(x :Fractional) -> i32 {
let Fractional(n, d) = x;
(n / d + if (n % d).abs() < (n / 2).abs() { 0 } else { 1 }) as i32
}
thread::spawn(move || {
loop {
tx1.send(0).unwrap();
thread::sleep(time::Duration::from_millis(10));
}
});
let mut deg :i32 = 0;
for x in rx {
match x {
1 => break,
_ => {
let rot :TMatrix<Fractional> = rotate_z(deg);
let Vector(ix, iy, _) = rot.apply(&i);
let Vector(jx, jy, _) = rot.apply(&j);
let Vector(kx, ky, _) = rot.apply(&k);
let pg = Polygon(
Coordinates(vec!( Coordinate(to_i32(ix), to_i32(iy))
, Coordinate(to_i32(jx), to_i32(jy))
, Coordinate(to_i32(kx), to_i32(ky)) )));
canvas.clear();
canvas.draw(&pg, Coordinate(75,75));
canvas.show();
deg = (deg + 3) % 359;
},
}
}
}

232
fractional/src/xcb.rs

@ -0,0 +1,232 @@
//
// XCB implementation for drawing some stuff...
//
// Georg Hopp <georg@steffers.org>
//
// Copyright © 2019 Georg Hopp
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
extern crate xcb;
use std::sync::Arc;
use std::ptr; //::{null, null_mut};
use std::thread;
use std::sync::mpsc;
use crate::easel::{Easel, Canvas, Drawable, Coordinate, Coordinates};
#[derive(Clone)]
pub struct XcbEasel (Arc<xcb::Connection>, i32);
pub struct XcbCanvas<'a> { conn :Arc<xcb::Connection>
, width :u16
, height :u16
, window :u32
, pixmap :u32
, gc :u32
, shm :&'a mut [u32] }
impl XcbEasel {
pub fn new() -> Result<XcbEasel, xcb::ConnError> {
let (conn, num) = xcb::Connection::connect(None)?;
Ok(XcbEasel(Arc::new(conn), num))
}
pub fn setup(&self) -> xcb::Setup {
let XcbEasel(conn, _) = self;
conn.get_setup()
}
pub fn screen(&self) -> Option<xcb::Screen> {
let XcbEasel(_, num) = self;
self.setup().roots().nth(*num as usize)
}
pub fn canvas(&self, width :u16, height :u16) -> Option<XcbCanvas> {
let Self(conn, _) = self;
let conn = conn.clone();
let screen = match self.screen() {
None => return None,
Some(screen) => screen,
};
let shmseg = conn.generate_id();
let gc = conn.generate_id();
let pixmap = conn.generate_id();
let window = conn.generate_id();
xcb::create_window( &conn, xcb::COPY_FROM_PARENT as u8, window
, screen.root(), 0, 0, width, width, 0
, xcb::WINDOW_CLASS_INPUT_OUTPUT as u16
, screen.root_visual()
, &[(xcb::CW_BACK_PIXEL, screen.white_pixel())] );
xcb::create_gc( &conn, gc, screen.root()
, &[ (xcb::GC_FOREGROUND, screen.black_pixel())
, (xcb::GC_GRAPHICS_EXPOSURES, 0) ] );
let (shmid, shm) = getshm((width * height) as usize);
xcb::shm::attach(&conn, shmseg, shmid as u32, false);
unsafe { libc::shmctl(shmid, libc::IPC_RMID, ptr::null_mut()); }
xcb::shm::create_pixmap( &conn, pixmap, window, width, height
, screen.root_depth(), shmseg, 0 );
xcb::map_window(&conn, window);
conn.flush();
Some(XcbCanvas{ conn: conn
, width: width
, height: height
, window: window
, pixmap: pixmap
, gc: gc
, shm: shm } )
}
}
impl<'a> XcbCanvas<'a> {
pub fn set_title(&self, title :&str) {
let c = xcb::change_property_checked( &self.conn
, xcb::PROP_MODE_REPLACE as u8
, self.window
, xcb::ATOM_WM_NAME
, xcb::ATOM_STRING
, 8
, title.as_bytes() );
if self.conn.has_error().is_err() || c.request_check().is_err() {
println!("Error setting title");
}
}
}
fn getshm<'a>(size :usize) -> (i32, &'a mut [u32]) {
use std::slice::from_raw_parts_mut;
unsafe {
let id = libc::shmget( libc::IPC_PRIVATE
, size * 4
, libc::IPC_CREAT | 0o744 );
let ptr = libc::shmat(id, ptr::null(), 0);
(id as i32, from_raw_parts_mut(ptr as *mut u32, size))
}
}
impl Easel for XcbEasel {}
impl<'a> Canvas for XcbCanvas<'a> {
fn init_events(&self) {
let mask = [( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE
| xcb::EVENT_MASK_KEY_PRESS
| xcb::EVENT_MASK_STRUCTURE_NOTIFY
| xcb::EVENT_MASK_PROPERTY_CHANGE )];
xcb::change_window_attributes(&self.conn, self.window, &mask);
self.conn.flush();
}
fn start_events(&self, tx :mpsc::Sender<i32>) {
let conn = self.conn.clone();
let window = self.window;
let pixmap = self.pixmap;
let gc = self.gc;
let width = self.width;
let height = self.height;
thread::spawn(move || {
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::copy_area( &conn, pixmap, window, gc
, 0, 0, 0, 0
, width, height );
conn.flush();
},
xcb::KEY_PRESS => {
let key_press: &xcb::KeyPressEvent
= unsafe { xcb::cast_event(&event) };
println!( "Key '{}' pressed"
, key_press.detail() );
// Q (on qwerty)
if key_press.detail() == 0x18 {
tx.send(1).unwrap();
break;
}
},
_ => {},
}
},
}
}
});
}
fn clear(&mut self) {
unsafe {
let ptr = self.shm.as_mut_ptr();
ptr::write_bytes( ptr, 0
, self.width as usize * self.height as usize);
}
}
fn draw(&mut self, d :&dyn Drawable, ofs :Coordinate) {
let Coordinates(c) = d.plot();
let Coordinate(xofs, yofs) = ofs;
for Coordinate(x, y) in c {
let idx :usize = ((y+yofs)*(self.width as i32)+x+xofs) as usize;
self.shm[idx] = 0xFFFFFF;
}
}
fn show(&self) {
xcb::copy_area( &self.conn, self.pixmap, self.window, self.gc
, 0, 0, 0, 0
, self.width, self.height );
self.conn.flush();
}
}
Loading…
Cancel
Save