Last active
December 21, 2015 06:28
-
-
Save luqmana/6264106 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern mod sdl; | |
use std::libc::{c_int, c_void}; | |
use std::rt::comm; | |
use std::rt::io::extensions::*; | |
use std::rt::io::io_error; | |
use std::rt::io::net::ip::{IpAddr, Ipv4Addr, Port, SocketAddr}; | |
use std::rt::io::net::tcp::TcpStream; | |
use std::task; | |
use std::vec; | |
static DEFAULT_RJ_IP: IpAddr = Ipv4Addr(127, 0, 0, 1); | |
static DEFAULT_RJ_PORT: Port = 10004; | |
static JOY_MAGIC: u32 = 0x909ACCEF; | |
struct JoyHeader { | |
magic: u32, // JOY_MAGIC | |
mode: i32, // Image mode (0-3) | |
size: u32, // Size of payload | |
vcount: u32 // sceDisplayGetVcount | |
} | |
struct ScreenBuffer { | |
head: JoyHeader, | |
surface: ~sdl::video::Surface, | |
pixels: ~[u8], | |
width: uint, | |
height: uint | |
} | |
fn write_joyevent(wr: &mut TcpStream, t: i32, v: u32) { | |
// Write the magic | |
wr.write_le_u32(JOY_MAGIC); | |
// Next the event kind | |
wr.write_le_i32(t); | |
// And finally the value | |
wr.write_le_u32(v); | |
} | |
// Takes a TcpStream and tries to read in | |
// and populate a `JoyHeader`. | |
fn read_head(rdr: &mut TcpStream) -> JoyHeader { | |
let head = JoyHeader { | |
magic: (*rdr).read_le_u32(), | |
mode: (*rdr).read_le_i32(), | |
size: (*rdr).read_le_u32(), | |
vcount: (*rdr).read_le_u32() | |
}; | |
assert_eq!(head.magic, JOY_MAGIC); | |
head | |
} | |
// Connects to the RemoteJoy API endpoint | |
// and continuously reads in frames | |
// which it sends back through the given | |
// chan, `c`. | |
fn remote_joy(c: comm::Chan<ScreenBuffer>) { | |
let addr = SocketAddr { | |
ip: DEFAULT_RJ_IP, | |
port: DEFAULT_RJ_PORT | |
}; | |
// Connect | |
let mut sock = do io_error::cond.trap(|_| { | |
fail!("Unable to connect to %s.", addr.to_str()); | |
}).inside { | |
TcpStream::connect(addr).unwrap() | |
}; | |
// Now just perpetually read everything in! | |
loop { | |
let head = read_head(&mut sock); | |
if head.mode < 0 { | |
// Enable Screen | |
write_joyevent(&mut sock, 5, 1); | |
} else if head.mode > 3 { | |
// Something about flushing here | |
} else { | |
// Read in the next screen frame | |
let screen = sock.read_bytes(head.size as uint); | |
let width = 480u; | |
let height = 272u; | |
let (bpp, rmask, gmask, bmask) = match head.mode { | |
3 => (32, 0xFF, 0xFF00, 0xFF0000), | |
2 => (16, 0xF, 0xF0, 0xF00), | |
1 => (16, 0x1F, 0x1F << 5, 0x1F << 10), | |
0 => (16, 0x1F, 0x3F << 5, 0x1F << 11), | |
_ => fail!("Invalid mode.") | |
}; | |
// Create the SDL surface | |
let pixels = vec::raw::to_ptr(screen) as *c_void; | |
let raw = unsafe { | |
sdl::video::ll::SDL_CreateRGBSurfaceFrom( | |
pixels, width as c_int, height as c_int, | |
bpp as i32, (width * (bpp / 8)) as i32, | |
rmask, gmask, bmask, 0) | |
}; | |
let s = ScreenBuffer { | |
head: head, | |
surface: ~sdl::video::Surface { | |
raw: raw, | |
owned: true | |
}, | |
pixels: screen, | |
width: width, | |
height: height | |
}; | |
// Now send it off | |
c.send(s); | |
} | |
} | |
} | |
#[start] | |
fn start(argc: int, argv: **u8, crate_map: *u8) -> int { | |
std::rt::start_on_main_thread(argc, argv, crate_map, main) | |
} | |
fn main() { | |
do sdl::start { | |
// Init SDL | |
sdl::init([sdl::InitVideo]); | |
sdl::wm::set_caption("RemoteJoy", "RemoteJoy"); | |
// Now let's set up a surface to render to | |
let screen = match sdl::video::set_video_mode(480, 272, 32, | |
[sdl::video::HWSurface], | |
[sdl::video::DoubleBuf]) { | |
Ok(screen) => screen, | |
Err(e) => fail!("Unabled to set video mode: %s", e) | |
}; | |
// Let's create a chan/port pair to | |
// communicate with the net task | |
let (nport, nchan) = comm::stream(); | |
// Start the remote joy net task and give it its chan | |
let mut net_task = task::task(); | |
net_task.sched_mode(task::SingleThreaded); | |
net_task.spawn_with(nchan, remote_joy); | |
// Start the main loop! | |
'main: loop { | |
// And our event loop | |
'event: loop { | |
match sdl::event::poll_event() { | |
sdl::event::QuitEvent => break 'main, | |
sdl::event::NoEvent => break 'event, | |
sdl::event::KeyEvent(k, _, _, _) | |
if k == sdl::event::EscapeKey | |
=> break 'main, | |
_ => {} | |
} | |
} | |
// Anything from the net task? | |
if nport.peek() { | |
// Render the new frame | |
let frame = nport.recv(); | |
screen.blit(frame.surface); | |
} | |
screen.flip(); | |
} | |
sdl::quit(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment