Compare commits
	
		
			No commits in common. "4c224a51ecd31ee83073ea439597bb53c346ae0f" and "5a5e1feae55e77d7a7f883d806c98e69833b56b0" have entirely different histories.
		
	
	
		
			4c224a51ec
			...
			5a5e1feae5
		
	
		
@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestInsertCartridge(t *testing.T) {
 | 
					func TestInsertCartridge(t *testing.T) {
 | 
				
			||||||
	cartridge := Insert("rom.gb")
 | 
						cartridge := Insert("../rom.gb")
 | 
				
			||||||
	assert := assert.New(t)
 | 
						assert := assert.New(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Equal(cartridge.Title, "SEIKEN DENSETSU")
 | 
						assert.Equal(cartridge.Title, "SEIKEN DENSETSU")
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										301
									
								
								gb/cartridge.go
									
									
									
									
									
								
							
							
						
						
									
										301
									
								
								gb/cartridge.go
									
									
									
									
									
								
							@ -1,301 +0,0 @@
 | 
				
			|||||||
package gb
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"bytes"
 | 
					 | 
				
			||||||
	"encoding/binary"
 | 
					 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// See https://gbdev.io/pandocs/The_Cartridge_Header.html#0104-0133--nintendo-logo
 | 
					 | 
				
			||||||
var expectedLogo = [48]byte{
 | 
					 | 
				
			||||||
	0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B,
 | 
					 | 
				
			||||||
	0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D,
 | 
					 | 
				
			||||||
	0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E,
 | 
					 | 
				
			||||||
	0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99,
 | 
					 | 
				
			||||||
	0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC,
 | 
					 | 
				
			||||||
	0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Cartridge types
 | 
					 | 
				
			||||||
// See https://gbdev.io/pandocs/The_Cartridge_Header.html#0147--cartridge-type
 | 
					 | 
				
			||||||
var cartridgeTypes = map[byte]string{
 | 
					 | 
				
			||||||
	0x00: "ROM ONLY",
 | 
					 | 
				
			||||||
	0x01: "MBC1",
 | 
					 | 
				
			||||||
	0x02: "MBC1+RAM",
 | 
					 | 
				
			||||||
	0x03: "MBC1+RAM+BATTERY",
 | 
					 | 
				
			||||||
	0x05: "MBC2",
 | 
					 | 
				
			||||||
	0x06: "MBC2+BATTERY",
 | 
					 | 
				
			||||||
	0x08: "ROM+RAM 9",
 | 
					 | 
				
			||||||
	0x09: "ROM+RAM+BATTERY 9",
 | 
					 | 
				
			||||||
	0x0B: "MMM01",
 | 
					 | 
				
			||||||
	0x0C: "MMM01+RAM",
 | 
					 | 
				
			||||||
	0x0D: "MMM01+RAM+BATTERY",
 | 
					 | 
				
			||||||
	0x0F: "MBC3+TIMER+BATTERY",
 | 
					 | 
				
			||||||
	0x10: "MBC3+TIMER+RAM+BATTERY 10",
 | 
					 | 
				
			||||||
	0x11: "MBC3",
 | 
					 | 
				
			||||||
	0x12: "MBC3+RAM 10",
 | 
					 | 
				
			||||||
	0x13: "MBC3+RAM+BATTERY 10",
 | 
					 | 
				
			||||||
	0x19: "MBC5",
 | 
					 | 
				
			||||||
	0x1A: "MBC5+RAM",
 | 
					 | 
				
			||||||
	0x1B: "MBC5+RAM+BATTERY",
 | 
					 | 
				
			||||||
	0x1C: "MBC5+RUMBLE",
 | 
					 | 
				
			||||||
	0x1D: "MBC5+RUMBLE+RAM",
 | 
					 | 
				
			||||||
	0x1E: "MBC5+RUMBLE+RAM+BATTERY",
 | 
					 | 
				
			||||||
	0x20: "MBC6",
 | 
					 | 
				
			||||||
	0x22: "MBC7+SENSOR+RUMBLE+RAM+BATTERY",
 | 
					 | 
				
			||||||
	0xFC: "POCKET CAMERA",
 | 
					 | 
				
			||||||
	0xFD: "BANDAI TAMA5",
 | 
					 | 
				
			||||||
	0xFE: "HuC3",
 | 
					 | 
				
			||||||
	0xFF: "HuC1+RAM+BATTERY",
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// RAM sizes
 | 
					 | 
				
			||||||
// https://gbdev.io/pandocs/The_Cartridge_Header.html#0149--ram-size
 | 
					 | 
				
			||||||
var ramSizes = map[byte]string{
 | 
					 | 
				
			||||||
	0x00: "0 - No RAM",
 | 
					 | 
				
			||||||
	0x01: "UNUSED VALUE",
 | 
					 | 
				
			||||||
	0x02: "8 KiB - 1 bank",
 | 
					 | 
				
			||||||
	0x03: "32 KiB - 4 banks of 8 KiB each",
 | 
					 | 
				
			||||||
	0x04: "128 KiB 16 banks of 8 KiB each",
 | 
					 | 
				
			||||||
	0x05: "64 KiB  8 banks of 8 KiB each",
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Old licensees
 | 
					 | 
				
			||||||
// https://gbdev.io/pandocs/The_Cartridge_Header.html#014b--old-licensee-code
 | 
					 | 
				
			||||||
var oldLicensees = map[byte]string{
 | 
					 | 
				
			||||||
	0x00: "None",
 | 
					 | 
				
			||||||
	0x01: "Nintendo",
 | 
					 | 
				
			||||||
	0x08: "Capcom",
 | 
					 | 
				
			||||||
	0x09: "HOT-B",
 | 
					 | 
				
			||||||
	0x0A: "Jaleco",
 | 
					 | 
				
			||||||
	0x0B: "Coconuts Japan",
 | 
					 | 
				
			||||||
	0x0C: "Elite Systems",
 | 
					 | 
				
			||||||
	0x13: "EA (Electronic Arts)",
 | 
					 | 
				
			||||||
	0x18: "Hudson Soft",
 | 
					 | 
				
			||||||
	0x19: "ITC Entertainment",
 | 
					 | 
				
			||||||
	0x1A: "Yanoman",
 | 
					 | 
				
			||||||
	0x1D: "Japan Clary",
 | 
					 | 
				
			||||||
	0x1F: "Virgin Games Ltd.3",
 | 
					 | 
				
			||||||
	0x24: "PCM Complete",
 | 
					 | 
				
			||||||
	0x25: "San-X",
 | 
					 | 
				
			||||||
	0x28: "Kemco",
 | 
					 | 
				
			||||||
	0x29: "SETA Corporation",
 | 
					 | 
				
			||||||
	0x30: "Infogrames5",
 | 
					 | 
				
			||||||
	0x31: "Nintendo",
 | 
					 | 
				
			||||||
	0x32: "Bandai",
 | 
					 | 
				
			||||||
	0x33: "Indicates that the New licensee code should be used instead.",
 | 
					 | 
				
			||||||
	0x34: "Konami",
 | 
					 | 
				
			||||||
	0x35: "HectorSoft",
 | 
					 | 
				
			||||||
	0x38: "Capcom",
 | 
					 | 
				
			||||||
	0x39: "Banpresto",
 | 
					 | 
				
			||||||
	0x3C: "Entertainment Interactive (stub)",
 | 
					 | 
				
			||||||
	0x3E: "Gremlin",
 | 
					 | 
				
			||||||
	0x41: "Ubi Soft1",
 | 
					 | 
				
			||||||
	0x42: "Atlus",
 | 
					 | 
				
			||||||
	0x44: "Malibu Interactive",
 | 
					 | 
				
			||||||
	0x46: "Angel",
 | 
					 | 
				
			||||||
	0x47: "Spectrum HoloByte",
 | 
					 | 
				
			||||||
	0x49: "Irem",
 | 
					 | 
				
			||||||
	0x4A: "Virgin Games Ltd.3",
 | 
					 | 
				
			||||||
	0x4D: "Malibu Interactive",
 | 
					 | 
				
			||||||
	0x4F: "U.S. Gold",
 | 
					 | 
				
			||||||
	0x50: "Absolute",
 | 
					 | 
				
			||||||
	0x51: "Acclaim Entertainment",
 | 
					 | 
				
			||||||
	0x52: "Activision",
 | 
					 | 
				
			||||||
	0x53: "Sammy USA Corporation",
 | 
					 | 
				
			||||||
	0x54: "GameTek",
 | 
					 | 
				
			||||||
	0x55: "Park Place13",
 | 
					 | 
				
			||||||
	0x56: "LJN",
 | 
					 | 
				
			||||||
	0x57: "Matchbox",
 | 
					 | 
				
			||||||
	0x59: "Milton Bradley Company",
 | 
					 | 
				
			||||||
	0x5A: "Mindscape",
 | 
					 | 
				
			||||||
	0x5B: "Romstar",
 | 
					 | 
				
			||||||
	0x5C: "Naxat Soft14",
 | 
					 | 
				
			||||||
	0x5D: "Tradewest",
 | 
					 | 
				
			||||||
	0x60: "Titus Interactive",
 | 
					 | 
				
			||||||
	0x61: "Virgin Games Ltd.3",
 | 
					 | 
				
			||||||
	0x67: "Ocean Software",
 | 
					 | 
				
			||||||
	0x69: "EA (Electronic Arts)",
 | 
					 | 
				
			||||||
	0x6E: "Elite Systems",
 | 
					 | 
				
			||||||
	0x6F: "Electro Brain",
 | 
					 | 
				
			||||||
	0x70: "Infogrames5",
 | 
					 | 
				
			||||||
	0x71: "Interplay Entertainment",
 | 
					 | 
				
			||||||
	0x72: "Broderbund",
 | 
					 | 
				
			||||||
	0x73: "Sculptured Software6",
 | 
					 | 
				
			||||||
	0x75: "The Sales Curve Limited7",
 | 
					 | 
				
			||||||
	0x78: "THQ",
 | 
					 | 
				
			||||||
	0x79: "Accolade15",
 | 
					 | 
				
			||||||
	0x7A: "Triffix Entertainment",
 | 
					 | 
				
			||||||
	0x7C: "MicroProse",
 | 
					 | 
				
			||||||
	0x7F: "Kemco",
 | 
					 | 
				
			||||||
	0x80: "Misawa Entertainment",
 | 
					 | 
				
			||||||
	0x83: "LOZC G.",
 | 
					 | 
				
			||||||
	0x86: "Tokuma Shoten",
 | 
					 | 
				
			||||||
	0x8B: "Bullet-Proof Software2",
 | 
					 | 
				
			||||||
	0x8C: "Vic Tokai Corp.16",
 | 
					 | 
				
			||||||
	0x8E: "Ape Inc.17",
 | 
					 | 
				
			||||||
	0x8F: "I'Max18",
 | 
					 | 
				
			||||||
	0x91: "Chunsoft Co.8",
 | 
					 | 
				
			||||||
	0x92: "Video System",
 | 
					 | 
				
			||||||
	0x93: "Tsubaraya Productions",
 | 
					 | 
				
			||||||
	0x95: "Varie",
 | 
					 | 
				
			||||||
	0x96: "Yonezawa19/S'Pal",
 | 
					 | 
				
			||||||
	0x97: "Kemco",
 | 
					 | 
				
			||||||
	0x99: "Arc",
 | 
					 | 
				
			||||||
	0x9A: "Nihon Bussan",
 | 
					 | 
				
			||||||
	0x9B: "Tecmo",
 | 
					 | 
				
			||||||
	0x9C: "Imagineer",
 | 
					 | 
				
			||||||
	0x9D: "Banpresto",
 | 
					 | 
				
			||||||
	0x9F: "Nova",
 | 
					 | 
				
			||||||
	0xA1: "Hori Electric",
 | 
					 | 
				
			||||||
	0xA2: "Bandai",
 | 
					 | 
				
			||||||
	0xA4: "Konami",
 | 
					 | 
				
			||||||
	0xA6: "Kawada",
 | 
					 | 
				
			||||||
	0xA7: "Takara",
 | 
					 | 
				
			||||||
	0xA9: "Technos Japan",
 | 
					 | 
				
			||||||
	0xAA: "Broderbund",
 | 
					 | 
				
			||||||
	0xAC: "Toei Animation",
 | 
					 | 
				
			||||||
	0xAD: "Toho",
 | 
					 | 
				
			||||||
	0xAF: "Namco",
 | 
					 | 
				
			||||||
	0xB0: "Acclaim Entertainment",
 | 
					 | 
				
			||||||
	0xB1: "ASCII Corporation or Nexsoft",
 | 
					 | 
				
			||||||
	0xB2: "Bandai",
 | 
					 | 
				
			||||||
	0xB4: "Square Enix",
 | 
					 | 
				
			||||||
	0xB6: "HAL Laboratory",
 | 
					 | 
				
			||||||
	0xB7: "SNK",
 | 
					 | 
				
			||||||
	0xB9: "Pony Canyon",
 | 
					 | 
				
			||||||
	0xBA: "Culture Brain",
 | 
					 | 
				
			||||||
	0xBB: "Sunsoft",
 | 
					 | 
				
			||||||
	0xBD: "Sony Imagesoft",
 | 
					 | 
				
			||||||
	0xBF: "Sammy Corporation",
 | 
					 | 
				
			||||||
	0xC0: "Taito",
 | 
					 | 
				
			||||||
	0xC2: "Kemco",
 | 
					 | 
				
			||||||
	0xC3: "Square",
 | 
					 | 
				
			||||||
	0xC4: "Tokuma Shoten",
 | 
					 | 
				
			||||||
	0xC5: "Data East",
 | 
					 | 
				
			||||||
	0xC6: "Tonkin House",
 | 
					 | 
				
			||||||
	0xC8: "Koei",
 | 
					 | 
				
			||||||
	0xC9: "UFL",
 | 
					 | 
				
			||||||
	0xCA: "Ultra Games",
 | 
					 | 
				
			||||||
	0xCB: "VAP, Inc.",
 | 
					 | 
				
			||||||
	0xCC: "Use Corporation",
 | 
					 | 
				
			||||||
	0xCD: "Meldac",
 | 
					 | 
				
			||||||
	0xCE: "Pony Canyon",
 | 
					 | 
				
			||||||
	0xCF: "Angel",
 | 
					 | 
				
			||||||
	0xD0: "Taito",
 | 
					 | 
				
			||||||
	0xD1: "SOFEL (Software Engineering Lab)",
 | 
					 | 
				
			||||||
	0xD2: "Quest",
 | 
					 | 
				
			||||||
	0xD3: "Sigma Enterprises",
 | 
					 | 
				
			||||||
	0xD4: "ASK Kodansha Co.",
 | 
					 | 
				
			||||||
	0xD6: "Naxat Soft14",
 | 
					 | 
				
			||||||
	0xD7: "Copya System",
 | 
					 | 
				
			||||||
	0xD9: "Banpresto",
 | 
					 | 
				
			||||||
	0xDA: "Tomy",
 | 
					 | 
				
			||||||
	0xDB: "LJN",
 | 
					 | 
				
			||||||
	0xDD: "Nippon Computer Systems",
 | 
					 | 
				
			||||||
	0xDE: "Human Ent.",
 | 
					 | 
				
			||||||
	0xDF: "Altron",
 | 
					 | 
				
			||||||
	0xE0: "Jaleco",
 | 
					 | 
				
			||||||
	0xE1: "Towa Chiki",
 | 
					 | 
				
			||||||
	0xE2: "Yutaka # Needs more info",
 | 
					 | 
				
			||||||
	0xE3: "Varie",
 | 
					 | 
				
			||||||
	0xE5: "Epoch",
 | 
					 | 
				
			||||||
	0xE7: "Athena",
 | 
					 | 
				
			||||||
	0xE8: "Asmik Ace Entertainment",
 | 
					 | 
				
			||||||
	0xE9: "Natsume",
 | 
					 | 
				
			||||||
	0xEA: "King Records",
 | 
					 | 
				
			||||||
	0xEB: "Atlus",
 | 
					 | 
				
			||||||
	0xEC: "Epic/Sony Records",
 | 
					 | 
				
			||||||
	0xEE: "IGS",
 | 
					 | 
				
			||||||
	0xF0: "A Wave",
 | 
					 | 
				
			||||||
	0xF3: "Extreme Entertainment",
 | 
					 | 
				
			||||||
	0xFF: "LJN",
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ROMHeader struct {
 | 
					 | 
				
			||||||
	EntryPoint [4]byte
 | 
					 | 
				
			||||||
	Logo       [48]byte
 | 
					 | 
				
			||||||
	// NOTE(m): Assuming "old" cartridges here. This may cause problems with newer cartridges.
 | 
					 | 
				
			||||||
	// See https://gbdev.io/pandocs/The_Cartridge_Header.html#0134-0143--title
 | 
					 | 
				
			||||||
	Title                [16]byte
 | 
					 | 
				
			||||||
	NewLicenseeCode      [2]byte
 | 
					 | 
				
			||||||
	SGBFlag              byte
 | 
					 | 
				
			||||||
	CartridgeType        byte
 | 
					 | 
				
			||||||
	ROMSize              byte
 | 
					 | 
				
			||||||
	RAMSize              byte
 | 
					 | 
				
			||||||
	DestinationCode      byte
 | 
					 | 
				
			||||||
	OldLicenseeCode      byte
 | 
					 | 
				
			||||||
	MaskROMVersionNumber byte
 | 
					 | 
				
			||||||
	HeaderChecksum       byte
 | 
					 | 
				
			||||||
	GlobalChecksum       [2]byte
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Cartridge struct {
 | 
					 | 
				
			||||||
	Filename    string
 | 
					 | 
				
			||||||
	Mapper      string
 | 
					 | 
				
			||||||
	Title       string
 | 
					 | 
				
			||||||
	Licensee    string
 | 
					 | 
				
			||||||
	SGBSupport  bool
 | 
					 | 
				
			||||||
	ROMSize     int
 | 
					 | 
				
			||||||
	RAMSize     string
 | 
					 | 
				
			||||||
	Destination string
 | 
					 | 
				
			||||||
	Version     int
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func InsertCartridge(path string) *Cartridge {
 | 
					 | 
				
			||||||
	file, err := os.Open(path)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer file.Close()
 | 
					 | 
				
			||||||
	cartridge := Cartridge{Filename: file.Name()}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Jump to start of header
 | 
					 | 
				
			||||||
	_, err = file.Seek(0x0100, io.SeekStart)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Read header
 | 
					 | 
				
			||||||
	var header ROMHeader
 | 
					 | 
				
			||||||
	err = binary.Read(file, binary.LittleEndian, &header)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Validate the ROM by checking presence of the Nintendo logo
 | 
					 | 
				
			||||||
	if header.Logo != expectedLogo {
 | 
					 | 
				
			||||||
		log.Fatal("Invalid ROM file: No valid logo found!")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Convert some header values
 | 
					 | 
				
			||||||
	cartridge.Title = string(bytes.Trim(header.Title[:], "\x00"))
 | 
					 | 
				
			||||||
	cartridge.Mapper = cartridgeTypes[header.CartridgeType]
 | 
					 | 
				
			||||||
	if header.OldLicenseeCode == 0x33 {
 | 
					 | 
				
			||||||
		// FIXME(m): Support new licensee codes
 | 
					 | 
				
			||||||
		cartridge.Licensee = "Indicates that the New licensee code should be used instead."
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		cartridge.Licensee = oldLicensees[header.OldLicenseeCode]
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	cartridge.SGBSupport = (header.SGBFlag == 0x03)
 | 
					 | 
				
			||||||
	cartridge.ROMSize = 32 * (1 << header.ROMSize)
 | 
					 | 
				
			||||||
	cartridge.RAMSize = ramSizes[header.RAMSize]
 | 
					 | 
				
			||||||
	switch header.DestinationCode {
 | 
					 | 
				
			||||||
	case 0x00:
 | 
					 | 
				
			||||||
		cartridge.Destination = "Japan (and possibly overseas)"
 | 
					 | 
				
			||||||
	case 0x01:
 | 
					 | 
				
			||||||
		cartridge.Destination = "Overseas only"
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		cartridge.Destination = "UNKNOWN"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	cartridge.Version = int(header.MaskROMVersionNumber)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// TODO(m): Verify header checksum
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// NOTE(m): Ignoring global checksum which is not used, except by one emulator.
 | 
					 | 
				
			||||||
	// See https://gbdev.io/pandocs/The_Cartridge_Header.html#014e-014f--global-checksum
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &cartridge
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,17 +0,0 @@
 | 
				
			|||||||
package gb
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Console struct {
 | 
					 | 
				
			||||||
	Cartridge *Cartridge
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewConsole(path string) (*Console, error) {
 | 
					 | 
				
			||||||
	cartridge := InsertCartridge(path)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	console := Console{cartridge}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &console, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (console *Console) Update(dt uint64) {
 | 
					 | 
				
			||||||
	console.StepSeconds(dt)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										129
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								main.go
									
									
									
									
									
								
							@ -1,16 +1,127 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"gb-player/ui"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/veandco/go-sdl2/sdl"
 | 
				
			||||||
 | 
						"github.com/veandco/go-sdl2/ttf"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					var renderer *sdl.Renderer
 | 
				
			||||||
	// FIXME(m): Allow specifying rom file on command line
 | 
					var font *ttf.Font
 | 
				
			||||||
	// if len(os.Args) != 2 {
 | 
					 | 
				
			||||||
	// 	log.Fatalln("No rom file specified")
 | 
					 | 
				
			||||||
	// }
 | 
					 | 
				
			||||||
	// romPath := os.Args[1]
 | 
					 | 
				
			||||||
	romPath := "rom.gb"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ui.Run(romPath)
 | 
					func init() {
 | 
				
			||||||
 | 
						runtime.LockOSThread()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
						if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
 | 
				
			||||||
 | 
							log.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer sdl.Quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := ttf.Init(); err != nil {
 | 
				
			||||||
 | 
							log.Fatal((err))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer ttf.Quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						window, err := sdl.CreateWindow(
 | 
				
			||||||
 | 
							"GB Player",
 | 
				
			||||||
 | 
							sdl.WINDOWPOS_UNDEFINED,
 | 
				
			||||||
 | 
							sdl.WINDOWPOS_UNDEFINED,
 | 
				
			||||||
 | 
							800, 600,
 | 
				
			||||||
 | 
							sdl.WINDOW_SHOWN)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer window.Destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						renderer, err = sdl.CreateRenderer(window, -1, 0)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer renderer.Destroy()
 | 
				
			||||||
 | 
						renderer.RenderSetVSync(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						font, err = ttf.OpenFont("SourceCodePro.ttf", 18)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer font.Close()
 | 
				
			||||||
 | 
						font.SetStyle(ttf.STYLE_BOLD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var fps float64
 | 
				
			||||||
 | 
						var frameCount uint32
 | 
				
			||||||
 | 
						var startTicks = sdl.GetTicks64()
 | 
				
			||||||
 | 
						var now uint64
 | 
				
			||||||
 | 
						var last uint64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cartridge := Insert("rom.gb")
 | 
				
			||||||
 | 
						fmt.Println(cartridge)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						running := true
 | 
				
			||||||
 | 
						for running {
 | 
				
			||||||
 | 
							for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
 | 
				
			||||||
 | 
								switch event.(type) {
 | 
				
			||||||
 | 
								case *sdl.QuitEvent:
 | 
				
			||||||
 | 
									println("Quit")
 | 
				
			||||||
 | 
									running = false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							last = now
 | 
				
			||||||
 | 
							now = sdl.GetPerformanceCounter()
 | 
				
			||||||
 | 
							deltaTime := float64((now - last) * 1000.0 / sdl.GetPerformanceFrequency())
 | 
				
			||||||
 | 
							_ = deltaTime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Clear screen
 | 
				
			||||||
 | 
							renderer.SetDrawColor(0x63, 0x94, 0xED, 0xff)
 | 
				
			||||||
 | 
							renderer.Clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Update state
 | 
				
			||||||
 | 
							rect := sdl.Rect{X: 100, Y: 100, W: 200, H: 150}
 | 
				
			||||||
 | 
							renderer.SetDrawColor(0, 0, 255, 255)
 | 
				
			||||||
 | 
							renderer.FillRect(&rect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							drawDebugWindow(fps)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Present to screen
 | 
				
			||||||
 | 
							renderer.Present()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Calculate framerate
 | 
				
			||||||
 | 
							frameCount++
 | 
				
			||||||
 | 
							currentTicks := sdl.GetTicks64()
 | 
				
			||||||
 | 
							elapsed := currentTicks - startTicks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if elapsed >= 1000 {
 | 
				
			||||||
 | 
								fps = float64(frameCount) / (float64(elapsed) / 1000.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Reset counters
 | 
				
			||||||
 | 
								frameCount = 0
 | 
				
			||||||
 | 
								startTicks = currentTicks
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func drawDebugWindow(fps float64) {
 | 
				
			||||||
 | 
						var textSurface *sdl.Surface
 | 
				
			||||||
 | 
						var textTexture *sdl.Texture
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// FPS
 | 
				
			||||||
 | 
						textSurface, err := font.RenderUTF8Blended(fmt.Sprintf("FPS: %.2f", fps), sdl.Color{R: 0, G: 0, B: 0, A: 255})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer textSurface.Free()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						textTexture, err = renderer.CreateTextureFromSurface(textSurface)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer textTexture.Destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						textRect := sdl.Rect{X: 0, Y: 0, W: textSurface.W, H: textSurface.H}
 | 
				
			||||||
 | 
						renderer.Copy(textTexture, nil, &textRect)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,86 +0,0 @@
 | 
				
			|||||||
package ui
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"gb-player/gb"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/veandco/go-sdl2/sdl"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Controller struct {
 | 
					 | 
				
			||||||
	renderer  *sdl.Renderer
 | 
					 | 
				
			||||||
	view      *View
 | 
					 | 
				
			||||||
	timestamp uint64
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewController(renderer *sdl.Renderer) *Controller {
 | 
					 | 
				
			||||||
	controller := Controller{}
 | 
					 | 
				
			||||||
	controller.renderer = renderer
 | 
					 | 
				
			||||||
	return &controller
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Controller) Start(path string) {
 | 
					 | 
				
			||||||
	console := gb.NewConsole(path)
 | 
					 | 
				
			||||||
	c.view = NewView(c, console)
 | 
					 | 
				
			||||||
	c.Run()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Controller) Step() {
 | 
					 | 
				
			||||||
	timestamp := sdl.GetTicks64()
 | 
					 | 
				
			||||||
	dt := timestamp - c.timestamp
 | 
					 | 
				
			||||||
	c.view.Update(timestamp, dt)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Controller) Run() {
 | 
					 | 
				
			||||||
	var fps float64
 | 
					 | 
				
			||||||
	var frameCount uint32
 | 
					 | 
				
			||||||
	var startTicks = sdl.GetTicks64()
 | 
					 | 
				
			||||||
	var now, last uint64
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// cartridge := gb.Insert(romPath)
 | 
					 | 
				
			||||||
	// fmt.Println(cartridge)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	running := true
 | 
					 | 
				
			||||||
	for running {
 | 
					 | 
				
			||||||
		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
 | 
					 | 
				
			||||||
			switch event.(type) {
 | 
					 | 
				
			||||||
			case *sdl.QuitEvent:
 | 
					 | 
				
			||||||
				println("Quit")
 | 
					 | 
				
			||||||
				running = false
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		last = now
 | 
					 | 
				
			||||||
		now = sdl.GetPerformanceCounter()
 | 
					 | 
				
			||||||
		deltaTime := float64((now - last) * 1000.0 / sdl.GetPerformanceFrequency())
 | 
					 | 
				
			||||||
		_ = deltaTime
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Clear screen
 | 
					 | 
				
			||||||
		renderer.SetDrawColor(0x63, 0x94, 0xED, 0xff)
 | 
					 | 
				
			||||||
		renderer.Clear()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Update state
 | 
					 | 
				
			||||||
		c.Step()
 | 
					 | 
				
			||||||
		rect := sdl.Rect{X: 100, Y: 100, W: 200, H: 150}
 | 
					 | 
				
			||||||
		renderer.SetDrawColor(0, 0, 255, 255)
 | 
					 | 
				
			||||||
		renderer.FillRect(&rect)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		drawDebugWindow(fps)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Present to screen
 | 
					 | 
				
			||||||
		renderer.Present()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Calculate framerate
 | 
					 | 
				
			||||||
		frameCount++
 | 
					 | 
				
			||||||
		currentTicks := sdl.GetTicks64()
 | 
					 | 
				
			||||||
		elapsed := currentTicks - startTicks
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if elapsed >= 1000 {
 | 
					 | 
				
			||||||
			fps = float64(frameCount) / (float64(elapsed) / 1000.0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Reset counters
 | 
					 | 
				
			||||||
			frameCount = 0
 | 
					 | 
				
			||||||
			startTicks = currentTicks
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										75
									
								
								ui/run.go
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								ui/run.go
									
									
									
									
									
								
							@ -1,75 +0,0 @@
 | 
				
			|||||||
package ui
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
	"runtime"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/veandco/go-sdl2/sdl"
 | 
					 | 
				
			||||||
	"github.com/veandco/go-sdl2/ttf"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var renderer *sdl.Renderer
 | 
					 | 
				
			||||||
var font *ttf.Font
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	runtime.LockOSThread()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func Run(romPath string) {
 | 
					 | 
				
			||||||
	if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer sdl.Quit()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := ttf.Init(); err != nil {
 | 
					 | 
				
			||||||
		log.Fatal((err))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer ttf.Quit()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	window, err := sdl.CreateWindow(
 | 
					 | 
				
			||||||
		"GB Player",
 | 
					 | 
				
			||||||
		sdl.WINDOWPOS_UNDEFINED,
 | 
					 | 
				
			||||||
		sdl.WINDOWPOS_UNDEFINED,
 | 
					 | 
				
			||||||
		800, 600,
 | 
					 | 
				
			||||||
		sdl.WINDOW_SHOWN)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		panic(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer window.Destroy()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	renderer, err = sdl.CreateRenderer(window, -1, 0)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		panic(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer renderer.Destroy()
 | 
					 | 
				
			||||||
	renderer.RenderSetVSync(true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	font, err = ttf.OpenFont("SourceCodePro.ttf", 18)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer font.Close()
 | 
					 | 
				
			||||||
	font.SetStyle(ttf.STYLE_BOLD)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	controller := NewController(renderer)
 | 
					 | 
				
			||||||
	controller.Start(romPath)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func drawDebugWindow(fps float64) {
 | 
					 | 
				
			||||||
	// FPS
 | 
					 | 
				
			||||||
	textSurface, err := font.RenderUTF8Blended(fmt.Sprintf("FPS: %.2f", fps), sdl.Color{R: 0, G: 0, B: 0, A: 255})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer textSurface.Free()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	textTexture, err := renderer.CreateTextureFromSurface(textSurface)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer textTexture.Destroy()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	textRect := sdl.Rect{X: 0, Y: 0, W: textSurface.W, H: textSurface.H}
 | 
					 | 
				
			||||||
	renderer.Copy(textTexture, nil, &textRect)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										14
									
								
								ui/view.go
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								ui/view.go
									
									
									
									
									
								
							@ -1,14 +0,0 @@
 | 
				
			|||||||
package ui
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"gb-player/gb"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type View struct {
 | 
					 | 
				
			||||||
	controller *Controller
 | 
					 | 
				
			||||||
	console    *gb.Console
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewView(controller *Controller, console *gb.Console) *View {
 | 
					 | 
				
			||||||
	return &View{controller, console}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user