mirror of
https://github.com/libretro/sameduck.git
synced 2024-11-26 18:50:26 +00:00
Strip irrelevant features
This commit is contained in:
parent
dcb59d4cd4
commit
6610180717
Binary file not shown.
Before Width: | Height: | Size: 479 B |
@ -1,2 +0,0 @@
|
||||
AGB EQU 1
|
||||
include "cgb_boot.asm"
|
File diff suppressed because it is too large
Load Diff
@ -1,2 +0,0 @@
|
||||
FAST EQU 1
|
||||
include "cgb_boot.asm"
|
@ -1,177 +0,0 @@
|
||||
; SameBoy DMG bootstrap ROM
|
||||
; Todo: use friendly names for HW registers instead of magic numbers
|
||||
SECTION "BootCode", ROM0[$0]
|
||||
Start:
|
||||
; Init stack pointer
|
||||
ld sp, $fffe
|
||||
|
||||
; Clear memory VRAM
|
||||
ld hl, $8000
|
||||
|
||||
.clearVRAMLoop
|
||||
ldi [hl], a
|
||||
bit 5, h
|
||||
jr z, .clearVRAMLoop
|
||||
|
||||
; Init Audio
|
||||
ld a, $80
|
||||
ldh [$26], a
|
||||
ldh [$11], a
|
||||
ld a, $f3
|
||||
ldh [$12], a
|
||||
ldh [$25], a
|
||||
ld a, $77
|
||||
ldh [$24], a
|
||||
|
||||
; Init BG palette
|
||||
ld a, $54
|
||||
ldh [$47], a
|
||||
|
||||
; Load logo from ROM.
|
||||
; A nibble represents a 4-pixels line, 2 bytes represent a 4x4 tile, scaled to 8x8.
|
||||
; Tiles are ordered left to right, top to bottom.
|
||||
ld de, $104 ; Logo start
|
||||
ld hl, $8010 ; This is where we load the tiles in VRAM
|
||||
|
||||
.loadLogoLoop
|
||||
ld a, [de] ; Read 2 rows
|
||||
ld b, a
|
||||
call DoubleBitsAndWriteRow
|
||||
call DoubleBitsAndWriteRow
|
||||
inc de
|
||||
ld a, e
|
||||
xor $34 ; End of logo
|
||||
jr nz, .loadLogoLoop
|
||||
|
||||
; Load trademark symbol
|
||||
ld de, TrademarkSymbol
|
||||
ld c,$08
|
||||
.loadTrademarkSymbolLoop:
|
||||
ld a,[de]
|
||||
inc de
|
||||
ldi [hl],a
|
||||
inc hl
|
||||
dec c
|
||||
jr nz, .loadTrademarkSymbolLoop
|
||||
|
||||
; Set up tilemap
|
||||
ld a,$19 ; Trademark symbol
|
||||
ld [$9910], a ; ... put in the superscript position
|
||||
ld hl,$992f ; Bottom right corner of the logo
|
||||
ld c,$c ; Tiles in a logo row
|
||||
.tilemapLoop
|
||||
dec a
|
||||
jr z, .tilemapDone
|
||||
ldd [hl], a
|
||||
dec c
|
||||
jr nz, .tilemapLoop
|
||||
ld l,$0f ; Jump to top row
|
||||
jr .tilemapLoop
|
||||
.tilemapDone
|
||||
|
||||
ld a, 30
|
||||
ldh [$ff42], a
|
||||
|
||||
; Turn on LCD
|
||||
ld a, $91
|
||||
ldh [$40], a
|
||||
|
||||
ld d, (-119) & $FF
|
||||
ld c, 15
|
||||
|
||||
.animate
|
||||
call WaitFrame
|
||||
ld a, d
|
||||
sra a
|
||||
sra a
|
||||
ldh [$ff42], a
|
||||
ld a, d
|
||||
add c
|
||||
ld d, a
|
||||
ld a, c
|
||||
cp 8
|
||||
jr nz, .noPaletteChange
|
||||
ld a, $A8
|
||||
ldh [$47], a
|
||||
.noPaletteChange
|
||||
dec c
|
||||
jr nz, .animate
|
||||
ld a, $fc
|
||||
ldh [$47], a
|
||||
|
||||
; Play first sound
|
||||
ld a, $83
|
||||
call PlaySound
|
||||
ld b, 5
|
||||
call WaitBFrames
|
||||
; Play second sound
|
||||
ld a, $c1
|
||||
call PlaySound
|
||||
|
||||
|
||||
|
||||
; Wait ~1 second
|
||||
ld b, 60
|
||||
call WaitBFrames
|
||||
|
||||
; Set registers to match the original DMG boot
|
||||
ld hl, $01B0
|
||||
push hl
|
||||
pop af
|
||||
ld hl, $014D
|
||||
ld bc, $0013
|
||||
ld de, $00D8
|
||||
|
||||
; Boot the game
|
||||
jp BootGame
|
||||
|
||||
|
||||
DoubleBitsAndWriteRow:
|
||||
; Double the most significant 4 bits, b is shifted by 4
|
||||
ld a, 4
|
||||
ld c, 0
|
||||
.doubleCurrentBit
|
||||
sla b
|
||||
push af
|
||||
rl c
|
||||
pop af
|
||||
rl c
|
||||
dec a
|
||||
jr nz, .doubleCurrentBit
|
||||
ld a, c
|
||||
; Write as two rows
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
ret
|
||||
|
||||
WaitFrame:
|
||||
push hl
|
||||
ld hl, $FF0F
|
||||
res 0, [hl]
|
||||
.wait
|
||||
bit 0, [hl]
|
||||
jr z, .wait
|
||||
pop hl
|
||||
ret
|
||||
|
||||
WaitBFrames:
|
||||
call WaitFrame
|
||||
dec b
|
||||
jr nz, WaitBFrames
|
||||
ret
|
||||
|
||||
PlaySound:
|
||||
ldh [$13], a
|
||||
ld a, $87
|
||||
ldh [$14], a
|
||||
ret
|
||||
|
||||
|
||||
TrademarkSymbol:
|
||||
db $3c,$42,$b9,$a5,$b9,$a5,$42,$3c
|
||||
|
||||
SECTION "BootGame", ROM0[$fe]
|
||||
BootGame:
|
||||
ldh [$50], a
|
102
BootROMs/pb12.c
102
BootROMs/pb12.c
@ -1,102 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
void opts(uint8_t byte, uint8_t *options)
|
||||
{
|
||||
*(options++) = byte | ((byte << 1) & 0xff);
|
||||
*(options++) = byte & (byte << 1);
|
||||
*(options++) = byte | ((byte >> 1) & 0xff);
|
||||
*(options++) = byte & (byte >> 1);
|
||||
}
|
||||
|
||||
void write_all(int fd, const void *buf, size_t count) {
|
||||
while (count) {
|
||||
ssize_t written = write(fd, buf, count);
|
||||
if (written < 0) {
|
||||
fprintf(stderr, "write");
|
||||
exit(1);
|
||||
}
|
||||
count -= written;
|
||||
buf += written;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
static uint8_t source[0x4000];
|
||||
size_t size = read(STDIN_FILENO, &source, sizeof(source));
|
||||
unsigned pos = 0;
|
||||
assert(size <= 0x4000);
|
||||
while (size && source[size - 1] == 0) {
|
||||
size--;
|
||||
}
|
||||
|
||||
uint8_t literals[8];
|
||||
size_t literals_size = 0;
|
||||
unsigned bits = 0;
|
||||
unsigned control = 0;
|
||||
unsigned prev[2] = {-1, -1}; // Unsigned to allow "not set" values
|
||||
|
||||
while (true) {
|
||||
|
||||
uint8_t byte = 0;
|
||||
if (pos == size){
|
||||
if (bits == 0) break;
|
||||
}
|
||||
else {
|
||||
byte = source[pos++];
|
||||
}
|
||||
|
||||
if (byte == prev[0] || byte == prev[1]) {
|
||||
bits += 2;
|
||||
control <<= 1;
|
||||
control |= 1;
|
||||
control <<= 1;
|
||||
if (byte == prev[1]) {
|
||||
control |= 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bits += 2;
|
||||
control <<= 2;
|
||||
uint8_t options[4];
|
||||
opts(prev[1], options);
|
||||
bool found = false;
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
if (options[i] == byte) {
|
||||
// 01 = modify
|
||||
control |= 1;
|
||||
|
||||
bits += 2;
|
||||
control <<= 2;
|
||||
control |= i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
literals[literals_size++] = byte;
|
||||
}
|
||||
}
|
||||
|
||||
prev[0] = prev[1];
|
||||
prev[1] = byte;
|
||||
if (bits >= 8) {
|
||||
uint8_t outctl = control >> (bits - 8);
|
||||
assert(outctl != 1);
|
||||
write_all(STDOUT_FILENO, &outctl, 1);
|
||||
write_all(STDOUT_FILENO, literals, literals_size);
|
||||
bits -= 8;
|
||||
control &= (1 << bits) - 1;
|
||||
literals_size = 0;
|
||||
}
|
||||
}
|
||||
uint8_t end_byte = 1;
|
||||
write_all(STDOUT_FILENO, &end_byte, 1);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
SGB2 EQU 1
|
||||
include "sgb_boot.asm"
|
@ -1,213 +0,0 @@
|
||||
; SameBoy SGB bootstrap ROM
|
||||
; Todo: use friendly names for HW registers instead of magic numbers
|
||||
SECTION "BootCode", ROM0[$0]
|
||||
Start:
|
||||
; Init stack pointer
|
||||
ld sp, $fffe
|
||||
|
||||
; Clear memory VRAM
|
||||
ld hl, $8000
|
||||
|
||||
.clearVRAMLoop
|
||||
ldi [hl], a
|
||||
bit 5, h
|
||||
jr z, .clearVRAMLoop
|
||||
|
||||
; Init Audio
|
||||
ld a, $80
|
||||
ldh [$26], a
|
||||
ldh [$11], a
|
||||
ld a, $f3
|
||||
ldh [$12], a
|
||||
ldh [$25], a
|
||||
ld a, $77
|
||||
ldh [$24], a
|
||||
|
||||
; Init BG palette to white
|
||||
ld a, $0
|
||||
ldh [$47], a
|
||||
|
||||
; Load logo from ROM.
|
||||
; A nibble represents a 4-pixels line, 2 bytes represent a 4x4 tile, scaled to 8x8.
|
||||
; Tiles are ordered left to right, top to bottom.
|
||||
ld de, $104 ; Logo start
|
||||
ld hl, $8010 ; This is where we load the tiles in VRAM
|
||||
|
||||
.loadLogoLoop
|
||||
ld a, [de] ; Read 2 rows
|
||||
ld b, a
|
||||
call DoubleBitsAndWriteRow
|
||||
call DoubleBitsAndWriteRow
|
||||
inc de
|
||||
ld a, e
|
||||
xor $34 ; End of logo
|
||||
jr nz, .loadLogoLoop
|
||||
|
||||
; Load trademark symbol
|
||||
ld de, TrademarkSymbol
|
||||
ld c,$08
|
||||
.loadTrademarkSymbolLoop:
|
||||
ld a,[de]
|
||||
inc de
|
||||
ldi [hl],a
|
||||
inc hl
|
||||
dec c
|
||||
jr nz, .loadTrademarkSymbolLoop
|
||||
|
||||
; Set up tilemap
|
||||
ld a,$19 ; Trademark symbol
|
||||
ld [$9910], a ; ... put in the superscript position
|
||||
ld hl,$992f ; Bottom right corner of the logo
|
||||
ld c,$c ; Tiles in a logo row
|
||||
.tilemapLoop
|
||||
dec a
|
||||
jr z, .tilemapDone
|
||||
ldd [hl], a
|
||||
dec c
|
||||
jr nz, .tilemapLoop
|
||||
ld l,$0f ; Jump to top row
|
||||
jr .tilemapLoop
|
||||
.tilemapDone
|
||||
|
||||
; Turn on LCD
|
||||
ld a, $91
|
||||
ldh [$40], a
|
||||
|
||||
ld a, $f1 ; Packet magic, increases by 2 for every packet
|
||||
ldh [$80], a
|
||||
ld hl, $104 ; Header start
|
||||
|
||||
xor a
|
||||
ld c, a ; JOYP
|
||||
|
||||
.sendCommand
|
||||
xor a
|
||||
ld [c], a
|
||||
ld a, $30
|
||||
ld [c], a
|
||||
|
||||
ldh a, [$80]
|
||||
call SendByte
|
||||
push hl
|
||||
ld b, $e
|
||||
ld d, 0
|
||||
|
||||
.checksumLoop
|
||||
call ReadHeaderByte
|
||||
add d
|
||||
ld d, a
|
||||
dec b
|
||||
jr nz, .checksumLoop
|
||||
|
||||
; Send checksum
|
||||
call SendByte
|
||||
pop hl
|
||||
|
||||
ld b, $e
|
||||
.sendLoop
|
||||
call ReadHeaderByte
|
||||
call SendByte
|
||||
dec b
|
||||
jr nz, .sendLoop
|
||||
|
||||
; Done bit
|
||||
ld a, $20
|
||||
ld [c], a
|
||||
ld a, $30
|
||||
ld [c], a
|
||||
|
||||
; Update command
|
||||
ldh a, [$80]
|
||||
add 2
|
||||
ldh [$80], a
|
||||
|
||||
ld a, $58
|
||||
cp l
|
||||
jr nz, .sendCommand
|
||||
|
||||
; Write to sound registers for DMG compatibility
|
||||
ld c, $13
|
||||
ld a, $c1
|
||||
ld [c], a
|
||||
inc c
|
||||
ld a, 7
|
||||
ld [c], a
|
||||
|
||||
; Init BG palette
|
||||
ld a, $fc
|
||||
ldh [$47], a
|
||||
|
||||
; Set registers to match the original SGB boot
|
||||
IF DEF(SGB2)
|
||||
ld a, $FF
|
||||
ELSE
|
||||
ld a, 1
|
||||
ENDC
|
||||
ld hl, $c060
|
||||
|
||||
; Boot the game
|
||||
jp BootGame
|
||||
|
||||
ReadHeaderByte:
|
||||
ld a, $4F
|
||||
cp l
|
||||
jr c, .zero
|
||||
ld a, [hli]
|
||||
ret
|
||||
.zero:
|
||||
inc hl
|
||||
xor a
|
||||
ret
|
||||
|
||||
SendByte:
|
||||
ld e, a
|
||||
ld d, 8
|
||||
.loop
|
||||
ld a, $10
|
||||
rr e
|
||||
jr c, .zeroBit
|
||||
add a ; 10 -> 20
|
||||
.zeroBit
|
||||
ld [c], a
|
||||
ld a, $30
|
||||
ld [c], a
|
||||
dec d
|
||||
ret z
|
||||
jr .loop
|
||||
|
||||
DoubleBitsAndWriteRow:
|
||||
; Double the most significant 4 bits, b is shifted by 4
|
||||
ld a, 4
|
||||
ld c, 0
|
||||
.doubleCurrentBit
|
||||
sla b
|
||||
push af
|
||||
rl c
|
||||
pop af
|
||||
rl c
|
||||
dec a
|
||||
jr nz, .doubleCurrentBit
|
||||
ld a, c
|
||||
; Write as two rows
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
ret
|
||||
|
||||
WaitFrame:
|
||||
push hl
|
||||
ld hl, $FF0F
|
||||
res 0, [hl]
|
||||
.wait
|
||||
bit 0, [hl]
|
||||
jr z, .wait
|
||||
pop hl
|
||||
ret
|
||||
|
||||
TrademarkSymbol:
|
||||
db $3c,$42,$b9,$a5,$b9,$a5,$42,$3c
|
||||
|
||||
SECTION "BootGame", ROM0[$fe]
|
||||
BootGame:
|
||||
ldh [$50], a
|
@ -546,17 +546,6 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
||||
|
||||
- (void) loadBootROM: (GB_boot_rom_t)type
|
||||
{
|
||||
static NSString *const names[] = {
|
||||
[GB_BOOT_ROM_DMG0] = @"dmg0_boot",
|
||||
[GB_BOOT_ROM_DMG] = @"dmg_boot",
|
||||
[GB_BOOT_ROM_MGB] = @"mgb_boot",
|
||||
[GB_BOOT_ROM_SGB] = @"sgb_boot",
|
||||
[GB_BOOT_ROM_SGB2] = @"sgb2_boot",
|
||||
[GB_BOOT_ROM_CGB0] = @"cgb0_boot",
|
||||
[GB_BOOT_ROM_CGB] = @"cgb_boot",
|
||||
[GB_BOOT_ROM_AGB] = @"agb_boot",
|
||||
};
|
||||
GB_load_boot_rom(&gb, [[self bootROMPathForName:names[type]] UTF8String]);
|
||||
}
|
||||
|
||||
- (IBAction)reset:(id)sender
|
||||
|
@ -25,14 +25,11 @@
|
||||
<outlet property="memoryBankItem" destination="bWC-FW-IYP" id="Lf2-dh-z32"/>
|
||||
<outlet property="memoryView" destination="8hr-8o-3rN" id="fF0-rh-8ND"/>
|
||||
<outlet property="memoryWindow" destination="mRm-dL-mCj" id="VPR-lu-vtI"/>
|
||||
<outlet property="paletteTableView" destination="gfC-d3-dmq" id="fTC-eL-Qg3"/>
|
||||
<outlet property="printerFeedWindow" destination="NdE-0B-WCf" id="yVK-cS-NOJ"/>
|
||||
<outlet property="spritesTableView" destination="TOc-XJ-w9w" id="O4R-4Z-9hU"/>
|
||||
<outlet property="tilemapImageView" destination="LlK-tV-bjv" id="nSY-Xd-BjZ"/>
|
||||
<outlet property="tilemapMapButton" destination="YIJ-Qc-SIZ" id="BB7-Gg-7XP"/>
|
||||
<outlet property="tilemapPaletteButton" destination="loB-0k-Qff" id="2Or-7l-6vn"/>
|
||||
<outlet property="tilesetImageView" destination="QcQ-ex-36R" id="8SY-Ag-eIf"/>
|
||||
<outlet property="tilesetPaletteButton" destination="TLv-xS-X5K" id="uE2-K1-5sj"/>
|
||||
<outlet property="view" destination="uqf-pe-VAF" id="HMP-rf-Yqk"/>
|
||||
<outlet property="vramStatusLabel" destination="6vK-IP-PmP" id="A2d-dI-R3J"/>
|
||||
<outlet property="vramTabView" destination="AZz-Mh-rPA" id="ZCG-SP-Lfw"/>
|
||||
@ -250,7 +247,7 @@
|
||||
<popUpButton key="view" verticalHuggingPriority="750" id="vfJ-vu-gqJ">
|
||||
<rect key="frame" x="0.0" y="14" width="128" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bpD-j9-omo">
|
||||
<popUpButtonCell key="cell" type="roundTextured" title="Entire Space" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="border" imageScaling="proportionallyDown" inset="2" selectedItem="Zp5-J9-dd3" id="bpD-j9-omo">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="gTX-6Z-mOH">
|
||||
@ -258,7 +255,6 @@
|
||||
<menuItem title="Entire Space" id="Zp5-J9-dd3"/>
|
||||
<menuItem title="ROM" tag="1" id="ANn-pq-5SA"/>
|
||||
<menuItem title="Video RAM" tag="2" id="m35-GY-cKE"/>
|
||||
<menuItem title="Cartridge RAM" tag="3" id="AOc-Up-PNm"/>
|
||||
<menuItem title="RAM" tag="4" id="dg4-zf-bo4"/>
|
||||
</items>
|
||||
</menu>
|
||||
@ -341,7 +337,7 @@
|
||||
<font key="font" metaFont="system"/>
|
||||
<tabViewItems>
|
||||
<tabViewItem label="Tileset" identifier="1" id="pXb-od-Wb1">
|
||||
<view key="view" ambiguous="YES" id="lCG-Gt-XMF">
|
||||
<view key="view" id="lCG-Gt-XMF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
@ -354,38 +350,6 @@
|
||||
<outlet property="delegate" destination="-2" id="xoo-Uo-872"/>
|
||||
</connections>
|
||||
</imageView>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TLv-xS-X5K">
|
||||
<rect key="frame" x="4" y="388" width="128" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundRect" title="None" bezelStyle="roundedRect" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" selectedItem="G8p-CH-PlV" id="1jI-s4-4YY">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<menu key="menu" id="S6C-6Y-U3e">
|
||||
<items>
|
||||
<menuItem title="None" state="on" id="G8p-CH-PlV"/>
|
||||
<menuItem title="Background Palette 0" id="Vf5-1r-wB0"/>
|
||||
<menuItem title="Background Palette 1" id="Hnm-oM-jIq"/>
|
||||
<menuItem title="Background Palette 2" id="IBU-wD-IfI"/>
|
||||
<menuItem title="Background Palette 3" id="Pje-be-VHT"/>
|
||||
<menuItem title="Background Palette 4" id="E1K-4g-hvR"/>
|
||||
<menuItem title="Background Palette 5" id="juQ-bJ-lIt"/>
|
||||
<menuItem title="Background Palette 6" id="T1z-Jc-wIg"/>
|
||||
<menuItem title="Background Palette 7" id="oxC-qV-3EG"/>
|
||||
<menuItem title="Object Palette 0" id="nnZ-qm-fjY"/>
|
||||
<menuItem title="Object Palette 1" id="B9u-1l-0j9"/>
|
||||
<menuItem title="Object Palette 2" id="XVN-y3-Wp5"/>
|
||||
<menuItem title="Object Palette 3" id="bDp-1h-ShO"/>
|
||||
<menuItem title="Object Palette 4" id="Idr-Th-IVi"/>
|
||||
<menuItem title="Object Palette 5" id="NRU-gL-bIa"/>
|
||||
<menuItem title="Object Palette 6" id="HtN-zW-2PB"/>
|
||||
<menuItem title="Object Palette 7" id="HWA-Tl-Egd"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="reloadVRAMData:" target="-2" id="Qtf-p4-Rqh"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fL6-2S-Rgd">
|
||||
<rect key="frame" x="452" y="388" width="56" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
@ -425,41 +389,8 @@
|
||||
<outlet property="delegate" destination="-2" id="EAG-Zh-oRi"/>
|
||||
</connections>
|
||||
</imageView>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="loB-0k-Qff">
|
||||
<rect key="frame" x="4" y="388" width="128" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundRect" title="Effective Palettes" bezelStyle="roundedRect" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" selectedItem="oUH-Sa-Ec1" id="Eij-Cp-URa">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<menu key="menu" id="KYk-85-hF3">
|
||||
<items>
|
||||
<menuItem title="None" id="BhZ-lk-ned"/>
|
||||
<menuItem title="Effective Palettes" state="on" id="oUH-Sa-Ec1"/>
|
||||
<menuItem title="Background Palette 0" id="q5g-HD-mPF"/>
|
||||
<menuItem title="Background Palette 1" id="1qY-bS-27N"/>
|
||||
<menuItem title="Background Palette 2" id="4JV-8v-9q6"/>
|
||||
<menuItem title="Background Palette 3" id="58P-TR-RjD"/>
|
||||
<menuItem title="Background Palette 4" id="voq-Pf-ZKh"/>
|
||||
<menuItem title="Background Palette 5" id="e7w-HT-Q5N"/>
|
||||
<menuItem title="Background Palette 6" id="Tgx-oy-4YI"/>
|
||||
<menuItem title="Background Palette 7" id="3lv-Bj-iqf"/>
|
||||
<menuItem title="Object Palette 0" id="z29-eH-Mq8"/>
|
||||
<menuItem title="Object Palette 1" id="2Ef-30-IRL"/>
|
||||
<menuItem title="Object Palette 2" id="Rrs-nT-Zpe"/>
|
||||
<menuItem title="Object Palette 3" id="C1P-ei-elS"/>
|
||||
<menuItem title="Object Palette 4" id="DeX-Ey-45n"/>
|
||||
<menuItem title="Object Palette 5" id="luQ-S6-lpg"/>
|
||||
<menuItem title="Object Palette 6" id="pWP-64-0lY"/>
|
||||
<menuItem title="Object Palette 7" id="qGs-73-oac"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="reloadVRAMData:" target="-2" id="BmB-JE-W8g"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="YIJ-Qc-SIZ">
|
||||
<rect key="frame" x="135" y="388" width="96" height="17"/>
|
||||
<rect key="frame" x="4" y="388" width="96" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundRect" title="Effective Tilemap" bezelStyle="roundedRect" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" selectedItem="XRF-Vj-3gs" id="3W1-Db-wDn">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
@ -477,7 +408,7 @@
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="k4c-Vg-MBu">
|
||||
<rect key="frame" x="235" y="388" width="96" height="17"/>
|
||||
<rect key="frame" x="104" y="388" width="96" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundRect" title="Effective Tileset" bezelStyle="roundedRect" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" selectedItem="CRe-dX-rzY" id="h53-sb-Odg">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
@ -498,7 +429,7 @@
|
||||
</view>
|
||||
</tabViewItem>
|
||||
<tabViewItem label="Sprites" identifier="" id="a08-eg-Maw">
|
||||
<view key="view" id="EiO-p0-3xn">
|
||||
<view key="view" ambiguous="YES" id="EiO-p0-3xn">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
@ -507,7 +438,7 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" id="3VT-AA-xVT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="none" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="18" headerView="of1-KC-dXC" id="TOc-XJ-w9w">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="391"/>
|
||||
@ -641,111 +572,6 @@
|
||||
</subviews>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
<tabViewItem label="Palettes" identifier="" id="vLb-Nh-UYE">
|
||||
<view key="view" id="qIg-ci-WTA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="20" horizontalPageScroll="10" verticalLineScroll="20" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" usesPredominantAxisScrolling="NO" horizontalScrollElasticity="none" verticalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="iSs-Ow-wwb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" id="bP9-su-zQw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="18" id="gfC-d3-dmq">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableViewGridLines key="gridStyleMask" dashed="YES"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="125" minWidth="40" maxWidth="1000" id="Aje-FQ-fUw">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" title="Text Cell" id="Ygb-xo-X8v">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="93" minWidth="40" maxWidth="1000" id="4EN-0j-lda">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" title="Text Cell" id="3a2-A4-XQW" customClass="GBColorCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="93" minWidth="10" maxWidth="3.4028234663852886e+38" id="syl-os-nSf">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" alignment="left" title="Text Cell" id="3ql-bn-AxP" customClass="GBColorCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="93" minWidth="10" maxWidth="3.4028234663852886e+38" id="Qw3-u2-c1s">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" title="Text Cell" id="9at-mH-PWc" customClass="GBColorCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="93" minWidth="10" maxWidth="3.4028234663852886e+38" id="gTl-gN-qLn">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" alignment="left" title="Text Cell" id="dY8-Zu-d4t" customClass="GBColorCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="-2" id="F2f-nK-QTN"/>
|
||||
<outlet property="delegate" destination="-2" id="7hn-MM-DDD"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="OS3-sw-bjv">
|
||||
<rect key="frame" x="-100" y="-100" width="510" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="4HA-2m-8TZ">
|
||||
<rect key="frame" x="-100" y="-100" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
</tabViewItems>
|
||||
</tabView>
|
||||
</subviews>
|
||||
@ -755,10 +581,10 @@
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="hnI-48-dYt"/>
|
||||
<toolbarItem implicitItemIdentifier="B9D3CF98-8020-4389-9372-F99361440794" label="" paletteLabel="" id="fmK-Jl-Koj">
|
||||
<nil key="toolTip"/>
|
||||
<size key="minSize" width="100" height="25"/>
|
||||
<size key="maxSize" width="268" height="25"/>
|
||||
<size key="minSize" width="100" height="24"/>
|
||||
<size key="maxSize" width="213" height="25"/>
|
||||
<segmentedControl key="view" verticalHuggingPriority="750" id="Aul-vO-dCK">
|
||||
<rect key="frame" x="0.0" y="14" width="268" height="25"/>
|
||||
<rect key="frame" x="0.0" y="14" width="213" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<segmentedCell key="cell" borderStyle="border" alignment="left" style="texturedSquare" trackingMode="selectOne" id="HhR-ky-5NN">
|
||||
<font key="font" metaFont="system"/>
|
||||
@ -766,7 +592,6 @@
|
||||
<segment label="Tileset" selected="YES"/>
|
||||
<segment label="Tilemap" tag="1"/>
|
||||
<segment label="Sprites"/>
|
||||
<segment label="Palettes"/>
|
||||
</segments>
|
||||
</segmentedCell>
|
||||
</segmentedControl>
|
||||
@ -978,7 +803,7 @@
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" id="mzf-yu-RID">
|
||||
<rect key="frame" x="1" y="0.0" width="398" height="274"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="none" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" headerView="pvX-uJ-qK5" id="tA3-8T-bxb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="398" height="249"/>
|
||||
|
@ -316,31 +316,6 @@
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="5GS-tt-E0a"/>
|
||||
<menuItem title="Game Boy" tag="1" id="g7C-LA-VAr">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="reset:" target="-1" id="rxG-cz-s1S"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Super Game Boy" tag="4" id="vc7-yy-ARW">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="reset:" target="-1" id="E4M-QG-ua9"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Game Boy Color" tag="2" id="hdG-Bl-8nJ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="reset:" target="-1" id="xAz-cr-0u2"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Game Boy Advance" tag="3" id="7jw-B1-tf5">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="reset:" target="-1" id="xQk-4e-kd7"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="DPb-Sh-5tg"/>
|
||||
<menuItem title="Mute Sound" keyEquivalent="m" id="1UK-8n-QPP">
|
||||
<connections>
|
||||
<action selector="mute:" target="-1" id="YE5-mi-Yzd"/>
|
||||
@ -377,9 +352,9 @@
|
||||
<action selector="disconnectAllAccessories:" target="-1" id="5hY-9U-nRn"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Game Link Cable & Infrared" id="V4S-Fo-xJK">
|
||||
<menuItem title="Game Link Cable" id="V4S-Fo-xJK">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Game Link Cable & Infrared" id="6sJ-Wz-QLj">
|
||||
<menu key="submenu" title="Game Link Cable" id="6sJ-Wz-QLj">
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="PMY-5j-25T"/>
|
||||
</connections>
|
||||
@ -394,12 +369,6 @@
|
||||
<action selector="connectPrinter:" target="-1" id="tl1-CL-tAw"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Workboy" id="lo9-CX-BJj">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="connectWorkboy:" target="-1" id="6vS-bq-wAX"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
|
@ -60,16 +60,10 @@
|
||||
<connections>
|
||||
<outlet property="analogControlsCheckbox" destination="RuW-Db-dzW" id="FRE-hI-mnU"/>
|
||||
<outlet property="aspectRatioCheckbox" destination="Vfj-tg-7OP" id="Yw0-xS-DBr"/>
|
||||
<outlet property="bootROMsButton" destination="T3Y-Ln-Onl" id="tdL-Yv-E2K"/>
|
||||
<outlet property="bootROMsFolderItem" destination="Dzv-Gc-zoL" id="yhV-ZI-avD"/>
|
||||
<outlet property="cgbPopupButton" destination="dlD-sk-SHO" id="4tg-SR-e17"/>
|
||||
<outlet property="colorCorrectionPopupButton" destination="VEz-N4-uP6" id="EO2-Vt-JFJ"/>
|
||||
<outlet property="colorPalettePopupButton" destination="Iwr-eI-SD1" id="Xzc-RZ-JtV"/>
|
||||
<outlet property="configureJoypadButton" destination="Qa7-Z7-yfO" id="RaX-P3-oCX"/>
|
||||
<outlet property="controlsTableView" destination="UDd-IJ-fxX" id="a1D-Md-yXv"/>
|
||||
<outlet property="delegate" destination="-2" id="ASc-vN-Zbq"/>
|
||||
<outlet property="displayBorderPopupButton" destination="R9D-FV-bpd" id="VfO-b4-gqH"/>
|
||||
<outlet property="dmgPopupButton" destination="LFw-Uk-cPR" id="KDw-i2-k4u"/>
|
||||
<outlet property="frameBlendingModePopupButton" destination="lxk-db-Sxv" id="wzt-uo-TE6"/>
|
||||
<outlet property="graphicsFilterPopupButton" destination="6pP-kK-EEC" id="LS7-HY-kHC"/>
|
||||
<outlet property="highpassFilterPopupButton" destination="T69-6N-dhT" id="0p6-4m-hb1"/>
|
||||
@ -77,17 +71,16 @@
|
||||
<outlet property="preferredJoypadButton" destination="0Az-0R-oNw" id="7JM-tw-BhK"/>
|
||||
<outlet property="rewindPopupButton" destination="7fg-Ww-JjR" id="Ka2-TP-B1x"/>
|
||||
<outlet property="rumbleModePopupButton" destination="Ogs-xG-b4b" id="vuw-VN-MTp"/>
|
||||
<outlet property="sgbPopupButton" destination="dza-T7-RkX" id="B0o-Nb-pIH"/>
|
||||
<outlet property="skipButton" destination="d2I-jU-sLb" id="udX-8K-0sK"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="183" y="354"/>
|
||||
</window>
|
||||
<customView id="sRK-wO-K6R">
|
||||
<rect key="frame" x="0.0" y="0.0" width="292" height="323"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="292" height="215"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T91-rh-rRp">
|
||||
<rect key="frame" x="18" y="286" width="256" height="17"/>
|
||||
<rect key="frame" x="18" y="178" width="256" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Graphics filter:" id="pXg-WY-8Q5">
|
||||
<font key="font" metaFont="system"/>
|
||||
@ -96,7 +89,7 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6pP-kK-EEC">
|
||||
<rect key="frame" x="30" y="254" width="234" height="26"/>
|
||||
<rect key="frame" x="30" y="146" width="234" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Nearest neighbor (Pixelated)" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="neN-eo-LA7" id="I1w-05-lGl">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
@ -132,39 +125,8 @@
|
||||
<action selector="graphicFilterChanged:" target="QvC-M9-y7g" id="n87-t4-fbV"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wc3-2K-6CD">
|
||||
<rect key="frame" x="18" y="232" width="256" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Color correction:" id="5Si-hz-EK3">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VEz-N4-uP6">
|
||||
<rect key="frame" x="30" y="200" width="234" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Disabled" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="D2J-wV-1vu" id="fNJ-Fi-yOm">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="6go-Lb-a4m">
|
||||
<items>
|
||||
<menuItem title="Disabled" state="on" id="D2J-wV-1vu">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Correct color curves" id="B3Q-x1-VRl"/>
|
||||
<menuItem title="Emulate hardware" id="XBL-hS-7ke"/>
|
||||
<menuItem title="Preserve brightness" id="tlx-WB-Bkw"/>
|
||||
<menuItem title="Reduce contrast" id="wuO-Xv-0mQ"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="colorCorrectionChanged:" target="QvC-M9-y7g" id="Oq4-B5-nO6"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MLC-Rx-FgO">
|
||||
<rect key="frame" x="20" y="178" width="252" height="17"/>
|
||||
<rect key="frame" x="20" y="124" width="252" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Frame blending" id="UCa-EO-tzh">
|
||||
<font key="font" metaFont="system"/>
|
||||
@ -173,7 +135,7 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lxk-db-Sxv">
|
||||
<rect key="frame" x="32" y="149" width="229" height="22"/>
|
||||
<rect key="frame" x="32" y="95" width="229" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Disabled" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="iHP-Yz-fiH" id="aQ6-HN-7Aj">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
@ -193,16 +155,16 @@
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8fG-zm-hpr">
|
||||
<rect key="frame" x="18" y="122" width="252" height="17"/>
|
||||
<rect key="frame" x="18" y="68" width="252" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Color palette for monochrome models:" id="LAN-8Y-T7H">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Color palette:" id="LAN-8Y-T7H">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Iwr-eI-SD1">
|
||||
<rect key="frame" x="30" y="93" width="234" height="22"/>
|
||||
<rect key="frame" x="30" y="39" width="234" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Greyscale" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Ajr-5r-iIk" id="rEU-jh-m3j">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
@ -222,37 +184,8 @@
|
||||
<action selector="colorPaletteChanged:" target="QvC-M9-y7g" id="ui3-rg-PTs"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3Kz-cf-5X6">
|
||||
<rect key="frame" x="18" y="71" width="248" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Display border:" id="HZd-qi-yyk">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="R9D-FV-bpd">
|
||||
<rect key="frame" x="30" y="39" width="234" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Never" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="heL-AV-0az" id="DY9-2D-h1L">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="Rgf-mF-K9q">
|
||||
<items>
|
||||
<menuItem title="Never" state="on" tag="1" id="heL-AV-0az">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Super Game Boy only" id="bBJ-Vn-5rk"/>
|
||||
<menuItem title="Always" tag="2" id="JUs-gW-qcM"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="displayBorderChanged:" target="QvC-M9-y7g" id="GoA-BU-v3h"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vfj-tg-7OP">
|
||||
<rect key="frame" x="18" y="18" width="256" height="18"/>
|
||||
<rect key="frame" x="20" y="18" width="256" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" title="Keep aspect ratio" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="lsj-rC-Eo6">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
@ -263,14 +196,14 @@
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="-176" y="667.5"/>
|
||||
<point key="canvasLocation" x="-176" y="613.5"/>
|
||||
</customView>
|
||||
<customView id="ymk-46-SX7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="292" height="320"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="292" height="86"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7fg-Ww-JjR">
|
||||
<rect key="frame" x="30" y="193" width="234" height="26"/>
|
||||
<rect key="frame" x="30" y="17" width="234" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Disabled" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="lxQ-4n-kEv" id="lvb-QF-0Ht">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
@ -294,7 +227,7 @@
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="w9w-yX-KxB">
|
||||
<rect key="frame" x="18" y="225" width="256" height="17"/>
|
||||
<rect key="frame" x="18" y="49" width="256" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Rewinding duration:" id="JaO-5h-ugl">
|
||||
<font key="font" metaFont="system"/>
|
||||
@ -302,130 +235,8 @@
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MI2-ql-f6M">
|
||||
<rect key="frame" x="18" y="283" width="256" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Boot ROMs location:" id="nj0-Cb-gEA">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wC4-aJ-mhQ">
|
||||
<rect key="frame" x="30" y="251" width="234" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Use built-in boot ROMs" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Tnm-SR-ZEm" id="T3Y-Ln-Onl">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="edo-AN-gRh">
|
||||
<items>
|
||||
<menuItem title="Use built-in boot ROMs" state="on" id="Tnm-SR-ZEm">
|
||||
<connections>
|
||||
<action selector="useBuiltinBootROMs:" target="QvC-M9-y7g" id="Kmo-wz-ZtB"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem id="Dzv-Gc-zoL"/>
|
||||
<menuItem isSeparatorItem="YES" id="BqG-uI-xqE"/>
|
||||
<menuItem title="Other..." id="ikb-cd-hZe">
|
||||
<connections>
|
||||
<action selector="selectOtherBootROMFolder:" target="QvC-M9-y7g" id="ofn-ll-0bo"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wg8-hJ-df9">
|
||||
<rect key="frame" x="18" y="157" width="256" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Game Boy revision:" id="GIA-ep-SBi">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LFw-Uk-cPR">
|
||||
<rect key="frame" x="30" y="125" width="234" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="DMG-CPU B" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="2" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" selectedItem="aXT-sE-m5Z" id="FuX-Hc-uO7">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" autoenablesItems="NO" id="R0h-k6-Q5l">
|
||||
<items>
|
||||
<menuItem title="DMG-CPU 0" enabled="NO" id="pvp-Mo-9S8"/>
|
||||
<menuItem title="DMG-CPU A" tag="1" enabled="NO" id="QLn-5i-Vlg"/>
|
||||
<menuItem title="DMG-CPU B" state="on" tag="2" id="aXT-sE-m5Z"/>
|
||||
<menuItem title="DMG-CPU C" tag="3" enabled="NO" id="Ecl-YM-oAA"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="dmgModelChanged:" target="QvC-M9-y7g" id="FIe-Wz-aSc"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MAq-1X-Gpo">
|
||||
<rect key="frame" x="18" y="49" width="256" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Game Boy Color revision:" id="edD-t7-vwk">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dlD-sk-SHO">
|
||||
<rect key="frame" x="30" y="17" width="234" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="CPU-CGB E" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="517" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" selectedItem="3lF-1Q-2SS" id="Edt-1S-dXz">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" autoenablesItems="NO" id="bbF-hB-Hv7">
|
||||
<items>
|
||||
<menuItem title="CPU-CGB 0" tag="512" enabled="NO" id="2Uk-u3-6Gw"/>
|
||||
<menuItem title="CPU-CGB A" tag="513" enabled="NO" id="axv-yk-RWM"/>
|
||||
<menuItem title="CPU-CGB B" tag="514" enabled="NO" id="NtJ-oo-IM2"/>
|
||||
<menuItem title="CPU-CGB C (Experimental)" tag="515" id="9YL-u8-12z"/>
|
||||
<menuItem title="CPU-CGB D" tag="516" enabled="NO" id="c76-oF-fkU"/>
|
||||
<menuItem title="CPU-CGB E" state="on" tag="517" id="3lF-1Q-2SS"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="cgbModelChanged:" target="QvC-M9-y7g" id="SY1-oj-VWQ"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tAa-0A-0fP">
|
||||
<rect key="frame" x="18" y="103" width="256" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Super Game Boy model:" id="d0g-rk-FK0">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="mdm-eW-ia1">
|
||||
<rect key="frame" x="12" y="180" width="268" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</box>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dza-T7-RkX">
|
||||
<rect key="frame" x="30" y="71" width="234" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Super Game Boy (NTSC)" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="4" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" selectedItem="x5A-7f-ef9" id="2Mt-ci-bB0">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" autoenablesItems="NO" id="czw-Hi-jyM">
|
||||
<items>
|
||||
<menuItem title="Super Game Boy (NTSC)" state="on" tag="4" id="x5A-7f-ef9"/>
|
||||
<menuItem title="Super Game Boy (PAL)" tag="4100" id="Cix-n2-l4L"/>
|
||||
<menuItem title="Super Game Boy 2" tag="257" id="gZG-1g-KF0"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="sgbModelChanged:" target="QvC-M9-y7g" id="ybk-EV-WPS"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="-176" y="848"/>
|
||||
<point key="canvasLocation" x="-176" y="731"/>
|
||||
</customView>
|
||||
<customView id="Zn1-Y5-RbR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="292" height="86"/>
|
||||
@ -477,9 +288,9 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DZu-ts-deW">
|
||||
<rect key="frame" x="18" y="87" width="105" height="17"/>
|
||||
<rect key="frame" x="18" y="87" width="114" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Enable rumble:" id="QMX-3p-s1Z">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Controller rumble:" id="QMX-3p-s1Z">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
@ -603,14 +414,13 @@
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ogs-xG-b4b">
|
||||
<rect key="frame" x="30" y="58" width="245" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Never" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="jki-7x-bnM" id="o9b-MH-8kd">
|
||||
<popUpButtonCell key="cell" type="push" title="Disabled" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="jki-7x-bnM" id="o9b-MH-8kd">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="8p7-je-0Fh">
|
||||
<items>
|
||||
<menuItem title="Never" state="on" id="jki-7x-bnM"/>
|
||||
<menuItem title="For rumble-enabled Game Paks" tag="1" id="58e-Tp-TWd"/>
|
||||
<menuItem title="Always" tag="2" id="qVe-2b-W1P"/>
|
||||
<menuItem title="Disabled" state="on" id="jki-7x-bnM"/>
|
||||
<menuItem title="Enabled" tag="2" id="qVe-2b-W1P"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
|
@ -33,7 +33,6 @@ static uint16_t bank_for_addr(GB_gameboy_t *gb, uint16_t addr)
|
||||
void GB_apply_cheat(GB_gameboy_t *gb, uint16_t address, uint8_t *value)
|
||||
{
|
||||
if (!gb->cheat_enabled) return;
|
||||
if (!gb->boot_rom_finished) return;
|
||||
const GB_cheat_hash_t *hash = gb->cheat_hash[hash_addr(address)];
|
||||
if (hash) {
|
||||
for (unsigned i = 0; i < hash->size; i++) {
|
||||
|
115
Core/display.c
115
Core/display.c
@ -115,11 +115,6 @@ static void display_vblank(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->vblank_just_occured = true;
|
||||
|
||||
/* TODO: Slow in turbo mode! */
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
GB_sgb_render(gb);
|
||||
}
|
||||
|
||||
if (gb->turbo) {
|
||||
if (GB_timing_sync_turbo(gb)) {
|
||||
return;
|
||||
@ -155,51 +150,6 @@ static void display_vblank(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
|
||||
if (gb->border_mode == GB_BORDER_ALWAYS && !GB_is_sgb(gb)) {
|
||||
GB_borrow_sgb_border(gb);
|
||||
uint32_t border_colors[16 * 4];
|
||||
|
||||
if (!gb->has_sgb_border && GB_is_cgb(gb) && gb->model != GB_MODEL_AGB) {
|
||||
static uint16_t colors[] = {
|
||||
0x2095, 0x5129, 0x1EAF, 0x1EBA, 0x4648,
|
||||
0x30DA, 0x69AD, 0x2B57, 0x2B5D, 0x632C,
|
||||
0x1050, 0x3C84, 0x0E07, 0x0E18, 0x2964,
|
||||
};
|
||||
unsigned index = gb->rom? gb->rom[0x14e] % 5 : 0;
|
||||
gb->borrowed_border.palette[0] = colors[index];
|
||||
gb->borrowed_border.palette[10] = colors[5 + index];
|
||||
gb->borrowed_border.palette[14] = colors[10 + index];
|
||||
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 16 * 4; i++) {
|
||||
border_colors[i] = GB_convert_rgb15(gb, gb->borrowed_border.palette[i], true);
|
||||
}
|
||||
|
||||
for (unsigned tile_y = 0; tile_y < 28; tile_y++) {
|
||||
for (unsigned tile_x = 0; tile_x < 32; tile_x++) {
|
||||
if (tile_x >= 6 && tile_x < 26 && tile_y >= 5 && tile_y < 23) {
|
||||
continue;
|
||||
}
|
||||
uint16_t tile = gb->borrowed_border.map[tile_x + tile_y * 32];
|
||||
uint8_t flip_x = (tile & 0x4000)? 0x7 : 0;
|
||||
uint8_t flip_y = (tile & 0x8000)? 0x7 : 0;
|
||||
uint8_t palette = (tile >> 10) & 3;
|
||||
for (unsigned y = 0; y < 8; y++) {
|
||||
for (unsigned x = 0; x < 8; x++) {
|
||||
uint8_t color = gb->borrowed_border.tiles[(tile & 0xFF) * 64 + (x ^ flip_x) + (y ^ flip_y) * 8] & 0xF;
|
||||
uint32_t *output = gb->screen + tile_x * 8 + x + (tile_y * 8 + y) * 256;
|
||||
if (color == 0) {
|
||||
*output = border_colors[0];
|
||||
}
|
||||
else {
|
||||
*output = border_colors[color + palette * 16];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GB_handle_rumble(gb);
|
||||
|
||||
if (gb->vblank_callback) {
|
||||
@ -489,17 +439,7 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
|
||||
if (!gb->cgb_mode) {
|
||||
pixel = ((gb->io_registers[GB_IO_BGP] >> (pixel << 1)) & 3);
|
||||
}
|
||||
if (gb->sgb) {
|
||||
if (gb->current_lcd_line < LINES) {
|
||||
gb->sgb->screen_buffer[gb->lcd_x + gb->current_lcd_line * WIDTH] = gb->stopped? 0 : pixel;
|
||||
}
|
||||
}
|
||||
else if (gb->model & GB_MODEL_NO_SFC_BIT) {
|
||||
if (gb->icd_pixel_callback) {
|
||||
icd_pixel = pixel;
|
||||
}
|
||||
}
|
||||
else if (gb->cgb_palettes_ppu_blocked) {
|
||||
if (gb->cgb_palettes_ppu_blocked) {
|
||||
*dest = gb->rgb_encode_callback(gb, 0, 0, 0);
|
||||
}
|
||||
else {
|
||||
@ -513,18 +453,7 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
|
||||
/* Todo: Verify access timings */
|
||||
pixel = ((gb->io_registers[oam_fifo_item->palette? GB_IO_OBP1 : GB_IO_OBP0] >> (pixel << 1)) & 3);
|
||||
}
|
||||
if (gb->sgb) {
|
||||
if (gb->current_lcd_line < LINES) {
|
||||
gb->sgb->screen_buffer[gb->lcd_x + gb->current_lcd_line * WIDTH] = gb->stopped? 0 : pixel;
|
||||
}
|
||||
}
|
||||
else if (gb->model & GB_MODEL_NO_SFC_BIT) {
|
||||
if (gb->icd_pixel_callback) {
|
||||
icd_pixel = pixel;
|
||||
//gb->icd_pixel_callback(gb, pixel);
|
||||
}
|
||||
}
|
||||
else if (gb->cgb_palettes_ppu_blocked) {
|
||||
if (gb->cgb_palettes_ppu_blocked) {
|
||||
*dest = gb->rgb_encode_callback(gb, 0, 0, 0);
|
||||
}
|
||||
else {
|
||||
@ -1304,25 +1233,10 @@ abort_fetching_object:
|
||||
|
||||
void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index)
|
||||
{
|
||||
uint32_t none_palette[4];
|
||||
uint32_t *palette = NULL;
|
||||
|
||||
switch (GB_is_cgb(gb)? palette_type : GB_PALETTE_NONE) {
|
||||
default:
|
||||
case GB_PALETTE_NONE:
|
||||
none_palette[0] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF);
|
||||
none_palette[1] = gb->rgb_encode_callback(gb, 0xAA, 0xAA, 0xAA);
|
||||
none_palette[2] = gb->rgb_encode_callback(gb, 0x55, 0x55, 0x55);
|
||||
none_palette[3] = gb->rgb_encode_callback(gb, 0, 0, 0 );
|
||||
palette = none_palette;
|
||||
break;
|
||||
case GB_PALETTE_BACKGROUND:
|
||||
palette = gb->background_palettes_rgb + (4 * (palette_index & 7));
|
||||
break;
|
||||
case GB_PALETTE_OAM:
|
||||
palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7));
|
||||
break;
|
||||
}
|
||||
palette = gb->background_palettes_rgb;
|
||||
|
||||
|
||||
for (unsigned y = 0; y < 192; y++) {
|
||||
for (unsigned x = 0; x < 256; x++) {
|
||||
@ -1354,28 +1268,9 @@ void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette
|
||||
|
||||
void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index, GB_map_type_t map_type, GB_tileset_type_t tileset_type)
|
||||
{
|
||||
uint32_t none_palette[4];
|
||||
uint32_t *palette = NULL;
|
||||
uint32_t *palette = gb->background_palettes_rgb;
|
||||
uint16_t map = 0x1800;
|
||||
|
||||
switch (GB_is_cgb(gb)? palette_type : GB_PALETTE_NONE) {
|
||||
case GB_PALETTE_NONE:
|
||||
none_palette[0] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF);
|
||||
none_palette[1] = gb->rgb_encode_callback(gb, 0xAA, 0xAA, 0xAA);
|
||||
none_palette[2] = gb->rgb_encode_callback(gb, 0x55, 0x55, 0x55);
|
||||
none_palette[3] = gb->rgb_encode_callback(gb, 0, 0, 0 );
|
||||
palette = none_palette;
|
||||
break;
|
||||
case GB_PALETTE_BACKGROUND:
|
||||
palette = gb->background_palettes_rgb + (4 * (palette_index & 7));
|
||||
break;
|
||||
case GB_PALETTE_OAM:
|
||||
palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7));
|
||||
break;
|
||||
case GB_PALETTE_AUTO:
|
||||
break;
|
||||
}
|
||||
|
||||
if (map_type == GB_MAP_9C00 || (map_type == GB_MAP_AUTO && gb->io_registers[GB_IO_LCDC] & 0x04)) {
|
||||
map = 0x1c00;
|
||||
}
|
||||
|
176
Core/gb.c
176
Core/gb.c
@ -108,44 +108,9 @@ static char *default_async_input_callback(GB_gameboy_t *gb)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void load_default_border(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->has_sgb_border) return;
|
||||
|
||||
#define LOAD_BORDER() do { \
|
||||
memcpy(gb->borrowed_border.map, tilemap, sizeof(tilemap));\
|
||||
memcpy(gb->borrowed_border.palette, palette, sizeof(palette));\
|
||||
\
|
||||
/* Expand tileset */\
|
||||
for (unsigned tile = 0; tile < sizeof(tiles) / 32; tile++) {\
|
||||
for (unsigned y = 0; y < 8; y++) {\
|
||||
for (unsigned x = 0; x < 8; x++) {\
|
||||
gb->borrowed_border.tiles[tile * 8 * 8 + y * 8 + x] =\
|
||||
(tiles[tile * 32 + y * 2 + 0] & (1 << (7 ^ x)) ? 1 : 0) |\
|
||||
(tiles[tile * 32 + y * 2 + 1] & (1 << (7 ^ x)) ? 2 : 0) |\
|
||||
(tiles[tile * 32 + y * 2 + 16] & (1 << (7 ^ x)) ? 4 : 0) |\
|
||||
(tiles[tile * 32 + y * 2 + 17] & (1 << (7 ^ x)) ? 8 : 0);\
|
||||
}\
|
||||
}\
|
||||
}\
|
||||
} while (false);
|
||||
|
||||
if (gb->model == GB_MODEL_AGB) {
|
||||
#include "graphics/agb_border.inc"
|
||||
LOAD_BORDER();
|
||||
}
|
||||
else if (GB_is_cgb(gb)) {
|
||||
#include "graphics/cgb_border.inc"
|
||||
LOAD_BORDER();
|
||||
}
|
||||
else {
|
||||
#include "graphics/dmg_border.inc"
|
||||
LOAD_BORDER();
|
||||
}
|
||||
}
|
||||
|
||||
void GB_init(GB_gameboy_t *gb, GB_model_t model)
|
||||
{
|
||||
model = GB_MODEL_DMG_B;
|
||||
memset(gb, 0, sizeof(*gb));
|
||||
gb->model = model;
|
||||
if (GB_is_cgb(gb)) {
|
||||
@ -169,7 +134,6 @@ void GB_init(GB_gameboy_t *gb, GB_model_t model)
|
||||
}
|
||||
|
||||
GB_reset(gb);
|
||||
load_default_border(gb);
|
||||
}
|
||||
|
||||
GB_model_t GB_get_model(GB_gameboy_t *gb)
|
||||
@ -192,9 +156,6 @@ void GB_free(GB_gameboy_t *gb)
|
||||
if (gb->breakpoints) {
|
||||
free(gb->breakpoints);
|
||||
}
|
||||
if (gb->sgb) {
|
||||
free(gb->sgb);
|
||||
}
|
||||
if (gb->nontrivial_jump_state) {
|
||||
free(gb->nontrivial_jump_state);
|
||||
}
|
||||
@ -212,62 +173,11 @@ void GB_free(GB_gameboy_t *gb)
|
||||
|
||||
int GB_load_boot_rom(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f) {
|
||||
GB_log(gb, "Could not open boot ROM: %s.\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
fread(gb->boot_rom, sizeof(gb->boot_rom), 1, f);
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size)
|
||||
{
|
||||
if (size > sizeof(gb->boot_rom)) {
|
||||
size = sizeof(gb->boot_rom);
|
||||
}
|
||||
memset(gb->boot_rom, 0xFF, sizeof(gb->boot_rom));
|
||||
memcpy(gb->boot_rom, buffer, size);
|
||||
}
|
||||
|
||||
void GB_borrow_sgb_border(GB_gameboy_t *gb)
|
||||
{
|
||||
if (GB_is_sgb(gb)) return;
|
||||
if (gb->border_mode != GB_BORDER_ALWAYS) return;
|
||||
if (gb->tried_loading_sgb_border) return;
|
||||
gb->tried_loading_sgb_border = true;
|
||||
if (gb->rom && gb->rom[0x146] != 3) return; // Not an SGB game, nothing to borrow
|
||||
if (!gb->boot_rom_load_callback) return; // Can't borrow a border without this callback
|
||||
GB_gameboy_t sgb;
|
||||
GB_init(&sgb, GB_MODEL_SGB);
|
||||
sgb.rom = gb->rom;
|
||||
sgb.rom_size = gb->rom_size;
|
||||
sgb.turbo = true;
|
||||
sgb.turbo_dont_skip = true;
|
||||
// sgb.disable_rendering = true;
|
||||
|
||||
/* Load the boot ROM using the existing gb object */
|
||||
typeof(gb->boot_rom) boot_rom_backup;
|
||||
memcpy(boot_rom_backup, gb->boot_rom, sizeof(gb->boot_rom));
|
||||
gb->boot_rom_load_callback(gb, GB_BOOT_ROM_SGB);
|
||||
memcpy(sgb.boot_rom, gb->boot_rom, sizeof(gb->boot_rom));
|
||||
memcpy(gb->boot_rom, boot_rom_backup, sizeof(gb->boot_rom));
|
||||
sgb.sgb->intro_animation = -1;
|
||||
|
||||
for (unsigned i = 600; i--;) {
|
||||
GB_run_frame(&sgb);
|
||||
if (sgb.sgb->border_animation) {
|
||||
gb->has_sgb_border = true;
|
||||
memcpy(&gb->borrowed_border, &sgb.sgb->pending_border, sizeof(gb->borrowed_border));
|
||||
gb->borrowed_border.palette[0] = sgb.sgb->effective_palettes[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sgb.rom = NULL;
|
||||
sgb.rom_size = 0;
|
||||
GB_free(&sgb);
|
||||
}
|
||||
|
||||
int GB_load_rom(GB_gameboy_t *gb, const char *path)
|
||||
@ -579,18 +489,6 @@ void GB_load_battery(GB_gameboy_t *gb, const char *path)
|
||||
uint8_t GB_run(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->vblank_just_occured = false;
|
||||
|
||||
if (gb->sgb && gb->sgb->intro_animation < 140) {
|
||||
/* On the SGB, the GB is halted after finishing the boot ROM.
|
||||
Then, after the boot animation is almost done, it's reset.
|
||||
Since the SGB HLE does not perform any header validity checks,
|
||||
we just halt the CPU (with hacky code) until the correct time.
|
||||
This ensures the Nintendo logo doesn't flash on screen, and
|
||||
the game does "run in background" while the animation is playing. */
|
||||
GB_display_run(gb, 228);
|
||||
gb->cycles_since_last_sync += 228;
|
||||
return 228;
|
||||
}
|
||||
|
||||
GB_debugger_run(gb);
|
||||
gb->cycles_since_run = 0;
|
||||
@ -772,21 +670,6 @@ bool GB_is_inited(GB_gameboy_t *gb)
|
||||
return gb->magic == state_magic();
|
||||
}
|
||||
|
||||
bool GB_is_cgb(GB_gameboy_t *gb)
|
||||
{
|
||||
return (gb->model & GB_MODEL_FAMILY_MASK) == GB_MODEL_CGB_FAMILY;
|
||||
}
|
||||
|
||||
bool GB_is_sgb(GB_gameboy_t *gb)
|
||||
{
|
||||
return (gb->model & ~GB_MODEL_PAL_BIT & ~GB_MODEL_NO_SFC_BIT) == GB_MODEL_SGB || (gb->model & ~GB_MODEL_NO_SFC_BIT) == GB_MODEL_SGB2;
|
||||
}
|
||||
|
||||
bool GB_is_hle_sgb(GB_gameboy_t *gb)
|
||||
{
|
||||
return (gb->model & ~GB_MODEL_PAL_BIT) == GB_MODEL_SGB || gb->model == GB_MODEL_SGB2;
|
||||
}
|
||||
|
||||
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip)
|
||||
{
|
||||
gb->turbo = on;
|
||||
@ -962,32 +845,7 @@ static void reset_ram(GB_gameboy_t *gb)
|
||||
|
||||
static void request_boot_rom(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->boot_rom_load_callback) {
|
||||
GB_boot_rom_t type = 0;
|
||||
switch (gb->model) {
|
||||
case GB_MODEL_DMG_B:
|
||||
type = GB_BOOT_ROM_DMG;
|
||||
break;
|
||||
case GB_MODEL_SGB_NTSC:
|
||||
case GB_MODEL_SGB_PAL:
|
||||
case GB_MODEL_SGB_NTSC_NO_SFC:
|
||||
case GB_MODEL_SGB_PAL_NO_SFC:
|
||||
type = GB_BOOT_ROM_SGB;
|
||||
break;
|
||||
case GB_MODEL_SGB2:
|
||||
case GB_MODEL_SGB2_NO_SFC:
|
||||
type = GB_BOOT_ROM_SGB2;
|
||||
break;
|
||||
case GB_MODEL_CGB_C:
|
||||
case GB_MODEL_CGB_E:
|
||||
type = GB_BOOT_ROM_CGB;
|
||||
break;
|
||||
case GB_MODEL_AGB:
|
||||
type = GB_BOOT_ROM_AGB;
|
||||
break;
|
||||
}
|
||||
gb->boot_rom_load_callback(gb, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GB_reset(GB_gameboy_t *gb)
|
||||
@ -1027,28 +885,6 @@ void GB_reset(GB_gameboy_t *gb)
|
||||
|
||||
gb->accessed_oam_row = -1;
|
||||
|
||||
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
if (!gb->sgb) {
|
||||
gb->sgb = malloc(sizeof(*gb->sgb));
|
||||
}
|
||||
memset(gb->sgb, 0, sizeof(*gb->sgb));
|
||||
memset(gb->sgb_intro_jingle_phases, 0, sizeof(gb->sgb_intro_jingle_phases));
|
||||
gb->sgb_intro_sweep_phase = 0;
|
||||
gb->sgb_intro_sweep_previous_sample = 0;
|
||||
gb->sgb->intro_animation = -10;
|
||||
|
||||
gb->sgb->player_count = 1;
|
||||
GB_sgb_load_default_data(gb);
|
||||
|
||||
}
|
||||
else {
|
||||
if (gb->sgb) {
|
||||
free(gb->sgb);
|
||||
gb->sgb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Todo: Ugly, fixme, see comment in the timer state machine */
|
||||
gb->div_state = 3;
|
||||
|
||||
@ -1065,6 +901,7 @@ void GB_reset(GB_gameboy_t *gb)
|
||||
|
||||
void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model)
|
||||
{
|
||||
model = GB_MODEL_DMG_B;
|
||||
gb->model = model;
|
||||
if (GB_is_cgb(gb)) {
|
||||
gb->ram = realloc(gb->ram, gb->ram_size = 0x1000 * 8);
|
||||
@ -1076,7 +913,6 @@ void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model)
|
||||
}
|
||||
GB_rewind_free(gb);
|
||||
GB_reset(gb);
|
||||
load_default_border(gb);
|
||||
}
|
||||
|
||||
void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *size, uint16_t *bank)
|
||||
@ -1119,9 +955,9 @@ void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *
|
||||
*bank = 0;
|
||||
return &gb->io_registers;
|
||||
case GB_DIRECT_ACCESS_BOOTROM:
|
||||
*size = GB_is_cgb(gb)? sizeof(gb->boot_rom) : 0x100;
|
||||
*size = 0;
|
||||
*bank = 0;
|
||||
return &gb->boot_rom;
|
||||
return NULL;
|
||||
case GB_DIRECT_ACCESS_OAM:
|
||||
*size = sizeof(gb->oam);
|
||||
*bank = 0;
|
||||
@ -1196,7 +1032,7 @@ unsigned GB_get_screen_height(GB_gameboy_t *gb)
|
||||
|
||||
unsigned GB_get_player_count(GB_gameboy_t *gb)
|
||||
{
|
||||
return GB_is_hle_sgb(gb)? gb->sgb->player_count : 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GB_set_update_input_hint_callback(GB_gameboy_t *gb, GB_update_input_hint_callback_t callback)
|
||||
|
18
Core/gb.h
18
Core/gb.h
@ -19,7 +19,6 @@
|
||||
#include "rewind.h"
|
||||
#include "sm83_cpu.h"
|
||||
#include "symbol_hash.h"
|
||||
#include "sgb.h"
|
||||
#include "cheats.h"
|
||||
#include "rumble.h"
|
||||
#include "workboy.h"
|
||||
@ -348,7 +347,6 @@ struct GB_gameboy_internal_s {
|
||||
bool cgb_double_speed;
|
||||
bool halted;
|
||||
bool stopped;
|
||||
bool boot_rom_finished;
|
||||
bool ime_toggle; /* ei has delayed a effect.*/
|
||||
bool halt_bug;
|
||||
bool just_halted;
|
||||
@ -553,7 +551,6 @@ struct GB_gameboy_internal_s {
|
||||
GB_color_correction_mode_t color_correction_mode;
|
||||
bool keys[4][GB_KEY_MAX];
|
||||
GB_border_mode_t border_mode;
|
||||
GB_sgb_border_t borrowed_border;
|
||||
bool tried_loading_sgb_border;
|
||||
bool has_sgb_border;
|
||||
|
||||
@ -639,10 +636,7 @@ struct GB_gameboy_internal_s {
|
||||
unsigned pos;
|
||||
} *rewind_sequences; // lasts about 4 seconds
|
||||
size_t rewind_pos;
|
||||
|
||||
/* SGB - saved and allocated optionally */
|
||||
GB_sgb_t *sgb;
|
||||
|
||||
|
||||
double sgb_intro_jingle_phases[7];
|
||||
double sgb_intro_sweep_phase;
|
||||
double sgb_intro_sweep_previous_sample;
|
||||
@ -657,7 +651,6 @@ struct GB_gameboy_internal_s {
|
||||
bool turbo;
|
||||
bool turbo_dont_skip;
|
||||
bool disable_rendering;
|
||||
uint8_t boot_rom[0x900];
|
||||
bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank
|
||||
uint8_t cycles_since_run; // How many cycles have passed since the last call to GB_run(), in 8MHz units
|
||||
double clock_multiplier;
|
||||
@ -667,6 +660,9 @@ struct GB_gameboy_internal_s {
|
||||
|
||||
/* Temporary state */
|
||||
bool wx_just_changed;
|
||||
|
||||
/* For SmaeBoy-SameDuck source camptibility*/
|
||||
const void *sgb;
|
||||
);
|
||||
};
|
||||
|
||||
@ -685,9 +681,9 @@ __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
||||
|
||||
void GB_init(GB_gameboy_t *gb, GB_model_t model);
|
||||
bool GB_is_inited(GB_gameboy_t *gb);
|
||||
bool GB_is_cgb(GB_gameboy_t *gb);
|
||||
bool GB_is_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2
|
||||
bool GB_is_hle_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2 and the SFC/SNES side is HLE'd
|
||||
#define GB_is_cgb(x) false
|
||||
#define GB_is_sgb(x) false
|
||||
#define GB_is_hle_sgb(x) false
|
||||
GB_model_t GB_get_model(GB_gameboy_t *gb);
|
||||
void GB_free(GB_gameboy_t *gb);
|
||||
void GB_reset(GB_gameboy_t *gb);
|
||||
|
@ -12,16 +12,11 @@ void GB_update_joyp(GB_gameboy_t *gb)
|
||||
previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
|
||||
key_selection = (gb->io_registers[GB_IO_JOYP] >> 4) & 3;
|
||||
gb->io_registers[GB_IO_JOYP] &= 0xF0;
|
||||
uint8_t current_player = gb->sgb? (gb->sgb->current_player & (gb->sgb->player_count - 1) & 3) : 0;
|
||||
uint8_t current_player = 0;
|
||||
switch (key_selection) {
|
||||
case 3:
|
||||
if (gb->sgb && gb->sgb->player_count > 1) {
|
||||
gb->io_registers[GB_IO_JOYP] |= 0xF - current_player;
|
||||
}
|
||||
else {
|
||||
/* Nothing is wired, all up */
|
||||
gb->io_registers[GB_IO_JOYP] |= 0x0F;
|
||||
}
|
||||
/* Nothing is wired, all up */
|
||||
gb->io_registers[GB_IO_JOYP] |= 0x0F;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
@ -338,7 +338,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
||||
case GB_IO_BGPD:
|
||||
case GB_IO_OBPD:
|
||||
{
|
||||
if (!gb->cgb_mode && gb->boot_rom_finished) {
|
||||
if (!gb->cgb_mode) {
|
||||
return 0xFF;
|
||||
}
|
||||
if (gb->cgb_palettes_blocked) {
|
||||
@ -580,7 +580,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
gb->io_registers[addr & 0xFF] = value;
|
||||
return;
|
||||
case GB_IO_OPRI:
|
||||
if ((!gb->boot_rom_finished || (gb->io_registers[GB_IO_KEY0] & 8)) && GB_is_cgb(gb)) {
|
||||
if (((gb->io_registers[GB_IO_KEY0] & 8)) && GB_is_cgb(gb)) {
|
||||
gb->io_registers[addr & 0xFF] = value;
|
||||
gb->object_priority = (value & 1) ? GB_OBJECT_PRIORITY_X : GB_OBJECT_PRIORITY_INDEX;
|
||||
}
|
||||
@ -695,18 +695,16 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
GB_update_joyp(gb);
|
||||
}
|
||||
else if ((gb->io_registers[GB_IO_JOYP] & 0x30) != (value & 0x30)) {
|
||||
GB_sgb_write(gb, value);
|
||||
gb->io_registers[GB_IO_JOYP] = (value & 0xF0) | (gb->io_registers[GB_IO_JOYP] & 0x0F);
|
||||
GB_update_joyp(gb);
|
||||
}
|
||||
return;
|
||||
|
||||
case GB_IO_BANK:
|
||||
gb->boot_rom_finished = true;
|
||||
return;
|
||||
|
||||
case GB_IO_KEY0:
|
||||
if (GB_is_cgb(gb) && !gb->boot_rom_finished) {
|
||||
if (GB_is_cgb(gb)) {
|
||||
gb->cgb_mode = !(value & 0xC); /* The real "contents" of this register aren't quite known yet. */
|
||||
gb->io_registers[GB_IO_KEY0] = value;
|
||||
}
|
||||
@ -751,7 +749,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
return;
|
||||
case GB_IO_BGPD:
|
||||
case GB_IO_OBPD:
|
||||
if (!gb->cgb_mode && gb->boot_rom_finished) {
|
||||
if (!gb->cgb_mode) {
|
||||
/* Todo: Due to the behavior of a broken Game & Watch Gallery 2 ROM on a real CGB. A proper test ROM
|
||||
is required. */
|
||||
return;
|
||||
|
@ -36,10 +36,6 @@ int GB_save_state(GB_gameboy_t *gb, const char *path)
|
||||
if (!DUMP_SECTION(gb, f, rtc )) goto error;
|
||||
if (!DUMP_SECTION(gb, f, video )) goto error;
|
||||
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
if (!dump_section(f, gb->sgb, sizeof(*gb->sgb))) goto error;
|
||||
}
|
||||
|
||||
if (fwrite(gb->ram, 1, gb->ram_size, f) != gb->ram_size) {
|
||||
goto error;
|
||||
}
|
||||
@ -68,7 +64,6 @@ size_t GB_get_save_state_size(GB_gameboy_t *gb)
|
||||
+ GB_SECTION_SIZE(apu ) + sizeof(uint32_t)
|
||||
+ GB_SECTION_SIZE(rtc ) + sizeof(uint32_t)
|
||||
+ GB_SECTION_SIZE(video ) + sizeof(uint32_t)
|
||||
+ (GB_is_hle_sgb(gb)? sizeof(*gb->sgb) + sizeof(uint32_t) : 0)
|
||||
+ gb->ram_size
|
||||
+ gb->vram_size;
|
||||
}
|
||||
@ -99,10 +94,6 @@ void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer)
|
||||
DUMP_SECTION(gb, buffer, rtc );
|
||||
DUMP_SECTION(gb, buffer, video );
|
||||
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
buffer_dump_section(&buffer, gb->sgb, sizeof(*gb->sgb));
|
||||
}
|
||||
|
||||
|
||||
buffer_write(gb->ram, gb->ram_size, &buffer);
|
||||
buffer_write(gb->vram, gb->vram_size, &buffer);
|
||||
@ -250,10 +241,6 @@ int GB_load_state(GB_gameboy_t *gb, const char *path)
|
||||
errno = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
if (!read_section(f, gb->sgb, sizeof(*gb->sgb), false)) goto error;
|
||||
}
|
||||
|
||||
if (fread(gb->ram, 1, gb->ram_size, f) != gb->ram_size) {
|
||||
fclose(f);
|
||||
@ -364,10 +351,6 @@ int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t le
|
||||
if (!verify_and_update_state_compatibility(gb, &save)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (GB_is_hle_sgb(gb)) {
|
||||
if (!buffer_read_section(&buffer, &length, gb->sgb, sizeof(*gb->sgb), false)) return -1;
|
||||
}
|
||||
|
||||
if (buffer_read(gb->ram, gb->ram_size, &buffer, &length) != gb->ram_size) {
|
||||
return -1;
|
||||
|
913
Core/sgb.c
913
Core/sgb.c
@ -1,913 +0,0 @@
|
||||
#include "gb.h"
|
||||
#include "random.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#define INTRO_ANIMATION_LENGTH 200
|
||||
|
||||
enum {
|
||||
PAL01 = 0x00,
|
||||
PAL23 = 0x01,
|
||||
PAL03 = 0x02,
|
||||
PAL12 = 0x03,
|
||||
ATTR_BLK = 0x04,
|
||||
ATTR_LIN = 0x05,
|
||||
ATTR_DIV = 0x06,
|
||||
ATTR_CHR = 0x07,
|
||||
PAL_SET = 0x0A,
|
||||
PAL_TRN = 0x0B,
|
||||
DATA_SND = 0x0F,
|
||||
MLT_REQ = 0x11,
|
||||
CHR_TRN = 0x13,
|
||||
PCT_TRN = 0x14,
|
||||
ATTR_TRN = 0x15,
|
||||
ATTR_SET = 0x16,
|
||||
MASK_EN = 0x17,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
MASK_DISABLED,
|
||||
MASK_FREEZE,
|
||||
MASK_BLACK,
|
||||
MASK_COLOR_0,
|
||||
} mask_mode_t;
|
||||
|
||||
typedef enum {
|
||||
TRANSFER_LOW_TILES,
|
||||
TRANSFER_HIGH_TILES,
|
||||
TRANSFER_BORDER_DATA,
|
||||
TRANSFER_PALETTES,
|
||||
TRANSFER_ATTRIBUTES,
|
||||
} transfer_dest_t;
|
||||
|
||||
#define SGB_PACKET_SIZE 16
|
||||
static inline void pal_command(GB_gameboy_t *gb, unsigned first, unsigned second)
|
||||
{
|
||||
gb->sgb->effective_palettes[0] = gb->sgb->effective_palettes[4] =
|
||||
gb->sgb->effective_palettes[8] = gb->sgb->effective_palettes[12] =
|
||||
gb->sgb->command[1] | (gb->sgb->command[2] << 8);
|
||||
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
gb->sgb->effective_palettes[first * 4 + i + 1] = gb->sgb->command[3 + i * 2] | (gb->sgb->command[4 + i * 2] << 8);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
gb->sgb->effective_palettes[second * 4 + i + 1] = gb->sgb->command[9 + i * 2] | (gb->sgb->command[10 + i * 2] << 8);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void load_attribute_file(GB_gameboy_t *gb, unsigned file_index)
|
||||
{
|
||||
if (file_index > 0x2C) return;
|
||||
uint8_t *output = gb->sgb->attribute_map;
|
||||
for (unsigned i = 0; i < 90; i++) {
|
||||
uint8_t byte = gb->sgb->attribute_files[file_index * 90 + i];
|
||||
for (unsigned j = 4; j--;) {
|
||||
*(output++) = byte >> 6;
|
||||
byte <<= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const uint16_t built_in_palettes[] =
|
||||
{
|
||||
0x67BF, 0x265B, 0x10B5, 0x2866,
|
||||
0x637B, 0x3AD9, 0x0956, 0x0000,
|
||||
0x7F1F, 0x2A7D, 0x30F3, 0x4CE7,
|
||||
0x57FF, 0x2618, 0x001F, 0x006A,
|
||||
0x5B7F, 0x3F0F, 0x222D, 0x10EB,
|
||||
0x7FBB, 0x2A3C, 0x0015, 0x0900,
|
||||
0x2800, 0x7680, 0x01EF, 0x2FFF,
|
||||
0x73BF, 0x46FF, 0x0110, 0x0066,
|
||||
0x533E, 0x2638, 0x01E5, 0x0000,
|
||||
0x7FFF, 0x2BBF, 0x00DF, 0x2C0A,
|
||||
0x7F1F, 0x463D, 0x74CF, 0x4CA5,
|
||||
0x53FF, 0x03E0, 0x00DF, 0x2800,
|
||||
0x433F, 0x72D2, 0x3045, 0x0822,
|
||||
0x7FFA, 0x2A5F, 0x0014, 0x0003,
|
||||
0x1EED, 0x215C, 0x42FC, 0x0060,
|
||||
0x7FFF, 0x5EF7, 0x39CE, 0x0000,
|
||||
0x4F5F, 0x630E, 0x159F, 0x3126,
|
||||
0x637B, 0x121C, 0x0140, 0x0840,
|
||||
0x66BC, 0x3FFF, 0x7EE0, 0x2C84,
|
||||
0x5FFE, 0x3EBC, 0x0321, 0x0000,
|
||||
0x63FF, 0x36DC, 0x11F6, 0x392A,
|
||||
0x65EF, 0x7DBF, 0x035F, 0x2108,
|
||||
0x2B6C, 0x7FFF, 0x1CD9, 0x0007,
|
||||
0x53FC, 0x1F2F, 0x0E29, 0x0061,
|
||||
0x36BE, 0x7EAF, 0x681A, 0x3C00,
|
||||
0x7BBE, 0x329D, 0x1DE8, 0x0423,
|
||||
0x739F, 0x6A9B, 0x7293, 0x0001,
|
||||
0x5FFF, 0x6732, 0x3DA9, 0x2481,
|
||||
0x577F, 0x3EBC, 0x456F, 0x1880,
|
||||
0x6B57, 0x6E1B, 0x5010, 0x0007,
|
||||
0x0F96, 0x2C97, 0x0045, 0x3200,
|
||||
0x67FF, 0x2F17, 0x2230, 0x1548,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
char name[16];
|
||||
unsigned palette_index;
|
||||
} palette_assignments[] =
|
||||
{
|
||||
{"ZELDA", 5},
|
||||
{"SUPER MARIOLAND", 6},
|
||||
{"MARIOLAND2", 0x14},
|
||||
{"SUPERMARIOLAND3", 2},
|
||||
{"KIRBY DREAM LAND", 0xB},
|
||||
{"HOSHINOKA-BI", 0xB},
|
||||
{"KIRBY'S PINBALL", 3},
|
||||
{"YOSSY NO TAMAGO", 0xC},
|
||||
{"MARIO & YOSHI", 0xC},
|
||||
{"YOSSY NO COOKIE", 4},
|
||||
{"YOSHI'S COOKIE", 4},
|
||||
{"DR.MARIO", 0x12},
|
||||
{"TETRIS", 0x11},
|
||||
{"YAKUMAN", 0x13},
|
||||
{"METROID2", 0x1F},
|
||||
{"KAERUNOTAMENI", 9},
|
||||
{"GOLF", 0x18},
|
||||
{"ALLEY WAY", 0x16},
|
||||
{"BASEBALL", 0xF},
|
||||
{"TENNIS", 0x17},
|
||||
{"F1RACE", 0x1E},
|
||||
{"KID ICARUS", 0xE},
|
||||
{"QIX", 0x19},
|
||||
{"SOLARSTRIKER", 7},
|
||||
{"X", 0x1C},
|
||||
{"GBWARS", 0x15},
|
||||
};
|
||||
|
||||
static void command_ready(GB_gameboy_t *gb)
|
||||
{
|
||||
/* SGB header commands are used to send the contents of the header to the SNES CPU.
|
||||
A header command looks like this:
|
||||
Command ID: 0b1111xxx1, where xxx is the packet index. (e.g. F1 for [0x104, 0x112), F3 for [0x112, 0x120))
|
||||
Checksum: Simple one byte sum for the following content bytes
|
||||
0xE content bytes. The last command, FB, is padded with zeros, so information past the header is not sent. */
|
||||
|
||||
if ((gb->sgb->command[0] & 0xF1) == 0xF1) {
|
||||
if (gb->boot_rom_finished) return;
|
||||
|
||||
uint8_t checksum = 0;
|
||||
for (unsigned i = 2; i < 0x10; i++) {
|
||||
checksum += gb->sgb->command[i];
|
||||
}
|
||||
if (checksum != gb->sgb->command[1]) {
|
||||
GB_log(gb, "Failed checksum for SGB header command, disabling SGB features\n");
|
||||
gb->sgb->disable_commands = true;
|
||||
return;
|
||||
}
|
||||
unsigned index = (gb->sgb->command[0] >> 1) & 7;
|
||||
if (index > 5) {
|
||||
return;
|
||||
}
|
||||
memcpy(&gb->sgb->received_header[index * 14], &gb->sgb->command[2], 14);
|
||||
if (gb->sgb->command[0] == 0xfb) {
|
||||
if (gb->sgb->received_header[0x42] != 3 || gb->sgb->received_header[0x47] != 0x33) {
|
||||
gb->sgb->disable_commands = true;
|
||||
for (unsigned i = 0; i < sizeof(palette_assignments) / sizeof(palette_assignments[0]); i++) {
|
||||
if (memcmp(palette_assignments[i].name, &gb->sgb->received_header[0x30], sizeof(palette_assignments[i].name)) == 0) {
|
||||
gb->sgb->effective_palettes[0] = built_in_palettes[palette_assignments[i].palette_index * 4 - 4];
|
||||
gb->sgb->effective_palettes[1] = built_in_palettes[palette_assignments[i].palette_index * 4 + 1 - 4];
|
||||
gb->sgb->effective_palettes[2] = built_in_palettes[palette_assignments[i].palette_index * 4 + 2 - 4];
|
||||
gb->sgb->effective_palettes[3] = built_in_palettes[palette_assignments[i].palette_index * 4 + 3 - 4];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ignore malformed commands (0 length)*/
|
||||
if ((gb->sgb->command[0] & 7) == 0) return;
|
||||
|
||||
switch (gb->sgb->command[0] >> 3) {
|
||||
case PAL01:
|
||||
pal_command(gb, 0, 1);
|
||||
break;
|
||||
case PAL23:
|
||||
pal_command(gb, 2, 3);
|
||||
break;
|
||||
case PAL03:
|
||||
pal_command(gb, 0, 3);
|
||||
break;
|
||||
case PAL12:
|
||||
pal_command(gb, 1, 2);
|
||||
break;
|
||||
case ATTR_BLK: {
|
||||
struct {
|
||||
uint8_t count;
|
||||
struct {
|
||||
uint8_t control;
|
||||
uint8_t palettes;
|
||||
uint8_t left, top, right, bottom;
|
||||
} data[];
|
||||
} *command = (void *)(gb->sgb->command + 1);
|
||||
if (command->count > 0x12) return;
|
||||
|
||||
for (unsigned i = 0; i < command->count; i++) {
|
||||
bool inside = command->data[i].control & 1;
|
||||
bool middle = command->data[i].control & 2;
|
||||
bool outside = command->data[i].control & 4;
|
||||
uint8_t inside_palette = command->data[i].palettes & 0x3;
|
||||
uint8_t middle_palette = (command->data[i].palettes >> 2) & 0x3;
|
||||
uint8_t outside_palette = (command->data[i].palettes >> 4) & 0x3;
|
||||
|
||||
if (inside && !middle && !outside) {
|
||||
middle = true;
|
||||
middle_palette = inside_palette;
|
||||
}
|
||||
else if (outside && !middle && !inside) {
|
||||
middle = true;
|
||||
middle_palette = outside_palette;
|
||||
}
|
||||
|
||||
command->data[i].left &= 0x1F;
|
||||
command->data[i].top &= 0x1F;
|
||||
command->data[i].right &= 0x1F;
|
||||
command->data[i].bottom &= 0x1F;
|
||||
|
||||
for (unsigned y = 0; y < 18; y++) {
|
||||
for (unsigned x = 0; x < 20; x++) {
|
||||
if (x < command->data[i].left || x > command->data[i].right ||
|
||||
y < command->data[i].top || y > command->data[i].bottom) {
|
||||
if (outside) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = outside_palette;
|
||||
}
|
||||
}
|
||||
else if (x > command->data[i].left && x < command->data[i].right &&
|
||||
y > command->data[i].top && y < command->data[i].bottom) {
|
||||
if (inside) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = inside_palette;
|
||||
}
|
||||
}
|
||||
else if (middle) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = middle_palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_CHR: {
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t x, y;
|
||||
uint16_t length;
|
||||
uint8_t direction;
|
||||
uint8_t data[];
|
||||
} *command = (void *)(gb->sgb->command + 1);
|
||||
|
||||
uint16_t count = command->length;
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
count = __builtin_bswap16(count);
|
||||
#endif
|
||||
uint8_t x = command->x;
|
||||
uint8_t y = command->y;
|
||||
if (x >= 20 || y >= 18 || (count + 3) / 4 > sizeof(gb->sgb->command) - sizeof(*command) - 1) {
|
||||
/* TODO: Verify with the SFC BIOS */
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
uint8_t palette = (command->data[i / 4] >> (((~i) & 3) << 1)) & 3;
|
||||
gb->sgb->attribute_map[x + 20 * y] = palette;
|
||||
if (command->direction) {
|
||||
y++;
|
||||
if (y == 18) {
|
||||
x++;
|
||||
y = 0;
|
||||
if (x == 20) {
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
x++;
|
||||
if (x == 20) {
|
||||
y++;
|
||||
x = 0;
|
||||
if (y == 18) {
|
||||
y = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ATTR_LIN: {
|
||||
struct {
|
||||
uint8_t count;
|
||||
uint8_t data[];
|
||||
} *command = (void *)(gb->sgb->command + 1);
|
||||
if (command->count > sizeof(gb->sgb->command) - 2) return;
|
||||
|
||||
for (unsigned i = 0; i < command->count; i++) {
|
||||
bool horizontal = command->data[i] & 0x80;
|
||||
uint8_t palette = (command->data[i] >> 5) & 0x3;
|
||||
uint8_t line = (command->data[i]) & 0x1F;
|
||||
|
||||
if (horizontal) {
|
||||
if (line > 18) continue;
|
||||
for (unsigned x = 0; x < 20; x++) {
|
||||
gb->sgb->attribute_map[x + 20 * line] = palette;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (line > 20) continue;
|
||||
for (unsigned y = 0; y < 18; y++) {
|
||||
gb->sgb->attribute_map[line + 20 * y] = palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_DIV: {
|
||||
uint8_t high_palette = gb->sgb->command[1] & 3;
|
||||
uint8_t low_palette = (gb->sgb->command[1] >> 2) & 3;
|
||||
uint8_t middle_palette = (gb->sgb->command[1] >> 4) & 3;
|
||||
bool horizontal = gb->sgb->command[1] & 0x40;
|
||||
uint8_t line = gb->sgb->command[2] & 0x1F;
|
||||
|
||||
for (unsigned y = 0; y < 18; y++) {
|
||||
for (unsigned x = 0; x < 20; x++) {
|
||||
if ((horizontal? y : x) < line) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = low_palette;
|
||||
}
|
||||
else if ((horizontal? y : x) == line) {
|
||||
gb->sgb->attribute_map[x + 20 * y] = middle_palette;
|
||||
}
|
||||
else {
|
||||
gb->sgb->attribute_map[x + 20 * y] = high_palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PAL_SET:
|
||||
memcpy(&gb->sgb->effective_palettes[0],
|
||||
&gb->sgb->ram_palettes[4 * (gb->sgb->command[1] + (gb->sgb->command[2] & 1) * 0x100)],
|
||||
8);
|
||||
memcpy(&gb->sgb->effective_palettes[4],
|
||||
&gb->sgb->ram_palettes[4 * (gb->sgb->command[3] + (gb->sgb->command[4] & 1) * 0x100)],
|
||||
8);
|
||||
memcpy(&gb->sgb->effective_palettes[8],
|
||||
&gb->sgb->ram_palettes[4 * (gb->sgb->command[5] + (gb->sgb->command[6] & 1) * 0x100)],
|
||||
8);
|
||||
memcpy(&gb->sgb->effective_palettes[12],
|
||||
&gb->sgb->ram_palettes[4 * (gb->sgb->command[7] + (gb->sgb->command[8] & 1) * 0x100)],
|
||||
8);
|
||||
|
||||
gb->sgb->effective_palettes[12] = gb->sgb->effective_palettes[8] =
|
||||
gb->sgb->effective_palettes[4] = gb->sgb->effective_palettes[0];
|
||||
|
||||
if (gb->sgb->command[9] & 0x80) {
|
||||
load_attribute_file(gb, gb->sgb->command[9] & 0x3F);
|
||||
}
|
||||
|
||||
if (gb->sgb->command[9] & 0x40) {
|
||||
gb->sgb->mask_mode = MASK_DISABLED;
|
||||
}
|
||||
break;
|
||||
case PAL_TRN:
|
||||
gb->sgb->vram_transfer_countdown = 2;
|
||||
gb->sgb->transfer_dest = TRANSFER_PALETTES;
|
||||
break;
|
||||
case DATA_SND:
|
||||
// Not supported, but used by almost all SGB games for hot patching, so let's mute the warning for this
|
||||
break;
|
||||
case MLT_REQ:
|
||||
if (gb->sgb->player_count == 1) {
|
||||
gb->sgb->current_player = 0;
|
||||
}
|
||||
gb->sgb->player_count = (gb->sgb->command[1] & 3) + 1; /* Todo: When breaking save state comaptibility,
|
||||
fix this to be 0 based. */
|
||||
if (gb->sgb->player_count == 3) {
|
||||
gb->sgb->current_player++;
|
||||
}
|
||||
gb->sgb->mlt_lock = true;
|
||||
break;
|
||||
case CHR_TRN:
|
||||
gb->sgb->vram_transfer_countdown = 2;
|
||||
gb->sgb->transfer_dest = (gb->sgb->command[1] & 1)? TRANSFER_HIGH_TILES : TRANSFER_LOW_TILES;
|
||||
break;
|
||||
case PCT_TRN:
|
||||
gb->sgb->vram_transfer_countdown = 2;
|
||||
gb->sgb->transfer_dest = TRANSFER_BORDER_DATA;
|
||||
break;
|
||||
case ATTR_TRN:
|
||||
gb->sgb->vram_transfer_countdown = 2;
|
||||
gb->sgb->transfer_dest = TRANSFER_ATTRIBUTES;
|
||||
break;
|
||||
case ATTR_SET:
|
||||
load_attribute_file(gb, gb->sgb->command[0] & 0x3F);
|
||||
|
||||
if (gb->sgb->command[0] & 0x40) {
|
||||
gb->sgb->mask_mode = MASK_DISABLED;
|
||||
}
|
||||
break;
|
||||
case MASK_EN:
|
||||
gb->sgb->mask_mode = gb->sgb->command[1] & 3;
|
||||
break;
|
||||
default:
|
||||
if ((gb->sgb->command[0] >> 3) == 8 &&
|
||||
(gb->sgb->command[1] & ~0x80) == 0 &&
|
||||
(gb->sgb->command[2] & ~0x80) == 0) {
|
||||
/* Mute/dummy sound commands, ignore this command as it's used by many games at startup */
|
||||
break;
|
||||
}
|
||||
GB_log(gb, "Unimplemented SGB command %x: ", gb->sgb->command[0] >> 3);
|
||||
for (unsigned i = 0; i < gb->sgb->command_write_index / 8; i++) {
|
||||
GB_log(gb, "%02x ", gb->sgb->command[i]);
|
||||
}
|
||||
GB_log(gb, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void GB_sgb_write(GB_gameboy_t *gb, uint8_t value)
|
||||
{
|
||||
if (!GB_is_sgb(gb)) return;
|
||||
if (!GB_is_hle_sgb(gb)) {
|
||||
/* Notify via callback */
|
||||
return;
|
||||
}
|
||||
if (gb->sgb->disable_commands) return;
|
||||
if (gb->sgb->command_write_index >= sizeof(gb->sgb->command) * 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t command_size = (gb->sgb->command[0] & 7 ?: 1) * SGB_PACKET_SIZE * 8;
|
||||
if ((gb->sgb->command[0] & 0xF1) == 0xF1) {
|
||||
command_size = SGB_PACKET_SIZE * 8;
|
||||
}
|
||||
|
||||
if ((value & 0x20) == 0 && (gb->io_registers[GB_IO_JOYP] & 0x20) != 0) {
|
||||
gb->sgb->mlt_lock ^= true;
|
||||
}
|
||||
|
||||
switch ((value >> 4) & 3) {
|
||||
case 3:
|
||||
gb->sgb->ready_for_pulse = true;
|
||||
if ((gb->sgb->player_count & 1) == 0 && !gb->sgb->mlt_lock) {
|
||||
gb->sgb->current_player++;
|
||||
gb->sgb->current_player &= 3;
|
||||
gb->sgb->mlt_lock = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // Zero
|
||||
if (!gb->sgb->ready_for_pulse || !gb->sgb->ready_for_write) return;
|
||||
if (gb->sgb->ready_for_stop) {
|
||||
if (gb->sgb->command_write_index == command_size) {
|
||||
command_ready(gb);
|
||||
gb->sgb->command_write_index = 0;
|
||||
memset(gb->sgb->command, 0, sizeof(gb->sgb->command));
|
||||
}
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
gb->sgb->ready_for_write = false;
|
||||
gb->sgb->ready_for_stop = false;
|
||||
}
|
||||
else {
|
||||
gb->sgb->command_write_index++;
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) == 0) {
|
||||
gb->sgb->ready_for_stop = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: // One
|
||||
if (!gb->sgb->ready_for_pulse || !gb->sgb->ready_for_write) return;
|
||||
if (gb->sgb->ready_for_stop) {
|
||||
GB_log(gb, "Corrupt SGB command.\n");
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
gb->sgb->ready_for_write = false;
|
||||
gb->sgb->command_write_index = 0;
|
||||
memset(gb->sgb->command, 0, sizeof(gb->sgb->command));
|
||||
}
|
||||
else {
|
||||
gb->sgb->command[gb->sgb->command_write_index / 8] |= 1 << (gb->sgb->command_write_index & 7);
|
||||
gb->sgb->command_write_index++;
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) == 0) {
|
||||
gb->sgb->ready_for_stop = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
if (!gb->sgb->ready_for_pulse) return;
|
||||
gb->sgb->ready_for_write = true;
|
||||
gb->sgb->ready_for_pulse = false;
|
||||
if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) != 0 ||
|
||||
gb->sgb->command_write_index == 0 ||
|
||||
gb->sgb->ready_for_stop) {
|
||||
gb->sgb->command_write_index = 0;
|
||||
memset(gb->sgb->command, 0, sizeof(gb->sgb->command));
|
||||
gb->sgb->ready_for_stop = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t convert_rgb15(GB_gameboy_t *gb, uint16_t color)
|
||||
{
|
||||
return GB_convert_rgb15(gb, color, false);
|
||||
}
|
||||
|
||||
static uint32_t convert_rgb15_with_fade(GB_gameboy_t *gb, uint16_t color, uint8_t fade)
|
||||
{
|
||||
uint8_t r = ((color) & 0x1F) - fade;
|
||||
uint8_t g = ((color >> 5) & 0x1F) - fade;
|
||||
uint8_t b = ((color >> 10) & 0x1F) - fade;
|
||||
|
||||
if (r >= 0x20) r = 0;
|
||||
if (g >= 0x20) g = 0;
|
||||
if (b >= 0x20) b = 0;
|
||||
|
||||
color = r | (g << 5) | (b << 10);
|
||||
|
||||
return GB_convert_rgb15(gb, color, false);
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
static void render_boot_animation (GB_gameboy_t *gb)
|
||||
{
|
||||
#include "graphics/sgb_animation_logo.inc"
|
||||
uint32_t *output = gb->screen;
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 48 + 40 * 256;
|
||||
}
|
||||
uint8_t *input = animation_logo;
|
||||
unsigned fade_blue = 0;
|
||||
unsigned fade_red = 0;
|
||||
if (gb->sgb->intro_animation < 80 - 32) {
|
||||
fade_blue = 32;
|
||||
}
|
||||
else if (gb->sgb->intro_animation < 80) {
|
||||
fade_blue = 80 - gb->sgb->intro_animation;
|
||||
}
|
||||
else if (gb->sgb->intro_animation > INTRO_ANIMATION_LENGTH - 32) {
|
||||
fade_red = fade_blue = gb->sgb->intro_animation - INTRO_ANIMATION_LENGTH + 32;
|
||||
}
|
||||
uint32_t colors[] = {
|
||||
convert_rgb15(gb, 0),
|
||||
convert_rgb15_with_fade(gb, 0x14A5, fade_blue),
|
||||
convert_rgb15_with_fade(gb, 0x54E0, fade_blue),
|
||||
convert_rgb15_with_fade(gb, 0x0019, fade_red),
|
||||
convert_rgb15(gb, 0x0011),
|
||||
convert_rgb15(gb, 0x0009),
|
||||
};
|
||||
unsigned y_min = (144 - animation_logo_height) / 2;
|
||||
unsigned y_max = y_min + animation_logo_height;
|
||||
for (unsigned y = 0; y < 144; y++) {
|
||||
for (unsigned x = 0; x < 160; x++) {
|
||||
if (y < y_min || y >= y_max) {
|
||||
*(output++) = colors[0];
|
||||
}
|
||||
else {
|
||||
uint8_t color = *input;
|
||||
if (color >= 3) {
|
||||
if (color == gb->sgb->intro_animation / 2 - 3) {
|
||||
color = 5;
|
||||
}
|
||||
else if (color == gb->sgb->intro_animation / 2 - 4) {
|
||||
color = 4;
|
||||
}
|
||||
else if (color < gb->sgb->intro_animation / 2 - 4) {
|
||||
color = 3;
|
||||
}
|
||||
else {
|
||||
color = 0;
|
||||
}
|
||||
}
|
||||
*(output++) = colors[color];
|
||||
input++;
|
||||
}
|
||||
}
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 256 - 160;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void render_jingle(GB_gameboy_t *gb, size_t count);
|
||||
void GB_sgb_render(GB_gameboy_t *gb)
|
||||
{
|
||||
if (gb->apu_output.sample_rate) {
|
||||
render_jingle(gb, gb->apu_output.sample_rate / GB_get_usual_frame_rate(gb));
|
||||
}
|
||||
|
||||
if (gb->sgb->intro_animation < INTRO_ANIMATION_LENGTH) gb->sgb->intro_animation++;
|
||||
|
||||
if (gb->sgb->vram_transfer_countdown) {
|
||||
if (--gb->sgb->vram_transfer_countdown == 0) {
|
||||
if (gb->sgb->transfer_dest == TRANSFER_LOW_TILES || gb->sgb->transfer_dest == TRANSFER_HIGH_TILES) {
|
||||
uint8_t *base = &gb->sgb->pending_border.tiles[gb->sgb->transfer_dest == TRANSFER_HIGH_TILES ? 0x80 * 8 * 8 : 0];
|
||||
for (unsigned tile = 0; tile < 0x80; tile++) {
|
||||
unsigned tile_x = (tile % 10) * 16;
|
||||
unsigned tile_y = (tile / 10) * 8;
|
||||
for (unsigned y = 0; y < 0x8; y++) {
|
||||
for (unsigned x = 0; x < 0x8; x++) {
|
||||
base[tile * 8 * 8 + y * 8 + x] = gb->sgb->screen_buffer[(tile_x + x) + (tile_y + y) * 160] +
|
||||
gb->sgb->screen_buffer[(tile_x + x + 8) + (tile_y + y) * 160] * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
unsigned size = 0;
|
||||
uint16_t *data = NULL;
|
||||
|
||||
switch (gb->sgb->transfer_dest) {
|
||||
case TRANSFER_PALETTES:
|
||||
size = 0x100;
|
||||
data = gb->sgb->ram_palettes;
|
||||
break;
|
||||
case TRANSFER_BORDER_DATA:
|
||||
size = 0x88;
|
||||
data = gb->sgb->pending_border.raw_data;
|
||||
break;
|
||||
case TRANSFER_ATTRIBUTES:
|
||||
size = 0xFE;
|
||||
data = (uint16_t *)gb->sgb->attribute_files;
|
||||
break;
|
||||
default:
|
||||
return; // Corrupt state?
|
||||
}
|
||||
|
||||
for (unsigned tile = 0; tile < size; tile++) {
|
||||
unsigned tile_x = (tile % 20) * 8;
|
||||
unsigned tile_y = (tile / 20) * 8;
|
||||
for (unsigned y = 0; y < 0x8; y++) {
|
||||
static const uint16_t pixel_to_bits[4] = {0x0000, 0x0080, 0x8000, 0x8080};
|
||||
*data = 0;
|
||||
for (unsigned x = 0; x < 8; x++) {
|
||||
*data |= pixel_to_bits[gb->sgb->screen_buffer[(tile_x + x) + (tile_y + y) * 160] & 3] >> x;
|
||||
}
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
if (gb->sgb->transfer_dest == TRANSFER_ATTRIBUTES) {
|
||||
*data = __builtin_bswap16(*data);
|
||||
}
|
||||
#endif
|
||||
data++;
|
||||
}
|
||||
}
|
||||
if (gb->sgb->transfer_dest == TRANSFER_BORDER_DATA) {
|
||||
gb->sgb->border_animation = 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gb->screen || !gb->rgb_encode_callback || gb->disable_rendering) return;
|
||||
|
||||
uint32_t colors[4 * 4];
|
||||
for (unsigned i = 0; i < 4 * 4; i++) {
|
||||
colors[i] = convert_rgb15(gb, gb->sgb->effective_palettes[i]);
|
||||
}
|
||||
|
||||
if (gb->sgb->mask_mode != MASK_FREEZE) {
|
||||
memcpy(gb->sgb->effective_screen_buffer,
|
||||
gb->sgb->screen_buffer,
|
||||
sizeof(gb->sgb->effective_screen_buffer));
|
||||
}
|
||||
|
||||
if (gb->sgb->intro_animation < INTRO_ANIMATION_LENGTH) {
|
||||
render_boot_animation(gb);
|
||||
}
|
||||
else {
|
||||
uint32_t *output = gb->screen;
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 48 + 40 * 256;
|
||||
}
|
||||
uint8_t *input = gb->sgb->effective_screen_buffer;
|
||||
switch ((mask_mode_t) gb->sgb->mask_mode) {
|
||||
case MASK_DISABLED:
|
||||
case MASK_FREEZE: {
|
||||
for (unsigned y = 0; y < 144; y++) {
|
||||
for (unsigned x = 0; x < 160; x++) {
|
||||
uint8_t palette = gb->sgb->attribute_map[x / 8 + y / 8 * 20] & 3;
|
||||
*(output++) = colors[(*(input++) & 3) + palette * 4];
|
||||
}
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 256 - 160;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MASK_BLACK:
|
||||
{
|
||||
uint32_t black = convert_rgb15(gb, 0);
|
||||
for (unsigned y = 0; y < 144; y++) {
|
||||
for (unsigned x = 0; x < 160; x++) {
|
||||
*(output++) = black;
|
||||
}
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 256 - 160;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MASK_COLOR_0:
|
||||
{
|
||||
for (unsigned y = 0; y < 144; y++) {
|
||||
for (unsigned x = 0; x < 160; x++) {
|
||||
*(output++) = colors[0];
|
||||
}
|
||||
if (gb->border_mode != GB_BORDER_NEVER) {
|
||||
output += 256 - 160;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t border_colors[16 * 4];
|
||||
if (gb->sgb->border_animation == 0 || gb->sgb->intro_animation < INTRO_ANIMATION_LENGTH) {
|
||||
for (unsigned i = 0; i < 16 * 4; i++) {
|
||||
border_colors[i] = convert_rgb15(gb, gb->sgb->border.palette[i]);
|
||||
}
|
||||
}
|
||||
else if (gb->sgb->border_animation > 32) {
|
||||
gb->sgb->border_animation--;
|
||||
for (unsigned i = 0; i < 16 * 4; i++) {
|
||||
border_colors[i] = convert_rgb15_with_fade(gb, gb->sgb->border.palette[i], 64 - gb->sgb->border_animation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gb->sgb->border_animation--;
|
||||
for (unsigned i = 0; i < 16 * 4; i++) {
|
||||
border_colors[i] = convert_rgb15_with_fade(gb, gb->sgb->border.palette[i], gb->sgb->border_animation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (gb->sgb->border_animation == 32) {
|
||||
memcpy(&gb->sgb->border, &gb->sgb->pending_border, sizeof(gb->sgb->border));
|
||||
}
|
||||
|
||||
for (unsigned tile_y = 0; tile_y < 28; tile_y++) {
|
||||
for (unsigned tile_x = 0; tile_x < 32; tile_x++) {
|
||||
bool gb_area = false;
|
||||
if (tile_x >= 6 && tile_x < 26 && tile_y >= 5 && tile_y < 23) {
|
||||
gb_area = true;
|
||||
}
|
||||
else if (gb->border_mode == GB_BORDER_NEVER) {
|
||||
continue;
|
||||
}
|
||||
uint16_t tile = gb->sgb->border.map[tile_x + tile_y * 32];
|
||||
uint8_t flip_x = (tile & 0x4000)? 0x7 : 0;
|
||||
uint8_t flip_y = (tile & 0x8000)? 0x7 : 0;
|
||||
uint8_t palette = (tile >> 10) & 3;
|
||||
for (unsigned y = 0; y < 8; y++) {
|
||||
for (unsigned x = 0; x < 8; x++) {
|
||||
uint8_t color = gb->sgb->border.tiles[(tile & 0xFF) * 64 + (x ^ flip_x) + (y ^ flip_y) * 8] & 0xF;
|
||||
uint32_t *output = gb->screen;
|
||||
if (gb->border_mode == GB_BORDER_NEVER) {
|
||||
output += (tile_x - 6) * 8 + x + ((tile_y - 5) * 8 + y) * 160;
|
||||
}
|
||||
else {
|
||||
output += tile_x * 8 + x + (tile_y * 8 + y) * 256;
|
||||
}
|
||||
if (color == 0) {
|
||||
if (gb_area) continue;
|
||||
*output = colors[0];
|
||||
}
|
||||
else {
|
||||
*output = border_colors[color + palette * 16];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GB_sgb_load_default_data(GB_gameboy_t *gb)
|
||||
{
|
||||
|
||||
#include "graphics/sgb_border.inc"
|
||||
|
||||
memcpy(gb->sgb->border.map, tilemap, sizeof(tilemap));
|
||||
memcpy(gb->sgb->border.palette, palette, sizeof(palette));
|
||||
|
||||
/* Expand tileset */
|
||||
for (unsigned tile = 0; tile < sizeof(tiles) / 32; tile++) {
|
||||
for (unsigned y = 0; y < 8; y++) {
|
||||
for (unsigned x = 0; x < 8; x++) {
|
||||
gb->sgb->border.tiles[tile * 8 * 8 + y * 8 + x] =
|
||||
(tiles[tile * 32 + y * 2 + 0] & (1 << (7 ^ x)) ? 1 : 0) |
|
||||
(tiles[tile * 32 + y * 2 + 1] & (1 << (7 ^ x)) ? 2 : 0) |
|
||||
(tiles[tile * 32 + y * 2 + 16] & (1 << (7 ^ x)) ? 4 : 0) |
|
||||
(tiles[tile * 32 + y * 2 + 17] & (1 << (7 ^ x)) ? 8 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gb->model != GB_MODEL_SGB2) {
|
||||
/* Delete the "2" */
|
||||
gb->sgb->border.map[25 * 32 + 25] = gb->sgb->border.map[25 * 32 + 26] =
|
||||
gb->sgb->border.map[26 * 32 + 25] = gb->sgb->border.map[26 * 32 + 26] =
|
||||
gb->sgb->border.map[27 * 32 + 25] = gb->sgb->border.map[27 * 32 + 26] =
|
||||
gb->sgb->border.map[0];
|
||||
|
||||
/* Re-center */
|
||||
memmove(&gb->sgb->border.map[25 * 32 + 1], &gb->sgb->border.map[25 * 32], (32 * 3 - 1) * sizeof(gb->sgb->border.map[0]));
|
||||
}
|
||||
gb->sgb->effective_palettes[0] = built_in_palettes[0];
|
||||
gb->sgb->effective_palettes[1] = built_in_palettes[1];
|
||||
gb->sgb->effective_palettes[2] = built_in_palettes[2];
|
||||
gb->sgb->effective_palettes[3] = built_in_palettes[3];
|
||||
}
|
||||
|
||||
static double fm_synth(double phase)
|
||||
{
|
||||
return (sin(phase * M_PI * 2) +
|
||||
sin(phase * M_PI * 2 + sin(phase * M_PI * 2)) +
|
||||
sin(phase * M_PI * 2 + sin(phase * M_PI * 3)) +
|
||||
sin(phase * M_PI * 2 + sin(phase * M_PI * 4))) / 4;
|
||||
}
|
||||
|
||||
static double fm_sweep(double phase)
|
||||
{
|
||||
double ret = 0;
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
ret += sin((phase * M_PI * 2 + sin(phase * M_PI * 8) / 4) * pow(1.25, i)) * (8 - i) / 36;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static double random_double(void)
|
||||
{
|
||||
return ((signed)(GB_random32() % 0x10001) - 0x8000) / (double) 0x8000;
|
||||
}
|
||||
|
||||
static void render_jingle(GB_gameboy_t *gb, size_t count)
|
||||
{
|
||||
const double frequencies[7] = {
|
||||
466.16, // Bb4
|
||||
587.33, // D5
|
||||
698.46, // F5
|
||||
830.61, // Ab5
|
||||
1046.50, // C6
|
||||
1244.51, // Eb6
|
||||
1567.98, // G6
|
||||
};
|
||||
|
||||
assert(gb->apu_output.sample_callback);
|
||||
|
||||
if (gb->sgb->intro_animation < 0) {
|
||||
GB_sample_t sample = {0, 0};
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
gb->apu_output.sample_callback(gb, &sample);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (gb->sgb->intro_animation >= INTRO_ANIMATION_LENGTH) return;
|
||||
|
||||
signed jingle_stage = (gb->sgb->intro_animation - 64) / 3;
|
||||
double sweep_cutoff_ratio = 2000.0 * pow(2, gb->sgb->intro_animation / 20.0) / gb->apu_output.sample_rate;
|
||||
double sweep_phase_shift = 1000.0 * pow(2, gb->sgb->intro_animation / 40.0) / gb->apu_output.sample_rate;
|
||||
if (sweep_cutoff_ratio > 1) {
|
||||
sweep_cutoff_ratio = 1;
|
||||
}
|
||||
|
||||
GB_sample_t stereo;
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
double sample = 0;
|
||||
for (signed f = 0; f < 7 && f < jingle_stage; f++) {
|
||||
sample += fm_synth(gb->sgb_intro_jingle_phases[f]) *
|
||||
(0.75 * pow(0.5, jingle_stage - f) + 0.25) / 5.0;
|
||||
gb->sgb_intro_jingle_phases[f] += frequencies[f] / gb->apu_output.sample_rate;
|
||||
}
|
||||
if (gb->sgb->intro_animation > 100) {
|
||||
sample *= pow((INTRO_ANIMATION_LENGTH - gb->sgb->intro_animation) / (INTRO_ANIMATION_LENGTH - 100.0), 3);
|
||||
}
|
||||
|
||||
if (gb->sgb->intro_animation < 120) {
|
||||
double next = fm_sweep(gb->sgb_intro_sweep_phase) * 0.3 + random_double() * 0.7;
|
||||
gb->sgb_intro_sweep_phase += sweep_phase_shift;
|
||||
|
||||
gb->sgb_intro_sweep_previous_sample = next * (sweep_cutoff_ratio) +
|
||||
gb->sgb_intro_sweep_previous_sample * (1 - sweep_cutoff_ratio);
|
||||
sample += gb->sgb_intro_sweep_previous_sample * pow((120 - gb->sgb->intro_animation) / 120.0, 2) * 0.8;
|
||||
}
|
||||
|
||||
stereo.left = stereo.right = sample * 0x7000;
|
||||
gb->apu_output.sample_callback(gb, &stereo);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
67
Core/sgb.h
67
Core/sgb.h
@ -1,67 +0,0 @@
|
||||
#ifndef sgb_h
|
||||
#define sgb_h
|
||||
#include "gb_struct_def.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct GB_sgb_s GB_sgb_t;
|
||||
typedef struct {
|
||||
uint8_t tiles[0x100 * 8 * 8]; /* High nibble not used*/
|
||||
union {
|
||||
struct {
|
||||
uint16_t map[32 * 32];
|
||||
uint16_t palette[16 * 4];
|
||||
};
|
||||
uint16_t raw_data[0x440];
|
||||
};
|
||||
} GB_sgb_border_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
struct GB_sgb_s {
|
||||
uint8_t command[16 * 7];
|
||||
uint16_t command_write_index;
|
||||
bool ready_for_pulse;
|
||||
bool ready_for_write;
|
||||
bool ready_for_stop;
|
||||
bool disable_commands;
|
||||
|
||||
/* Screen buffer */
|
||||
uint8_t screen_buffer[160 * 144]; // Live image from the Game Boy
|
||||
uint8_t effective_screen_buffer[160 * 144]; // Image actually rendered to the screen
|
||||
|
||||
/* Multiplayer Input */
|
||||
uint8_t player_count, current_player;
|
||||
|
||||
/* Mask */
|
||||
uint8_t mask_mode;
|
||||
|
||||
/* Data Transfer */
|
||||
uint8_t vram_transfer_countdown, transfer_dest;
|
||||
|
||||
/* Border */
|
||||
GB_sgb_border_t border, pending_border;
|
||||
uint8_t border_animation;
|
||||
|
||||
/* Colorization */
|
||||
uint16_t effective_palettes[4 * 4];
|
||||
uint16_t ram_palettes[4 * 512];
|
||||
uint8_t attribute_map[20 * 18];
|
||||
uint8_t attribute_files[0xFE0];
|
||||
|
||||
/* Intro */
|
||||
int16_t intro_animation;
|
||||
|
||||
/* GB Header */
|
||||
uint8_t received_header[0x54];
|
||||
|
||||
/* Multiplayer (cont) */
|
||||
bool mlt_lock;
|
||||
};
|
||||
|
||||
void GB_sgb_write(GB_gameboy_t *gb, uint8_t value);
|
||||
void GB_sgb_render(GB_gameboy_t *gb);
|
||||
void GB_sgb_load_default_data(GB_gameboy_t *gb);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
54
Makefile
54
Makefile
@ -188,9 +188,8 @@ endif
|
||||
|
||||
cocoa: $(BIN)/SameDuck.app
|
||||
quicklook: $(BIN)/SameDuck.qlgenerator
|
||||
sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/agb_boot.bin $(BIN)/SDL/sgb_boot.bin $(BIN)/SDL/sgb2_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders
|
||||
bootroms: $(BIN)/BootROMs/agb_boot.bin $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin $(BIN)/BootROMs/sgb_boot.bin $(BIN)/BootROMs/sgb2_boot.bin
|
||||
tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin $(BIN)/tester/agb_boot.bin $(BIN)/tester/sgb_boot.bin $(BIN)/tester/sgb2_boot.bin
|
||||
sdl: $(SDL_TARGET) $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders
|
||||
tester: $(TESTER_TARGET)
|
||||
all: cocoa sdl tester libretro
|
||||
|
||||
# Get a list of our source files and their respective object file targets
|
||||
@ -267,11 +266,6 @@ $(BIN)/SameDuck.app: $(BIN)/SameDuck.app/Contents/MacOS/SameDuck \
|
||||
Cocoa/License.html \
|
||||
Cocoa/Info.plist \
|
||||
Misc/registers.sym \
|
||||
$(BIN)/SameDuck.app/Contents/Resources/dmg_boot.bin \
|
||||
$(BIN)/SameDuck.app/Contents/Resources/cgb_boot.bin \
|
||||
$(BIN)/SameDuck.app/Contents/Resources/agb_boot.bin \
|
||||
$(BIN)/SameDuck.app/Contents/Resources/sgb_boot.bin \
|
||||
$(BIN)/SameDuck.app/Contents/Resources/sgb2_boot.bin \
|
||||
$(patsubst %.xib,%.nib,$(addprefix $(BIN)/SameDuck.app/Contents/Resources/Base.lproj/,$(shell cd Cocoa;ls *.xib))) \
|
||||
$(BIN)/SameDuck.qlgenerator \
|
||||
Shaders
|
||||
@ -298,8 +292,7 @@ $(BIN)/SameDuck.app/Contents/Resources/Base.lproj/%.nib: Cocoa/%.xib
|
||||
|
||||
$(BIN)/SameDuck.qlgenerator: $(BIN)/SameDuck.qlgenerator/Contents/MacOS/SameDuckQL \
|
||||
$(shell ls QuickLook/*.png) \
|
||||
QuickLook/Info.plist \
|
||||
$(BIN)/SameDuck.qlgenerator/Contents/Resources/cgb_boot_fast.bin
|
||||
QuickLook/Info.plist
|
||||
$(MKDIR) -p $(BIN)/SameDuck.qlgenerator/Contents/Resources
|
||||
cp QuickLook/*.png $(BIN)/SameDuck.qlgenerator/Contents/Resources/
|
||||
sed s/@VERSION/$(VERSION)/ < QuickLook/Info.plist > $(BIN)/SameDuck.qlgenerator/Contents/Info.plist
|
||||
@ -309,12 +302,6 @@ $(BIN)/SameDuck.qlgenerator: $(BIN)/SameDuck.qlgenerator/Contents/MacOS/SameDuck
|
||||
$(BIN)/SameDuck.qlgenerator/Contents/MacOS/SameDuckQL: $(CORE_OBJECTS) $(QUICKLOOK_OBJECTS)
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
$(CC) $^ -o $@ $(LDFLAGS) $(FAT_FLAGS) -Wl,-exported_symbols_list,QuickLook/exports.sym -bundle -framework Cocoa -framework Quicklook
|
||||
|
||||
# cgb_boot_fast.bin is not a standard boot ROM, we don't expect it to exist in the user-provided
|
||||
# boot ROM directory.
|
||||
$(BIN)/SameDuck.qlgenerator/Contents/Resources/cgb_boot_fast.bin: $(BIN)/BootROMs/cgb_boot_fast.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
|
||||
# SDL Port
|
||||
|
||||
@ -366,18 +353,6 @@ $(BIN)/tester/sameduck_tester.exe: $(CORE_OBJECTS) $(SDL_OBJECTS)
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
$(CC) $^ -o $@ $(LDFLAGS) -Wl,/subsystem:console
|
||||
|
||||
$(BIN)/SDL/%.bin: $(BOOTROMS_DIR)/%.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
|
||||
$(BIN)/tester/%.bin: $(BOOTROMS_DIR)/%.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
|
||||
$(BIN)/SameDuck.app/Contents/Resources/%.bin: $(BOOTROMS_DIR)/%.bin
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
|
||||
$(BIN)/SDL/LICENSE: LICENSE
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
cp -f $^ $@
|
||||
@ -394,29 +369,6 @@ $(BIN)/SDL/Shaders: Shaders
|
||||
-@$(MKDIR) -p $@
|
||||
cp -rf Shaders/*.fsh $@
|
||||
|
||||
# Boot ROMs
|
||||
|
||||
$(OBJ)/%.2bpp: %.png
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
rgbgfx -h -u -o $@ $<
|
||||
|
||||
$(OBJ)/BootROMs/SameDuckLogo.pb12: $(OBJ)/BootROMs/SameDuckLogo.2bpp $(PB12_COMPRESS)
|
||||
$(realpath $(PB12_COMPRESS)) < $< > $@
|
||||
|
||||
$(PB12_COMPRESS): BootROMs/pb12.c
|
||||
$(NATIVE_CC) -std=c99 -Wall -Werror $< -o $@
|
||||
|
||||
$(BIN)/BootROMs/agb_boot.bin: BootROMs/cgb_boot.asm
|
||||
$(BIN)/BootROMs/cgb_boot_fast.bin: BootROMs/cgb_boot.asm
|
||||
$(BIN)/BootROMs/sgb2_boot: BootROMs/sgb_boot.asm
|
||||
|
||||
$(BIN)/BootROMs/%.bin: BootROMs/%.asm $(OBJ)/BootROMs/SameDuckLogo.pb12
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
rgbasm -i $(OBJ)/BootROMs/ -i BootROMs/ -o $@.tmp $<
|
||||
rgblink -o $@.tmp2 $@.tmp
|
||||
dd if=$@.tmp2 of=$@ count=1 bs=$(if $(findstring dmg,$@)$(findstring sgb,$@),256,2304) 2> $(NULL)
|
||||
@rm $@.tmp $@.tmp2
|
||||
|
||||
# Libretro Core (uses its own build system)
|
||||
libretro:
|
||||
CFLAGS="$(WARNINGS)" $(MAKE) -C libretro
|
||||
|
125
SDL/gui.c
125
SDL/gui.c
@ -324,56 +324,6 @@ static void return_to_root_menu(unsigned index)
|
||||
scroll = 0;
|
||||
}
|
||||
|
||||
static void cycle_model(unsigned index)
|
||||
{
|
||||
|
||||
configuration.model++;
|
||||
if (configuration.model == MODEL_MAX) {
|
||||
configuration.model = 0;
|
||||
}
|
||||
pending_command = GB_SDL_RESET_COMMAND;
|
||||
}
|
||||
|
||||
static void cycle_model_backwards(unsigned index)
|
||||
{
|
||||
if (configuration.model == 0) {
|
||||
configuration.model = MODEL_MAX;
|
||||
}
|
||||
configuration.model--;
|
||||
pending_command = GB_SDL_RESET_COMMAND;
|
||||
}
|
||||
|
||||
const char *current_model_string(unsigned index)
|
||||
{
|
||||
return (const char *[]){"Game Boy", "Game Boy Color", "Game Boy Advance", "Super Game Boy"}
|
||||
[configuration.model];
|
||||
}
|
||||
|
||||
static void cycle_sgb_revision(unsigned index)
|
||||
{
|
||||
|
||||
configuration.sgb_revision++;
|
||||
if (configuration.sgb_revision == SGB_MAX) {
|
||||
configuration.sgb_revision = 0;
|
||||
}
|
||||
pending_command = GB_SDL_RESET_COMMAND;
|
||||
}
|
||||
|
||||
static void cycle_sgb_revision_backwards(unsigned index)
|
||||
{
|
||||
if (configuration.sgb_revision == 0) {
|
||||
configuration.sgb_revision = SGB_MAX;
|
||||
}
|
||||
configuration.sgb_revision--;
|
||||
pending_command = GB_SDL_RESET_COMMAND;
|
||||
}
|
||||
|
||||
const char *current_sgb_revision_string(unsigned index)
|
||||
{
|
||||
return (const char *[]){"Super Game Boy NTSC", "Super Game Boy PAL", "Super Game Boy 2"}
|
||||
[configuration.sgb_revision];
|
||||
}
|
||||
|
||||
static const uint32_t rewind_lengths[] = {0, 10, 30, 60, 60 * 2, 60 * 5, 60 * 10};
|
||||
static const char *rewind_strings[] = {"Disabled",
|
||||
"10 Seconds",
|
||||
@ -421,8 +371,6 @@ const char *current_rewind_string(unsigned index)
|
||||
}
|
||||
|
||||
static const struct menu_item emulation_menu[] = {
|
||||
{"Emulated Model:", cycle_model, current_model_string, cycle_model_backwards},
|
||||
{"SGB Revision:", cycle_sgb_revision, current_sgb_revision_string, cycle_sgb_revision_backwards},
|
||||
{"Rewind Length:", cycle_rewind, current_rewind_string, cycle_rewind_backwards},
|
||||
{"Back", return_to_root_menu},
|
||||
{NULL,}
|
||||
@ -447,24 +395,12 @@ const char *current_default_scale(unsigned index)
|
||||
[configuration.default_scale - 1];
|
||||
}
|
||||
|
||||
const char *current_color_correction_mode(unsigned index)
|
||||
{
|
||||
return (const char *[]){"Disabled", "Correct Color Curves", "Emulate Hardware", "Preserve Brightness", "Reduce Contrast"}
|
||||
[configuration.color_correction_mode];
|
||||
}
|
||||
|
||||
const char *current_palette(unsigned index)
|
||||
{
|
||||
return (const char *[]){"Greyscale", "Lime (Game Boy)", "Olive (Pocket)", "Teal (Light)"}
|
||||
[configuration.dmg_palette];
|
||||
}
|
||||
|
||||
const char *current_border_mode(unsigned index)
|
||||
{
|
||||
return (const char *[]){"SGB Only", "Never", "Always"}
|
||||
[configuration.border_mode];
|
||||
}
|
||||
|
||||
void cycle_scaling(unsigned index)
|
||||
{
|
||||
configuration.scaling_mode++;
|
||||
@ -513,26 +449,6 @@ void cycle_default_scale_backwards(unsigned index)
|
||||
update_viewport();
|
||||
}
|
||||
|
||||
static void cycle_color_correction(unsigned index)
|
||||
{
|
||||
if (configuration.color_correction_mode == GB_COLOR_CORRECTION_REDUCE_CONTRAST) {
|
||||
configuration.color_correction_mode = GB_COLOR_CORRECTION_DISABLED;
|
||||
}
|
||||
else {
|
||||
configuration.color_correction_mode++;
|
||||
}
|
||||
}
|
||||
|
||||
static void cycle_color_correction_backwards(unsigned index)
|
||||
{
|
||||
if (configuration.color_correction_mode == GB_COLOR_CORRECTION_DISABLED) {
|
||||
configuration.color_correction_mode = GB_COLOR_CORRECTION_REDUCE_CONTRAST;
|
||||
}
|
||||
else {
|
||||
configuration.color_correction_mode--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cycle_palette(unsigned index)
|
||||
{
|
||||
if (configuration.dmg_palette == 3) {
|
||||
@ -553,26 +469,6 @@ static void cycle_palette_backwards(unsigned index)
|
||||
}
|
||||
}
|
||||
|
||||
static void cycle_border_mode(unsigned index)
|
||||
{
|
||||
if (configuration.border_mode == GB_BORDER_ALWAYS) {
|
||||
configuration.border_mode = GB_BORDER_SGB;
|
||||
}
|
||||
else {
|
||||
configuration.border_mode++;
|
||||
}
|
||||
}
|
||||
|
||||
static void cycle_border_mode_backwards(unsigned index)
|
||||
{
|
||||
if (configuration.border_mode == GB_BORDER_SGB) {
|
||||
configuration.border_mode = GB_BORDER_ALWAYS;
|
||||
}
|
||||
else {
|
||||
configuration.border_mode--;
|
||||
}
|
||||
}
|
||||
|
||||
struct shader_name {
|
||||
const char *file_name;
|
||||
const char *display_name;
|
||||
@ -683,10 +579,8 @@ static const struct menu_item graphics_menu[] = {
|
||||
{"Scaling Mode:", cycle_scaling, current_scaling_mode, cycle_scaling_backwards},
|
||||
{"Default Window Scale:", cycle_default_scale, current_default_scale, cycle_default_scale_backwards},
|
||||
{"Scaling Filter:", cycle_filter, current_filter_name, cycle_filter_backwards},
|
||||
{"Color Correction:", cycle_color_correction, current_color_correction_mode, cycle_color_correction_backwards},
|
||||
{"Frame Blending:", cycle_blending_mode, blending_mode_string, cycle_blending_mode_backwards},
|
||||
{"Mono Palette:", cycle_palette, current_palette, cycle_palette_backwards},
|
||||
{"Display Border:", cycle_border_mode, current_border_mode, cycle_border_mode_backwards},
|
||||
{"Palette:", cycle_palette, current_palette, cycle_palette_backwards},
|
||||
{"Back", return_to_root_menu},
|
||||
{NULL,}
|
||||
};
|
||||
@ -896,27 +790,22 @@ static void detect_joypad_layout(unsigned index)
|
||||
|
||||
static void cycle_rumble_mode(unsigned index)
|
||||
{
|
||||
if (configuration.rumble_mode == GB_RUMBLE_ALL_GAMES) {
|
||||
configuration.rumble_mode = GB_RUMBLE_DISABLED;
|
||||
if (configuration.rumble_mode == GB_RUMBLE_DISABLED) {
|
||||
configuration.rumble_mode = GB_RUMBLE_ALL_GAMES;
|
||||
}
|
||||
else {
|
||||
configuration.rumble_mode++;
|
||||
configuration.rumble_mode = GB_RUMBLE_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
static void cycle_rumble_mode_backwards(unsigned index)
|
||||
{
|
||||
if (configuration.rumble_mode == GB_RUMBLE_DISABLED) {
|
||||
configuration.rumble_mode = GB_RUMBLE_ALL_GAMES;
|
||||
}
|
||||
else {
|
||||
configuration.rumble_mode--;
|
||||
}
|
||||
cycle_rumble_mode(index);
|
||||
}
|
||||
|
||||
const char *current_rumble_mode(unsigned index)
|
||||
{
|
||||
return (const char *[]){"Disabled", "Rumble Game Paks Only", "All Games"}
|
||||
return (const char *[]){"Disabled", "Rumble Game Paks Only", "Enabled"}
|
||||
[configuration.rumble_mode];
|
||||
}
|
||||
|
||||
@ -1333,7 +1222,7 @@ void run_gui(bool is_running)
|
||||
switch (gui_state) {
|
||||
case SHOWING_DROP_MESSAGE:
|
||||
draw_text_centered(pixels, width, height, 8 + y_offset, "Press ESC for menu", gui_palette_native[3], gui_palette_native[0], false);
|
||||
draw_text_centered(pixels, width, height, 116 + y_offset, "Drop a GB or GBC", gui_palette_native[3], gui_palette_native[0], false);
|
||||
draw_text_centered(pixels, width, height, 116 + y_offset, "Drop a BIN", gui_palette_native[3], gui_palette_native[0], false);
|
||||
draw_text_centered(pixels, width, height, 128 + y_offset, "file to play", gui_palette_native[3], gui_palette_native[0], false);
|
||||
break;
|
||||
case SHOWING_MENU:
|
||||
|
14
SDL/main.c
14
SDL/main.c
@ -448,20 +448,6 @@ static bool handle_pending_command(void)
|
||||
|
||||
static void load_boot_rom(GB_gameboy_t *gb, GB_boot_rom_t type)
|
||||
{
|
||||
bool error = false;
|
||||
start_capturing_logs();
|
||||
static const char *const names[] = {
|
||||
[GB_BOOT_ROM_DMG0] = "dmg0_boot.bin",
|
||||
[GB_BOOT_ROM_DMG] = "dmg_boot.bin",
|
||||
[GB_BOOT_ROM_MGB] = "mgb_boot.bin",
|
||||
[GB_BOOT_ROM_SGB] = "sgb_boot.bin",
|
||||
[GB_BOOT_ROM_SGB2] = "sgb2_boot.bin",
|
||||
[GB_BOOT_ROM_CGB0] = "cgb0_boot.bin",
|
||||
[GB_BOOT_ROM_CGB] = "cgb_boot.bin",
|
||||
[GB_BOOT_ROM_AGB] = "agb_boot.bin",
|
||||
};
|
||||
GB_load_boot_rom(gb, resource_path(names[type]));
|
||||
end_capturing_logs(true, error);
|
||||
}
|
||||
|
||||
static void run(void)
|
||||
|
@ -324,22 +324,6 @@ CFLAGS += -D__LIBRETRO__ $(fpic) $(INCFLAGS) -std=gnu11 -D_GNU_SOURCE -D_USE_M
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(CORE_DIR)/libretro/%_boot.c: $(CORE_DIR)/build/bin/BootROMs/%_boot.bin
|
||||
echo "/* AUTO-GENERATED */" > $@
|
||||
echo "const unsigned char $(notdir $(@:%.c=%))[] = {" >> $@
|
||||
ifneq ($(findstring Haiku,$(shell uname -s)),)
|
||||
# turns out od is posix, hexdump is not hence is less portable
|
||||
# this is still rather ugly and could be done better I guess
|
||||
od -A none -t x1 -v $< | sed -e 's/^\ /0x/' -e 's/\ /,\ 0x/g' -e 's/$$/,/g' | tr '\n' ' ' >> $@
|
||||
else
|
||||
hexdump -v -e '/1 "0x%02x, "' $< >> $@
|
||||
endif
|
||||
echo "};" >> $@
|
||||
echo "const unsigned $(notdir $(@:%.c=%))_length = sizeof($(notdir $(@:%.c=%)));" >> $@
|
||||
|
||||
$(CORE_DIR)/build/bin/BootROMs/%_boot.bin:
|
||||
$(MAKE) -C $(CORE_DIR) $(patsubst $(CORE_DIR)/%,%,$@)
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
ifeq ($(STATIC_LINKING), 1)
|
||||
|
@ -3,7 +3,6 @@ include $(CORE_DIR)/version.mk
|
||||
INCFLAGS := -I$(CORE_DIR)
|
||||
|
||||
SOURCES_C := $(CORE_DIR)/Core/gb.c \
|
||||
$(CORE_DIR)/Core/sgb.c \
|
||||
$(CORE_DIR)/Core/apu.c \
|
||||
$(CORE_DIR)/Core/memory.c \
|
||||
$(CORE_DIR)/Core/timing.c \
|
||||
@ -15,11 +14,6 @@ SOURCES_C := $(CORE_DIR)/Core/gb.c \
|
||||
$(CORE_DIR)/Core/save_state.c \
|
||||
$(CORE_DIR)/Core/random.c \
|
||||
$(CORE_DIR)/Core/rumble.c \
|
||||
$(CORE_DIR)/libretro/agb_boot.c \
|
||||
$(CORE_DIR)/libretro/cgb_boot.c \
|
||||
$(CORE_DIR)/libretro/dmg_boot.c \
|
||||
$(CORE_DIR)/libretro/sgb_boot.c \
|
||||
$(CORE_DIR)/libretro/sgb2_boot.c \
|
||||
$(CORE_DIR)/libretro/libretro.c
|
||||
|
||||
CFLAGS += -DGB_DISABLE_TIMEKEEPING -DGB_DISABLE_REWIND -DGB_DISABLE_DEBUGGER -DGB_DISABLE_CHEATS
|
||||
|
@ -23,12 +23,6 @@
|
||||
#include <Core/gb.h>
|
||||
#include "libretro.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
static const char slash = '\\';
|
||||
#else
|
||||
static const char slash = '/';
|
||||
#endif
|
||||
|
||||
#define MAX_VIDEO_WIDTH 256
|
||||
#define MAX_VIDEO_HEIGHT 224
|
||||
#define MAX_VIDEO_PIXELS (MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT)
|
||||
@ -104,8 +98,6 @@ char retro_game_path[4096];
|
||||
|
||||
GB_gameboy_t gameboy[2];
|
||||
|
||||
extern const unsigned char dmg_boot[], cgb_boot[], agb_boot[], sgb_boot[], sgb2_boot[];
|
||||
extern const unsigned dmg_boot_length, cgb_boot_length, agb_boot_length, sgb_boot_length, sgb2_boot_length;
|
||||
bool vblank1_occurred = false, vblank2_occurred = false;
|
||||
|
||||
static void fallback_log(enum retro_log_level level, const char *fmt, ...)
|
||||
@ -224,9 +216,7 @@ static retro_environment_t environ_cb;
|
||||
static const struct retro_variable vars_single[] = {
|
||||
{ "sameduck_color_correction_mode", "Color correction; emulate hardware|preserve brightness|reduce contrast|off|correct curves" },
|
||||
{ "sameduck_high_pass_filter_mode", "High-pass filter; accurate|remove dc offset|off" },
|
||||
{ "sameduck_model", "Emulated model (Restart game); Auto|Game Boy|Game Boy Color|Game Boy Advance|Super Game Boy|Super Game Boy 2" },
|
||||
{ "sameduck_border", "Display border; Super Game Boy only|always|never" },
|
||||
{ "sameduck_rumble", "Enable rumble; rumble-enabled games|all games|never" },
|
||||
{ "sameduck_rumble", "Enable rumble; all games|never" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -235,15 +225,11 @@ static const struct retro_variable vars_dual[] = {
|
||||
{ "sameduck_link", "Link cable emulation; enabled|disabled" },
|
||||
/*{ "sameduck_ir", "Infrared Sensor Emulation; disabled|enabled" },*/
|
||||
{ "sameduck_screen_layout", "Screen layout; top-down|left-right" },
|
||||
{ "sameduck_audio_output", "Audio output; Game Boy #1|Game Boy #2" },
|
||||
{ "sameduck_model_1", "Emulated model for Game Boy #1 (Restart game); Auto|Game Boy|Game Boy Color|Game Boy Advance" },
|
||||
{ "sameduck_model_2", "Emulated model for Game Boy #2 (Restart game); Auto|Game Boy|Game Boy Color|Game Boy Advance" },
|
||||
{ "sameduck_color_correction_mode_1", "Color correction for Game Boy #1; emulate hardware|preserve brightness|reduce contrast|off|correct curves" },
|
||||
{ "sameduck_color_correction_mode_2", "Color correction for Game Boy #2; emulate hardware|preserve brightness|reduce contrast|off|correct curves" },
|
||||
{ "sameduck_high_pass_filter_mode_1", "High-pass filter for Game Boy #1; accurate|remove dc offset|off" },
|
||||
{ "sameduck_high_pass_filter_mode_2", "High-pass filter for Game Boy #2; accurate|remove dc offset|off" },
|
||||
{ "sameduck_rumble_1", "Enable rumble for Game Boy #1; rumble-enabled games|all games|never" },
|
||||
{ "sameduck_rumble_2", "Enable rumble for Game Boy #2; rumble-enabled games|all games|never" },
|
||||
{ "sameduck_audio_output", "Audio output; Mega Duck #1|Mega Duck #2" },
|
||||
{ "sameduck_high_pass_filter_mode_1", "High-pass filter for Mega Duck #1; accurate|remove dc offset|off" },
|
||||
{ "sameduck_high_pass_filter_mode_2", "High-pass filter for Mega Duck #2; accurate|remove dc offset|off" },
|
||||
{ "sameduck_rumble_1", "Enable rumble for Mega Duck #1; all games|never" },
|
||||
{ "sameduck_rumble_2", "Enable rumble for Mega Duck #2; all games|never" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -263,7 +249,7 @@ static const struct retro_subsystem_rom_info gb_roms[] = {
|
||||
};
|
||||
|
||||
static const struct retro_subsystem_info subsystems[] = {
|
||||
{ "2 Player Game Boy Link", "gb_link_2p", gb_roms, 2, RETRO_GAME_TYPE_GAMEBOY_LINK_2P },
|
||||
{ "2 Player Mega Duck Link", "gb_link_2p", gb_roms, 2, RETRO_GAME_TYPE_GAMEBOY_LINK_2P },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
@ -360,52 +346,6 @@ static void set_link_cable_state(bool state)
|
||||
}
|
||||
}
|
||||
|
||||
static void boot_rom_load(GB_gameboy_t *gb, GB_boot_rom_t type)
|
||||
{
|
||||
const char *model_name = (char *[]){
|
||||
[GB_BOOT_ROM_DMG0] = "dmg0",
|
||||
[GB_BOOT_ROM_DMG] = "dmg",
|
||||
[GB_BOOT_ROM_MGB] = "mgb",
|
||||
[GB_BOOT_ROM_SGB] = "sgb",
|
||||
[GB_BOOT_ROM_SGB2] = "sgb2",
|
||||
[GB_BOOT_ROM_CGB0] = "cgb0",
|
||||
[GB_BOOT_ROM_CGB] = "cgb",
|
||||
[GB_BOOT_ROM_AGB] = "agb",
|
||||
}[type];
|
||||
|
||||
const uint8_t *boot_code = (const unsigned char *[])
|
||||
{
|
||||
[GB_BOOT_ROM_DMG0] = dmg_boot, // dmg0 not implemented yet
|
||||
[GB_BOOT_ROM_DMG] = dmg_boot,
|
||||
[GB_BOOT_ROM_MGB] = dmg_boot, // mgb not implemented yet
|
||||
[GB_BOOT_ROM_SGB] = sgb_boot,
|
||||
[GB_BOOT_ROM_SGB2] = sgb2_boot,
|
||||
[GB_BOOT_ROM_CGB0] = cgb_boot, // cgb0 not implemented yet
|
||||
[GB_BOOT_ROM_CGB] = cgb_boot,
|
||||
[GB_BOOT_ROM_AGB] = agb_boot,
|
||||
}[type];
|
||||
|
||||
unsigned boot_length = (unsigned []){
|
||||
[GB_BOOT_ROM_DMG0] = dmg_boot_length, // dmg0 not implemented yet
|
||||
[GB_BOOT_ROM_DMG] = dmg_boot_length,
|
||||
[GB_BOOT_ROM_MGB] = dmg_boot_length, // mgb not implemented yet
|
||||
[GB_BOOT_ROM_SGB] = sgb_boot_length,
|
||||
[GB_BOOT_ROM_SGB2] = sgb2_boot_length,
|
||||
[GB_BOOT_ROM_CGB0] = cgb_boot_length, // cgb0 not implemented yet
|
||||
[GB_BOOT_ROM_CGB] = cgb_boot_length,
|
||||
[GB_BOOT_ROM_AGB] = agb_boot_length,
|
||||
}[type];
|
||||
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "%s%c%s_boot.bin", retro_system_directory, slash, model_name);
|
||||
log_cb(RETRO_LOG_INFO, "Initializing as model: %s\n", model_name);
|
||||
log_cb(RETRO_LOG_INFO, "Loading boot image: %s\n", buf);
|
||||
|
||||
if (GB_load_boot_rom(gb, buf)) {
|
||||
GB_load_boot_rom_from_buffer(gb, boot_code, boot_length);
|
||||
}
|
||||
}
|
||||
|
||||
static void retro_set_memory_maps(void)
|
||||
{
|
||||
struct retro_memory_descriptor descs[11];
|
||||
@ -491,8 +431,6 @@ static void init_for_current_model(unsigned id)
|
||||
GB_init(&gameboy[i], libretro_to_internal_model[effective_model]);
|
||||
}
|
||||
|
||||
GB_set_boot_rom_load_callback(&gameboy[i], boot_rom_load);
|
||||
|
||||
/* When running multiple devices they are assumed to use the same resolution */
|
||||
|
||||
GB_set_pixels_output(&gameboy[i],
|
||||
|
Loading…
Reference in New Issue
Block a user