Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24f3845fac | ||
|
|
3d5a36d68e | ||
|
|
30b044de2e | ||
|
|
07e25636ca |
@@ -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();
|
||||
|
||||
92
load_gfx.c
92
load_gfx.c
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
9
main.c
@@ -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);
|
||||
|
||||
177
messaging.c
177
messaging.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
137
nmi.c
@@ -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
1
nmi.h
@@ -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
343
poly.c
@@ -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
15
poly.h
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
796
snes/ppu.c
796
snes/ppu.c
File diff suppressed because it is too large
Load Diff
31
snes/ppu.h
31
snes/ppu.h
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
]
|
||||
1
types.h
1
types.h
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
32
zelda_rtl.h
32
zelda_rtl.h
@@ -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_
|
||||
|
||||
Reference in New Issue
Block a user