Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
boytacean
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
João Magalhães
boytacean
Commits
5c0d48e7
Verified
Commit
5c0d48e7
authored
2 years ago
by
João Magalhães
Browse files
Options
Downloads
Patches
Plain Diff
feat: initial tentative support for GB drawing
parent
96aa6366
No related branches found
No related tags found
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
README.md
+1
-1
1 addition, 1 deletion
README.md
examples/sdl/src/main.rs
+101
-7
101 additions, 7 deletions
examples/sdl/src/main.rs
src/gb.rs
+4
-0
4 additions, 0 deletions
src/gb.rs
src/ppu.rs
+17
-18
17 additions, 18 deletions
src/ppu.rs
with
123 additions
and
26 deletions
README.md
+
1
−
1
View file @
5c0d48e7
# Boytac
i
an
# Boytac
e
an
A Game Boy emulator that is written in Rust 🦀.
...
...
This diff is collapsed.
Click to expand it.
examples/sdl/src/main.rs
+
101
−
7
View file @
5c0d48e7
use
boytacean
::
gb
::
GameBoy
;
use
boytacean
::{
gb
::
GameBoy
,
ppu
::{
DISPLAY_WIDTH
,
DISPLAY_HEIGHT
}};
use
sdl2
::{
video
::
Window
,
pixels
::
PixelFormatEnum
,
VideoSubsystem
,
TimerSubsystem
,
EventPump
};
/// The base title to be used in the window.
static
TITLE
:
&
'static
str
=
"Boytacean"
;
pub
struct
Graphics
{
window
:
Window
,
video_subsystem
:
VideoSubsystem
,
timer_subsystem
:
TimerSubsystem
,
event_pump
:
EventPump
,
}
fn
start_sdl
()
->
Graphics
{
// initializes the SDL sub-system, making it ready to be
// used for display of graphics and audio
let
sdl
=
sdl2
::
init
()
.unwrap
();
let
video_subsystem
=
sdl
.video
()
.unwrap
();
let
timer_subsystem
=
sdl
.timer
()
.unwrap
();
let
audio_subsystem
=
sdl
.audio
()
.unwrap
();
let
event_pump
=
sdl
.event_pump
()
.unwrap
();
// initialized the fonts context to be used
// in the loading of fonts
let
ttf_context
=
sdl2
::
ttf
::
init
()
.unwrap
();
// creates the system window that is going to be used to
// show the emulator and sets it to the central are o screen
let
mut
window
=
video_subsystem
.window
(
TITLE
,
2
as
u32
*
DISPLAY_WIDTH
as
u32
,
//@todo check screen scale
2
as
u32
*
DISPLAY_HEIGHT
as
u32
,
//@todo check screen scale
)
.resizable
()
.position_centered
()
.opengl
()
.build
()
.unwrap
();
Graphics
{
window
:
window
,
video_subsystem
:
video_subsystem
,
timer_subsystem
:
timer_subsystem
,
event_pump
:
event_pump
}
}
fn
main
()
{
let
mut
graphics
=
start_sdl
();
let
mut
canvas
=
graphics
.window
.into_canvas
()
.accelerated
()
.build
()
.unwrap
();
canvas
.clear
();
canvas
.present
();
let
texture_creator
=
canvas
.texture_creator
();
// creates the texture streaming that is going to be used
// as the target for the pixel buffer
let
mut
texture
=
texture_creator
.create_texture_streaming
(
PixelFormatEnum
::
RGB24
,
DISPLAY_WIDTH
as
u32
,
DISPLAY_HEIGHT
as
u32
,
)
.unwrap
();
let
mut
game_boy
=
GameBoy
::
new
();
game_boy
.load_boot_default
();
for
i
in
0
..
37000
{
// runs the Game Boy clock, this operations should
// include the advance of both the CPU and the PPU
game_boy
.clock
();
let
mut
counter
=
0
;
if
game_boy
.cpu
()
.pc
()
>=
0x6032
{
println!
(
"{}"
,
i
);
'main
:
loop
{
if
counter
>=
7000000
{
break
;
}
while
let
Some
(
event
)
=
graphics
.event_pump
.poll_event
()
{
}
let
mut
counter_ticks
=
0u32
;
loop
{
// limits the number of ticks to the typical number
// of ticks required to do a complete PPU draw
if
counter_ticks
>=
70224
{
break
;
}
// runs the Game Boy clock, this operations should
// include the advance of both the CPU and the PPU
counter_ticks
+=
game_boy
.clock
()
as
u32
;
}
counter
+=
counter_ticks
;
let
frame_buffer
=
game_boy
.frame_buffer
()
.as_ref
();
texture
.update
(
None
,
frame_buffer
,
DISPLAY_WIDTH
as
usize
*
3
)
.unwrap
();
canvas
.copy
(
&
texture
,
None
,
None
)
.unwrap
();
// presents the canvas effectively updating the screen
// information presented to the user
canvas
.present
();
graphics
.timer_subsystem
.delay
(
17
);
}
//println!("{:?}", game_boy.frame_buffer().as_ref());
}
This diff is collapsed.
Click to expand it.
src/gb.rs
+
4
−
0
View file @
5c0d48e7
...
...
@@ -38,6 +38,10 @@ impl GameBoy {
self
.cpu
.ppu
()
}
pub
fn
frame_buffer
(
&
mut
self
)
->
&
Box
<
[
u8
;
73920
]
>
{
&
(
self
.ppu
()
.frame_buffer
)
}
pub
fn
load_boot
(
&
mut
self
,
path
:
&
str
)
{
let
data
=
read_file
(
path
);
self
.cpu
.mmu
()
.write_boot
(
0x0000
,
&
data
);
...
...
This diff is collapsed.
Click to expand it.
src/ppu.rs
+
17
−
18
View file @
5c0d48e7
pub
const
VRAM_SIZE
:
usize
=
8192
;
pub
const
HRAM_SIZE
:
usize
=
128
;
pub
const
PALETTE_SIZE
:
usize
=
4
;
pub
const
RGB
A
_SIZE
:
usize
=
4
;
pub
const
RGB_SIZE
:
usize
=
3
;
/// The number of tiles that can be store in Game Boy's
/// VRAM memory according to specifications.
pub
const
TILE_COUNT
:
usize
=
384
;
/// The width of the Game Boy screen in pixels.
pub
const
SCREEN
_WIDTH
:
usize
=
160
;
pub
const
DISPLAY
_WIDTH
:
usize
=
160
;
/// The height of the Game Boy screen in pixels.
pub
const
SCREEN
_HEIGHT
:
usize
=
154
;
pub
const
DISPLAY
_HEIGHT
:
usize
=
154
;
/// Represents the Game Boy PPU (Pixel Processing Unit) and controls
/// all of the logic behind the graphics processing and presentation.
/// Should store both the VRAM and HRAM together with the internal
/// graphic related registers.
/// Outputs the screen as a RGB
A
8 bit frame buffer.
/// Outputs the screen as a RGB 8 bit frame buffer.
///
/// # Basic usage
/// ```rust
...
...
@@ -25,9 +25,9 @@ pub const SCREEN_HEIGHT: usize = 154;
/// ppu.tick();
/// ```
pub
struct
Ppu
{
/// The 8 bit based RGB
A
frame buffer with the
/// The 8 bit based RGB frame buffer with the
/// processed set of pixels ready to be displayed on screen.
pub
frame_buffer
:
Box
<
[
u8
;
SCREEN
_WIDTH
*
SCREEN
_HEIGHT
*
RGB
A
_SIZE
]
>
,
pub
frame_buffer
:
Box
<
[
u8
;
DISPLAY
_WIDTH
*
DISPLAY
_HEIGHT
*
RGB_SIZE
]
>
,
/// Video dedicated memory (VRAM) where both the tiles and
/// the sprites are going to be stored.
pub
vram
:
[
u8
;
VRAM_SIZE
],
...
...
@@ -38,7 +38,7 @@ pub struct Ppu {
/// PPU related structures.
tiles
:
[[[
u8
;
8
];
8
];
TILE_COUNT
],
/// The palette of colors that is currently loaded in Game Boy.
palette
:
[[
u8
;
RGB
A
_SIZE
];
PALETTE_SIZE
],
palette
:
[[
u8
;
RGB_SIZE
];
PALETTE_SIZE
],
/// The scroll Y register that controls the Y offset
/// of the background.
scy
:
u8
,
...
...
@@ -71,11 +71,11 @@ pub enum PpuMode {
impl
Ppu
{
pub
fn
new
()
->
Ppu
{
Ppu
{
frame_buffer
:
Box
::
new
([
0u8
;
SCREEN
_WIDTH
*
SCREEN
_HEIGHT
*
RGB
A
_SIZE
]),
frame_buffer
:
Box
::
new
([
0u8
;
DISPLAY
_WIDTH
*
DISPLAY
_HEIGHT
*
RGB_SIZE
]),
vram
:
[
0u8
;
VRAM_SIZE
],
hram
:
[
0u8
;
HRAM_SIZE
],
tiles
:
[[[
0u8
;
8
];
8
];
TILE_COUNT
],
palette
:
[[
0u8
;
RGB
A
_SIZE
];
PALETTE_SIZE
],
palette
:
[[
0u8
;
RGB_SIZE
];
PALETTE_SIZE
],
scy
:
0x0
,
scx
:
0x0
,
line
:
0x0
,
...
...
@@ -168,10 +168,10 @@ impl Ppu {
0x0047
=>
{
for
index
in
0
..
PALETTE_SIZE
{
match
(
value
>>
(
index
*
2
))
&
3
{
0
=>
self
.palette
[
index
]
=
[
255
,
255
,
255
,
255
],
1
=>
self
.palette
[
index
]
=
[
192
,
192
,
192
,
255
],
2
=>
self
.palette
[
index
]
=
[
96
,
96
,
96
,
255
],
3
=>
self
.palette
[
index
]
=
[
0
,
0
,
0
,
255
],
0
=>
self
.palette
[
index
]
=
[
255
,
255
,
255
],
1
=>
self
.palette
[
index
]
=
[
192
,
192
,
192
],
2
=>
self
.palette
[
index
]
=
[
96
,
96
,
96
],
3
=>
self
.palette
[
index
]
=
[
0
,
0
,
0
],
color_index
=>
panic!
(
"Invalid palette color index {:04x}"
,
color_index
),
}
}
...
...
@@ -225,10 +225,10 @@ impl Ppu {
}
// calculates the frame buffer offset position assuming the proper
// Game Boy screen width and RGB
A
pixel (
4
bytes) size
let
mut
frame_offset
=
self
.line
as
usize
*
SCREEN
_WIDTH
*
RGB
A
_SIZE
;
// Game Boy screen width and RGB pixel (
3
bytes) size
let
mut
frame_offset
=
self
.line
as
usize
*
DISPLAY
_WIDTH
*
RGB_SIZE
;
for
_index
in
0
..
SCREEN
_WIDTH
{
for
_index
in
0
..
DISPLAY
_WIDTH
{
// in case the end of tile width has been reached then
// a new tile must be retrieved for plotting
if
x
==
8
{
...
...
@@ -257,9 +257,8 @@ impl Ppu {
self
.frame_buffer
[
frame_offset
]
=
color
[
0
];
self
.frame_buffer
[
frame_offset
+
1
]
=
color
[
1
];
self
.frame_buffer
[
frame_offset
+
2
]
=
color
[
2
];
self
.frame_buffer
[
frame_offset
+
3
]
=
color
[
3
];
frame_offset
+=
RGB
A
_SIZE
;
frame_offset
+=
RGB_SIZE
;
// increments the current tile X position in drawing
x
+=
1
;
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment