4 Commits

Author SHA1 Message Date
Snesrev
24f3845fac stuff 2022-10-07 17:32:25 +02:00
Snesrev
3d5a36d68e Fix resource script 2022-10-07 17:22:30 +02:00
Snesrev
30b044de2e adsf 2022-10-07 17:22:30 +02:00
Snesrev
07e25636ca Experimental extended hud resolution 2022-10-07 17:22:30 +02:00
22 changed files with 1267 additions and 670 deletions

View File

@@ -416,7 +416,11 @@ void Attract_InitGraphics() { // 8cee0c
Palette_Load_OWBGMain();
Palette_Load_HUD();
Palette_Load_LinkArmorAndGloves();
// Set text color blue
main_palette_buffer[0x1d] = 0x3800;
if (kPpuUpsample2x2)
g_zenv.cgram[0x171] = 0x3800;
flag_update_cgram_in_nmi++;
BYTE(BG3VOFS_copy2) = 20;
Attract_BuildBackgrounds();

View File

@@ -6,6 +6,12 @@
#include "player.h"
#include "sprite.h"
#include "assets.h"
#include "snes/ppu.h"
struct ImageDataX2 g_image_data_x2;
uint16 g_cgram_data_x2[256];
// Allow this to be overwritten
uint16 kGlovesColor[2] = {0x52f6, 0x376};
@@ -420,7 +426,7 @@ void RecoverPegGFXFromMapping() {
Dungeon_UpdatePegGFXBuffer(0x180, 0x0);
else
Dungeon_UpdatePegGFXBuffer(0x0, 0x180);
}
}
void LoadOverworldMapPalette() {
memcpy(main_palette_buffer, &kOverworldMapPaletteData[overworld_screen_index & 0x40 ? 0x80 : 0], 256);
@@ -824,6 +830,7 @@ void InitializeTilesets() { // 80e19b
LoadSpriteGraphics(&g_zenv.vram[0x5400], sprite_gfx_subset_1, &g_ram[0x7e00]);
LoadSpriteGraphics(&g_zenv.vram[0x5800], sprite_gfx_subset_2, &g_ram[0x8400]);
LoadSpriteGraphics(&g_zenv.vram[0x5c00], sprite_gfx_subset_3, &g_ram[0x8a00]);
CONVERT_SPRITE_TO_X2(0x5000, 256);
const uint8 *mt = kMainTilesets[main_tile_theme_index];
const uint8 *at = kAuxTilesets[aux_tile_theme_index];
@@ -841,6 +848,7 @@ void InitializeTilesets() { // 80e19b
LoadBackgroundGraphics(&g_zenv.vram[0x3400], aux_bg_subset_2, 2, &g_ram[0x6c00]);
LoadBackgroundGraphics(&g_zenv.vram[0x3800], aux_bg_subset_3, 1, &g_ram[0x7200]);
LoadBackgroundGraphics(&g_zenv.vram[0x3c00], mt[7], 0, &g_ram[0x14000]);
CONVERT_BG_TO_X2(0x2000, 512);
}
void LoadDefaultGraphics() { // 80e2d0
@@ -858,16 +866,22 @@ void LoadDefaultGraphics() { // 80e2d0
*vram_ptr++ = src[0] | (src[0] | tmp[i]) << 8;
}
} while (--num);
CONVERT_SPRITE_TO_X2(0x4000, 64);
// Load 2bpp graphics used for hud
DecompAndUpload2bpp(&g_zenv.vram[0x7000], 0x6a);
DecompAndUpload2bpp(&g_zenv.vram[0x7400], 0x6b);
DecompAndUpload2bpp(&g_zenv.vram[0x7800], 0x69);
// Load the 2X hud icons
if (kPpuXPixels)
memcpy(g_zenv.ext_vram, g_image_data_x2.icons, sizeof(g_image_data_x2.icons));
}
void Attract_LoadBG3GFX() { // 80e36d
// load 2bpp gfx for attract images
DecompAndUpload2bpp(&g_zenv.vram[0x7800], 0x67);
CONVERT_HUD_TO_X2(0x7800, 8 * 16);
}
void Graphics_LoadChrHalfSlot() { // 80e3fa
@@ -933,6 +947,8 @@ void Graphics_LoadChrHalfSlot() { // 80e3fa
void TransferFontToVRAM() { // 80e556
memcpy(&g_zenv.vram[0x7000], kFontData, 0x800 * sizeof(uint16));
if (kPpuUpsample2x2)
memcpy(g_zenv.ext_vram, g_image_data_x2.font, sizeof(g_image_data_x2.font));
}
void Do3To4High(uint16 *vram_ptr, const uint8 *decomp_addr) { // 80e5af
@@ -986,6 +1002,7 @@ void LoadCommonSprites() { // 80e6b7
LoadSpriteGraphics(&g_zenv.vram[0x4800], 94, &g_ram[0x14000]);
LoadSpriteGraphics(&g_zenv.vram[0x4c00], 95, &g_ram[0x14000]);
}
CONVERT_SPRITE_TO_X2(0x4400, 64 * 3);
}
int Decomp_spr(uint8 *dst, int gfx) { // 80e772
@@ -1903,11 +1920,6 @@ void LoadGearPalettes(uint8 sword, uint8 shield, uint8 armor) { // 8ed6e8
flag_update_cgram_in_nmi++;
}
void LoadGearPalette(int dst, const uint16 *src, int n) { // 8ed741
memcpy(&aux_palette_buffer[dst >> 1], src, sizeof(uint16) * n);
memcpy(&main_palette_buffer[dst >> 1], src, sizeof(uint16) * n);
}
void Filter_Majorly_Whiten_Bg() { // 8ed757
for (int i = 32; i < 128; i++)
main_palette_buffer[i] = Filter_Majorly_Whiten_Color(aux_palette_buffer[i]);
@@ -2034,6 +2046,7 @@ void Palette_Load_DungeonMapBG() { // 9bee3a
void Palette_Load_HUD() { // 9bee52
const uint16 *src = kHudPalData + hud_palette * 32;
Palette_LoadMultiple(src, 0x0, 15, 1);
LoadHudPaletteX2();
}
void Palette_Load_DungeonSet() { // 9bee74
@@ -2141,3 +2154,70 @@ void HandleScreenFlash() { // 9de9b6
flag_update_cgram_in_nmi++;
}
void LoadImageFilesX2() {
FILE *f = fopen("tables/x2_icons.bin", "rb");
if (f) {
if (fread(&g_image_data_x2, 1, sizeof(g_image_data_x2), f) != sizeof(g_image_data_x2))
fprintf(stderr, "Unable to read all x2 icons\n");
fclose(f);
} else {
printf("Error reading bitmap!\n");
}
f = fopen("tables/x2_icons.pal", "rb");
if (f) {
fread(g_cgram_data_x2, 1, sizeof(g_cgram_data_x2), f);
fclose(f);
} else {
printf("Error reading palette!\n");
}
LoadHudPaletteX2();
LoadGraphicsExtended();
}
void LoadHudPaletteX2() {
struct Ppu *ppu = g_zenv.ppu;
ppu->cgramDirty = true;
memcpy(ppu->cgram + 256, g_cgram_data_x2 + hud_palette * 128, 128 * 2);
}
void LoadGraphicsExtended() {
// todo: fix so snapshot restore works on other places than in-game
struct Ppu *ppu = g_zenv.ppu;
memcpy(ppu->extendedVram, g_image_data_x2.icons, sizeof(g_image_data_x2.icons));
}
void Convert2bppToX2(const uint16 *src, uint32 dst_addr, size_t count) {
#define DO_PIXEL(i) r += (uint64)((bits >> (7 - i)) & 1 | (bits >> (14 - i)) & 2) << (i * 8)
uint16 *dst = g_zenv.ext_vram + dst_addr;
do {
for (size_t j = 0; j < 8; j++) {
uint32 bits = *src++;
uint64 r = 0;
DO_PIXEL(0); DO_PIXEL(1); DO_PIXEL(2); DO_PIXEL(3);
DO_PIXEL(4); DO_PIXEL(5); DO_PIXEL(6); DO_PIXEL(7);
*(uint64 *)&dst[4] = *(uint64 *)&dst[0] = r + (r << 4);
dst += 8;
}
} while (--count);
#undef DO_PIXEL
}
void Convert4bppToX2(const uint16 *src, uint32 dst_addr, size_t count) {
#define DO_PIXEL(i) r += (uint64)((bits >> (7 - i)) & 1 | (bits >> (14 - i)) & 2 | (bits >> (21 - i)) & 4 | (bits >> (28 - i)) & 8) << (i * 8)
uint16 *dst = g_zenv.ext_vram + dst_addr;
do {
for (size_t j = 0; j < 8; j++) {
uint32 bits = src[0] | src[8] << 16;
uint64 r = 0;
DO_PIXEL(0); DO_PIXEL(1); DO_PIXEL(2); DO_PIXEL(3);
DO_PIXEL(4); DO_PIXEL(5); DO_PIXEL(6); DO_PIXEL(7);
// r = j&1 ? 0x23456789abcdef1 : 0x123456789abcdef;
*(uint64 *)&dst[4] = *(uint64 *)&dst[0] = r + (r << 4);
dst += 8, src += 1;
}
} while (src += 8, --count);
#undef DO_PIXEL
}

View File

@@ -126,7 +126,6 @@ void LoadActualGearPalettes();
void Palette_ElectroThemedGear();
void LoadGearPalettes_bunny();
void LoadGearPalettes(uint8 sword, uint8 shield, uint8 armor);
void LoadGearPalette(int dst, const uint16 *src, int n);
void Filter_Majorly_Whiten_Bg();
uint16 Filter_Majorly_Whiten_Color(uint16 c);
void Palette_Restore_BG_From_Flash();

9
main.c
View File

@@ -60,7 +60,7 @@ static int g_input1_state;
static bool g_display_perf;
static int g_curr_fps;
static int g_ppu_render_flags = 0;
static bool g_run_without_emu = false;
static bool g_run_without_emu = 0;
static int g_snes_width, g_snes_height;
static int g_sdl_audio_mixer_volume = SDL_MIX_MAXVOLUME;
@@ -208,6 +208,8 @@ int main(int argc, char** argv) {
LoadLinkGraphics();
ZeldaInitialize();
LoadImageFilesX2();
g_zenv.ppu->extraLeftRight = UintMin(g_config.extended_aspect_ratio, kPpuExtraLeftRight);
g_snes_width = 2 * (g_config.extended_aspect_ratio * 2 + 256);
g_snes_height = (g_config.extend_y ? 240 : 224) * 2;
@@ -392,7 +394,7 @@ int main(int argc, char** argv) {
continue;
}
RenderScreen(window, renderer, texture, (g_win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0);
RenderScreen(window, renderer, texture, (g_win_flags &SDL_WINDOW_FULLSCREEN_DESKTOP) != 0);
SDL_RenderPresent(renderer); // vsyncs to 60 FPS?
// if vsync isn't working, delay manually
@@ -597,6 +599,9 @@ static void HandleCommand_Locked(uint32 j, bool pressed) {
}
static void HandleInput(int keyCode, int keyMod, bool pressed) {
if (keyCode == SDLK_SPACE)
LoadImageFilesX2(g_zenv.ppu);
int j = FindCmdForSdlKey(keyCode, keyMod);
if (j >= 0)
HandleCommand(j, pressed);

View File

@@ -208,9 +208,6 @@ static const uint8 kText_CommandLengths[25] = {
1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 1, 1, 1, 1, 1,
};
static const uint8 kVWF_RenderCharacter_setMasks[8] = {0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1};
static const uint16 kVWF_RenderCharacter_renderPos[3] = {0, 0x2a0, 0x540};
static const uint16 kVWF_RenderCharacter_linePositions[3] = {0, 0x40, 0x80};
static const uint8 kVWF_RenderCharacter_widths[99] = {
6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6,
6, 6, 3, 5, 6, 3, 7, 6, 6, 6, 6, 5, 6, 6, 6, 7, 7, 7, 7, 6, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 3, 7,
@@ -334,6 +331,8 @@ static PlayerHandlerFunc *const kModule_Death[16] = {
};
static const uint8 kLocationMenuStartPos[3] = {0, 1, 6};
static void RunInterface();
static uint16 *RenderText_DrawBorderRow(uint16 *d, int y);
const uint8 *GetDungmapFloorLayout() {
return kDungMap_FloorLayout + *(uint32 *)(kDungMap_FloorLayout + (cur_palace_index_x2 >> 1) * 4);
}
@@ -382,7 +381,7 @@ void SaveGameFile() { // 80894a
}
void TransferMode7Characters() { // 80e399
uint16 *dst = g_zenv.vram;
uint16 *dst = &g_zenv.vram[0];
const uint8 *src = kOverworldMapGfx;
for (int i = 0; i != 0x4000; i++)
HIBYTE(dst[i]) = src[i];
@@ -1390,7 +1389,7 @@ void WorldMap_SetUpHDMA() { // 8abc96
}
void WorldMap_FillTilemapWithEF() { // 8abda5
uint16 *dst = g_zenv.vram;
uint16 *dst = &g_zenv.vram[0];
for (int i = 0; i != 0x4000; i++)
BYTE(dst[i]) = 0xef;
}
@@ -1765,17 +1764,17 @@ void Module0E_03_01_03_DrawRooms() { // 8ae384
void DungeonMap_DrawBorderForRooms(uint16 pd, uint16 mask) { // 8ae449
for (int i = 0; i != 4; i++)
messaging_buf[((kDungMap_Tab10[i] + pd) & 0xfff) >> 1] = kDungMap_Tab11[i] & mask;
dungmap_buf[((kDungMap_Tab10[i] + pd) & 0xfff) >> 1] = kDungMap_Tab11[i] & mask;
for (int i = 0; i != 2; i++) {
int r4 = kDungMap_Tab12[i] + pd;
for (int j = 0; j != 20; j+=2)
messaging_buf[((r4 + j) & 0xfff) >> 1] = kDungMap_Tab13[i] & mask;
dungmap_buf[((r4 + j) & 0xfff) >> 1] = kDungMap_Tab13[i] & mask;
}
for (int i = 0; i != 2; i++) {
int r4 = kDungMap_Tab14[i] + pd;
for (int j = 0; j != 0x280; j+=0x40)
messaging_buf[((r4 + j) & 0xfff) >> 1] = kDungMap_Tab15[i] & mask;
dungmap_buf[((r4 + j) & 0xfff) >> 1] = kDungMap_Tab15[i] & mask;
}
}
@@ -1783,14 +1782,14 @@ void DungeonMap_DrawFloorNumbersByRoom(uint16 pd, uint16 r8) { // 8ae4f9
uint16 p = 0xDE;
do {
int t = ((p + pd) & 0xfff) >> 1;
messaging_buf[t] = 0xf00;
messaging_buf[t+1] = 0xf00;
dungmap_buf[t] = 0xf00;
dungmap_buf[t+1] = 0xf00;
} while (p += 0x40, p != 0x39e);
int t = ((0x35e + pd) & 0xfff) >> 1;
uint16 q1 = (dungmap_cur_floor & 0x80) ? 0x1F1C : kDungMap_Tab16[dungmap_cur_floor & 0xf];
uint16 q2 = (dungmap_cur_floor & 0x80) ? kDungMap_Tab16[(uint8)~dungmap_cur_floor] : 0x1F1D;
messaging_buf[t+0] = q1 & r8;
messaging_buf[t+1] = q2 & r8;
dungmap_buf[t+0] = q1 & r8;
dungmap_buf[t+1] = q2 & r8;
}
void DungeonMap_DrawDungeonLayout(int pd) { // 8ae579
@@ -1832,7 +1831,7 @@ void DungeonMap_DrawSingleRowOfRooms(int i, int arg_x) { // 8ae5bc
}
av = ((link_dungeon_map & dungmask) || (r14 & 8)) ? r12 + r12_org : 0xb00;
write_3:
messaging_buf[arg_x] = av;
dungmap_buf[arg_x] = av;
r12 = kDungMap_Tab23[yv * 4 + 1], r12_org = r12;
if (r12 != 0xB00 && (r14 & 4) == 0) {
@@ -1849,7 +1848,7 @@ void DungeonMap_DrawSingleRowOfRooms(int i, int arg_x) { // 8ae5bc
}
av = ((link_dungeon_map & dungmask) || (r14 & 4)) ? r12 + r12_org : 0xb00;
write_4:
messaging_buf[arg_x + 1] = av;
dungmap_buf[arg_x + 1] = av;
r12 = kDungMap_Tab23[yv * 4 + 2], r12_org = r12;
if (r12 != 0xB00 && (r14 & 2) == 0) {
@@ -1866,7 +1865,7 @@ void DungeonMap_DrawSingleRowOfRooms(int i, int arg_x) { // 8ae5bc
}
av = ((link_dungeon_map & dungmask) || (r14 & 2)) ? r12 + r12_org : 0xb00;
write_5:
messaging_buf[arg_x + 32] = av;
dungmap_buf[arg_x + 32] = av;
r12 = kDungMap_Tab23[yv * 4 + 3], r12_org = r12;
if (r12 != 0xB00 && (r14 & 1) == 0) {
@@ -1883,7 +1882,7 @@ void DungeonMap_DrawSingleRowOfRooms(int i, int arg_x) { // 8ae5bc
}
av = ((link_dungeon_map & dungmask) || (r14 & 1)) ? r12 + r12_org : 0xb00;
write_6:
messaging_buf[arg_x + 33] = av;
dungmap_buf[arg_x + 33] = av;
}
}
@@ -2443,7 +2442,7 @@ restart:
case 6: //
case 7: //
case 8: // RenderText_Draw_Ignore
byte_7E1CEA = messaging_text_buffer[dialogue_msg_dst_offs + 1];
render_vwf_scroll_speed = messaging_text_buffer[dialogue_msg_dst_offs + 1];
dialogue_msg_dst_offs += 2;
break;
case 9: // RenderText_Draw_Choose2HiOr3
@@ -2560,68 +2559,61 @@ void VWF_RenderSingle() { // 8ecab8
vwf_line_mode = vwf_line_speed;
}
static void RenderFontPixelsInternal(int dst_pos, int width, int icon_index) {
const uint16 *src = kFontData + icon_index * 8;
for (int i = 0; i != 8; i++) {
int bits = *src++;
uint8 *dstbuf = (uint8 *)messaging_buf + (dst_pos & 0xff0) + i * 2;
int j = (dst_pos >> 1) & 7;
int n = width;
do {
int mask = 0x80 >> j;
dstbuf[0] = (dstbuf[0] & ~mask) | ((bits & 0x0080) ? mask : 0);
dstbuf[1] = (dstbuf[1] & ~mask) | ((bits & 0x8000) ? mask : 0);
bits = (bits & ~0x8080) << 1;
} while (--n && ++j != 8);
if (bits != 0)
WORD(dstbuf[16]) = bits;
}
// Write directly to the region in extended vram. No vblanks to worry about.
if (kPpuUpsample2x2) {
for (int x = 0; x < width; x++) {
// It's at 0x7c00
uint8 *dstbuf = (uint8 *)g_zenv.ext_vram + (256 * 384) / 2 +
((dst_pos & 0xff0) >> 4) * (16 * 16 / 2) +
((dst_pos >> 1) & 7);
uint8 *src = &g_image_data_x2.font[icon_index * 128] + x;
// draw a vertical strip
for (int y = 0; y < 8; y++) {
dstbuf[y * 16 + 0] = src[y * 16 + 0];
dstbuf[y * 16 + 8] = src[y * 16 + 8];
}
dst_pos += 2;
}
}
}
void VWF_RenderCharacter() { // 8ecb5e
if (vwf_flag_next_line) {
vwf_line_ptr = kVWF_RenderCharacter_renderPos[vwf_curline>>1];
vwf_var1 = kVWF_RenderCharacter_linePositions[vwf_curline>>1];
vwf_line_ptr = 0x2a0 * (vwf_curline >> 1);
vwf_var1 = 0x40 * (vwf_curline >> 1);
vwf_flag_next_line = 0;
}
uint8 c = messaging_text_buffer[dialogue_msg_dst_offs];
uint8 width = kVWF_RenderCharacter_widths[c];
int i = vwf_var1++;
uint8 arrval = vwf_arr[i];
vwf_arr[i + 1] = arrval + width;
uint16 r10 = (c & 0x70) * 2 + (c & 0xf);
uint16 r0 = arrval * 2;
const uint16 *const kTextBits = kFontData;
const uint16 *src2 = kTextBits + r10 * 8;
uint8 *mbuf = (uint8 *)messaging_buf;
for (int i = 0; i != 16; i += 2) {
uint16 r4 = *src2++;
int y = r0 + vwf_line_ptr;
int x = (y & 0xff0) + i;
y = (y >> 1) & 7;
uint8 r3 = width;
do {
if (r4 & 0x0080)
mbuf[x + 0] ^= kVWF_RenderCharacter_setMasks[y];
else
mbuf[x + 0] &= ~kVWF_RenderCharacter_setMasks[y];
if (r4 & 0x8000)
mbuf[x + 1] ^= kVWF_RenderCharacter_setMasks[y];
else
mbuf[x + 1] &= ~kVWF_RenderCharacter_setMasks[y];
r4 = (r4 & ~0x8080) << 1;
//r4 <<= 1;
} while (--r3 && ++y != 8);
x += 16;
if (r4 != 0)
WORD(mbuf[x + 0]) = r4;
}
uint16 r8 = vwf_line_ptr + 0x150;
const uint16 *src3 = kTextBits + (r10 + 16) * 8;
for (int i = 0; i != 16; i += 2) {
uint16 r4 = *src3++;
int y = r8 + r0;
int x = (y & 0xff0) + i;
y = (y >> 1) & 7;
uint8 r3 = width;
do {
if (r4 & 0x0080)
mbuf[x + 0] ^= kVWF_RenderCharacter_setMasks[y];
else
mbuf[x + 0] &= ~kVWF_RenderCharacter_setMasks[y];
if (r4 & 0x8000)
mbuf[x + 1] ^= kVWF_RenderCharacter_setMasks[y];
else
mbuf[x + 1] &= ~kVWF_RenderCharacter_setMasks[y];
//r4 <<= 1;
r4 = (r4 & ~0x8080) << 1;
} while (--r3 && ++y != 8);
x += 16;
if (r4 != 0)
WORD(mbuf[x + 0]) = r4;
}
uint8 base_x = vwf_arr[i];
vwf_arr[i + 1] = base_x + width;
int icon_index = (c & 0x70) * 2 + (c & 0xf);
// The two rows are spaced 21 sprites aside.
RenderFontPixelsInternal(base_x * 2 + vwf_line_ptr, width, icon_index);
RenderFontPixelsInternal(base_x * 2 + vwf_line_ptr + 0x150, width, icon_index + 16);
dialogue_msg_dst_offs++;
}
@@ -2767,10 +2759,12 @@ void RenderText_Draw_Choose1Or2() { // 8ecf72
}
void RenderText_Draw_Scroll() { // 8ecfe2
uint8 r2 = byte_7E1CEA;
int n = render_vwf_scroll_speed;
do {
for (int i = 0; i < 0x7e0; i += 16) {
uint16 *p = (uint16 *)((uint8 *)messaging_buf + i);
// Scroll up one line for each of the 21x6 sprites
for (size_t i = 0; i < 21 * 6; i++) {
uint16 *p = (uint16 *)((uint8 *)messaging_buf + i * 16);
// move each sprite up one line
p[0] = p[1];
p[1] = p[2];
p[2] = p[3];
@@ -2778,11 +2772,27 @@ void RenderText_Draw_Scroll() { // 8ecfe2
p[4] = p[5];
p[5] = p[6];
p[6] = p[7];
p[7] = p[168];
p[7] = p[0x15 * 8];
}
// Clear the last line (p[7] above) for the bottom-most set of sprites
uint16 *p = messaging_buf;
for (int i = 0x34f; i <= 0x3ef; i += 8)
p[i] = 0;
for (size_t i = (21 * 5) * 8; i < (21 * 6) * 8; i += 8)
p[i + 7] = 0;
if (kPpuUpsample2x2) {
for (size_t i = 0; i < 21 * 6; i++) {
uint64 *p = (uint64 *)((uint8*)g_zenv.ext_vram + (256 * 384) / 2 + i * 128);
for (size_t j = 0; j < 15; j++) {
p[j + 0] = p[j + 2];
p[j + 1] = p[j + 3];
}
p[14] = p[0x15 * 128 / 8 + 0];
p[15] = p[0x15 * 128 / 8 + 1];
}
uint64 *p = (uint64 *)((uint8 *)g_zenv.ext_vram + (256 * 384) / 2);
for (size_t i = (21 * 5) * 16; i < (21 * 6) * 16; i += 16)
p[i + 14] = p[i + 15] = 0;
}
if ((++byte_7E1CDF & 0xf) == 0) {
dialogue_msg_dst_offs++;
@@ -2792,7 +2802,7 @@ void RenderText_Draw_Scroll() { // 8ecfe2
text_next_position = 0;
break;
}
} while (r2--);
} while (n--);
}
void RenderText_Draw_Command7B() { // 8ed18d
@@ -2818,7 +2828,10 @@ void RenderText_Draw_ABunchOfSpaces() { // 8ed1bd
}
void RenderText_Draw_EmptyBuffer() { // 8ed1f9
memset(messaging_buf, 0, 0x7e0);
memset(messaging_buf, 0, 21 * 6 * 16);
if (kPpuUpsample2x2)
memset((uint8 *)g_zenv.ext_vram + (256 * 384) / 2, 0, 21 * 6 * 128);
dialogue_msg_src_offs = 0;
dialogue_msg_dst_offs++;
text_next_position = 0;
@@ -2834,7 +2847,7 @@ void RenderText_DrawBorderInitialize() { // 8ed29c
text_msgbox_topleft_copy = text_msgbox_topleft;
}
uint16 *RenderText_DrawBorderRow(uint16 *d, int y) { // 8ed2ab
static uint16 *RenderText_DrawBorderRow(uint16 *d, int y) { // 8ed2ab
y >>= 1;
*d++ = swap16(text_msgbox_topleft_copy);
text_msgbox_topleft_copy += 0x20;
@@ -2928,7 +2941,7 @@ void DungMap_Backup() { // 8ed94c
CGWSEL_copy = 0x02;
CGADSUB_copy = 0x20;
for (int i = 0; i < 2048; i++)
messaging_buf[i] = 0x300;
dungmap_buf[i] = 0x300;
sound_effect_2 = 16;
music_control = 0xf2;
}

View File

@@ -127,7 +127,6 @@ void RenderText_Draw_ABunchOfSpaces();
void RenderText_Draw_EmptyBuffer();
void RenderText_SetDefaultWindowPosition();
void RenderText_DrawBorderInitialize();
uint16 *RenderText_DrawBorderRow(uint16 *d, int y);
void Text_BuildCharacterTilemap();
void RenderText_Refresh();
void Text_GenerateMessagePointers();

137
nmi.c
View File

@@ -6,11 +6,6 @@
#include "snes/ppu.h"
#include "assets.h"
static const uint8 kNmiVramAddrs[] = {
0, 0, 4, 8, 12, 8, 12, 0, 4, 0, 8, 4, 12, 4, 12, 0,
8, 16, 20, 24, 28, 24, 28, 16, 20, 16, 24, 20, 28, 20, 28, 16,
24, 96, 104,
};
static PlayerHandlerFunc *const kNmiSubroutines[25] = {
&NMI_UploadTilemap_doNothing,
&NMI_UploadTilemap,
@@ -46,20 +41,14 @@ void NMI_UploadSubscreenOverlayLatter() {
NMI_HandleArbitraryTileMap(&g_ram[0x13000], 0x40, 0x80);
}
static void CopyToVram(uint32 dstv, const uint8 *src, int len) {
memcpy(&g_zenv.vram[dstv], src, len);
}
static void CopyToVramVertical(uint32 dstv, const uint8 *src, int len) {
static void CopyToVramVertical(uint16 *dst, const uint8 *src, int len) {
assert(!(len & 1));
uint16 *dst = &g_zenv.vram[dstv];
for (int i = 0, i_end = len >> 1; i < i_end; i++, dst += 32, src += 2)
*dst = WORD(*src);
}
static void CopyToVramLow(const uint8 *src, uint32 addr, int num) {
uint16 *dst = &g_zenv.vram[addr];
for (int i = 0; i < num; i++)
static void CopyToVramLow(uint16 *dst, const uint8 *src, int num) {
for (int i = 0; i < num; i++)
dst[i] = (dst[i] & ~0xff) | src[i];
}
@@ -164,19 +153,32 @@ void NMI_ReadJoypads(uint16 joypad_input) { // 8083d1
void NMI_DoUpdates() { // 8089e0
if (!nmi_disable_core_updates) {
memcpy(&g_zenv.vram[0x4100], &kLinkGraphics[dma_source_addr_0 - 0x8000], 0x40);
memcpy(&g_zenv.vram[0x4120], &kLinkGraphics[dma_source_addr_1 - 0x8000], 0x40);
memcpy(&g_zenv.vram[0x4140], &kLinkGraphics[dma_source_addr_2 - 0x8000], 0x20);
memcpy(&g_zenv.vram[0x4000], &kLinkGraphics[dma_source_addr_3 - 0x8000], 0x40);
memcpy(&g_zenv.vram[0x4020], &kLinkGraphics[dma_source_addr_4 - 0x8000], 0x40);
memcpy(&g_zenv.vram[0x4040], &kLinkGraphics[dma_source_addr_5 - 0x8000], 0x20);
memcpy(&g_zenv.vram[0x4100], &kLinkGraphics[dma_source_addr_0 - 0x8000], 0x40);
memcpy(&g_zenv.vram[0x4120], &kLinkGraphics[dma_source_addr_1 - 0x8000], 0x40);
memcpy(&g_zenv.vram[0x4140], &kLinkGraphics[dma_source_addr_2 - 0x8000], 0x20);
if (0) {
CONVERT_SPRITE_TO_X2(0x4000, (0x4050 - 0x4000) / 16);
CONVERT_SPRITE_TO_X2(0x4100, (0x4150 - 0x4100) / 16);
} else {
#define GET_LINK_SPRITE(x) g_image_data_x2.link_sprite[(x - 0x8000) >> 5]
memcpy(&g_zenv.ext_vram[GET_SPRITE_ADDR_X2(0x4000)], GET_LINK_SPRITE(dma_source_addr_3), 2 * 128);
memcpy(&g_zenv.ext_vram[GET_SPRITE_ADDR_X2(0x4020)], GET_LINK_SPRITE(dma_source_addr_4), 2 * 128);
memcpy(&g_zenv.ext_vram[GET_SPRITE_ADDR_X2(0x4040)], GET_LINK_SPRITE(dma_source_addr_5), 128);
memcpy(&g_zenv.ext_vram[GET_SPRITE_ADDR_X2(0x4100)], GET_LINK_SPRITE(dma_source_addr_0), 2 * 128);
memcpy(&g_zenv.ext_vram[GET_SPRITE_ADDR_X2(0x4120)], GET_LINK_SPRITE(dma_source_addr_1), 2 * 128);
memcpy(&g_zenv.ext_vram[GET_SPRITE_ADDR_X2(0x4140)], GET_LINK_SPRITE(dma_source_addr_2), 128);
#undef GET_LINK_SPRITE
}
memcpy(&g_zenv.vram[0x4050], &g_ram[dma_source_addr_6], 0x40);
memcpy(&g_zenv.vram[0x4070], &g_ram[dma_source_addr_7], 0x40);
memcpy(&g_zenv.vram[0x4090], &g_ram[dma_source_addr_8], 0x40);
memcpy(&g_zenv.vram[0x40b0], &g_ram[dma_source_addr_9], 0x20);
memcpy(&g_zenv.vram[0x40c0], &g_ram[dma_source_addr_10], 0x40);
memcpy(&g_zenv.vram[0x4150], &g_ram[dma_source_addr_11], 0x40);
memcpy(&g_zenv.vram[0x4170], &g_ram[dma_source_addr_12], 0x40);
memcpy(&g_zenv.vram[0x4190], &g_ram[dma_source_addr_13], 0x40);
@@ -193,8 +195,14 @@ void NMI_DoUpdates() { // 8089e0
memcpy(&g_zenv.vram[0x40e0], &g_ram[dma_source_addr_20], 0x40);
memcpy(&g_zenv.vram[0x41e0], &g_ram[dma_source_addr_21], 0x40);
}
CONVERT_SPRITE_TO_X2(0x4050, (0x4100 - 0x4050) / 16);
CONVERT_SPRITE_TO_X2(0x4150, (0x4360 - 0x4150) / 16);
memcpy(&g_zenv.vram[animated_tile_vram_addr], &g_ram[animated_tile_data_src], 0x400);
if (animated_tile_vram_addr >= 0x4000 && animated_tile_vram_addr < 0x6000)
CONVERT_SPRITE_TO_X2(animated_tile_vram_addr, 32);
else if (animated_tile_vram_addr >= 0x2000 && animated_tile_vram_addr < 0x4000)
CONVERT_BG_TO_X2(animated_tile_vram_addr, 32);
}
if (flag_update_hud_in_nmi) {
@@ -202,6 +210,7 @@ void NMI_DoUpdates() { // 8089e0
}
if (flag_update_cgram_in_nmi) {
g_zenv.ppu->cgramDirty = true;
memcpy(g_zenv.ppu->cgram, main_palette_buffer, 0x200);
}
@@ -231,7 +240,11 @@ void NMI_DoUpdates() { // 8089e0
}
if (nmi_update_tilemap_dst) {
// This is about sprites
memcpy(&g_zenv.vram[nmi_update_tilemap_dst * 256], &g_ram[0x10000 + nmi_update_tilemap_src], 0x200);
if (nmi_update_tilemap_dst * 256 >= 0x4000 && nmi_update_tilemap_dst * 256 < 0x6000)
CONVERT_SPRITE_TO_X2(nmi_update_tilemap_dst * 256, 16);
nmi_update_tilemap_dst = 0;
}
@@ -261,13 +274,20 @@ void NMI_DoUpdates() { // 8089e0
}
int idx = nmi_subroutine_index;
nmi_subroutine_index = 0;
kNmiSubroutines[idx]();
if (idx) {
nmi_subroutine_index = 0;
kNmiSubroutines[idx]();
}
}
void NMI_UploadTilemap() { // 808cb0
memcpy(&g_zenv.vram[kNmiVramAddrs[BYTE(nmi_load_target_addr)] << 8], &g_ram[0x1000], 0x800);
static const uint8 kNmiVramAddrs[] = {
0, 0, 4, 8, 12, 8, 12, 0, 4, 0, 8, 4, 12, 4, 12, 0,
8, 16, 20, 24, 28, 24, 28, 16, 20, 16, 24, 20, 28, 20, 28, 16,
24, 96, 104,
};
int load_addr = kNmiVramAddrs[BYTE(nmi_load_target_addr)] << 8;
memcpy(&g_zenv.vram[load_addr], &g_ram[0x1000], 0x800);
*(uint16 *)&g_ram[0x1000] = 0;
nmi_disable_core_updates = 0;
}
@@ -276,7 +296,7 @@ void NMI_UploadTilemap_doNothing() { // 808ce3
}
void NMI_UploadBG3Text() { // 808ce4
memcpy(&g_zenv.vram[0x7c00], &g_ram[0x10000], 0x7e0);
memcpy(&g_zenv.vram[0x7c00], messaging_buf, 0x7e0);
nmi_disable_core_updates = 0;
}
@@ -310,8 +330,8 @@ void NMI_HandleArbitraryTileMap(const uint8 *src, int i, int i_end) { // 808dae
void NMI_UpdateBG1Wall() { // 808e09
// Secret Wall Right
CopyToVramVertical(nmi_load_target_addr, &g_ram[0xc880], 0x40);
CopyToVramVertical(nmi_load_target_addr + 0x800, &g_ram[0xc8c0], 0x40);
CopyToVramVertical(&g_zenv.vram[nmi_load_target_addr], &g_ram[0xc880], 0x40);
CopyToVramVertical(&g_zenv.vram[nmi_load_target_addr + 0x800], &g_ram[0xc8c0], 0x40);
}
void NMI_TileMapNothing() { // 808e4b
@@ -323,7 +343,7 @@ void NMI_UpdateLoadLightWorldMap() { // 808e54
for (int j = 0; j != 4; j++) {
int t = kLightWorldTileMapDsts[j];
for (int i = 0x20; i; i--) {
CopyToVramLow(src, t, 0x20);
CopyToVramLow(&g_zenv.vram[t], src, 0x20);
src += 32;
t += 0x80;
}
@@ -331,80 +351,94 @@ void NMI_UpdateLoadLightWorldMap() { // 808e54
}
void NMI_UpdateBG2Left() { // 808ea9
CopyToVram(0, &g_ram[0x10000], 0x800);
CopyToVram(0x800, &g_ram[0x10800], 0x800);
memcpy(&g_zenv.vram[0], &g_ram[0x10000], 0x800);
memcpy(&g_zenv.vram[0x800], &g_ram[0x10800], 0x800);
}
static void NMI_RunTileMapUpdateDMA(uint16 *dst) { // 808fc9
memcpy(dst, &g_ram[0x10000], 0x1000);
nmi_disable_core_updates = 0;
}
void NMI_UpdateBGChar3and4() { // 808ee7
memcpy(&g_zenv.vram[0x2c00], &g_ram[0x10000], 0x1000);
nmi_disable_core_updates = 0;
NMI_RunTileMapUpdateDMA(&g_zenv.vram[0x2c00]);
CONVERT_BG_TO_X2(0x2c00, 128);
}
void NMI_UpdateBGChar5and6() { // 808f16
memcpy(&g_zenv.vram[0x3400], &g_ram[0x11000], 0x1000);
CONVERT_BG_TO_X2(0x3400, 128);
nmi_disable_core_updates = 0;
}
void NMI_UpdateBGCharHalf() { // 808f45
memcpy(&g_zenv.vram[BYTE(nmi_load_target_addr) * 256], &g_ram[0x11000], 0x400);
int dst_addr = BYTE(nmi_load_target_addr) * 256;
memcpy(&g_zenv.vram[dst_addr], &g_ram[0x11000], 0x400);
if (dst_addr >= 0x4000 && dst_addr < 0x6000)
CONVERT_SPRITE_TO_X2(dst_addr, 32);
}
void NMI_UpdateBGChar0() { // 808f72
NMI_RunTileMapUpdateDMA(0x2000);
NMI_RunTileMapUpdateDMA(&g_zenv.vram[0x2000]);
CONVERT_BG_TO_X2(0x2000, 128);
}
void NMI_UpdateBGChar1() { // 808f79
NMI_RunTileMapUpdateDMA(0x2800);
NMI_RunTileMapUpdateDMA(&g_zenv.vram[0x2800]);
CONVERT_BG_TO_X2(0x2800, 128);
}
void NMI_UpdateBGChar2() { // 808f80
NMI_RunTileMapUpdateDMA(0x3000);
NMI_RunTileMapUpdateDMA(&g_zenv.vram[0x3000]);
CONVERT_BG_TO_X2(0x3000, 128);
}
void NMI_UpdateBGChar3() { // 808f87
NMI_RunTileMapUpdateDMA(0x3800);
NMI_RunTileMapUpdateDMA(&g_zenv.vram[0x3800]);
CONVERT_BG_TO_X2(0x3800, 128);
}
void NMI_UpdateObjChar0() { // 808f8e
CopyToVram(0x4400, &g_ram[0x10000], 0x800);
memcpy(&g_zenv.vram[0x4400], &g_ram[0x10000], 0x800);
CONVERT_SPRITE_TO_X2(0x4400, 64);
nmi_disable_core_updates = 0;
}
void NMI_UpdateObjChar2() { // 808fbd
NMI_RunTileMapUpdateDMA(0x5000);
NMI_RunTileMapUpdateDMA(&g_zenv.vram[0x5000]);
CONVERT_SPRITE_TO_X2(0x5000, 64);
}
void NMI_UpdateObjChar3() { // 808fc4
NMI_RunTileMapUpdateDMA(0x5800);
}
void NMI_RunTileMapUpdateDMA(int dst) { // 808fc9
CopyToVram(dst, &g_ram[0x10000], 0x1000);
nmi_disable_core_updates = 0;
NMI_RunTileMapUpdateDMA(&g_zenv.vram[0x5800]);
CONVERT_SPRITE_TO_X2(0x5800, 64);
}
void NMI_UploadDarkWorldMap() { // 808ff3
static const uint16 kLightWorldTileMapSrcs[4] = { 0, 0x20, 0x1000, 0x1020 };
const uint8 *src = g_ram + 0x1000;
int t = 0x810;
uint16 *dst = &g_zenv.vram[0x810];
for (int i = 0x20; i; i--) {
CopyToVramLow(src, t, 0x20);
CopyToVramLow(dst, src, 0x20);
src += 32;
t += 0x80;
dst += 0x80;
}
}
void NMI_UploadGameOverText() { // 809038
CopyToVram(0x7800, &g_ram[0x2000], 0x800);
CopyToVram(0x7d00, &g_ram[0x3400], 0x600);
memcpy(&g_zenv.vram[0x7800], &g_ram[0x2000], 0x800);
memcpy(&g_zenv.vram[0x7d00], &g_ram[0x3400], 0x600);
CONVERT_HUD_TO_X2(0x7800, 128);
CONVERT_HUD_TO_X2(0x7d00, 96);
}
void NMI_UpdatePegTiles() { // 80908b
CopyToVram(0x3d00, &g_ram[0x10000], 0x100);
memcpy(&g_zenv.vram[0x3d00], &g_ram[0x10000], 0x100);
CONVERT_BG_TO_X2(0x3d00, 8);
}
void NMI_UpdateStarTiles() { // 8090b7
CopyToVram(0x3ed0, &g_ram[0x10000], 0x40);
memcpy(&g_zenv.vram[0x3ed0], &g_ram[0x10000], 0x40);
CONVERT_BG_TO_X2(0x3ed0, 2);
}
void HandleStripes14(const uint8 *p) { // 8092a1
@@ -449,6 +483,7 @@ void HandleStripes14(const uint8 *p) { // 8092a1
void NMI_UpdateIRQGFX() { // 809347
if (nmi_flag_update_polyhedral) {
memcpy(&g_zenv.vram[0x5800], &g_ram[0xe800], 0x800);
// CONVERT_SPRITE_TO_X2(0x5800, 64);
nmi_flag_update_polyhedral = 0;
}
}

1
nmi.h
View File

@@ -26,7 +26,6 @@ void NMI_UpdateBGChar3();
void NMI_UpdateObjChar0();
void NMI_UpdateObjChar2();
void NMI_UpdateObjChar3();
void NMI_RunTileMapUpdateDMA(int dst);
void NMI_UploadDarkWorldMap();
void NMI_UploadGameOverText();
void NMI_UpdatePegTiles();

343
poly.c
View File

@@ -24,9 +24,11 @@ static const int8 kPolySinCos[320] = {
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
};
typedef struct Vertex3 {
int8 x, y, z;
} Vertex3;
static const Vertex3 kPoly0_Vtx[6] = {
{ 0, 65, 0},
{ 0, -65, 0},
@@ -35,6 +37,7 @@ static const Vertex3 kPoly0_Vtx[6] = {
{ 0, 0, 40},
{ 40, 0, 0},
};
static const uint8 kPoly0_Polys[40] = {
3, 0, 5, 2, 4,
3, 0, 2, 3, 1,
@@ -45,6 +48,7 @@ static const uint8 kPoly0_Polys[40] = {
3, 1, 4, 3, 2,
3, 1, 5, 4, 3,
};
static const Vertex3 kPoly1_Vtx[6] = {
{ 0, 40, 10},
{ 40, -40, 10},
@@ -53,6 +57,7 @@ static const Vertex3 kPoly1_Vtx[6] = {
{-40, -40, -10},
{ 40, -40, -10},
};
static const uint8 kPoly1_Polys[28] = {
3, 0, 1, 2, 7,
3, 3, 4, 5, 6,
@@ -60,30 +65,35 @@ static const uint8 kPoly1_Polys[28] = {
4, 1, 5, 4, 2, 4,
4, 3, 0, 2, 4, 3,
};
typedef struct PolyConfig {
uint8 num_vtx, num_poly;
uint16 vtx_val, polys_val;
const Vertex3 *vertex;
const uint8 *poly;
} PolyConfig;
static const PolyConfig kPolyConfigs[2] = {
{6, 8, 0xff98, 0xffaa, kPoly0_Vtx, kPoly0_Polys},
{6, 5, 0xffd2, 0xffe4, kPoly1_Vtx, kPoly1_Polys},
};
static const uint32 kPoly_RasterColors[16] = {
0x00, 0xff, 0xff00, 0xffff,
0xff0000, 0xff00ff, 0xffff00, 0xffffff,
0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
};
static const uint16 kPoly_LeftSideMask[8] = {0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0xf0f, 0x707, 0x303, 0x101};
static const uint16 kPoly_RightSideMask[8] = {0x8080, 0xc0c0, 0xe0e0, 0xf0f0, 0xf8f8, 0xfcfc, 0xfefe, 0xffff};
uint16 Poly_Divide(uint16 a, uint16 b) {
poly_tmp1 = sign16(a) ? -a : a;
poly_tmp0 = b;
while (poly_tmp0 >= 256)
poly_tmp0 >>= 1, poly_tmp1 >>= 1;
int q = poly_tmp1 / poly_tmp0;
static uint16 Poly_Divide(uint16 a, uint16 b);
static void Polyhedral_SetShapePointer();
static void Polyhedral_SetRotationMatrix();
static void Polyhedral_OperateRotation();
static void Polyhedral_RotatePoint();
static void Polyhedral_ProjectPoint();
static void Polyhedral_DrawPolyhedron();
static int Polyhedral_CalcForegroundColor(int16 facing);
static void Polyhedral_EmptyBitMapBuffer();
static uint16 Poly_Divide(uint16 a, uint16 b) {
uint16 tmp1 = sign16(a) ? -a : a;
uint16 tmp0 = b;
while (tmp0 >= 256)
tmp0 >>= 1, tmp1 >>= 1;
int q = tmp1 / tmp0;
return sign16(a) ? -q : q;
}
@@ -95,7 +105,7 @@ void Poly_RunFrame() {
Polyhedral_DrawPolyhedron();
}
void Polyhedral_SetShapePointer() { // 89f83d
static void Polyhedral_SetShapePointer() { // 89f83d
poly_var1 = poly_config1 * 2 + 0x80;
poly_tmp0 = poly_which_model * 2;
@@ -106,7 +116,7 @@ void Polyhedral_SetShapePointer() { // 89f83d
poly_fromlut_ptr4 = poly_config->polys_val;
}
void Polyhedral_SetRotationMatrix() { // 89f864
static void Polyhedral_SetRotationMatrix() { // 89f864
poly_sin_a = kPolySinCos[poly_a];
poly_cos_a = kPolySinCos[poly_a + 64];
poly_sin_b = kPolySinCos[poly_b];
@@ -117,7 +127,7 @@ void Polyhedral_SetRotationMatrix() { // 89f864
poly_e3 = (int16)poly_sin_b * (int8)poly_cos_a >> 8 << 2;
}
void Polyhedral_OperateRotation() { // 89f8fb
static void Polyhedral_OperateRotation() { // 89f8fb
const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
const int8 *src = &poly_config->vertex[0].x;
int i = poly_config_num_vertex;
@@ -134,7 +144,7 @@ void Polyhedral_OperateRotation() { // 89f8fb
} while (i);
}
void Polyhedral_RotatePoint() { // 89f931
static void Polyhedral_RotatePoint() { // 89f931
int x = (int8)poly_fromlut_x;
int y = (int8)poly_fromlut_y;
int z = (int8)poly_fromlut_z;
@@ -144,180 +154,217 @@ void Polyhedral_RotatePoint() { // 89f931
poly_f2 = ((int16)poly_e3 * z >> 8) - ((int16)poly_sin_a * y >> 8) + ((int16)poly_e1 * x >> 8) + poly_var1;
}
void Polyhedral_ProjectPoint() { // 89f9d6
static void Polyhedral_ProjectPoint() { // 89f9d6
poly_f0 = Poly_Divide(poly_f0, poly_f2);
poly_f1 = Poly_Divide(poly_f1, poly_f2);
}
void Polyhedral_DrawPolyhedron() { // 89fa4f
struct PolyPoint {
uint8 x, y;
};
static int16 Polyhedral_CalculateCrossProduct(struct PolyPoint *pt) { // 89fb24
int tmp0 = (pt[1].x - pt[0].x) * (pt[2].y - pt[1].y);
tmp0 -= (pt[2].x - pt[1].x) * (pt[1].y - pt[0].y);
return tmp0;
}
static void Polyhedral_DrawFace(int color, struct PolyPoint *pt, int npt, bool x2);
static void Polyhedral_DrawPolyhedron() { // 89fa4f
const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
const uint8 *src = poly_config->poly;
struct PolyPoint points[16];
do {
poly_num_vertex_in_poly = *src++;
BYTE(poly_tmp0) = poly_num_vertex_in_poly;
poly_xy_coords[0] = poly_num_vertex_in_poly * 2;
int i = 1;
do {
int n = *src++;
for(int i = 0; i < n; i++) {
int j = *src++;
poly_xy_coords[i + 0] = poly_arr_x[j];
poly_xy_coords[i + 1] = poly_arr_y[j];
i += 2;
} while (--BYTE(poly_tmp0));
points[i].x = poly_arr_x[j];
points[i].y = poly_arr_y[j];
}
poly_raster_color_config = *src++;
int order = Polyhedral_CalculateCrossProduct();
if (order > 0) {
Polyhedral_SetForegroundColor();
Polyhedral_DrawFace();
int16 facing = Polyhedral_CalculateCrossProduct(points);
if (facing > 0) {
int color = Polyhedral_CalcForegroundColor(facing);
Polyhedral_DrawFace(color, points, n, false);
if (kPpuUpsample2x2) {
for (int i = 0; i < n; i++)
points[i].x *= 2, points[i].y *= 2;
Polyhedral_DrawFace(color, points, n, true);
}
}
} while (--poly_config_num_polys);
}
void Polyhedral_SetForegroundColor() { // 89faca
static int Polyhedral_CalcForegroundColor(int16 facing) { // 89faca
uint8 t = poly_which_model ? (poly_config1 >> 5) : 0;
uint8 a = (poly_tmp0 << (t + 1)) >> 8;
Polyhedral_SetColorMask(a <= 1 ? 1 : a >= 7 ? 7 : a);
uint8 a = (facing << (t + 1)) >> 8;
return a <= 1 ? 1 : a >= 7 ? 7 : a;
}
int16 Polyhedral_CalculateCrossProduct() { // 89fb24
int16 a = poly_xy_coords[3] - poly_xy_coords[1];
poly_tmp0 = a * (int8)(poly_xy_coords[6] - poly_xy_coords[4]);
a = poly_xy_coords[5] - poly_xy_coords[3];
poly_tmp0 -= a * (int8)(poly_xy_coords[4] - poly_xy_coords[2]);
return poly_tmp0;
}
void Polyhedral_SetColorMask(int c) { // 89fcae
uint32 v = kPoly_RasterColors[c];
poly_raster_color0 = v;
poly_raster_color1 = v >> 16;
}
void Polyhedral_EmptyBitMapBuffer() { // 89fd04
static void Polyhedral_EmptyBitMapBuffer() { // 89fd04
memset(polyhedral_buffer, 0, 0x800);
if (kPpuUpsample2x2)
memset(&g_zenv.ext_vram[GET_SPRITE_ADDR_X2(0x5800)], 0, 0x800 * 4);
}
void Polyhedral_DrawFace() { // 89fd1e
int n = poly_xy_coords[0];
uint8 min_y = poly_xy_coords[n];
int min_idx = n;
while (n -= 2) {
if (poly_xy_coords[n] < min_y)
min_y = poly_xy_coords[n], min_idx = n;
struct PolyFaceRender {
struct PolyPoint *pt;
uint8 npt;
uint8 color;
uint8 total_num_steps;
struct PolyPoint target0, target1;
struct PolyPoint cur0, cur1;
uint16 x0_frac, x0_step;
uint8 cur_vertex_idx0, cur_vertex_idx1;
uint16 x1_frac, x1_step;
};
static void Polyhedral_FillLine(struct PolyFaceRender *poly, int y);
static void Polyhedral_FillLineX2(struct PolyFaceRender *poly, int y);
static bool Polyhedral_StepLeft(struct PolyFaceRender *poly);
static bool Polyhedral_StepRight(struct PolyFaceRender *poly);
static void Polyhedral_DrawFace(int color, struct PolyPoint *pt, int npt, bool x2) { // 89fd1e
struct PolyFaceRender poly;
poly.pt = pt;
poly.color = color;
poly.total_num_steps = poly.npt = npt;
uint8 min_y = pt[npt - 1].y;
int min_idx = npt - 1;
while (--npt) {
if (pt[npt - 1].y < min_y)
min_y = pt[npt - 1].y, min_idx = npt - 1;
}
poly_raster_dst_ptr = 0xe800 + (((min_y & 0x38) ^ (min_y & 0x20 ? 0x24 : 0)) << 6) + (min_y & 7) * 2;
poly_cur_vertex_idx0 = poly_cur_vertex_idx1 = min_idx;
poly_total_num_steps = poly_xy_coords[0] >> 1;
poly_y0_cur = poly_y1_cur = poly_xy_coords[min_idx];
poly_x0_cur = poly_x1_cur = poly_xy_coords[min_idx - 1];
if (Polyhedral_SetLeft() || Polyhedral_SetRight())
int y = min_y;
poly.cur_vertex_idx0 = poly.cur_vertex_idx1 = min_idx;
poly.cur1 = poly.cur0 = pt[min_idx];
if (Polyhedral_StepLeft(&poly) || Polyhedral_StepRight(&poly))
return;
for (;;) {
Polyhedral_FillLine();
if (BYTE(poly_raster_dst_ptr) != 0xe) {
poly_raster_dst_ptr += 2;
} else {
uint8 a = HIBYTE(poly_raster_dst_ptr) + 2;
poly_raster_dst_ptr = (a ^ ((a & 8) ? 0 : 0x19)) << 8;
}
if (poly_y0_cur == poly_y0_trig) {
poly_x0_cur = poly_x0_target;
if (Polyhedral_SetLeft())
x2 ? Polyhedral_FillLineX2(&poly, y) : Polyhedral_FillLine(&poly, y);
y++;
if (poly.cur0.y == poly.target0.y) {
poly.cur0.x = poly.target0.x;
if (Polyhedral_StepLeft(&poly))
return;
}
poly_y0_cur++;
if (poly_y1_cur == poly_y1_trig) {
poly_x1_cur = poly_x1_target;
if (Polyhedral_SetRight())
poly.cur0.y++;
if (poly.cur1.y == poly.target1.y) {
poly.cur1.x = poly.target1.x;
if (Polyhedral_StepRight(&poly))
return;
}
poly_y1_cur++;
poly_x0_frac += poly_x0_step;
poly_x1_frac += poly_x1_step;
poly.cur1.y++;
poly.x0_frac += poly.x0_step;
poly.x1_frac += poly.x1_step;
}
}
void Polyhedral_FillLine() { // 89fdcf
uint16 left = kPoly_LeftSideMask[(poly_x0_frac >> 8) & 7];
uint16 right = kPoly_RightSideMask[(poly_x1_frac >> 8) & 7];
poly_tmp2 = (poly_x0_frac >> 8) & 0x38;
int d0 = ((poly_x1_frac >> 8) & 0x38);
uint16 *ptr = (uint16*)&g_ram[poly_raster_dst_ptr + d0 * 4];
if ((d0 -= poly_tmp2) == 0) {
poly_tmp1 = left & right;
ptr[0] ^= (ptr[0] ^ poly_raster_color0) & poly_tmp1;
ptr[8] ^= (ptr[8] ^ poly_raster_color1) & poly_tmp1;
return;
static void Polyhedral_FillLine(struct PolyFaceRender *poly, int y) { // 89fdcf
static const uint16 kPoly_LeftSideMask[8] = { 0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0xf0f, 0x707, 0x303, 0x101 };
static const uint16 kPoly_RightSideMask[8] = { 0x8080, 0xc0c0, 0xe0e0, 0xf0f0, 0xf8f8, 0xfcfc, 0xfefe, 0xffff };
static const uint32 kPoly_RasterColors[16] = {
0x00, 0xff, 0xff00, 0xffff,
0xff0000, 0xff00ff, 0xffff00, 0xffffff,
0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
};
uint32 v = kPoly_RasterColors[poly->color];
uint16 color0 = v, color1 = v >> 16;
uint16 leftmask = kPoly_LeftSideMask[(poly->x0_frac >> 8) & 7];
uint16 rightmask = kPoly_RightSideMask[(poly->x1_frac >> 8) & 7];
int left = (poly->x0_frac >> 11) & 7;
int right = (poly->x1_frac >> 11) & 7;
int tile_index = (y >> 3 & 3) * 16 + (y & 0x20 ? 8 : 0) + right;
uint16 *ptr = (uint16*)&g_ram[0xe800 + tile_index * 32 + (y & 7) * 2];
if ((right -= left) == 0) {
ptr[0] ^= (ptr[0] ^ color0) & (leftmask & rightmask);
ptr[8] ^= (ptr[8] ^ color1) & (leftmask & rightmask);
} else if (right >= 0) {
ptr[0] ^= (ptr[0] ^ color0) & rightmask;
ptr[8] ^= (ptr[8] ^ color1) & rightmask;
ptr -= 32 / 2;
while (--right) {
ptr[0] = color0;
ptr[8] = color1;
ptr -= 32 / 2;
}
ptr[0] ^= (ptr[0] ^ color0) & leftmask;
ptr[8] ^= (ptr[8] ^ color1) & leftmask;
}
if (d0 < 0)
return;
int n = d0 >> 3;
ptr[0] ^= (ptr[0] ^ poly_raster_color0) & right;
ptr[8] ^= (ptr[8] ^ poly_raster_color1) & right;
ptr -= 0x10;
while (--n) {
ptr[0] = poly_raster_color0;
ptr[8] = poly_raster_color1;
ptr -= 0x10;
}
ptr[0] ^= (ptr[0] ^ poly_raster_color0) & left;
ptr[8] ^= (ptr[8] ^ poly_raster_color1) & left;
poly_tmp1 = left, poly_raster_numfull = 0;
}
bool Polyhedral_SetLeft() { // 89feb4
int i;
for (;;) {
if (sign8(--poly_total_num_steps))
return true;
i = poly_cur_vertex_idx0 - 2;
if (i == 0)
i = poly_xy_coords[0];
if (poly_xy_coords[i] < poly_y0_cur)
return true;
if (poly_xy_coords[i] != poly_y0_cur)
break;
poly_x0_cur = poly_xy_coords[i - 1];
poly_cur_vertex_idx0 = i;
static void Polyhedral_FillLineX2(struct PolyFaceRender *poly, int y) { // 89fdcf
uint32 x0_frac = poly->x0_frac, x1_frac = poly->x1_frac;
int tile_index = (y >> 4 & 3) * 16 + (y & 0x40 ? 8 : 0);
uint64 *ptr = (uint64 *)(&g_zenv.ext_vram[GET_SPRITE_ADDR_X2(tile_index * 16 + 0x5800)]) + (y & 15);
uint64 color = poly->color * 0x1111111111111111ull;
uint64 lmask = 0xffffffffffffffffull << (((x0_frac >> 8) & 15) * 4);
uint64 rmask = 0xffffffffffffffffull >> ((15 - ((x1_frac >> 8) & 15)) * 4);
int left = (x0_frac >> 12) & 7;
int right = (x1_frac >> 12) & 7;
ptr += left * 16;
if ((right -= left) == 0) {
ptr[0] ^= (ptr[0] ^ color) & (lmask & rmask);
} else if (right >= 0) {
ptr[0] ^= (ptr[0] ^ color) & lmask;
ptr += 128 / 8;
while (--right) {
ptr[0] = color;
ptr += 128 / 8;
}
ptr[0] ^= (ptr[0] ^ color) & rmask;
}
poly_y0_trig = poly_xy_coords[i];
poly_x0_target = poly_xy_coords[i - 1];
poly_cur_vertex_idx0 = i;
int t = poly_x0_target - poly_x0_cur, u = t;
}
static uint16 PolyDivide2(int num, uint8 denom) {
int t = num, u = t;
if (t < 0)
t = -t;
t = ((t & 0xff) << 8) / (uint8)(poly_y0_trig - poly_y0_cur);
poly_x0_frac = (poly_x0_cur << 8) | 0x80;
poly_x0_step = (u < 0) ? -t : t;
t = ((t & 0xff) << 8) / denom;
return (u < 0) ? -t : t;
}
static bool Polyhedral_StepLeft(struct PolyFaceRender *poly) { // 89feb4
int i;
for (;;) {
if (sign8(--poly->total_num_steps))
return true;
i = (poly->cur_vertex_idx0 == 0 ? poly->npt : poly->cur_vertex_idx0) - 1;
poly->cur_vertex_idx0 = i;
if (poly->pt[i].y < poly->cur0.y)
return true;
if (poly->pt[i].y != poly->cur0.y)
break;
poly->cur0.x = poly->pt[i].x;
}
poly->x0_frac = (poly->cur0.x << 8) | 0x80;
poly->target0 = poly->pt[i];
poly->x0_step = PolyDivide2(poly->target0.x - poly->cur0.x, poly->target0.y - poly->cur0.y);
return false;
}
bool Polyhedral_SetRight() { // 89ff1e
static bool Polyhedral_StepRight(struct PolyFaceRender *poly) { // 89ff1e
int i;
for (;;) {
if (sign8(--poly_total_num_steps))
if (sign8(--poly->total_num_steps))
return true;
i = poly_cur_vertex_idx1;
if (i == poly_xy_coords[0])
i = 0;
i += 2;
if (poly_xy_coords[i] < poly_y1_cur)
i = (poly->cur_vertex_idx1 + 1 == poly->npt) ? 0 : poly->cur_vertex_idx1 + 1;
poly->cur_vertex_idx1 = i;
if (poly->pt[i].y < poly->cur1.y)
return true;
if (poly_xy_coords[i] != poly_y1_cur)
if (poly->pt[i].y != poly->cur1.y)
break;
poly_x1_cur = poly_xy_coords[i - 1];
poly_cur_vertex_idx1 = i;
poly->cur1.x = poly->pt[i].x;
}
poly_y1_trig = poly_xy_coords[i];
poly_x1_target = poly_xy_coords[i - 1];
poly_cur_vertex_idx1 = i;
int t = poly_x1_target - poly_x1_cur, u = t;
if (t < 0)
t = -t;
t = ((t & 0xff) << 8) / (uint8)(poly_y1_trig - poly_y1_cur);
poly_x1_frac = (poly_x1_cur << 8) | 0x80;
poly_x1_step = (u < 0) ? -t : t;
poly->x1_frac = (poly->cur1.x << 8) | 0x80;
poly->target1 = poly->pt[i];
poly->x1_step = PolyDivide2(poly->target1.x - poly->cur1.x, poly->target1.y - poly->cur1.y);
return false;
}

15
poly.h
View File

@@ -1,19 +1,4 @@
#pragma once
#include "types.h"
uint16 Poly_Divide(uint16 a, uint16 b);
void Poly_RunFrame();
void Polyhedral_SetShapePointer();
void Polyhedral_SetRotationMatrix();
void Polyhedral_OperateRotation();
void Polyhedral_RotatePoint();
void Polyhedral_ProjectPoint();
void Polyhedral_DrawPolyhedron();
void Polyhedral_SetForegroundColor();
int16 Polyhedral_CalculateCrossProduct();
void Polyhedral_SetColorMask(int c);
void Polyhedral_EmptyBitMapBuffer();
void Polyhedral_DrawFace();
void Polyhedral_FillLine();
bool Polyhedral_SetLeft();
bool Polyhedral_SetRight();

View File

@@ -165,14 +165,17 @@ void Intro_FixCksum(uint8 *s) {
void LoadFileSelectGraphics() { // 80e4e9
Decomp_spr(&g_ram[0x14000], 0x5e);
Do3To4High(&g_zenv.vram[0x5000], &g_ram[0x14000]);
CONVERT_SPRITE_TO_X2(0x5000, 64);
Decomp_spr(&g_ram[0x14000], 0x5f);
Do3To4High(&g_zenv.vram[0x5400], &g_ram[0x14000]);
CONVERT_SPRITE_TO_X2(0x5400, 64);
TransferFontToVRAM();
Decomp_spr(&g_ram[0x14000], 0x6b);
memcpy(&g_zenv.vram[0x7800], &g_ram[0x14000], 0x300 * sizeof(uint16));
CONVERT_HUD_TO_X2(0x7800, 96);
}
void Intro_ValidateSram() { // 828054

File diff suppressed because it is too large Load Diff

View File

@@ -21,10 +21,13 @@ typedef struct BgLayer {
uint16_t tilemapAdr;
// -- snapshot ends here
uint16_t tileAdr;
uint32 tileAdrX2;
} BgLayer;
enum {
kPpuXPixels = 256 + kPpuExtraLeftRight * 2,
kPpuCgramSize = 256 + 256,
};
typedef uint16_t PpuZbufType;
@@ -34,6 +37,13 @@ typedef struct PpuPixelPrioBufs {
PpuZbufType data[kPpuXPixels];
} PpuPixelPrioBufs;
// This is also the pixel prios but upsampled 2x2
typedef struct PpuPixelPrioBufs2x2 {
// This holds the prio in the upper 8 bits and the color in the lower 8 bits.
PpuZbufType data[kPpuXPixels * 4];
} PpuPixelPrioBufs2x2;
enum {
kPpuRenderFlags_NewRenderer = 1,
// Render mode7 upsampled by 4x4
@@ -44,9 +54,9 @@ enum {
kPpuRenderFlags_NoSpriteLimits = 8,
};
struct Ppu {
bool lineHasSprites;
bool cgramDirty;
uint8_t lastBrightnessMult;
uint8_t lastMosaicModulo;
uint8_t renderFlags;
@@ -61,8 +71,6 @@ struct Ppu {
uint8 mosaicEnabled;
uint8 mosaicSize;
// object/sprites
uint16_t objTileAdr1;
uint16_t objTileAdr2;
uint8_t objSize;
// Window
uint8_t window1left;
@@ -79,6 +87,9 @@ struct Ppu {
bool halfColor;
uint8 mathEnabled;
uint8_t fixedColorR, fixedColorG, fixedColorB;
uint32_t fixedColor;
uint8 *halfColorMap;
// settings
bool forcedBlank;
uint8_t brightness;
@@ -119,18 +130,26 @@ struct Ppu {
// store 31 extra entries to remove the need for clamp
uint8_t brightnessMult[32 + 31];
uint8_t brightnessMultHalf[32 * 2];
uint16_t cgram[0x100];
uint16_t cgram[kPpuCgramSize];
uint32_t cgramWithBrightness[kPpuCgramSize];
uint8_t mosaicModulo[kPpuXPixels];
uint32_t colorMapRgb[256];
PpuPixelPrioBufs bgBuffers[2];
PpuPixelPrioBufs objBuffer;
PpuPixelPrioBufs2x2 objBuffer2x2;
PpuPixelPrioBufs2x2 bgBuffers2x2[2];
uint16_t vram[0x8000];
// Provides 512kb of additional vram
uint16_t extendedVram[0x20000];
};
Ppu* ppu_init();
void ppu_free(Ppu* ppu);
void ppu_reset(Ppu* ppu);
void ppu_handleVblank(Ppu* ppu);
void ppu_runLine(Ppu* ppu, int line);
uint8_t ppu_read(Ppu* ppu, uint8_t adr);
void ppu_write(Ppu* ppu, uint8_t adr, uint8_t val);

View File

@@ -80,41 +80,6 @@ def print_dialogue():
ROM = util.LoadedRom(sys.argv[1] if len(sys.argv) >= 2 else None)
kCompSpritePtrs = [
0x10f000,0x10f600,0x10fc00,0x118200,0x118800,0x118e00,0x119400,0x119a00,
0x11a000,0x11a600,0x11ac00,0x11b200,0x14fffc,0x1585d4,0x158ab6,0x158fbe,
0x1593f8,0x1599a6,0x159f32,0x15a3d7,0x15a8f1,0x15aec6,0x15b418,0x15b947,
0x15bed0,0x15c449,0x15c975,0x15ce7c,0x15d394,0x15d8ac,0x15ddc0,0x15e34c,
0x15e8e8,0x15ee31,0x15f3a6,0x15f92d,0x15feba,0x1682ff,0x1688e0,0x168e41,
0x1692df,0x169883,0x169cd0,0x16a26e,0x16a275,0x16a787,0x16aa06,0x16ae9d,
0x16b3ff,0x16b87e,0x16be6b,0x16c13d,0x16c619,0x16cbbb,0x16d0f1,0x16d641,
0x16d95a,0x16dd99,0x16e278,0x16e760,0x16ed25,0x16f20f,0x16f6b7,0x16fa5f,
0x16fd29,0x1781cd,0x17868d,0x178b62,0x178fd5,0x179527,0x17994b,0x179ea7,
0x17a30e,0x17a805,0x17acf8,0x17b2a2,0x17b7f9,0x17bc93,0x17c237,0x17c78e,
0x17cd55,0x17d2bc,0x17d82f,0x17dcec,0x17e1cc,0x17e36b,0x17e842,0x17eb38,
0x17ed58,0x17f06c,0x17f4fd,0x17fa39,0x17ff86,0x18845c,0x1889a1,0x188d64,
0x18919d,0x189610,0x189857,0x189b24,0x189dd2,0x18a03f,0x18a4ed,0x18a7ba,
0x18aedf,0x18af0d,0x18b520,0x18b953,
]
kCompBgPtrs = [
0x11b800,0x11bce2,0x11c15f,0x11c675,0x11cb84,0x11cf4c,0x11d2ce,0x11d726,
0x11d9cf,0x11dec4,0x11e393,0x11e893,0x11ed7d,0x11f283,0x11f746,0x11fc21,
0x11fff2,0x128498,0x128a0e,0x128f30,0x129326,0x129804,0x129d5b,0x12a272,
0x12a6fe,0x12aa77,0x12ad83,0x12b167,0x12b51d,0x12b840,0x12bd54,0x12c1c9,
0x12c73d,0x12cc86,0x12d198,0x12d6b1,0x12db6a,0x12e0ea,0x12e6bd,0x12eb51,
0x12f135,0x12f6c5,0x12fc71,0x138129,0x138693,0x138bad,0x139117,0x139609,
0x139b21,0x13a074,0x13a619,0x13ab2b,0x13b00c,0x13b4f5,0x13b9eb,0x13bebf,
0x13c3ce,0x13c817,0x13cb68,0x13cfb5,0x13d460,0x13d8c2,0x13dd7a,0x13e266,
0x13e7af,0x13ece5,0x13f245,0x13f6f0,0x13fc30,0x1480e9,0x14863b,0x148a7c,
0x148f2a,0x149346,0x1497ed,0x149cc2,0x14a173,0x14a61d,0x14ab5d,0x14b083,
0x14b4bd,0x14b94e,0x14be0e,0x14c291,0x14c7ba,0x14cce4,0x14d1db,0x14d6bd,
0x14db77,0x14ded1,0x14e2ac,0x14e754,0x14ebae,0x14ef4e,0x14f309,0x14f6f4,
0x14fa55,0x14ff8c,0x14ff93,0x14ff9a,0x14ffa1,0x14ffa8,0x14ffaf,0x14ffb6,
0x14ffbd,0x14ffc4,0x14ffcb,0x14ffd2,0x14ffd9,0x14ffe0,0x14ffe7,0x14ffee,
0x14fff5,0x18b520,0x18b953,
]
def compress_store(r):
rr = []
j, jend = 0, len(r)
@@ -138,16 +103,16 @@ def print_images():
lengths = b''
all = []
for i in range(12):
all.append(bytes(ROM.get_bytes(kCompSpritePtrs[i], 0x600)))
all.append(bytes(ROM.get_bytes(tables.kCompSpritePtrs[i], 0x600)))
for i in range(12, 108):
decomp, comp_len = util.decomp(kCompSpritePtrs[i], ROM.get_byte, False, True)
all.append(bytes(ROM.get_bytes(kCompSpritePtrs[i], comp_len)))
decomp, comp_len = util.decomp(tables.kCompSpritePtrs[i], ROM.get_byte, False, True)
all.append(bytes(ROM.get_bytes(tables.kCompSpritePtrs[i], comp_len)))
add_asset_uint8('kSprGfx', pack_u32_arrays(all))
all = []
for i in range(len(kCompBgPtrs)):
decomp, comp_len = util.decomp(kCompBgPtrs[i], ROM.get_byte, False, True)
all.append(bytes(ROM.get_bytes(kCompBgPtrs[i], comp_len)))
for i in range(len(tables.kCompBgPtrs)):
decomp, comp_len = util.decomp(tables.kCompBgPtrs[i], ROM.get_byte, False, True)
all.append(bytes(ROM.get_bytes(tables.kCompBgPtrs[i], comp_len)))
add_asset_uint8('kBgGfx', pack_u32_arrays(all))

View File

@@ -7,10 +7,19 @@ import tables
import yaml
import extract_music
import os
import array
import argparse
PATH=''
ROM = util.LoadedRom(sys.argv[1] if len(sys.argv) >= 2 else None)
parser = argparse.ArgumentParser(description='Extract resources.')
parser.add_argument('rom', nargs='?', help='the rom file')
parser.add_argument('--convert-x2-icons', action='store_true', help='convert X2 icons')
parser.add_argument('--fix-palette', action='store_true', help='only fix palette')
args = parser.parse_args()
ROM = util.LoadedRom(args.rom)
get_byte = ROM.get_byte
get_word = ROM.get_word
@@ -259,13 +268,6 @@ def print_all_overworld_areas():
def print_dialogue():
text_compression.print_strings(open('dialogue.txt', 'w'), get_byte)
def decomp_one_spr_2bit(data, offs, target, toffs, pitch):
for y in range(8):
d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
for x in range(8):
t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
target[toffs + y * pitch + (7 - x)] = t * 255 // 3
def decomp_one_spr_3bit(data, offs, target, toffs, pitch):
for y in range(8):
d0, d1, d2 = data[offs + y * 2], data[offs + y * 2 + 1], data[offs + y + 16]
@@ -297,10 +299,15 @@ def decomp_save(data, fname, func, step, height=32, palette=None):
save_array_as_image((128, height), dst, fname, palette)
def convert_snes_palette(v):
r=[]
for x in v:
r.extend(((x & 0x1f) << 3, (x >> 5 & 0x1f) << 3, (x >> 10 & 0x1f) << 3))
return r
res=[]
for i,x in enumerate(v):
r, g, b = (x & 0x1f), (x >> 5 & 0x1f), (x >> 10 & 0x1f)
if (i & 15) == 0:
# transparent color
res.extend((0, 0x80, 0x80))
else:
res.extend((r << 3 | r >> 2, g << 3 | g >> 2, b << 3 | b >> 2))
return res
def decode_link_sprites():
@@ -308,15 +315,12 @@ def decode_link_sprites():
decomp_save(get_bytes(0x108000, 32768), PATH+'linksprite.png',
decomp_one_spr_4bit, 32, 448, convert_snes_palette(kLinkPalette))
def decomp_save_2bit(data, fname):
dst=[0]*128*64
for i in range(128):
x = i % 16
y = i // 16
decomp_one_spr_2bit(data, i * 16, dst, x * 8 + y * 8 * 128, 128)
img = Image.new("L", (128, 64))
img.putdata(dst)
img.save(fname)
def decomp_one_spr_2bit(data, offs, target, toffs, pitch, palette_base):
for y in range(8):
d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
for x in range(8):
t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
target[toffs + y * pitch + (7 - x)] = t + palette_base
gfx_desc = {
@@ -353,22 +357,22 @@ gfx_desc = {
103 : ('2bpp', 'Attract images loaded to 7800'),
104 : ('2bpp', 'empty'),
105 : ('2bpp', 'hud icons loaded to 7xxx'),
106 : ('2bpp', 'hud icons loaded to 7xxx'),
107 : ('2bpp', 'hud icons loaded to 7xxx'),
105 : ('2bpp', 'hud icons loaded to 7800'),
106 : ('2bpp', 'hud icons loaded to 7000'),
107 : ('2bpp', 'hud icons loaded to 7400'),
}
def decomp_generic(k, mode, fname_add = "misc"):
fname = 'img/%.3d - %s.png' % (k, fname_add)
if mode == '2bpp':
r = util.decomp(kCompSpritePtrs[k], get_byte, False)
decomp_save_2bit(r, fname)
r = util.decomp(tables.kCompSpritePtrs[k], get_byte, False)
decomp_save_2bit(r, fname, k)
elif mode == '3bpp_np':
print(k)
r = get_bytes(kCompSpritePtrs[k], 0x600)
r = get_bytes(tables.kCompSpritePtrs[k], 0x600)
decomp_save(r, fname, decomp_one_spr_3bit, 24)
elif mode== '3bpp':
r = util.decomp(kCompSpritePtrs[k], get_byte, False)
r = util.decomp(tables.kCompSpritePtrs[k], get_byte, False)
decomp_save(r, fname, decomp_one_spr_3bit, 24)
else:
assert 0
@@ -663,5 +667,134 @@ def print_all():
print_map32_to_map16(open(PATH+'map32_to_map16.txt', 'w'))
extract_music.extract_sound_data(ROM)
def get_hud_snes_palette():
hud_palette = ROM.get_words(0x9BD660, 64)
palette = [(31 << 10 | 31) for i in range(256)]
for i in range(16):
for j in range(1, 4):
palette[i * 16 + j] = hud_palette[i * 4 + j]
return palette
print_all()
class PaletteUsage:
def __init__(self):
self.data = open('palette_usage.bin', 'rb').read()
def get(self, icon):
usage = self.data[icon]
for j in range(8):
if usage & (1 << j):
return j
return 0
def decode_hud_icons():
kBasePal = { 105 : 2, 106 : 0, 107 : 1 }
pu = PaletteUsage()
dst=[0]*128*64*3
for image_set, slot in kBasePal.items():
data = util.decomp(tables.kCompSpritePtrs[image_set], get_byte, False)
for i in range(128):
pal_base = pu.get(slot * 128 + i) * 16
x, y = i % 16, i // 16
decomp_one_spr_2bit(data, i * 16, dst, x * 8 + y * 8 * 128 + slot * 128 * 64, 128, pal_base)
save_array_as_image((128, 64 * 3), dst, 'hud_icons.png', convert_snes_palette(get_hud_snes_palette()[:128]))
def decode_font():
data = ROM.get_bytes(0xe8000, 2048 * 2)
dst=[0]*128*64*2
for i in range(256):
x, y = i % 16, i // 16
pal_base = 6 * 16
decomp_one_spr_2bit(data, i * 16, dst, x * 8 + y * 8 * 128, 128, pal_base)
save_array_as_image((128, 64 * 2), dst, 'font.png', convert_snes_palette(get_hud_snes_palette()[:128]))
def fix_palette(iconfile):
img_orig = Image.open('hud_icons_orig.png').tobytes()
img = Image.open(iconfile)
data = bytearray(img.tobytes())
palette = img.palette.tobytes()
colors = {}
snespal = ROM.get_words(0x9BD660, 32)
for i in range(8):
for j in range(1, 4):
colors[(i, snespal[i * 4 + j])] = j
def fix_pixel(pos, x, y, pal):
i = data[pos]
r, g, b = palette[i * 3 + 0], palette[i * 3 + 1], palette[i * 3 + 2]
if r == 0 and g == 0x80 and b == 0x80:
return pal * 16
sv = (b >> 3) << 10 | (g >> 3) << 5 | (r >> 3)
vv = colors.get((pal, sv))
# in the first version both black and transparent had the same color value
# if it was transparent in the original, make it transparent here too, otherwise black
if (r|g|b) == 0:
if vv == None or (img_orig[pos] & 0xf) == 0:
return pal * 16
if vv == None:
raise Exception('pixel at (%d, %d) with value (%d,%d,%d) palette %d not found %s' % (xo + x, yo + y, r, g, b, pal, (pal, sv)))
data[pos] = pal * 16 + vv
def fix_single_16x16(pos, pal):
for y in range(16):
for x in range(16):
fix_pixel(pos + y * 256 + x, x, y, pal)
pu = PaletteUsage()
for yo in range(24):
for xo in range(16):
fix_single_16x16(yo * 256 * 16 + xo * 16, pu.get(yo * 16 + xo))
save_array_as_image((256, 128 * 3), data, 'hud_icons_fixed.png', convert_snes_palette(get_hud_snes_palette()[:128]))
def append_4bpp_tiles_to_binary_x2(data, tiles_w, tiles_h):
def pack_pixels_4bpp(a):
r = []
for i in range(len(a) // 2):
r.append(a[i * 2 + 0] & 0xf | (a[i * 2 + 1] & 0xf) << 4)
return r
def convert_single_16x16(data, pos):
pixels = []
for y in range(16):
for x in range(16):
pixels.append(data[pos + y * 256 + x])
return pack_pixels_4bpp(pixels)
out = []
for yo in range(tiles_h):
for xo in range(tiles_w):
out.extend(convert_single_16x16(data, yo * 256 * 16 + xo * 16))
return out
def convert_x2_icons_to_binary():
# Convert to the new 4bpp ppu format
out = []
img = Image.open('hud_icons_x2.png')
img_data, img_palette = img.tobytes(), img.palette.tobytes() # need to call palette last, wtf
out.extend(append_4bpp_tiles_to_binary_x2(img_data, 16, 24))
img = Image.open('hud_font_x2.png')
out.extend(append_4bpp_tiles_to_binary_x2(img.tobytes(), 16, 16))
img = Image.open('linksprite_x2.png')
out.extend(append_4bpp_tiles_to_binary_x2(img.tobytes(), 16, 56))
open('x2_icons.bin', 'wb').write(bytes(out))
snespal = []
for i in range(128):
r, g, b = img_palette[i * 3 + 0], img_palette[i * 3 + 1], img_palette[i * 3 + 2]
snespal.append((b >> 3) << 10 | (g >> 3) << 5 | (r >> 3))
snespal.extend(get_hud_snes_palette()[128:])
open('x2_icons.pal', 'wb').write(array.array('H', snespal).tobytes())
if args.convert_x2_icons:
convert_x2_icons_to_binary()
elif args.fix_palette:
# decode_hud_icons()
fix_palette('hud_icons_broken.png')
else:
#print_all()
decode_font()

View File

@@ -880,3 +880,39 @@ def get_secret_names():
kSecretNames = get_secret_names()
kSecretNamesRev = invert_dict(kSecretNames)
kCompSpritePtrs = [
0x10f000,0x10f600,0x10fc00,0x118200,0x118800,0x118e00,0x119400,0x119a00,
0x11a000,0x11a600,0x11ac00,0x11b200,0x14fffc,0x1585d4,0x158ab6,0x158fbe,
0x1593f8,0x1599a6,0x159f32,0x15a3d7,0x15a8f1,0x15aec6,0x15b418,0x15b947,
0x15bed0,0x15c449,0x15c975,0x15ce7c,0x15d394,0x15d8ac,0x15ddc0,0x15e34c,
0x15e8e8,0x15ee31,0x15f3a6,0x15f92d,0x15feba,0x1682ff,0x1688e0,0x168e41,
0x1692df,0x169883,0x169cd0,0x16a26e,0x16a275,0x16a787,0x16aa06,0x16ae9d,
0x16b3ff,0x16b87e,0x16be6b,0x16c13d,0x16c619,0x16cbbb,0x16d0f1,0x16d641,
0x16d95a,0x16dd99,0x16e278,0x16e760,0x16ed25,0x16f20f,0x16f6b7,0x16fa5f,
0x16fd29,0x1781cd,0x17868d,0x178b62,0x178fd5,0x179527,0x17994b,0x179ea7,
0x17a30e,0x17a805,0x17acf8,0x17b2a2,0x17b7f9,0x17bc93,0x17c237,0x17c78e,
0x17cd55,0x17d2bc,0x17d82f,0x17dcec,0x17e1cc,0x17e36b,0x17e842,0x17eb38,
0x17ed58,0x17f06c,0x17f4fd,0x17fa39,0x17ff86,0x18845c,0x1889a1,0x188d64,
0x18919d,0x189610,0x189857,0x189b24,0x189dd2,0x18a03f,0x18a4ed,0x18a7ba,
0x18aedf,0x18af0d,0x18b520,0x18b953,
]
kCompBgPtrs = [
0x11b800,0x11bce2,0x11c15f,0x11c675,0x11cb84,0x11cf4c,0x11d2ce,0x11d726,
0x11d9cf,0x11dec4,0x11e393,0x11e893,0x11ed7d,0x11f283,0x11f746,0x11fc21,
0x11fff2,0x128498,0x128a0e,0x128f30,0x129326,0x129804,0x129d5b,0x12a272,
0x12a6fe,0x12aa77,0x12ad83,0x12b167,0x12b51d,0x12b840,0x12bd54,0x12c1c9,
0x12c73d,0x12cc86,0x12d198,0x12d6b1,0x12db6a,0x12e0ea,0x12e6bd,0x12eb51,
0x12f135,0x12f6c5,0x12fc71,0x138129,0x138693,0x138bad,0x139117,0x139609,
0x139b21,0x13a074,0x13a619,0x13ab2b,0x13b00c,0x13b4f5,0x13b9eb,0x13bebf,
0x13c3ce,0x13c817,0x13cb68,0x13cfb5,0x13d460,0x13d8c2,0x13dd7a,0x13e266,
0x13e7af,0x13ece5,0x13f245,0x13f6f0,0x13fc30,0x1480e9,0x14863b,0x148a7c,
0x148f2a,0x149346,0x1497ed,0x149cc2,0x14a173,0x14a61d,0x14ab5d,0x14b083,
0x14b4bd,0x14b94e,0x14be0e,0x14c291,0x14c7ba,0x14cce4,0x14d1db,0x14d6bd,
0x14db77,0x14ded1,0x14e2ac,0x14e754,0x14ebae,0x14ef4e,0x14f309,0x14f6f4,
0x14fa55,0x14ff8c,0x14ff93,0x14ff9a,0x14ffa1,0x14ffa8,0x14ffaf,0x14ffb6,
0x14ffbd,0x14ffc4,0x14ffcb,0x14ffd2,0x14ffd9,0x14ffe0,0x14ffe7,0x14ffee,
0x14fff5,0x18b520,0x18b953,
]

View File

@@ -8,6 +8,7 @@
// Build time config options
enum {
kEnableLargeScreen = 1,
kPpuUpsample2x2 = 1,
// How much extra spacing to add on the sides
kPpuExtraLeftRight = kEnableLargeScreen ? 96 : 0,
};

View File

@@ -827,7 +827,7 @@
#define text_next_position (*(uint8*)(g_ram+0x1CE6))
#define choice_in_multiselect_box (*(uint8*)(g_ram+0x1CE8))
#define text_wait_countdown2 (*(uint8*)(g_ram+0x1CE9))
#define byte_7E1CEA (*(uint8*)(g_ram+0x1CEA))
#define render_vwf_scroll_speed (*(uint8*)(g_ram+0x1CEA))
#define dialogue_message_index (*(uint16*)(g_ram+0x1CF0))
#define byte_7E1CF2 ((uint8*)(g_ram+0x1CF2))
#define choice_in_multiselect_box_bak (*(uint8*)(g_ram+0x1CF4))
@@ -1355,7 +1355,11 @@
#define scratch_0 (*(uint16*)(g_ram+0x72))
#define scratch_1 (*(uint16*)(g_ram+0x74))
#define srm_var1 (*(uint16*)(g_zenv.sram+0x1ffe))
// These share the same memory
#define messaging_buf ((uint16*)(g_ram+0x10000))
#define dungmap_buf ((uint16*)(g_ram+0x10000))
#define quake_arr1 ((uint8*)(g_ram+0x15800))
#define quake_arr2 ((uint8*)(g_ram+0x15805))
#define quake_var5 (*(uint8*)(g_ram+0x1580A))

View File

@@ -21,9 +21,9 @@ WindowSize = Auto
# Fullscreen mode (0=windowed, 1=desktop fullscreen, 2=fullscreen w/mode change)
Fullscreen = 0
# Window scale (1=100%, 2=200%, 3=300%, etc.)
WindowScale = 3
WindowScale = 2
NewRenderer = 1
EnhancedMode7 = 1
EnhancedMode7 = 0
IgnoreAspectRatio = 0
# Enable this option to remove the sprite limits per scan line

View File

@@ -99,6 +99,9 @@ static void VerifySnapshotsEq(Snapshot *b, Snapshot *a, Snapshot *prev) {
b->ram[0x128] = a->ram[0x128]; // irq_flag
b->ram[0x463] = a->ram[0x463]; // which_staircase_index_padding
b->ram[0x1f4e] = a->ram[0x1f4e];
memcpy(&b->ram[0x1FB0], &a->ram[0x1FB0], 0x50); // poly stuff
// c code is authoritative
WORD(a->ram[0x1f0a]) = WORD(b->ram[0x1f0a]);

View File

@@ -316,6 +316,8 @@ void ZeldaInitialize() {
g_zenv.ram = g_ram;
g_zenv.sram = (uint8*)calloc(8192, 1);
g_zenv.vram = g_zenv.ppu->vram;
g_zenv.ext_vram = g_zenv.ppu->extendedVram;
g_zenv.cgram = g_zenv.ppu->cgram;
g_zenv.player = SpcPlayer_Create();
SpcPlayer_Initialize(g_zenv.player);
dma_reset(g_zenv.dma);
@@ -485,6 +487,9 @@ static void LoadSnesState(SaveLoadFunc *func, void *ctx) {
EmuSynchronizeWholeState();
ZeldaResetApuQueue();
ZeldaOpenMsuFile();
LoadHudPaletteX2();
LoadGraphicsExtended();
}
static void SaveSnesState(SaveLoadFunc *func, void *ctx) {
@@ -1085,3 +1090,5 @@ void ZeldaWriteSram() {
fprintf(stderr, "Unable to write saves/sram.dat\n");
}
}

View File

@@ -18,6 +18,8 @@ typedef struct ZeldaEnv {
uint8 *ram;
uint8 *sram;
uint16 *vram;
uint16 *ext_vram;
uint16 *cgram;
struct Ppu *ppu;
struct SpcPlayer *player;
struct Dma *dma;
@@ -76,4 +78,34 @@ typedef void ZeldaSyncAllFunc();
void ZeldaSetupEmuCallbacks(uint8 *emu_ram, ZeldaRunFrameFunc *func, ZeldaSyncAllFunc *sync_all);
void Convert2bppToX2(const uint16 *src, uint32 dst_addr, size_t count);
void Convert4bppToX2(const uint16 *src, uint32 dst_addr, size_t count);
// BG uses 0x2xxx, 0x3xxxx
#define GET_BG_ADDR_X2(addr) (0x10000 + ((addr) - 0x2000) * 4)
#define CONVERT_BG_TO_X2(addr, count) do { if (kPpuUpsample2x2) Convert4bppToX2(&g_zenv.vram[addr], GET_BG_ADDR_X2(addr), count); } while(0)
// Sprites use 0x4xxx, 0x5xxx
#define GET_SPRITE_ADDR_X2(addr) (0x8000 + ((addr) - 0x4000) * 4)
#define CONVERT_SPRITE_TO_X2(addr, count) do { if (kPpuUpsample2x2) Convert4bppToX2(&g_zenv.vram[addr], GET_SPRITE_ADDR_X2(addr), count); } while(0)
// HUD uses 0x7xxx
#define CONVERT_HUD_TO_X2(addr, count) do { if (kPpuUpsample2x2) Convert2bppToX2(&g_zenv.vram[addr], ((addr) - 0x7000) * 8, count); } while (0)
void LoadHudPaletteX2();
void LoadGraphicsExtended();
void LoadImageFilesX2();
// For the upsampled hud
struct ImageDataX2 {
uint8 icons[3][256 * 128 / 2];
uint8 font[256 * 256 / 2];
uint8 link_sprite[896][128];
};
extern struct ImageDataX2 g_image_data_x2;
extern uint16 g_cgram_data_x2[256];
#endif // ZELDA3_ZELDA_RTL_H_