Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace glium with SDL2 #16

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
dist: trusty
sudo: required

language: rust

rust:
- nightly

before_install:
- sudo apt-get -qq update
- sudo apt-get install -y libsdl2-dev libsdl2-gfx-dev

notifications:
email: false
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ nom = "2.0.1"
num = "0.1.30"
gl = "0.6.1"
libc = "0.2.20"
glium = "0.16.0"

[dependencies.sdl2]
version = "0.28.0"
default-features = false
features = ["gfx"]
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# gba-roa
Game Boy Advance: Rusty Oxidation Action - The ROA Emulator

You need some SDL2. Follow these instructions: https://github.com/AngryLawyer/rust-sdl2
106 changes: 15 additions & 91 deletions src/display.rs
Original file line number Diff line number Diff line change
@@ -1,111 +1,35 @@
use interconnect::InterconnectWrite;
use glium::{self, DisplayBuild, Frame, Surface};
use glium::texture::RawImage2d;
use glium::texture::ClientFormat;
use utils::gba_to_display_format;
use utils::B5G5R5_to_B8G8R8;
use sdl2::gfx::primitives::DrawRenderer;
use sdl2::render::Renderer;

pub struct Display {
pub display: glium::backend::glutin_backend::GlutinFacade,
pub program: glium::Program,
pub buf: [u16; 240 * 160],
}

#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 2],
}

implement_vertex!(Vertex, position);

impl Display {
pub fn new() -> Self {
let display = glium::glutin::WindowBuilder::new()
.with_dimensions(240 * 2, 160 * 2)
.with_title("Game Boy Advance: Rusty Oxidation Action - The ROA Emulator")
.build_glium()
.unwrap();

let width = 160;
let height = 240;

let vertex_shader_src = r#"
#version 140

in vec2 position;
out vec2 vuv;

void main() {
vuv = position;
gl_Position = vec4(position, 0.0, 1.0);
}
"#;

let fragment_shader_src = r#"
#version 140

in vec2 vuv;
out vec4 color;

uniform sampler2D tex;

void main() {
color = texture(tex, vuv / 2.0 + 0.5);
}
"#;

let program =
glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
.unwrap();

Display {
display: display,
program: program,
buf: [0b0000_0000_0000_0000u16; 240 * 160],
}
}

fn vsync(&self) {
let shape = vec![Vertex { position: [-1.0, -1.0] },
Vertex { position: [1.0, -1.0] },
Vertex { position: [-1.0, 1.0] },
Vertex { position: [-1.0, 1.0] },
Vertex { position: [1.0, -1.0] },
Vertex { position: [1.0, 1.0] }];

let vertex_buffer = glium::VertexBuffer::new(&self.display, &shape).unwrap();
let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

use std::borrow::Cow;
let image = glium::texture::RawImage2d {
data: Cow::from(&self.buf[..]),
width: 240,
height: 160,
format: ClientFormat::U5U5U5U1,
};

let texture = glium::texture::Texture2d::new(&self.display, image).unwrap();
let sampler = texture.sampled()
.magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest);
let uniforms = uniform! {
tex: sampler,
};

let mut target = self.display.draw();
target.clear_color(0.0, 0.0, 0.0, 1.0);
target.draw(&vertex_buffer,
&indices,
&self.program,
&uniforms,
&Default::default())
.unwrap();
target.finish().unwrap();

pub fn draw(&self, renderer: &mut Renderer) {
renderer.clear();
for x in 0..240 {
for y in 0..160 {
renderer.pixel(
x as i16,
y as i16,
B5G5R5_to_B8G8R8(self.buf[y * 160 + x] as u16));
}
}
renderer.present();
}
}

impl InterconnectWrite for Display {
fn write(&mut self, address: u32, word: u32) {
self.buf[address as usize] = gba_to_display_format(word as u16);
self.vsync();
self.buf[address as usize] = word as u16;
}
}
26 changes: 13 additions & 13 deletions src/gamepad.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use glium::glutin::{ElementState, VirtualKeyCode};
use interconnect::InterconnectRead;
use sdl2::keyboard::Keycode;

