-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 290a634
Showing
8 changed files
with
402 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.sav |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
all: prepare | ||
go install | ||
|
||
prepare: | ||
go mod tidy |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/djhworld/gomeboycolor/types" | ||
"github.com/djhworld/gomeboycolor/inputoutput" | ||
|
||
"github.com/go-gl/gl/v2.1/gl" | ||
"github.com/go-gl/glfw/v3.2/glfw" | ||
) | ||
|
||
var DefaultControlScheme inputoutput.ControlScheme = inputoutput.ControlScheme{ | ||
int(glfw.KeyUp), | ||
int(glfw.KeyDown), | ||
int(glfw.KeyLeft), | ||
int(glfw.KeyRight), | ||
int(glfw.KeyZ), | ||
int(glfw.KeyX), | ||
int(glfw.KeyA), | ||
int(glfw.KeyS), | ||
} | ||
|
||
// GlfwIO is for running the emulator using GLFW. | ||
// libglfw3 will be required on the system | ||
type GlfwIO struct { | ||
*inputoutput.CoreIO | ||
glfwDisplay *glfwDisplay | ||
} | ||
|
||
func NewGlfwIO(frameRateLock int64, headless bool, displayFps bool) *GlfwIO { | ||
log.Println("Creating GLFW based IO Handler") | ||
glfwDisplay := new(glfwDisplay) | ||
|
||
frameRateReporter := func(v float32) { | ||
if displayFps { | ||
log.Printf("Average frame rate\t%.2f\tfps", v) | ||
} | ||
} | ||
|
||
return &GlfwIO{ | ||
inputoutput.NewCoreIO(frameRateLock, headless, frameRateReporter, glfwDisplay), | ||
glfwDisplay, | ||
} | ||
} | ||
|
||
func (i *GlfwIO) Init(title string, screenSize int, onCloseHandler func()) error { | ||
var err error | ||
i.OnCloseHandler = onCloseHandler | ||
|
||
if !i.Headless { | ||
err = i.glfwDisplay.init(title, screenSize) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
i.glfwDisplay.window.SetCloseCallback(func(w *glfw.Window) { | ||
i.StopChannel <- 1 | ||
}) | ||
|
||
i.KeyHandler.Init(DefaultControlScheme) //TODO: allow user to define controlscheme | ||
|
||
i.glfwDisplay.window.SetKeyCallback(func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { | ||
if action == glfw.Repeat { | ||
i.KeyHandler.KeyDown(int(key)) | ||
return | ||
} | ||
|
||
if action == glfw.Press { | ||
i.KeyHandler.KeyDown(int(key)) | ||
} else { | ||
i.KeyHandler.KeyUp(int(key)) | ||
} | ||
}) | ||
} | ||
|
||
return err | ||
} | ||
|
||
type glfwDisplay struct { | ||
Name string | ||
ScreenSizeMultiplier int | ||
window *glfw.Window | ||
} | ||
|
||
func (s *glfwDisplay) init(title string, screenSizeMultiplier int) error { | ||
var err error | ||
|
||
if err := glfw.Init(); err != nil { | ||
log.Fatalln("failed to initialize glfw:", err) | ||
} | ||
|
||
s.Name = inputoutput.PREFIX + "-SCREEN" | ||
|
||
log.Printf("%s: Initialising display", s.Name) | ||
|
||
s.ScreenSizeMultiplier = screenSizeMultiplier | ||
log.Printf("%s: Set screen size multiplier to %dx", s.Name, s.ScreenSizeMultiplier) | ||
|
||
glfw.WindowHint(glfw.Resizable, glfw.False) | ||
window, err := glfw.CreateWindow(inputoutput.SCREEN_WIDTH*s.ScreenSizeMultiplier, inputoutput.SCREEN_HEIGHT*s.ScreenSizeMultiplier, "Testing", nil, nil) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
window.SetTitle(title) | ||
|
||
vidMode := glfw.GetPrimaryMonitor().GetVideoMode() | ||
|
||
window.SetPos(vidMode.Width/3, vidMode.Height/3) | ||
|
||
window.MakeContextCurrent() | ||
|
||
if err := gl.Init(); err != nil { | ||
return err | ||
} | ||
|
||
gl.ClearColor(0.255, 0.255, 0.255, 0) | ||
|
||
s.window = window | ||
|
||
return nil | ||
|
||
} | ||
|
||
func (s *glfwDisplay) Stop() { | ||
log.Println("Stopping display") | ||
s.window.Destroy() | ||
glfw.Terminate() | ||
} | ||
|
||
func (s *glfwDisplay) DrawFrame(screenData *types.Screen) { | ||
fw, fh := s.window.GetFramebufferSize() | ||
gl.Viewport(0, 0, int32(fw), int32(fh)) | ||
gl.MatrixMode(gl.PROJECTION) | ||
gl.LoadIdentity() | ||
gl.Ortho(0, float64(inputoutput.SCREEN_WIDTH*s.ScreenSizeMultiplier), float64(inputoutput.SCREEN_HEIGHT*s.ScreenSizeMultiplier), 0, -1, 1) | ||
gl.ClearColor(0.255, 0.255, 0.255, 0) | ||
gl.Clear(gl.COLOR_BUFFER_BIT) | ||
gl.MatrixMode(gl.MODELVIEW) | ||
gl.LoadIdentity() | ||
|
||
gl.Clear(gl.COLOR_BUFFER_BIT) | ||
gl.Disable(gl.DEPTH_TEST) | ||
gl.PointSize(float32(s.ScreenSizeMultiplier) * 2.0) | ||
gl.Begin(gl.POINTS) | ||
for y := 0; y < inputoutput.SCREEN_HEIGHT; y++ { | ||
for x := 0; x < inputoutput.SCREEN_WIDTH; x++ { | ||
var pixel types.RGB = screenData[y][x] | ||
gl.Color3ub(pixel.Red, pixel.Green, pixel.Blue) | ||
gl.Vertex2i(int32(x*s.ScreenSizeMultiplier), int32(y*s.ScreenSizeMultiplier)) | ||
} | ||
} | ||
|
||
gl.End() | ||
glfw.PollEvents() | ||
s.window.SwapBuffers() | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module github.com/djhworld/gomeboycolor-glfw | ||
|
||
require ( | ||
github.com/djhworld/gomeboycolor v0.0.0 | ||
github.com/go-gl/gl v0.0.0-20180407155706-68e253793080 | ||
github.com/go-gl/glfw v0.0.0-20180813204114-2484f3e51bc4 | ||
) | ||
|
||
replace github.com/djhworld/gomeboycolor => ../gomeboycolor |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/go-gl/gl v0.0.0-20180407155706-68e253793080 h1:pNxZva3052YM+z2p1aP08FgaTE2NzrRJZ5BHJCmKLzE= | ||
github.com/go-gl/gl v0.0.0-20180407155706-68e253793080/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= | ||
github.com/go-gl/glfw v0.0.0-20180813204114-2484f3e51bc4 h1:4gBr8toVw4vfazzm1MpqiTd7ODKRRevdMEDO2yNggOk= | ||
github.com/go-gl/glfw v0.0.0-20180813204114-2484f3e51bc4/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= | ||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= | ||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchrcom/testify v1.2.2 h1:R5L+N9NKlaO/Q0Dvq8kBEV/uRKEa/Mt2Wt2WNtMqKTw= | ||
github.com/stretchrcom/testify v1.2.2/go.mod h1:zUrQijuLcfRPyrWG6SBFjct9CuJZz2Ybtack4DGF2Jo= | ||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 h1:00VmoueYNlNz/aHIilyyQz/MHSqGoWJzpFv/HW8xpzI= | ||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"flag" | ||
"fmt" | ||
"log" | ||
"os" | ||
"os/user" | ||
"runtime" | ||
"strings" | ||
|
||
"github.com/djhworld/gomeboycolor/cartridge" | ||
"github.com/djhworld/gomeboycolor/config" | ||
"github.com/djhworld/gomeboycolor/gbc" | ||
"github.com/djhworld/gomeboycolor-glfw/saves" | ||
) | ||
|
||
const TITLE string = "gomeboycolor" | ||
|
||
var VERSION string | ||
|
||
const ( | ||
SKIP_BOOT_FLAG string = "skipboot" | ||
SCREEN_SIZE_FLAG = "size" | ||
SHOW_FPS_FLAG = "showfps" | ||
TITLE_FLAG = "title" | ||
DUMP_FLAG = "dump" | ||
DEBUGGER_ON_FLAG = "debug" | ||
BREAK_WHEN_FLAG = "b" | ||
COLOR_MODE_FLAG = "color" | ||
HELP_FLAG = "help" | ||
HEADLESS_FLAG = "headless" | ||
FRAME_RATE_LOCK_FLAG = "fpsLock" | ||
) | ||
|
||
var title *string = flag.String(TITLE_FLAG, TITLE, "Title to use") | ||
var showFps *bool = flag.Bool(SHOW_FPS_FLAG, false, "Calculate and display frames per second") | ||
var screenSizeMultiplier *int = flag.Int(SCREEN_SIZE_FLAG, 1, "Screen size multiplier") | ||
var skipBoot *bool = flag.Bool(SKIP_BOOT_FLAG, false, "Skip boot sequence") | ||
var colorMode *bool = flag.Bool(COLOR_MODE_FLAG, true, "Emulates Gameboy Color Hardware") | ||
var help *bool = flag.Bool(HELP_FLAG, false, "Show this help message") | ||
var headless *bool = flag.Bool(HEADLESS_FLAG, false, "Run emulator without output") | ||
var frameRatelock *int64 = flag.Int64(FRAME_RATE_LOCK_FLAG, 58, "Lock framerate to this. Going higher than default might be unstable!") | ||
|
||
//debug stuff... | ||
var dumpState *bool = flag.Bool(DUMP_FLAG, false, "Print state of machine after each cycle (WARNING - WILL RUN SLOW)") | ||
var debug *bool = flag.Bool(DEBUGGER_ON_FLAG, false, "Enable debugger") | ||
var breakOn *string = flag.String(BREAK_WHEN_FLAG, "0x0000", "Break into debugger when PC equals a given value between 0x0000 and 0xFFFF") | ||
|
||
func PrintHelp() { | ||
fmt.Println("\nUsage: -\n") | ||
fmt.Println("To launch the emulator, simply run and pass it the location of your ROM file, e.g. ") | ||
fmt.Println("\n\tgomeboycolor location/of/romfile.gbc\n") | ||
fmt.Println("Flags: -\n") | ||
fmt.Println(" -help -> Show this help message") | ||
fmt.Println(" -skipboot -> Disables the boot sequence and will boot you straight into the ROM you have provided. Defaults to false") | ||
fmt.Println(" -color -> Turns color GB features on. Defaults to true") | ||
fmt.Println(" -showfps -> Prints average frames per second to the console. Defaults to false") | ||
fmt.Println(" -dump -> Dump CPU state after every cycle. Will be very SLOW and resource intensive. Defaults to false") | ||
fmt.Println(" -size=(1-6) -> Set screen size. Defaults to 1.") | ||
fmt.Println(" -headless -> Runs emulator without output") | ||
fmt.Println(" -fpsLock -> Lock framerate to this. Going higher than default might be unstable!") | ||
fmt.Println(" -title=(title) -> Change window title. Defaults to 'gomeboycolor'.") | ||
fmt.Println("\nYou can pass an option argument to the boolean flags if you want to enable that particular option. e.g. to disable the boot screen you would do the following") | ||
fmt.Println("\n\tgomeboycolor -skipboot=false location/of/romfile.gbc\n") | ||
} | ||
|
||
func main() { | ||
runtime.GOMAXPROCS(runtime.NumCPU()) | ||
fmt.Printf("%s. %s\n", TITLE, VERSION) | ||
fmt.Println("Copyright (c) 2018. Daniel James Harper.") | ||
fmt.Println("http://djhworld.github.io/gomeboycolor") | ||
fmt.Println(strings.Repeat("*", 120)) | ||
|
||
flag.Usage = PrintHelp | ||
|
||
flag.Parse() | ||
|
||
if *help { | ||
PrintHelp() | ||
os.Exit(1) | ||
} | ||
|
||
if flag.NArg() != 1 { | ||
log.Fatalf("Please specify the location of a ROM to boot") | ||
return | ||
} | ||
|
||
//Parse and validate settings file (if found) | ||
conf := &config.Config{ | ||
Title: TITLE, | ||
ScreenSize: *screenSizeMultiplier, | ||
SkipBoot: *skipBoot, | ||
DisplayFPS: *showFps, | ||
ColorMode: *colorMode, | ||
Debug: *debug, | ||
BreakOn: *breakOn, | ||
DumpState: *dumpState, | ||
Headless: *headless, | ||
FrameRateLock: *frameRatelock, | ||
} | ||
fmt.Println(conf) | ||
|
||
cart, err := createCartridge(flag.Arg(0)) | ||
if err != nil { | ||
log.Println(err) | ||
return | ||
} | ||
|
||
log.Println("Starting emulator") | ||
|
||
emulator, err := gbc.Init(cart, getSaveStore(), conf, NewGlfwIO(conf.FrameRateLock, conf.Headless, conf.DisplayFPS)) | ||
if err != nil { | ||
log.Println(err) | ||
return | ||
} | ||
|
||
//Starts emulator code in a goroutine | ||
go emulator.Run() | ||
|
||
//lock the OS thread here | ||
runtime.LockOSThread() | ||
|
||
//set the IO controller to run indefinitely (it waits for screen updates) | ||
emulator.RunIO() | ||
|
||
log.Println("Goodbye!") | ||
} | ||
|
||
func getSaveStore() *saves.FileSystemStore { | ||
user, _ := user.Current() | ||
saveDir := user.HomeDir + "/.gomeboycolor/saves" | ||
|
||
os.MkdirAll(saveDir, os.ModeDir) | ||
|
||
return saves.NewFileSystemStore(saveDir) | ||
} | ||
|
||
func createCartridge(romFilename string) (*cartridge.Cartridge, error) { | ||
romContents, err := retrieveROM(romFilename) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return cartridge.NewCartridge(romFilename, romContents) | ||
} | ||
|
||
func retrieveROM(filename string) ([]byte, error) { | ||
file, err := os.Open(filename) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
defer file.Close() | ||
|
||
stats, statsErr := file.Stat() | ||
if statsErr != nil { | ||
return nil, statsErr | ||
} | ||
|
||
var size int64 = stats.Size() | ||
bytes := make([]byte, size) | ||
|
||
bufr := bufio.NewReader(file) | ||
_, err = bufr.Read(bytes) | ||
|
||
return bytes, err | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package saves | ||
|
||
import ( | ||
"io" | ||
"os" | ||
"path/filepath" | ||
"fmt" | ||
) | ||
|
||
type FileSystemStore struct { | ||
baseDir string | ||
} | ||
|
||
func NewFileSystemStore(baseDir string) *FileSystemStore { | ||
f := new(FileSystemStore) | ||
f.baseDir = baseDir | ||
return f | ||
} | ||
|
||
func (f *FileSystemStore) Open(game string) (io.ReadCloser, error) { | ||
location := filepath.Join(f.baseDir, game+".sav") | ||
|
||
fmt.Println(location) | ||
return os.Open(location) | ||
} | ||
|
||
func (f *FileSystemStore) Create(game string) (io.WriteCloser, error) { | ||
location := filepath.Join(f.baseDir, game+".sav") | ||
fmt.Println(location) | ||
return os.Create(location) | ||
} |
Oops, something went wrong.