ref: 572f8dd7ed70fa2f4d4efd1e4f483a0d644d340c
parent: c11300e66940377c5d7266dae33859ff363572ed
author: Snesrev <[email protected]>
date: Mon Sep 12 13:31:48 EDT 2022
Add config option to play in 16:9 or 16:10 resolution (Fixes #37) - Add ExtendedAspectRatio = 16:10 to play in 16:10 - Doesn't behave perfect everywhere - Optionally spawn/kill sprites so they behave better
--- a/ancilla.c
+++ b/ancilla.c
@@ -382,11 +382,11 @@
assert(t < 32);
for(int i = 0; i < 4; i++, t++) {
if (kInitialSpinSpark_Char[t] != 0xff) {
- Ancilla_SetOam_XY(oam,
+ uint8 ext = Ancilla_SetOam_XY(oam,
info.x + kInitialSpinSpark_X[t], info.y + kInitialSpinSpark_Y[t]);
oam->charnum = kInitialSpinSpark_Char[t];
oam->flags = kInitialSpinSpark_Flags[t] & ~0x30 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
}
@@ -1487,10 +1487,10 @@
OamEnt *oam = GetOamCurPtr();
for (int n = 3; n >= 0; n--, t++) {
if (kWallHit_Char[t] != 0) {
- Ancilla_SetOam_XY(oam, info.x + kWallHit_X[t], info.y + kWallHit_Y[t]);
+ uint8 ext = Ancilla_SetOam_XY(oam, info.x + kWallHit_X[t], info.y + kWallHit_Y[t]);
oam->charnum = kWallHit_Char[t];
oam->flags = kWallHit_Flags[t] & ~0x30 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
oam = Ancilla_AllocateOamFromCustomRegion(oam);
@@ -1930,13 +1930,13 @@
for (int i = 0; i != 2; i++) {
int t = j * 2 + i;
//kDoorDebris_XY
- Ancilla_SetOam_XY(oam, x + kDoorDebris_XY[t * 2 + 1], y + kDoorDebris_XY[t * 2 + 0]);
+ uint8 ext = Ancilla_SetOam_XY(oam, x + kDoorDebris_XY[t * 2 + 1], y + kDoorDebris_XY[t * 2 + 0]);
uint16 d = kDoorDebris_CharFlags[t];
oam->charnum = d;
oam->flags = (d >> 8) & 0xc0 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
}
}
@@ -2048,10 +2048,10 @@
uint8 flags = (link_item_bow & 4) ? 2 : 4;
for (int i = 0; i != 2; i++, j++) {
if (kArrow_Draw_Char[j] != 0xff) {
- Ancilla_SetOam_XY(oam, x + kArrow_Draw_X[j], y + kArrow_Draw_Y[j]);
+ uint8 ext = Ancilla_SetOam_XY(oam, x + kArrow_Draw_X[j], y + kArrow_Draw_Y[j]);
oam->charnum = kArrow_Draw_Char[j];
oam->flags = kArrow_Draw_Flags[j] & ~0x3E | flags | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
}
@@ -2277,18 +2277,18 @@
int j = ancilla_item_to_link[k];
uint8 flags = 0;
for (int i = 0; i < 2; i++) {
- Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y);
oam->charnum = kAncilla_JumpSplash_Char[j];
oam->flags = 0x24 | flags;
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
pt.x = x8;
flags = 0x40;
}
- Ancilla_SetOam_XY(oam, x6, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x6, pt.y);
oam->charnum = 0xc0;
oam->flags = 0x24;
- bytewise_extended_oam[oam - oam_buf] = (j == 1) ? 1 : 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | ((j == 1) ? 1 : 2);
}
void Ancilla16_HitStars(int k) { // 88a8e5
@@ -2328,10 +2328,10 @@
uint16 x = info.x, y = info.y;
uint8 flags = 0;
for (int i = 1; i >= 0; i--) {
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = kAncilla_HitStars_Char[ancilla_item_to_link[k]];
oam->flags = HIBYTE(oam_priority_value) | 4 | flags;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
flags = 0x40;
BYTE(x) = r8;
oam = HitStars_UpdateOamBufferPosition(oam + 1);
@@ -2356,10 +2356,10 @@
pt.x += kShovelDirt_XY[j * 2 + 1];
pt.y += kShovelDirt_XY[j * 2 + 0];
for (int i = 0; i < 2; i++) {
- Ancilla_SetOam_XY(oam, pt.x + i * 8, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x + i * 8, pt.y);
oam->charnum = kShovelDirt_Char[b] + i;
oam->flags = 4 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
}
}
@@ -2386,10 +2386,10 @@
Point16U pt;
Ancilla_PrepOamCoord(k, &pt);
OamEnt *oam = GetOamCurPtr();
- Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y);
oam->charnum = kBlastWallFireball_Char[blastwall_var12[k] & 8 ? 0 : blastwall_var12[k] & 4 ? 1 : 2];
oam->flags = 0x22;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
void Ancilla18_EtherSpell(int k) { // 88aaa0
@@ -2554,10 +2554,10 @@
static const uint8 kEther_BlitzBall_Char[2] = {0x68, 0x6a};
int x = (arp->r6 ? -arp->r4 : arp->r4) + ether_x2 - 8 - BG2HOFS_copy2;
int y = (arp->r2 ? -arp->r0 : arp->r0) + ether_y3 - 8 - BG2VOFS_copy2;
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = kEther_BlitzBall_Char[s];
oam->flags = 0x3c;
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
return Ancilla_AllocateOamFromCustomRegion(oam + 1);
}
@@ -2574,18 +2574,18 @@
};
int x = (arp->r6 ? -arp->r4 : arp->r4);
int y = (arp->r2 ? -arp->r0 : arp->r0);
- Ancilla_SetOam_XY(oam, x + ether_x2 - 8 - BG2HOFS_copy2, y + ether_y3 - 8 - BG2VOFS_copy2);
+ uint8 ext = Ancilla_SetOam_XY(oam, x + ether_x2 - 8 - BG2HOFS_copy2, y + ether_y3 - 8 - BG2VOFS_copy2);
int t = s * 8 + k;
oam->charnum = kEther_SpllittingBlitzSegment_Char[t * 2];
oam->flags = kEther_SpllittingBlitzSegment_Flags[t * 2];
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
oam++;
- Ancilla_SetOam_XY(oam,
+ ext = Ancilla_SetOam_XY(oam,
x + ether_x2 + kEther_SpllittingBlitzSegment_X[t] - BG2HOFS_copy2,
y + ether_y3 + kEther_SpllittingBlitzSegment_Y[t] - BG2VOFS_copy2);
oam->charnum = kEther_SpllittingBlitzSegment_Char[t * 2 + 1];
oam->flags = kEther_SpllittingBlitzSegment_Flags[t * 2 + 1];
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
return Ancilla_AllocateOamFromCustomRegion(oam + 1);
}
@@ -2597,10 +2597,10 @@
int i = ancilla_arr25[k];
int m = 0;
do {
- Ancilla_SetOam_XY(oam, info.x, info.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, info.x, info.y);
oam->charnum = kEther_BlitzSegment_Char[t * 2 + m];
oam->flags = kEther_BlitzOrb_Flags[0] | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
info.y -= 16;
oam++;
m ^= 1;
@@ -2615,10 +2615,10 @@
int t = ancilla_item_to_link[k] * 4;
for (int i = 0; i < 4; i++) {
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = kEther_BlitzOrb_Char[t + i];
oam->flags = kEther_BlitzOrb_Flags[t + i];
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
oam++;
oam = Ancilla_AllocateOamFromCustomRegion(oam);
x += 16;
@@ -2803,10 +2803,10 @@
uint16 y = bombos_y_lo[kk] | bombos_y_hi[kk] << 8;
y += kBombosSpell_FireColumn_Y[k] - BG2VOFS_copy2;
x += kBombosSpell_FireColumn_X[k] - BG2HOFS_copy2;
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = kBombosSpell_FireColumn_Char[k];
oam->flags = kBombosSpell_FireColumn_Flags[k];
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
oam++;
}
oam = Ancilla_AllocateOamFromCustomRegion(oam);
@@ -2893,12 +2893,12 @@
int t = bombos_arr3[k] * 4 + 3;
for (int j = 0; j < 4; j++, t--) {
if (kBombosSpell_DrawBlast_Char[t] != 0xff) {
- Ancilla_SetOam_XY(oam,
+ uint8 ext = Ancilla_SetOam_XY(oam,
x + kBombosSpell_DrawBlast_X[t] - BG2HOFS_copy2,
y + kBombosSpell_DrawBlast_Y[t] - BG2VOFS_copy2);
oam->charnum = kBombosSpell_DrawBlast_Char[t];
oam->flags = kBombosSpell_DrawBlast_Flags[t];
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
oam++;
}
oam = Ancilla_AllocateOamFromCustomRegion(oam);
@@ -3075,10 +3075,10 @@
OamEnt *oam = GetOamCurPtr();
int b = ancilla_arr25[k];
for (int i = 0; i < 4; i++, oam++) {
- Ancilla_SetOam_XY(oam, info.x + kMagicPowder_DrawX[b * 4 + i], info.y + kMagicPowder_DrawY[b * 4 + i]);
+ uint8 ext = Ancilla_SetOam_XY(oam, info.x + kMagicPowder_DrawX[b * 4 + i], info.y + kMagicPowder_DrawY[b * 4 + i]);
oam->charnum = kMagicPowder_Draw_Char[b];
oam->flags = kMagicPowder_Draw_Flags[b * 4 + i] & ~0x30 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
}
@@ -3166,10 +3166,10 @@
for (int n = 2; n >= 0; n--, t++) {
if (kDashDust_Draw_Char[t] != 0xff) {
- Ancilla_SetOam_XY(oam, info.x + r12 + kDashDust_Draw_X[t], info.y + kDashDust_Draw_Y[t]);
+ uint8 ext = Ancilla_SetOam_XY(oam, info.x + r12 + kDashDust_Draw_X[t], info.y + kDashDust_Draw_Y[t]);
oam->charnum = kDashDust_Draw_Char[t];
oam->flags = 4 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
}
@@ -3284,10 +3284,10 @@
int x = info.x, y = info.y;
for (int i = 2; i >= 0; i--, j++) {
if (kHookShot_Draw_Char[j] != 0xff) {
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = kHookShot_Draw_Char[j];
oam->flags = kHookShot_Draw_Flags[j] | 2 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
if (i == 1)
@@ -3318,10 +3318,10 @@
if (kHookShot_Move_X[j])
x += kHookShot_Move_X[j] + r10;
if (!Hookshot_CheckProximityToLink(x, y)) {
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = 0x19;
oam->flags = (frame_counter & 2) << 6 | 2 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
} while (--n >= 0);
@@ -3343,10 +3343,10 @@
int j = link_pose_during_opening ? 4 : 0;
uint16 x = pt.x, y = pt.y;
for (int i = 3; i >= 0; i--, j++, oam++) {
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = kBedSpread_Char[j];
oam->flags = kBedSpread_Flags[j] | 0xd | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
x += 16;
if (i == 2)
x -= 32, y += 8;
@@ -3371,10 +3371,10 @@
Point16U pt;
Ancilla_PrepOamCoord(k, &pt);
OamEnt *oam = GetOamCurPtr();
- Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y);
oam->charnum = 9;
oam->flags = 0x24;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
void Ancilla3B_SwordUpSparkle(int k) { // 88c167
@@ -3404,12 +3404,12 @@
int j = ancilla_item_to_link[k] * 4;
for (int i = 0; i < 4; i++, j++) {
if (kAncilla_VictorySparkle_Char[j] != 0xff) {
- Ancilla_SetOam_XY(oam,
+ uint8 ext = Ancilla_SetOam_XY(oam,
link_x_coord + kAncilla_VictorySparkle_X[j] - BG2HOFS_copy2,
link_y_coord + kAncilla_VictorySparkle_Y[j] - BG2VOFS_copy2);
oam->charnum = kAncilla_VictorySparkle_Char[j];
oam->flags = kAncilla_VictorySparkle_Flags[j] | 4 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
}
@@ -3430,11 +3430,11 @@
Point16U info;
Ancilla_PrepOamCoord(k, &info);
OamEnt *oam = GetOamCurPtr();
- Ancilla_SetOam_XY(oam, info.x, info.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, info.x, info.y);
int j = ancilla_item_to_link[k];
oam->charnum = kSwordChargeSpark_Char[j];
oam->flags = kSwordChargeSpark_Flags[j] | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
void Ancilla35_MasterSwordReceipt(int k) { // 88c25f
@@ -3459,10 +3459,10 @@
return;
for (int i = 0; i < 4; i++, j++, oam++) {
- Ancilla_SetOam_XY(oam, pt.x + kSwordCeremony_X[j], pt.y + kSwordCeremony_Y[j]);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x + kSwordCeremony_X[j], pt.y + kSwordCeremony_Y[j]);
oam->charnum = kSwordCeremony_Char[j];
oam->flags = kSwordCeremony_Flags[j] & ~0x30 | 4 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
}
@@ -3643,20 +3643,20 @@
OamEnt *Ancilla_ReceiveItem_Draw(int k, int x, int y) { // 88c690
OamEnt *oam = GetOamCurPtr();
int j = ancilla_item_to_link[k];
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = 0x24;
uint8 a = kWishPond2_OamFlags[j];
if (sign8(a))
a = ancilla_arr4[k];
oam->flags = a * 2 | 0x30;
- uint8 ext = kReceiveItem_Tab1[j];
+ ext |= kReceiveItem_Tab1[j];
bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
if (ext == 0) {
- Ancilla_SetOam_XY(oam, x, y + 8);
+ ext = Ancilla_SetOam_XY(oam, x, y + 8);
oam->charnum = 0x34;
oam->flags = a * 2 | 0x30;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
return oam;
@@ -3825,10 +3825,10 @@
int j = ancilla_item_to_link[k] * 2;
for (int i = 0; i != 2; i++, j++) {
if (kObjectSplash_Draw_Char[j] != 0xff) {
- Ancilla_SetOam_XY(oam, pt.x + kObjectSplash_Draw_X[j], pt.y + kObjectSplash_Draw_Y[j]);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x + kObjectSplash_Draw_X[j], pt.y + kObjectSplash_Draw_Y[j]);
oam->charnum = kObjectSplash_Draw_Char[j];
oam->flags = kObjectSplash_Draw_Flags[j] | 0x24;
- bytewise_extended_oam[oam - oam_buf] = kObjectSplash_Draw_Ext[j];
+ bytewise_extended_oam[oam - oam_buf] = ext | kObjectSplash_Draw_Ext[j];
oam++;
}
}
@@ -4111,11 +4111,11 @@
int x = breaktowerseal_sparkle_x_hi[k] << 8 | breaktowerseal_sparkle_x_lo[k];
int y = breaktowerseal_sparkle_y_hi[k] << 8 | breaktowerseal_sparkle_y_lo[k];
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
int j = breaktowerseal_sparkle_var1[k];
oam->charnum = kSwordChargeSpark_Char[j];
oam->flags = kSwordChargeSpark_Flags[j] | 0x30;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
return oam;
@@ -4147,10 +4147,10 @@
Point16U pt;
Ancilla_PrepAdjustedOamCoord(k, &pt);
OamEnt *oam = GetOamCurPtr();
- Ancilla_SetOam_XY(oam, pt.x, pt.y - (int8)ancilla_z[k]);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y - (int8)ancilla_z[k]);
oam->charnum = 0x24;
oam->flags = HIBYTE(oam_priority_value) | 4;
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
if (oam->y == 0xf0)
ancilla_type[k] = 0;
}
@@ -4225,11 +4225,11 @@
if (sign8(i))
return;
OamEnt *oam = GetOamCurPtr() + (weathervane_var14 >> 2);
- Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y);
oam->charnum = kWeathervane_Explode_Char[i];
oam->flags = 0x3c;
weathervane_var14 += 4;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
void Ancilla38_CutsceneDuck(int k) { // 88d1d8
@@ -4279,10 +4279,10 @@
Ancilla_PrepOamCoord(k, &info);
OamEnt *oam = GetOamCurPtr();
- Ancilla_SetOam_XY(oam, info.x + kTravelBird_Draw_X[0], info.y + (int8)ancilla_z[k] + kTravelBird_Draw_Y[0]);
+ uint8 ext = Ancilla_SetOam_XY(oam, info.x + kTravelBird_Draw_X[0], info.y + (int8)ancilla_z[k] + kTravelBird_Draw_Y[0]);
oam->charnum = kTravelBird_Draw_Char[0];
oam->flags = kTravelBird_Draw_Flags[0] | 0x30 | kTravelBirdIntro_Tab0[ancilla_dir[k] & 1];
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
oam++;
AncillaDraw_Shadow(oam, 1, info.x, info.y + 48, 0x30);
if (!sign16(info.x) && info.x >= 248) {
@@ -4331,10 +4331,10 @@
uint8 ext = kMorphPoof_Ext[j];
uint8 chr = kMorphPoof_Char[j];
for (int i = 0; i < 4; i++, oam++) {
- Ancilla_SetOam_XY(oam, info.x + kMorphPoof_X[j * 4 + i], info.y + kMorphPoof_Y[j * 4 + i]);
+ uint8 ext2 = Ancilla_SetOam_XY(oam, info.x + kMorphPoof_X[j * 4 + i], info.y + kMorphPoof_Y[j * 4 + i]);
oam->charnum = chr;
oam->flags = kMorphPoof_Flags[j * 4 + i] | 4 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = ext;
+ bytewise_extended_oam[oam - oam_buf] = ext | ext2;
if (ext == 2)
break;
}
@@ -4372,10 +4372,10 @@
int j = ancilla_item_to_link[k] * 4;
for (int i = 0; i < 4; i++, j++, oam++) {
- Ancilla_SetOam_XY(oam, pt.x + kBushPoof_Draw_X[j], pt.y + kBushPoof_Draw_Y[j]);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x + kBushPoof_Draw_X[j], pt.y + kBushPoof_Draw_Y[j]);
oam->charnum = kBushPoof_Draw_Char[j];
oam->flags = kBushPoof_Draw_Flags[j] | 4 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
}
@@ -4421,8 +4421,8 @@
continue;
oam->charnum = chr;
oam->flags = kSwordSwingSparkle_Flags[k] | 0x4 | (oam_priority_value >> 8);
- Ancilla_SetOam_XY(oam, info.x + kSwordSwingSparkle_X[k], info.y + kSwordSwingSparkle_Y[k]);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ uint8 ext = Ancilla_SetOam_XY(oam, info.x + kSwordSwingSparkle_X[k], info.y + kSwordSwingSparkle_Y[k]);
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
}
@@ -4505,10 +4505,10 @@
if (submodule_index == 0)
swordbeam_arr[i] = (swordbeam_arr[i] + 4) & 0x3f;
Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
- Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y);
oam->charnum = kSpinSpark_Char[i];
oam->flags = flags | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
} while (oam++, --i >= 0);
if (submodule_index == 0) {
@@ -4527,10 +4527,10 @@
if (t != 3) {
static const uint8 kSpinSpark_Char2[3] = {0xb7, 0x80, 0x83};
Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_var1, swordbeam_var2));
- Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y);
oam->charnum = kSpinSpark_Char2[t];
oam->flags = 4 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
endif_2:
if (ancilla_item_to_link[k] == 7)
@@ -4591,10 +4591,10 @@
OamEnt *oam = GetOamCurPtr();
for (int i = 0; i < 4; i++, j++) {
if (kInitialCaneSpark_Draw_Char[j] != 255) {
- Ancilla_SetOam_XY(oam, pt.x + kInitialCaneSpark_Draw_X[j], pt.y + kInitialCaneSpark_Draw_Y[j]);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x + kInitialCaneSpark_Draw_X[j], pt.y + kInitialCaneSpark_Draw_Y[j]);
oam->charnum = kInitialCaneSpark_Draw_Char[j];
oam->flags = kInitialCaneSpark_Draw_Flags[j] & ~0x30 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
}
@@ -4674,10 +4674,10 @@
if (!submodule_index)
swordbeam_arr[i] = (swordbeam_arr[i] + 3) & 0x3f;
Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
- Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y);
oam->charnum = kCaneSpark_Char[i];
oam->flags = flags | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
Ancilla_SetXY(k, pt.x + BG2HOFS_copy2, pt.y + BG2VOFS_copy2);
ancilla_dir[k] = 0;
@@ -4724,10 +4724,10 @@
if (submodule_index == 0)
swordbeam_arr[i] = (swordbeam_arr[i] + s) & 0x3f;
Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
- Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y);
oam->charnum = kSwordBeam_Char[i];
oam->flags = flags | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
if (submodule_index == 0) {
@@ -4746,10 +4746,10 @@
if (t != 3) {
static const uint8 kSwordBeam_Char2[3] = {0xb7, 0x80, 0x83};
Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_var1, swordbeam_var2));
- Ancilla_SetOam_XY(oam, pt.x, pt.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y);
oam->charnum = kSwordBeam_Char2[t];
oam->flags = 4 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
endif_2:
oam -= 4;
@@ -4779,10 +4779,10 @@
oam_priority_value = kSwordFullChargeSpark_Flags[ancilla_floor[k]] << 8;
OamEnt *oam = GetOamCurPtr();
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = 0xd7;
oam->flags = HIBYTE(oam_priority_value) | 2;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
void Ancilla27_Duck(int k) { // 88dde8
@@ -4890,10 +4890,10 @@
int z = ancilla_z[k] ? ancilla_z[k] | ~0xff : 0;
int i = 0, n = ancilla_step[k] + 1;
do {
- Ancilla_SetOam_XY(oam, info.x + (int8)kTravelBird_Draw_X[i], info.y + z + (int8)kTravelBird_Draw_Y[i]);
+ uint8 ext = Ancilla_SetOam_XY(oam, info.x + (int8)kTravelBird_Draw_X[i], info.y + z + (int8)kTravelBird_Draw_Y[i]);
oam->charnum = kTravelBird_Draw_Char[i];
oam->flags = kTravelBird_Draw_Flags[i] | 0x30;
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
oam++;
} while (++i != n);
@@ -5270,10 +5270,10 @@
int j = ancilla_item_to_link[k] * 2;
for (int i = 0; i < 2; i++, j++, oam++) {
if (kSomariaBlockFizzle_Char[j] != 0xff) {
- Ancilla_SetOam_XY(oam, x + kSomariaBlockFizzle_X[j], y + kSomariaBlockFizzle_Y[j]);
+ uint8 ext = Ancilla_SetOam_XY(oam, x + kSomariaBlockFizzle_X[j], y + kSomariaBlockFizzle_Y[j]);
oam->charnum = kSomariaBlockFizzle_Char[j];
oam->flags = kSomariaBlockFizzle_Flags[j] & ~0x30 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
}
}
@@ -5332,10 +5332,10 @@
int8 z = ancilla_z[k] + (ancilla_K[k] == 3 && BYTE(link_z_coord) != 0xff ? BYTE(link_z_coord) : 0);
int j = ancilla_item_to_link[k] * 8;
for (int i = 0; i != 8; i++, j++, oam++) {
- Ancilla_SetOam_XY(oam, pt.x + kSomarianBlockDivide_X[j], pt.y + kSomarianBlockDivide_Y[j] - z);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x + kSomarianBlockDivide_X[j], pt.y + kSomarianBlockDivide_Y[j] - z);
oam->charnum = kSomarianBlockDivide_Char[j];
oam->flags = kSomarianBlockDivide_Flags[j] & ~0x30 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
}
@@ -5354,10 +5354,10 @@
int j = (ancilla_timer[k] & 0xf8) >> 1;
do {
if (kLampFlame_Draw_Char[j] != 0xff) {
- Ancilla_SetOam_XY(oam, pt.x + kLampFlame_Draw_X[j], pt.y + kLampFlame_Draw_Y[j]);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x + kLampFlame_Draw_X[j], pt.y + kLampFlame_Draw_Y[j]);
oam->charnum = kLampFlame_Draw_Char[j];
oam->flags = HIBYTE(oam_priority_value) | 2;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
} while (++j & 3);
@@ -5404,10 +5404,10 @@
int j = ancilla_item_to_link[k] * 2;
for (int i = 0; i != 2; i++, j++, oam++) {
if (kWaterfallSplash_Char[j] != 0xff) {
- Ancilla_SetOam_XY(oam, pt.x + kWaterfallSplash_X[j], pt.y + kWaterfallSplash_Y[j]);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x + kWaterfallSplash_X[j], pt.y + kWaterfallSplash_Y[j]);
oam->charnum = kWaterfallSplash_Char[j];
oam->flags = kWaterfallSplash_Flags[j] | 0x30;
- bytewise_extended_oam[oam - oam_buf] = kWaterfallSplash_Ext[j];
+ bytewise_extended_oam[oam - oam_buf] = ext | kWaterfallSplash_Ext[j];
}
}
}
@@ -5421,10 +5421,10 @@
OamEnt *oam = GetOamCurPtr();
uint16 x = pt.x, y = pt.y;
for (int i = 0; i < 4; i++, oam++) {
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = kAncilla_Gravestone_Char[i];
oam->flags = kAncilla_Gravestone_Flags[i] | 0x3d;
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
x += 16;
if (i == 1)
x -= 32, y += 8;
@@ -5487,17 +5487,17 @@
int j = skullwoodsfire_var0[k];
uint16 x = skullwoodsfire_x_arr[k] - BG2HOFS_copy2;
uint16 y = skullwoodsfire_y_arr[k] - BG2VOFS_copy2 + kSkullWoodsFire_Draw_Y[j];
- Ancilla_SetOam_XY(oam, x, y);
+ uint8 ext2 = Ancilla_SetOam_XY(oam, x, y);
oam->charnum = kSkullWoodsFire_Draw_Char[j];
oam->flags = 0x32;
uint8 ext = kSkullWoodsFire_Draw_Ext[j];
- bytewise_extended_oam[oam - oam_buf] = ext;
+ bytewise_extended_oam[oam - oam_buf] = ext | ext2;
oam++;
if (kSkullWoodsFire_Draw_Ext[j] != 2) {
- Ancilla_SetOam_XY(oam, x + 8, y);
+ uint8 ext2 = Ancilla_SetOam_XY(oam, x + 8, y);
oam->charnum = kSkullWoodsFire_Draw_Char[j] + 1;
oam->flags = 0x32;
- bytewise_extended_oam[oam - oam_buf] = ext;
+ bytewise_extended_oam[oam - oam_buf] = ext | ext2;
oam++;
}
}
@@ -5516,12 +5516,12 @@
int j = ancilla_item_to_link[k] * 6;
for (int i = 0; i < 6; i++, j++) {
if (kSkullWoodsFire_Draw2_Char[j] != 0xff) {
- Ancilla_SetOam_XY(oam,
+ uint8 ext = Ancilla_SetOam_XY(oam,
168 - BG2HOFS_copy2 + kSkullWoodsFire_Draw2_X[j],
200 - BG2VOFS_copy2 + kSkullWoodsFire_Draw2_Y[j]);
oam->charnum = kSkullWoodsFire_Draw2_Char[j];
oam->flags = kSkullWoodsFire_Draw2_Flags[j] | 0x32;
- bytewise_extended_oam[oam - oam_buf] = kSkullWoodsFire_Draw2_Ext[j];
+ bytewise_extended_oam[oam - oam_buf] = ext | kSkullWoodsFire_Draw2_Ext[j];
oam++;
}
}
@@ -5618,7 +5618,7 @@
Ancilla_PrepOamCoord(k, &pt);
OamEnt *oam = GetOamCurPtr();
int t = (ancilla_step[k] == 1 && ancilla_L[k]) ? ancilla_item_to_link[k] + 1 : 0;
- Ancilla_SetOam_XY(oam, pt.x, pt.y - (int8)ancilla_z[k]);
+ uint8 ext = Ancilla_SetOam_XY(oam, pt.x, pt.y - (int8)ancilla_z[k]);
if (t != 0)
t += 1;
else
@@ -5625,7 +5625,7 @@
t = (frame_counter >> 2) & 1;
oam->charnum = kAncilla_RevivalFaerie_Tab1[t];
oam->flags = 0x74;
- bytewise_extended_oam[oam - oam_buf] = 2;
+ bytewise_extended_oam[oam - oam_buf] = ext | 2;
if (oam->y == 0xf0) {
ancilla_step[k] = 3;
submodule_index++;
@@ -5708,15 +5708,15 @@
OamEnt *oam = GetOamCurPtr();
int k = flag_for_boomerang_in_place;
do {
- Ancilla_SetOam_XY(oam, Ancilla_GetX(k), 0x57);
+ uint8 ext = Ancilla_SetOam_XY(oam, Ancilla_GetX(k), 0x57);
oam->charnum = kGameOverText_Chars[k * 2 + 0];
oam->flags = 0x3c;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
- Ancilla_SetOam_XY(oam, Ancilla_GetX(k), 0x5f);
+ ext = Ancilla_SetOam_XY(oam, Ancilla_GetX(k), 0x5f);
oam->charnum = kGameOverText_Chars[k * 2 + 1];
oam->flags = 0x3c;
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
} while (--k >= 0);
}
@@ -5748,14 +5748,19 @@
info->y = Ancilla_GetY(k) - BG2VOFS_copy;
}
-void Ancilla_SetOam_XY(OamEnt *oam, uint16 x, uint16 y) { // 88f6e1
+
+uint8 Ancilla_SetOam_XY(OamEnt *oam, uint16 x, uint16 y) { // 88f6e1
+ uint8 rv = 0;
uint8 yval = 0xf0;
- if (x < 256 && y < 256) {
+ int xt = (g_ram[kRam_Features0] & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+ if ((uint16)(x + xt) < 256 + xt * 2 && y < 256) {
+ rv = (x >> 8) & 1;
oam->x = x;
if (y < 0xf0)
yval = y;
}
oam->y = yval;
+ return rv;
}
uint8 Ancilla_SetOam_XY_safe(OamEnt *oam, uint16 x, uint16 y) { // 88f702
@@ -7170,10 +7175,10 @@
Point16U info;
Ancilla_PrepOamCoord(k, &info);
OamEnt *oam = GetOamCurPtr();
- Ancilla_SetOam_XY(oam, info.x, info.y);
+ uint8 ext = Ancilla_SetOam_XY(oam, info.x, info.y);
oam->charnum = kMotiveDashDust_Draw_Char[ancilla_item_to_link[k]];
oam->flags = 4 | HIBYTE(oam_priority_value);
- bytewise_extended_oam[oam - oam_buf] = 0;
+ bytewise_extended_oam[oam - oam_buf] = ext;
}
uint8 Ancilla_CalculateSfxPan(int k) { // 8dbb5e
@@ -7302,9 +7307,10 @@
}
void Ancilla_TerminateIfOffscreen(int j) { // 8ffd52
- uint16 x = Ancilla_GetX(j) - BG2HOFS_copy2;
+ int xt = (g_ram[kRam_Features0] & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+ uint16 x = Ancilla_GetX(j) - BG2HOFS_copy2 + xt;
uint16 y = Ancilla_GetY(j) - BG2VOFS_copy2;
- if (x >= 244 || y >= 240)
+ if (x >= 244 + xt * 2 || y >= 240)
ancilla_type[j] = 0;
}
--- a/ancilla.h
+++ b/ancilla.h
@@ -197,7 +197,7 @@
int AncillaAdd_AddAncilla_Bank08(uint8 type, uint8 y);
void Ancilla_PrepOamCoord(int k, Point16U *info);
void Ancilla_PrepAdjustedOamCoord(int k, Point16U *info);
-void Ancilla_SetOam_XY(OamEnt *oam, uint16 x, uint16 y);
+uint8 Ancilla_SetOam_XY(OamEnt *oam, uint16 x, uint16 y);
uint8 Ancilla_SetOam_XY_safe(OamEnt *oam, uint16 x, uint16 y);
bool Ancilla_CheckLinkCollision(int k, int j, CheckPlayerCollOut *out);
bool Hookshot_CheckProximityToLink(int x, int y);
--- a/config.c
+++ b/config.c
@@ -238,6 +238,20 @@
if (StringEqualsNoCase(key, "Autosave")) {
g_config.autosave = (bool)strtol(value, (char**)NULL, 10);
return true;
+ } else if (StringEqualsNoCase(key, "ExtendedAspectRatio")) {
+ const char* s;
+ while ((s = NextDelim(&value, ',')) != NULL) {
+ if (strcmp(s, "16:9") == 0)
+ g_config.extended_aspect_ratio = (224 * 16 / 9 - 256) / 2;
+ else if (strcmp(s, "16:10") == 0)
+ g_config.extended_aspect_ratio = (224 * 16 / 10 - 256) / 2;
+ else if (strcmp(s, "unchanged_sprites") == 0)
+ g_config.extended_aspect_ratio_nospr = true;
+ else
+ return false;
+ }
+
+ return true;
} else if (StringEqualsNoCase(key, "DisplayPerfInTitle")) {
g_config.display_perf_title = (bool)strtol(value, (char**)NULL, 10);
return true;
@@ -265,23 +279,6 @@
if (length) *length = size;
return buffer;
}
-
-/*
-uint8 *WriteFile(const char *name) {
- FILE *f = fopen(name, "w");
- if (f == NULL)
- return NULL;
-}
-
-void SaveConfigFile() {
- uint8* file = ReadFile("zelda3.user.ini", NULL);
- if (!file) {
- file = ReadFile("zelda3.ini", NULL);
- if (!file)
- return;
- }
-}
-*/
void ParseConfigFile() {
uint8 *file = ReadFile("zelda3.user.ini", NULL);
--- a/config.h
+++ b/config.h
@@ -42,6 +42,8 @@
uint8 audio_channels;
uint16 audio_samples;
bool autosave;
+ uint8 extended_aspect_ratio;
+ bool extended_aspect_ratio_nospr;
bool display_perf_title;
} Config;
--- a/dungeon.h
+++ b/dungeon.h
@@ -1,5 +1,7 @@
#pragma once
+typedef struct RoomBounds RoomBounds;
+
enum {
kDoorType_Regular = 0,
kDoorType_Regular2 = 2,
@@ -40,18 +42,6 @@
uint8 pal2;
uint8 pal3;
} DungPalInfo;
-
-typedef struct RoomBounds {
- union {
- struct {
- uint16 a0, b0, a1, b1;
- };
- uint16 v[4];
- };
-} RoomBounds;
-
-#define room_bounds_y (*(RoomBounds*)(g_ram+0x600))
-#define room_bounds_x (*(RoomBounds*)(g_ram+0x608))
extern const uint8 kDungAnimatedTiles[24];
uint16 *DstoPtr(uint16 d);
--- a/main.c
+++ b/main.c
@@ -43,7 +43,6 @@
enum {
- kRenderWidth = 256 * 2,
kRenderHeight = 224 * 2,
kDefaultFullscreen = 0,
kDefaultWindowScale = 2,
@@ -66,9 +65,10 @@
static bool g_display_perf;
static int g_curr_fps;
static int g_ppu_render_flags = 0;
-bool g_run_without_emu = false;
+static bool g_run_without_emu = false;
+static int g_snes_width;
+static const int g_snes_height = kRenderHeight;
-
void NORETURN Die(const char *error) {
fprintf(stderr, "Error: %s\n", error);
exit(1);
@@ -99,14 +99,14 @@
bt = 31;
}
// Allow a scale level slightly above the max that fits on screen
- int mw = (bounds.w - bl - br + (kRenderWidth / kDefaultWindowScale) / 4) / (kRenderWidth / kDefaultWindowScale);
- int mh = (bounds.h - bt - bb + (kRenderHeight / kDefaultWindowScale) / 4) / (kRenderHeight / kDefaultWindowScale);
+ int mw = (bounds.w - bl - br + (g_snes_width / kDefaultWindowScale) / 4) / (g_snes_width / kDefaultWindowScale);
+ int mh = (bounds.h - bt - bb + (g_snes_height / kDefaultWindowScale) / 4) / (g_snes_height / kDefaultWindowScale);
max_scale = IntMin(mw, mh);
}
int new_scale = IntMax(IntMin(g_current_window_scale + scale_step, max_scale), 1);
g_current_window_scale = new_scale;
- int w = new_scale * (kRenderWidth / kDefaultWindowScale);
- int h = new_scale * (kRenderHeight / kDefaultWindowScale);
+ int w = new_scale * (g_snes_width / kDefaultWindowScale);
+ int h = new_scale * (g_snes_height / kDefaultWindowScale);
//SDL_RenderSetLogicalSize(g_renderer, w, h);
SDL_SetWindowSize(g_window, w, h);
@@ -179,6 +179,10 @@
ParseConfigFile();
AfterConfigParse();
+ ZeldaInitialize();
+ g_zenv.ppu->extraLeftRight = UintMin(g_config.extended_aspect_ratio, kPpuExtraLeftRight);
+ g_snes_width = 2 * (g_config.extended_aspect_ratio * 2 + 256);
+ g_wanted_zelda_features = (g_zenv.ppu->extraLeftRight && !g_config.extended_aspect_ratio_nospr) ? kFeatures0_ExtendScreen64 : 0;
g_ppu_render_flags = g_config.new_renderer * kPpuRenderFlags_NewRenderer | g_config.enhanced_mode7 * kPpuRenderFlags_4x4Mode7;
if (g_config.fullscreen == 1)
@@ -207,8 +211,8 @@
return 1;
}
- int window_width = g_current_window_scale * (kRenderWidth / kDefaultWindowScale);
- int window_height = g_current_window_scale * (kRenderHeight / kDefaultWindowScale);
+ int window_width = g_current_window_scale * (g_snes_width / kDefaultWindowScale);
+ int window_height = g_current_window_scale * (g_snes_height / kDefaultWindowScale);
SDL_Window* window = SDL_CreateWindow(kWindowTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, g_win_flags);
if(window == NULL) {
printf("Failed to create window: %s\n", SDL_GetError());
@@ -231,8 +235,8 @@
g_renderer = renderer;
if (!g_config.ignore_aspect_ratio)
- SDL_RenderSetLogicalSize(renderer, kRenderWidth, kRenderHeight);
- SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, kRenderWidth * 2, kRenderHeight * 2);
+ SDL_RenderSetLogicalSize(renderer, g_snes_width, g_snes_height);
+ SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, g_snes_width * 2, g_snes_height * 2);
if(texture == NULL) {
printf("Failed to create texture: %s\n", SDL_GetError());
return 1;
@@ -274,7 +278,6 @@
#endif
SetSnes(snes);
- ZeldaInitialize();
ZeldaReadSram(snes);
for (int i = 0; i < SDL_NumJoysticks(); i++)
@@ -486,7 +489,7 @@
uint64 t3 = SDL_GetPerformanceCounter();
SDL_RenderClear(renderer);
uint64 t4 = SDL_GetPerformanceCounter();
- SDL_Rect src_rect = { 0, 0, kRenderWidth, kRenderHeight };
+ SDL_Rect src_rect = { 0, 0, g_snes_width, g_snes_height };
SDL_RenderCopy(renderer, texture, hq ? NULL : &src_rect, NULL);
uint64 t5 = SDL_GetPerformanceCounter();
--- a/snes/ppu.c
+++ b/snes/ppu.c
@@ -38,6 +38,9 @@
memset(ppu->vram, 0, sizeof(ppu->vram));
ppu->lastBrightnessMult = 0xff;
ppu->lastMosaicModulo = 0xff;
+ ppu->extraLeftCur = 0;
+ ppu->extraRightCur = 0;
+ ppu->extraLeftRight = kPpuExtraLeftRight;
ppu->vramPointer = 0;
ppu->vramIncrementOnHigh = false;
ppu->vramIncrement = 1;
@@ -133,7 +136,9 @@
}
void ppu_saveload(Ppu *ppu, SaveLoadFunc *func, void *ctx) {
- func(ctx, &ppu->vram, offsetof(Ppu, mosaicModulo) - offsetof(Ppu, vram));
+ func(ctx, &ppu->vram, offsetof(Ppu, objBuffer) - offsetof(Ppu, vram));
+ func(ctx, &ppu->objBuffer, 512);
+ func(ctx, &ppu->timeOver, offsetof(Ppu, mosaicModulo) - offsetof(Ppu, timeOver));
}
bool PpuBeginDrawing(Ppu *ppu, uint8_t *pixels, size_t pitch, uint32_t render_flags) {
@@ -160,7 +165,6 @@
ppu->colorMapRgb[i] = ppu->brightnessMult[color & 0x1f] << 16 | ppu->brightnessMult[(color >> 5) & 0x1f] << 8 | ppu->brightnessMult[(color >> 10) & 0x1f];
}
}
-
return hq;
}
@@ -174,7 +178,7 @@
if (ppu->mosaicSize != ppu->lastMosaicModulo) {
int mod = ppu->mosaicSize;
ppu->lastMosaicModulo = mod;
- for (int i = 0, j = 0; i < 256; i++) {
+ for (int i = 0, j = 0; i < countof(ppu->mosaicModulo); i++) {
ppu->mosaicModulo[i] = i - j;
j = (j + 1 == mod ? 0 : j + 1);
}
@@ -195,19 +199,18 @@
uint8 *dst = ppu->renderBuffer + ((line - 1) * 2 * ppu->renderPitch);
memcpy(dst + ppu->renderPitch, dst, 512 * 4);
}
-
}
}
typedef struct PpuWindows {
- uint16 edges[6];
+ int16 edges[6];
uint8 nr;
uint8 bits;
} PpuWindows;
-static void PpuWindows_Clear(PpuWindows *win) {
- win->edges[0] = 0;
- win->edges[1] = 256;
+static void PpuWindows_Clear(PpuWindows *win, Ppu *ppu) {
+ win->edges[0] = -ppu->extraLeftCur;
+ win->edges[1] = 256 + ppu->extraRightCur;
win->nr = 1;
win->bits = 0;
}
@@ -218,19 +221,21 @@
// There are at most 5 windows.
// Algorithm from Snes9x
uint nr = 1;
- win->edges[0] = 0;
- win->edges[1] = 256;
+ int window_right = 256 + ppu->extraRightCur;
+ win->edges[0] = - ppu->extraLeftCur;
+ win->edges[1] = window_right;
uint8 window_bits = 0;
- uint i, j, t;
+ uint i, j;
+ int t;
bool w1_ena = wl->window1enabled && ppu->window1left <= ppu->window1right;
if (w1_ena) {
- if (ppu->window1left) {
+ if (ppu->window1left > win->edges[0]) {
win->edges[nr] = ppu->window1left;
- win->edges[++nr] = 256;
+ win->edges[++nr] = window_right;
}
- if (ppu->window1right < 255) {
+ if (ppu->window1right + 1 < window_right) {
win->edges[nr] = ppu->window1right + 1;
- win->edges[++nr] = 256;
+ win->edges[++nr] = window_right;
}
}
bool w2_ena = wl->window2enabled && ppu->window2left <= ppu->window2right;
@@ -276,10 +281,10 @@
static void PpuDrawBackground_4bpp(Ppu *ppu, uint y, bool sub, uint layer, uint8 zhi, uint8 zlo) {
#define DO_PIXEL(i) do { \
pixel = (bits >> i) & 1 | (bits >> (7 + i)) & 2 | (bits >> (14 + i)) & 4 | (bits >> (21 + i)) & 8; \
- if (pixel && z > dst[256 + i]) dst[i] = paletteBase + pixel, dst[256 + i] = z; } while (0)
+ if (pixel && z > dst[kPpuXPixels + i]) dst[i] = paletteBase + pixel, dst[kPpuXPixels + i] = z; } while (0)
#define DO_PIXEL_HFLIP(i) do { \
pixel = (bits >> (7 - i)) & 1 | (bits >> (14 - i)) & 2 | (bits >> (21 - i)) & 4 | (bits >> (28 - i)) & 8; \
- if (pixel && z > dst[256 + i]) dst[i] = paletteBase + pixel, dst[256 + i] = z; } while (0)
+ if (pixel && z > dst[kPpuXPixels + i]) dst[i] = paletteBase + pixel, dst[kPpuXPixels + i] = z; } while (0)
#define READ_BITS(ta, tile) (addr = &ppu->vram[((ta) + (tile) * 16) & 0x7fff], addr[0] | addr[8] << 16)
enum { kPaletteShift = 6 };
Layer *layerp = &ppu->layer[layer];
@@ -286,7 +291,7 @@
if (!layerp->screenEnabled[sub])
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win);
+ layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu);
BgLayer *bglayer = &ppu->bgLayer[layer];
y += bglayer->vScroll;
int sc_offs = bglayer->tilemapAdr + (((y >> 3) & 0x1f) << 5);
@@ -304,16 +309,17 @@
continue; // layer is disabled for this window part
uint x = win.edges[windex] + bglayer->hScroll;
uint w = win.edges[windex + 1] - win.edges[windex];
- uint8 *dst = ppu->bgBuffers[sub].pixel + win.edges[windex];
+ uint8 *dst = ppu->bgBuffers[sub].pixel + win.edges[windex] + kPpuExtraLeftRight;
const uint16 *tp = tps[x >> 8 & 1] + ((x >> 3) & 0x1f);
const uint16 *tp_last = tps[x >> 8 & 1] + 31;
const uint16 *tp_next = tps[(x >> 8 & 1) ^ 1];
+#define NEXT_TP() if (tp != tp_last) tp += 1; else tp = tp_next, tp_next = tp_last - 31, tp_last = tp + 31;
// Handle clipped pixels on left side
if (x & 7) {
int curw = IntMin(8 - (x & 7), w);
w -= curw;
uint32 tile = *tp;
- tp = (tp != tp_last) ? tp + 1 : tp_next;
+ NEXT_TP();
int ta = (tile & 0x8000) ? tileadr1 : tileadr0;
uint8 z = (tile & 0x2000) ? zhi : zlo;
uint32 bits = READ_BITS(ta, tile & 0x3ff);
@@ -333,7 +339,7 @@
// Handle full tiles in the middle
while (w >= 8) {
uint32 tile = *tp;
- tp = (tp != tp_last) ? tp + 1 : tp_next;
+ NEXT_TP();
int ta = (tile & 0x8000) ? tileadr1 : tileadr0;
uint8 z = (tile & 0x2000) ? zhi : zlo;
uint32 bits = READ_BITS(ta, tile & 0x3ff);
@@ -374,10 +380,10 @@
static void PpuDrawBackground_2bpp(Ppu *ppu, uint y, bool sub, uint layer, uint8 zhi, uint8 zlo) {
#define DO_PIXEL(i) do { \
pixel = (bits >> i) & 1 | (bits >> (7 + i)) & 2; \
- if (pixel && z > dst[256 + i]) dst[i] = paletteBase + pixel, dst[256 + i] = z; } while (0)
+ if (pixel && z > dst[kPpuXPixels + i]) dst[i] = paletteBase + pixel, dst[kPpuXPixels + i] = z; } while (0)
#define DO_PIXEL_HFLIP(i) do { \
pixel = (bits >> (7 - i)) & 1 | (bits >> (14 - i)) & 2; \
- if (pixel && z > dst[256 + i]) dst[i] = paletteBase + pixel, dst[256 + i] = z; } while (0)
+ if (pixel && z > dst[kPpuXPixels + i]) dst[i] = paletteBase + pixel, dst[kPpuXPixels + i] = z; } while (0)
#define READ_BITS(ta, tile) (addr = &ppu->vram[(ta) + (tile) * 8 & 0x7fff], addr[0])
enum { kPaletteShift = 8 };
Layer *layerp = &ppu->layer[layer];
@@ -384,7 +390,7 @@
if (!layerp->screenEnabled[sub])
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win);
+ layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu);
BgLayer *bglayer = &ppu->bgLayer[layer];
y += bglayer->vScroll;
int sc_offs = bglayer->tilemapAdr + (((y >> 3) & 0x1f) << 5);
@@ -396,6 +402,7 @@
};
int tileadr = ppu->bgLayer[layer].tileAdr, pixel;
int tileadr1 = tileadr + 7 - (y & 0x7), tileadr0 = tileadr + (y & 0x7);
+
const uint16 *addr;
for (size_t windex = 0; windex < win.nr; windex++) {
if (win.bits & (1 << windex))
@@ -402,16 +409,18 @@
continue; // layer is disabled for this window part
uint x = win.edges[windex] + bglayer->hScroll;
uint w = win.edges[windex + 1] - win.edges[windex];
- uint8 *dst = ppu->bgBuffers[sub].pixel + win.edges[windex];
+ uint8 *dst = ppu->bgBuffers[sub].pixel + win.edges[windex] + kPpuExtraLeftRight;
const uint16 *tp = tps[x >> 8 & 1] + ((x >> 3) & 0x1f);
const uint16 *tp_last = tps[x >> 8 & 1] + 31;
const uint16 *tp_next = tps[(x >> 8 & 1) ^ 1];
+
+#define NEXT_TP() if (tp != tp_last) tp += 1; else tp = tp_next, tp_next = tp_last - 31, tp_last = tp + 31;
// Handle clipped pixels on left side
if (x & 7) {
int curw = IntMin(8 - (x & 7), w);
w -= curw;
uint32 tile = *tp;
- tp = (tp != tp_last) ? tp + 1 : tp_next;
+ NEXT_TP();
int ta = (tile & 0x8000) ? tileadr1 : tileadr0;
uint8 z = (tile & 0x2000) ? zhi : zlo;
uint32 bits = READ_BITS(ta, tile & 0x3ff);
@@ -431,7 +440,7 @@
// Handle full tiles in the middle
while (w >= 8) {
uint32 tile = *tp;
- tp = (tp != tp_last) ? tp + 1 : tp_next;
+ NEXT_TP();
int ta = (tile & 0x8000) ? tileadr1 : tileadr0;
uint8 z = (tile & 0x2000) ? zhi : zlo;
uint32 bits = READ_BITS(ta, tile & 0x3ff);
@@ -463,6 +472,7 @@
}
}
}
+#undef NEXT_TP
#undef READ_BITS
#undef DO_PIXEL
#undef DO_PIXEL_HFLIP
@@ -478,7 +488,7 @@
if (!layerp->screenEnabled[sub])
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win);
+ layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu);
BgLayer *bglayer = &ppu->bgLayer[layer];
y = ppu->mosaicModulo[y] + bglayer->vScroll;
int sc_offs = bglayer->tilemapAdr + (((y >> 3) & 0x1f) << 5);
@@ -495,8 +505,8 @@
if (win.bits & (1 << windex))
continue; // layer is disabled for this window part
int sx = win.edges[windex];
- uint8 *dst = ppu->bgBuffers[sub].pixel + sx;
- uint8 *dst_end = ppu->bgBuffers[sub].pixel + win.edges[windex + 1];
+ uint8 *dst = ppu->bgBuffers[sub].pixel + sx + kPpuExtraLeftRight;
+ uint8 *dst_end = ppu->bgBuffers[sub].pixel + win.edges[windex + 1] + kPpuExtraLeftRight;
uint x = sx + bglayer->hScroll;
const uint16 *tp = tps[x >> 8 & 1] + ((x >> 3) & 0x1f);
const uint16 *tp_last = tps[x >> 8 & 1] + 31, *tp_next = tps[(x >> 8 & 1) ^ 1];
@@ -513,8 +523,8 @@
pixel += (tile & 0x1c00) >> kPaletteShift;
int i = 0;
do {
- if (z > dst[i + 256])
- dst[i] = pixel, dst[i + 256] = z;
+ if (z > dst[i + kPpuXPixels])
+ dst[i] = pixel, dst[i + kPpuXPixels] = z;
} while (++i != w);
}
dst += w, x += w;
@@ -538,7 +548,7 @@
if (!layerp->screenEnabled[sub])
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win);
+ layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu);
BgLayer *bglayer = &ppu->bgLayer[layer];
y = ppu->mosaicModulo[y] + bglayer->vScroll;
int sc_offs = bglayer->tilemapAdr + (((y >> 3) & 0x1f) << 5);
@@ -555,8 +565,8 @@
if (win.bits & (1 << windex))
continue; // layer is disabled for this window part
int sx = win.edges[windex];
- uint8 *dst = ppu->bgBuffers[sub].pixel + sx;
- uint8 *dst_end = ppu->bgBuffers[sub].pixel + win.edges[windex + 1];
+ uint8 *dst = ppu->bgBuffers[sub].pixel + sx + kPpuExtraLeftRight;
+ uint8 *dst_end = ppu->bgBuffers[sub].pixel + win.edges[windex + 1] + kPpuExtraLeftRight;
uint x = sx + bglayer->hScroll;
const uint16 *tp = tps[x >> 8 & 1] + ((x >> 3) & 0x1f);
const uint16 *tp_last = tps[x >> 8 & 1] + 31, *tp_next = tps[(x >> 8 & 1) ^ 1];
@@ -573,8 +583,8 @@
pixel += (tile & 0x1c00) >> kPaletteShift;
uint i = 0;
do {
- if (z > dst[i + 256])
- dst[i] = pixel, dst[i + 256] = z;
+ if (z > dst[i + kPpuXPixels])
+ dst[i] = pixel, dst[i + kPpuXPixels] = z;
} while (++i != w);
}
dst += w, x += w;
@@ -598,21 +608,21 @@
if (!layerp->screenEnabled[sub])
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, 4) : PpuWindows_Clear(&win);
+ layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, 4) : PpuWindows_Clear(&win, ppu);
for (size_t windex = 0; windex < win.nr; windex++) {
if (win.bits & (1 << windex))
continue; // layer is disabled for this window part
int left = win.edges[windex];
int width = win.edges[windex + 1] - left;
- uint8 *src = ppu->objBuffer.pixel + left;
- uint8 *dst = ppu->bgBuffers[sub].pixel + left;
+ uint8 *src = ppu->objBuffer.pixel + left + kPpuExtraLeftRight;
+ uint8 *dst = ppu->bgBuffers[sub].pixel + left + kPpuExtraLeftRight;
if (clear_backdrop) {
memcpy(dst, src, width);
- memcpy(dst + 256, src + 256, width);
+ memcpy(dst + kPpuXPixels, src + kPpuXPixels, width);
} else {
do {
- if (src[256] > dst[256])
- dst[0] = src[0], dst[256] = src[256];
+ if (src[kPpuXPixels] > dst[kPpuXPixels])
+ dst[0] = src[0], dst[kPpuXPixels] = src[kPpuXPixels];
} while (src++, dst++, --width);
}
}
@@ -625,7 +635,7 @@
if (!layerp->screenEnabled[sub])
return; // layer is completely hidden
PpuWindows win;
- layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win);
+ layerp->screenWindowed[sub] ? PpuWindows_Calc(&win, ppu, layer) : PpuWindows_Clear(&win, ppu);
// expand 13-bit values to signed values
int hScroll = ((int16_t)(ppu->m7matrix[6] << 3)) >> 3;
@@ -648,7 +658,7 @@
if (win.bits & (1 << windex))
continue; // layer is disabled for this window part
int x = win.edges[windex], x2 = win.edges[windex + 1], tile;
- uint8 *dst = ppu->bgBuffers[sub].pixel + x, *dst_end = ppu->bgBuffers[sub].pixel + x2;
+ uint8 *dst = ppu->bgBuffers[sub].pixel + x + kPpuExtraLeftRight, *dst_end = ppu->bgBuffers[sub].pixel + x2 + kPpuExtraLeftRight;
uint32 rx = ppu->m7xFlip ? 255 - x : x;
uint32 xpos = m7startX + ppu->m7matrix[0] * rx;
uint32 ypos = m7startY + ppu->m7matrix[2] * rx;
@@ -670,7 +680,7 @@
uint8 pixel = ppu->vram[tile * 64 + (ypos >> 8 & 7) * 8 + (xpos >> 8 & 7)] >> 8;
if (pixel) {
int i = 0;
- do dst[i] = pixel, dst[i + 256] = z; while (++i != w);
+ do dst[i] = pixel, dst[i + kPpuXPixels] = z; while (++i != w);
}
} while (xpos += dx * w, ypos += dy * w, dst += w, w = ppu->mosaicSize, dst_end - dst != 0);
} else {
@@ -684,18 +694,22 @@
}
uint8 pixel = ppu->vram[tile * 64 + (ypos >> 8 & 7) * 8 + (xpos >> 8 & 7)] >> 8;
if (pixel)
- dst[0] = pixel, dst[256] = z;
+ dst[0] = pixel, dst[kPpuXPixels] = z;
} while (xpos += dx, ypos += dy, ++dst != dst_end);
}
}
}
-uint16 g_mode7_lo, g_mode7_hi;
void PpuSetMode7PerspectiveCorrection(Ppu *ppu, int low, int high) {
ppu->mode7PerspectiveLow = low ? 1.0f / low : 0.0f;
ppu->mode7PerspectiveHigh = 1.0f / high;
}
+void PpuSetExtraSideSpace(Ppu *ppu, int left, int right) {
+ ppu->extraLeftCur = UintMin(left, ppu->extraLeftRight);
+ ppu->extraRightCur = UintMin(right, ppu->extraLeftRight);
+}
+
static FORCEINLINE float FloatInterpolate(float x, float xmin, float xmax, float ymin, float ymax) {
return ymin + (ymax - ymin) * (x - xmin) * (1.0f / (xmax - xmin));
}
@@ -710,7 +724,7 @@
uint32 clippedV = (((int16_t)(ppu->m7matrix[7] << 3)) >> 3) - yCenter;
uint32 m0 = ppu->m7matrix[0]; // xpos increment per horiz movement
uint32 m3 = ppu->m7matrix[3]; // ypos increment per vert movement
- uint8 *dst_start = &ppu->renderBuffer[(y - 1) * 4 * ppu->renderPitch], *dst_end, *dst = dst_start;
+ uint8 *dst_start = &ppu->renderBuffer[(y - 1) * 4 * ppu->renderPitch], *dst_end, *dst = dst_start + ppu->extraLeftRight * 4 * 4;
int32 m0v[4];
if (*(uint32*)&ppu->mode7PerspectiveLow == 0) {
m0v[0] = m0v[1] = m0v[2] = m0v[3] = ppu->m7matrix[0] << 12;
@@ -753,12 +767,11 @@
if (ppu->lineHasSprites) {
uint8 *pixels = ppu->objBuffer.pixel;
size_t pitch = ppu->renderPitch;
- for (size_t i = 0; i < 256; i++) {
- uint32 pixel = pixels[i];
+ uint8 *dst = dst_start + ppu->extraLeftRight * 16;
+ for (size_t i = 0; i < 256; i++, dst += 16) {
+ uint32 pixel = pixels[i + kPpuExtraLeftRight];
if (pixel) {
uint32 color = ppu->colorMapRgb[pixel];
- uint8 *dst = dst_start + i * 16;
-
((uint32 *)dst)[3] = ((uint32 *)dst)[2] = ((uint32 *)dst)[1] = ((uint32 *)dst)[0] = color;
((uint32 *)(dst + pitch * 1))[3] = ((uint32 *)(dst + pitch * 1))[2] = ((uint32 *)(dst + pitch * 1))[1] = ((uint32 *)(dst + pitch * 1))[0] = color;
((uint32 *)(dst + pitch * 2))[3] = ((uint32 *)(dst + pitch * 2))[2] = ((uint32 *)(dst + pitch * 2))[1] = ((uint32 *)(dst + pitch * 2))[0] = color;
@@ -767,6 +780,22 @@
}
}
+ if (ppu->extraLeftRight - ppu->extraLeftCur != 0) {
+ size_t n = 4 * sizeof(uint32) * (ppu->extraLeftRight - ppu->extraLeftCur);
+ size_t pitch = ppu->renderPitch;
+ for(int i = 0; i < 4; i++)
+ memset(dst_start + pitch * i, 0, n);
+ }
+ if (ppu->extraLeftRight - ppu->extraRightCur != 0) {
+ size_t n = 4 * sizeof(uint32) * (ppu->extraLeftRight - ppu->extraRightCur);
+ size_t pitch = ppu->renderPitch;
+ for (int i = 0; i < 4; i++)
+ memset(dst_start + pitch * i + (256 + ppu->extraLeftRight * 2 - (ppu->extraLeftRight - ppu->extraRightCur)) * 4 * sizeof(uint32), 0, n);
+ }
+
+
+
+
#undef DRAW_PIXEL
}
@@ -815,11 +844,9 @@
static NOINLINE void PpuDrawWholeLine(Ppu *ppu, uint y) {
if (ppu->forcedBlank) {
uint8 *dst = &ppu->renderBuffer[(y - 1) * 2 * ppu->renderPitch];
- size_t pitch = ppu->renderPitch;
- for (int i = 0; i < 256; i++, dst += 8) {
- ((uint32*)dst)[1] = ((uint32 *)dst)[0] = 0;
- ((uint32*)(dst + pitch))[1] = ((uint32*)(dst + pitch))[0] = 0;
- }
+ size_t n = sizeof(uint32) * 2 * (256 + ppu->extraLeftRight * 2);
+ memset(dst, 0, n);
+ memset(dst + ppu->renderPitch, 0, n);
return;
}
@@ -828,7 +855,6 @@
return;
}
-
// Default background is backdrop
memset(&ppu->bgBuffers[0].pixel, 0, sizeof(ppu->bgBuffers[0].pixel));
memset(&ppu->bgBuffers[0].prio, 0x05, sizeof(ppu->bgBuffers[0].prio));
@@ -862,11 +888,13 @@
uint32 cw_clip_math = ((cwin.bits & kCwBitsMod[ppu->clipMode]) ^ kCwBitsMod[ppu->clipMode + 4]) |
((cwin.bits & kCwBitsMod[ppu->preventMathMode]) ^ kCwBitsMod[ppu->preventMathMode + 4]) << 8;
- uint32 *dst = (uint32*)&ppu->renderBuffer[(y - 1) * 2 * ppu->renderPitch];
+ uint32 *dst = (uint32*)&ppu->renderBuffer[(y - 1) * 2 * ppu->renderPitch], *dst_org = dst;
+ dst += 2 * (ppu->extraLeftRight - ppu->extraLeftCur);
+
uint32 windex = 0;
do {
- uint32 left = cwin.edges[windex], right = cwin.edges[windex + 1];
+ uint32 left = cwin.edges[windex] + kPpuExtraLeftRight, right = cwin.edges[windex + 1] + kPpuExtraLeftRight;
// If clip is set, then zero out the rgb values from the main screen.
uint32 clip_color_mask = (cw_clip_math & 1) ? 0x1f : 0;
uint32 math_enabled_cur = (cw_clip_math & 0x100) ? math_enabled : 0;
@@ -918,9 +946,15 @@
}
} while (cw_clip_math >>= 1, ++windex < cwin.nr);
- // Duplicate one line
- memcpy((uint8*)(dst - 512) + ppu->renderPitch, dst - 512, 512 * 4);
+ // Clear out stuff on the sides.
+ if (ppu->extraLeftRight - ppu->extraLeftCur != 0)
+ memset(dst_org, 0, 2 * sizeof(uint32) * (ppu->extraLeftRight - ppu->extraLeftCur));
+ if (ppu->extraLeftRight - ppu->extraRightCur != 0)
+ memset(dst_org + 2 * (kPpuXPixels - (ppu->extraLeftRight - ppu->extraRightCur)), 0,
+ 2 * sizeof(uint32) * (ppu->extraLeftRight - ppu->extraRightCur));
+ // Duplicate one line
+ memcpy((uint8*)dst_org + ppu->renderPitch, dst_org, (ppu->extraLeftRight * 2 + 256) * 2 * sizeof(uint32));
}
static void ppu_handlePixel(Ppu* ppu, int x, int y) {
@@ -1245,6 +1279,7 @@
int index = ppu->objPriority ? (ppu->oamAdr & 0xfe) : 0, index_end = index;
int spritesFound = 0, tilesFound = 0;
uint8 spriteSizes[2] = { kSpriteSizes[ppu->objSize][0], kSpriteSizes[ppu->objSize][1] };
+ int extra_left_right = ppu->extraLeftRight;
do {
int yy = ppu->oam[index] >> 8;
if (yy == 0xf0)
@@ -1256,9 +1291,10 @@
if (row >= spriteSize)
continue;
// in y-range, get the x location, using the high bit as well
- int x = (ppu->oam[index] & 0xff) - (highOam & 1) * 256;
+ int x = (ppu->oam[index] & 0xff) + (highOam & 1) * 256;
+ x -= (x >= 256 + extra_left_right) * 512;
// if in x-range
- if (x <= -spriteSize)
+ if (x <= -(spriteSize + extra_left_right))
continue;
// break if we found 32 sprites already
if (++spritesFound > 32) {
@@ -1273,8 +1309,9 @@
// fetch all tiles in x-range
uint8 paletteBase = 0x80 + 16 * ((oam1 & 0xe00) >> 9);
uint8 prio = SPRITE_PRIO_TO_PRIO((oam1 & 0x3000) >> 12, (oam1 & 0x800) == 0);
+
for (int col = 0; col < spriteSize; col += 8) {
- if (col + x > -8 && col + x < 256) {
+ if (col + x > -8 - extra_left_right && col + x < 256 + extra_left_right) {
// break if we found 34 8*1 slivers already
if (++tilesFound > 34) {
ppu->timeOver = true;
@@ -1286,9 +1323,9 @@
uint16 *addr = &ppu->vram[(objAdr + usedTile * 16 + (row & 0x7)) & 0x7fff];
uint32 plane = addr[0] | addr[8] << 16;
// go over each pixel
- int px_left = IntMax(-(col + x), 0);
- int px_right = IntMin(256 - (col + x), 8);
- uint8 *dst = ppu->objBuffer.pixel + col + x + px_left;
+ int px_left = IntMax(-(col + x + kPpuExtraLeftRight), 0);
+ int px_right = IntMin(256 + kPpuExtraLeftRight - (col + x), 8);
+ uint8 *dst = ppu->objBuffer.pixel + col + x + px_left + kPpuExtraLeftRight;
for (int px = px_left; px < px_right; px++, dst++) {
int shift = oam1 & 0x4000 ? px : 7 - px;
@@ -1296,7 +1333,7 @@
int pixel = (bits >> 0) & 1 | (bits >> 7) & 2 | (bits >> 14) & 4 | (bits >> 21) & 8;
// draw it in the buffer if there is a pixel here, and the buffer there is still empty
if (pixel != 0 && dst[0] == 0)
- dst[0] = paletteBase + pixel, dst[256] = prio;
+ dst[0] = paletteBase + pixel, dst[kPpuXPixels] = prio;
}
}
}
--- a/snes/ppu.h
+++ b/snes/ppu.h
@@ -11,6 +11,7 @@
typedef struct Ppu Ppu;
#include "snes.h"
+#include "../types.h"
typedef struct BgLayer {
uint16_t hScroll;
@@ -36,9 +37,13 @@
uint8_t maskLogic_always_zero;
} WindowLayer;
+enum {
+ kPpuXPixels = 256 + kPpuExtraLeftRight * 2,
+};
+
typedef struct PpuPixelPrioBufs {
- uint8_t pixel[256];
- uint8_t prio[256];
+ uint8_t pixel[kPpuXPixels];
+ uint8_t prio[kPpuXPixels];
} PpuPixelPrioBufs;
enum {
@@ -55,6 +60,7 @@
uint8_t renderFlags;
uint32_t renderPitch;
uint8_t *renderBuffer;
+ uint8_t extraLeftCur, extraRightCur, extraLeftRight;
float mode7PerspectiveLow, mode7PerspectiveHigh;
Snes* snes;
@@ -148,7 +154,7 @@
uint8_t ppu1openBus;
uint8_t ppu2openBus;
- uint8_t mosaicModulo[256];
+ uint8_t mosaicModulo[kPpuXPixels];
uint32_t colorMapRgb[256];
};
@@ -163,5 +169,6 @@
bool PpuBeginDrawing(Ppu *ppu, uint8_t *buffer, size_t pitch, uint32_t render_flags);
void PpuSetMode7PerspectiveCorrection(Ppu *ppu, int low, int high);
+void PpuSetExtraSideSpace(Ppu *ppu, int left, int right);
#endif
--- a/sprite.c
+++ b/sprite.c
@@ -1867,7 +1867,10 @@
R2 = y - sprite_z[k];
ret->flags = sprite_oam_flags[k] ^ sprite_obj_prio[k];
ret->r4 = 0;
- if ((uint16)(x + 0x40) >= 0x170 || (uint16)(y + 0x40) >= 0x170 && !(sprite_flags4[k] & 0x20)) {
+ int xt = (g_ram[kRam_Features0] & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+
+ if ((uint16)(x + 0x40 + xt) >= (0x170 + xt * 2) ||
+ (uint16)(y + 0x40) >= 0x170 && !(sprite_flags4[k] & 0x20)) {
sprite_pause[k]++;
if (!(sprite_defl_bits[k] & 0x80))
Sprite_KillSelf(k);
@@ -3812,7 +3815,10 @@
uint16 bak0 = BG2HOFS_copy2;
uint8 bak1 = byte_7E069E[1];
byte_7E069E[1] = 0xff;
- for (int i = 21; i >= 0; i--) {
+
+ int xt = (g_ram[kRam_Features0] & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+ BG2HOFS_copy2 -= xt;
+ for (int i = 21 + (xt >> 3); i >= 0; i--) {
Sprite_ActivateWhenProximal();
BG2HOFS_copy2 += 16;
}
@@ -3835,8 +3841,9 @@
void Sprite_ActivateWhenProximal() { // 89c5bb
if (byte_7E069E[1]) {
- uint16 x = BG2HOFS_copy2 + (sign8(byte_7E069E[1]) ? -0x10 : 0x110);
- uint16 y = BG2VOFS_copy2 - 48;
+ int xt = (g_ram[kRam_Features0] & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+ uint16 x = BG2HOFS_copy2 + (sign8(byte_7E069E[1]) ? -0x10 - xt : 0x110 + xt);
+ uint16 y = BG2VOFS_copy2 - 0x30;
for (int i = 21; i >= 0; i--, y += 16)
Sprite_Overworld_ProximityMotivatedLoad(x, y);
}
@@ -3844,9 +3851,10 @@
void Sprite_ActivateWhenProximalBig() { // 89c5fa
if (byte_7E069E[0]) {
- uint16 x = BG2HOFS_copy2 - 48;
+ int xt = (g_ram[kRam_Features0] & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+ uint16 x = BG2HOFS_copy2 - 0x30 - xt;
uint16 y = BG2VOFS_copy2 + (sign8(byte_7E069E[0]) ? -0x10 : 0x110);
- for (int i = 21; i >= 0; i--, x += 16)
+ for (int i = 21 + (xt >> 3); i >= 0; i--, x += 16)
Sprite_Overworld_ProximityMotivatedLoad(x, y);
}
}
--- a/types.h
+++ b/types.h
@@ -3,6 +3,13 @@
#include <stdbool.h>
#pragma once
+// Build time config options
+enum {
+ kEnableLargeScreen = 1,
+ // How much extra spacing to add on the sides
+ kPpuExtraLeftRight = kEnableLargeScreen ? 71 : 0,
+};
+
typedef uint8_t uint8;
typedef int8_t int8;
typedef uint16_t uint16;
@@ -33,6 +40,8 @@
static FORCEINLINE uint8 abs8(uint8 t) { return sign8(t) ? -t : t; }
static FORCEINLINE int IntMin(int a, int b) { return a < b ? a : b; }
static FORCEINLINE int IntMax(int a, int b) { return a > b ? a : b; }
+static FORCEINLINE uint UintMin(uint a, uint b) { return a < b ? a : b; }
+static FORCEINLINE uint UintMax(uint a, uint b) { return a > b ? a : b; }
#define BYTE(x) (*(uint8*)&(x))
#define HIBYTE(x) (((uint8*)&(x))[1])
--- a/zelda3.ini
+++ b/zelda3.ini
@@ -3,6 +3,10 @@
Autosave = 0
DisplayPerfInTitle = 0
+# Extended aspect ratio, either 16:9 or 16:10.
+# Add ", unchanged_sprites" to avoid changing sprite spawn/die behavior. Without this
+# replays will be incompatible
+# ExtendedAspectRatio = 16:9
[Graphics]
# Fullscreen mode (0=windowed, 1=desktop fullscreen, 2=fullscreen w/mode change)
--- a/zelda_cpu_infra.c
+++ b/zelda_cpu_infra.c
@@ -17,6 +17,7 @@
Snes *g_snes;
Cpu *g_cpu;
uint8 g_emulated_ram[0x20000];
+uint32 g_wanted_zelda_features;
void SaveLoadSlot(int cmd, int which);
@@ -695,16 +696,23 @@
// This is whether APUI00 is true or false, this is used by the ancilla code.
uint8 apui00 = g_zenv.player->port_to_snes[0] != 0;
- if (apui00 != g_ram[0x648]) {
- g_emulated_ram[0x648] = g_ram[0x648] = apui00;
+ if (apui00 != g_ram[kRam_APUI00]) {
+ g_emulated_ram[kRam_APUI00] = g_ram[kRam_APUI00] = apui00;
StateRecorder_RecordPatchByte(&state_recorder, 0x648, &apui00, 1);
}
- // Whenever we're no longer replaying, we'll remember what bugs were fixed,
- // but only if game is initialized.
- if (g_ram[kRam_BugsFixed] < kBugFix_Latest && animated_tile_data_src != 0) {
- g_emulated_ram[kRam_BugsFixed] = g_ram[kRam_BugsFixed] = kBugFix_Latest;
- StateRecorder_RecordPatchByte(&state_recorder, kRam_BugsFixed, &g_ram[kRam_BugsFixed], 1);
+ if (animated_tile_data_src != 0) {
+ // Whenever we're no longer replaying, we'll remember what bugs were fixed,
+ // but only if game is initialized.
+ if (g_ram[kRam_BugsFixed] < kBugFix_Latest) {
+ g_emulated_ram[kRam_BugsFixed] = g_ram[kRam_BugsFixed] = kBugFix_Latest;
+ StateRecorder_RecordPatchByte(&state_recorder, kRam_BugsFixed, &g_ram[kRam_BugsFixed], 1);
+ }
+
+ if (g_ram[kRam_Features0] != g_wanted_zelda_features) {
+ g_emulated_ram[kRam_Features0] = g_ram[kRam_Features0] = g_wanted_zelda_features;
+ StateRecorder_RecordPatchByte(&state_recorder, kRam_Features0, &g_ram[kRam_Features0], 1);
+ }
}
}
@@ -721,7 +729,8 @@
g_emulated_ram[kRam_CrystalRotateCounter] = g_ram[kRam_CrystalRotateCounter];
}
- if (snes == NULL) {
+ if (snes == NULL || g_ram[kRam_Features0] != 0) {
+ // can't compare against real impl when running with extra features.
ZeldaRunFrame(input_state, run_what);
return turbo;
}
--- a/zelda_rtl.c
+++ b/zelda_rtl.c
@@ -161,6 +161,26 @@
c->rep_count--;
}
+void ConfigurePpuSideSpace() {
+ // Let PPU impl know about the maximum allowed extra space on the sides
+ int extra_right = 0, extra_left = 0;
+// printf("main %d, sub %d (%d, %d, %d)\n", main_module_index, submodule_index, BG2HOFS_copy2, room_bounds_x.v[2 | (quadrant_fullsize_x >> 1)], quadrant_fullsize_x >> 1);
+ int mod = main_module_index;
+ if (mod == 14)
+ mod = saved_module_for_menu;
+ if (mod == 9) {
+ extra_left = BG2HOFS_copy2 - ow_scroll_vars0.xstart;
+ extra_right = ow_scroll_vars0.xend - BG2HOFS_copy2;
+ } else if (mod == 7) {
+ int qm = quadrant_fullsize_x >> 1;
+ extra_left = IntMax(BG2HOFS_copy2 - room_bounds_x.v[qm], 0);
+ extra_right = IntMax(room_bounds_x.v[qm + 2] - BG2HOFS_copy2, 0);
+ } else if (mod == 20) {
+ extra_left = kPpuExtraLeftRight, extra_right = kPpuExtraLeftRight;
+ }
+ PpuSetExtraSideSpace(g_zenv.ppu, extra_left, extra_right);
+}
+
bool ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags) {
SimpleHdma hdma_chans[2];
@@ -182,6 +202,9 @@
else
PpuSetMode7PerspectiveCorrection(g_zenv.ppu, 0, 0);
}
+
+ if (g_zenv.ppu->extraLeftRight != 0)
+ ConfigurePpuSideSpace();
for (int i = 0; i < 225; i++) {
if (i == 128 && irq_flag) {
--- a/zelda_rtl.h
+++ b/zelda_rtl.h
@@ -47,10 +47,22 @@
#define movable_block_datas ((MovableBlockData*)(g_ram+0xf940))
#define oam_buf ((OamEnt*)(g_ram+0x800))
+
+typedef struct RoomBounds {
+ union {
+ struct { uint16 a0, b0, a1, b1; };
+ uint16 v[4];
+ };
+} RoomBounds;
+#define room_bounds_y (*(RoomBounds*)(g_ram+0x600))
+#define room_bounds_x (*(RoomBounds*)(g_ram+0x608))
+
+
typedef struct OwScrollVars {
uint16 ystart, yend, xstart, xend;
} OwScrollVars;
+
#define ow_scroll_vars0 (*(OwScrollVars*)(g_ram+0x600))
#define ow_scroll_vars1 (*(OwScrollVars*)(g_ram+0x608))
@@ -90,6 +102,7 @@
kRam_APUI00 = 0x648,
kRam_CrystalRotateCounter = 0x649,
kRam_BugsFixed = 0x64a,
+ kRam_Features0 = 0x64c,
};
enum {
@@ -97,8 +110,12 @@
kBugFix_PolyRenderer = 1,
kBugFix_AncillaOverwrites = 1,
kBugFix_Latest = 1,
+
+ // kRam_Features0
+ kFeatures0_ExtendScreen64 = 1,
};
+extern uint32 g_wanted_zelda_features;
#define scratch_0 (*(uint16*)(g_ram+0x72))
#define scratch_1 (*(uint16*)(g_ram+0x74))