#[derive(Default, Debug)]
pub struct Gamepad {
Expand All @@ -16,18 +16,18 @@ pub struct Gamepad {
}

impl Gamepad {
pub fn update(&mut self, key_state: ElementState, virtual_key_code: VirtualKeyCode) {
match virtual_key_code {
VirtualKeyCode::W => self.up = key_state == ElementState::Pressed,
VirtualKeyCode::A => self.left = key_state == ElementState::Pressed,
VirtualKeyCode::S => self.down = key_state == ElementState::Pressed,
VirtualKeyCode::D => self.right = key_state == ElementState::Pressed,
VirtualKeyCode::J => self.a = key_state == ElementState::Pressed,
VirtualKeyCode::K => self.b = key_state == ElementState::Pressed,
VirtualKeyCode::U => self.left_bumper = key_state == ElementState::Pressed,
VirtualKeyCode::I => self.right_bumper = key_state == ElementState::Pressed,
VirtualKeyCode::Return => self.start = key_state == ElementState::Pressed,
VirtualKeyCode::P => self.select = key_state == ElementState::Pressed,
pub fn update(&mut self, pressed: bool, keycode: Keycode) {
match keycode {
Keycode::W => self.up = pressed,
Keycode::A => self.left = pressed,
Keycode::S => self.down = pressed,
Keycode::D => self.right = pressed,
Keycode::J => self.a = pressed,
Keycode::K => self.b = pressed,
Keycode::U => self.left_bumper = pressed,
Keycode::I => self.right_bumper = pressed,
Keycode::Return => self.start = pressed,
Keycode::P => self.select = pressed,
_ => (),
}
}
Expand Down
36 changes: 25 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ extern crate nom;
#[macro_use]
extern crate enum_primitive;

extern crate sdl2;

extern crate num;

#[macro_use]
extern crate glium;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

mod cpu;
mod display;
Expand All @@ -28,8 +30,6 @@ mod errors {
use errors::*;
quick_main!(run);

use glium::glutin::Event;
use glium::{DisplayBuild, Surface};
use interconnect::InterconnectWrite;

fn run() -> Result<()> {
Expand All @@ -48,17 +48,31 @@ fn run() -> Result<()> {
gba.interconnect.write(vram_base + 80 * 240 + 120, 0b0_00000_11111_00000);
gba.interconnect.write(vram_base + 80 * 240 + 125, 0b0_11111_00000_00000);

let sdl_context = sdl2::init().unwrap();
let video_subsys = sdl_context.video().unwrap();
let window = video_subsys.window(
"Game Boy Advance: Rusty Oxidation Action - The ROA Emulator", 240, 160)
.position_centered()
.opengl()
.build()
.unwrap();

let mut renderer = window.renderer().build().unwrap();
let mut events = sdl_context.event_pump().unwrap();

loop {
for ev in gba.interconnect.display.display.poll_events() {
match ev {
Event::KeyboardInput(key_state, _, Some(virtual_key_code)) => {
gba.interconnect.gamepad.update(key_state, virtual_key_code)
for event in events.poll_iter() {
match event {
Event::Quit {..} => break,
Event::KeyUp {keycode: Some(keycode), ..} => {
gba.interconnect.gamepad.update(true, keycode)
}
Event::KeyDown {keycode: Some(keycode), ..} => {
gba.interconnect.gamepad.update(false, keycode)
}
Event::Closed => return Ok(()),
_ => (),
}

println!("Keyboard state: {:?}", gba.interconnect.gamepad);
gba.interconnect.display.draw(&mut renderer);
}
}
}
23 changes: 8 additions & 15 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
pub fn gba_to_display_format(gba_format: u16) -> u16 {
(gba_format & 0b0_00000_00000_11111) << 11 | // Red
(gba_format & 0b0_00000_11111_00000) << 1 | // Green
(gba_format & 0b0_11111_00000_00000) >> 9 // Blue
}

#[cfg(test)]
mod tests {
use super::gba_to_display_format;

#[test]
fn test_display_format_conversion() {
let gba_format = 0b0_10001_11111_00000;
let display_format = 0b00000_11111_10001_0;

assert_eq!(gba_to_display_format(gba_format), display_format);
}
pub fn B5G5R5_to_B8G8R8(B5G5R5: u16) -> u32 {
let upscale: [u32; 32] = [0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107,
115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239,
247, 255];
upscale[(B5G5R5 & 0b0_00000_00000_11111) as usize] |
(upscale[((B5G5R5 & 0b0_00000_11111_00000) >> 5) as usize] << 8) |
(upscale[((B5G5R5 & 0b0_11111_00000_00000) >> 10) as usize] << 16) |
0xFF000000u32
}