library: Implement another dual 3D Mode

This one is also stable, but it doesn't support the debug console.
This commit is contained in:
Antonio Niño Díaz 2023-10-10 01:02:45 +01:00
parent efaf04dadd
commit 8445136b6b
2 changed files with 150 additions and 26 deletions

View File

@ -88,7 +88,19 @@ void NE_Process(NE_Voidfunc drawscene);
/// @return Returns 0 on success.
int NE_InitDual3D(void);
// TODO
/// Inits Nitro Engine to draw 3D to both screens.
///
/// VRAM banks C and D are used as framebuffers, which means there is only 50%
/// of the normally available VRAM for textures.
///
/// Direct VRAM display mode is used for the main engine, which means there is
/// no way to display the debug console on either screen in a stable way, so the
/// debug console is not supported in this mode.
///
/// This mode is stable. If the framerate drops below 60 FPS the screens will
/// remain stable.
///
/// @return Returns 0 on success.
int NE_InitDual3D_FB(void);
/// Inits Nitro Engine to draw 3D to both screens.
@ -104,6 +116,9 @@ int NE_InitDual3D_FB(void);
/// to bank I. Because of this, it is unsafe to use the DMA In GFX FIFO mode to
/// draw models, which has a small performance hit.
///
/// This mode is stable. If the framerate drops below 60 FPS the screens will
/// remain stable.
///
/// In general, prefer NE_InitDual3D_DMA() over NE_InitDual3D().
///
/// @return Returns 0 on success.
@ -116,9 +131,6 @@ int NE_InitDual3D_DMA(void);
/// NE_MainScreenSetOnBottom() and NE_SwapScreens(). To check the current
/// position of the main screen, use NE_MainScreenIsOnTop().
///
/// Important note: When using safe dual 3D mode, use NE_ProcessSafeDual3D()
/// instead.
///
/// @param mainscreen Function that draws the main screen.
/// @param subscreen Function that draws the sub screen.
void NE_ProcessDual(NE_Voidfunc mainscreen, NE_Voidfunc subscreen);

View File

@ -84,7 +84,11 @@ void NE_End(void)
case NE_ModeDual3D_FB:
{
// TODO
videoSetMode(0);
videoSetModeSub(0);
vramSetBankC(VRAM_C_LCD);
vramSetBankD(VRAM_D_LCD);
break;
}
@ -313,6 +317,26 @@ int NE_Init3D(void)
return 0;
}
static void ne_setup_sprites(void)
{
// Reset sprites
for (int i = 0; i < 128; i++)
NE_Sprites[i].attribute[0] = ATTR0_DISABLED;
int i = 0;
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 4; x++)
{
NE_Sprites[i].attribute[0] = ATTR0_BMP | ATTR0_SQUARE | (64 * y);
NE_Sprites[i].attribute[1] = ATTR1_SIZE_64 | (64 * x);
NE_Sprites[i].attribute[2] = ATTR2_ALPHA(1) | (8 * 32 * y)
| (8 * x);
i++;
}
}
}
int NE_InitDual3D(void)
{
NE_End();
@ -330,22 +354,7 @@ int NE_InitDual3D(void)
return -2;
}
// Reset sprites
for (int i = 0; i < 128; i++)
NE_Sprites[i].attribute[0] = ATTR0_DISABLED;
int i = 0;
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 4; x++)
{
NE_Sprites[i].attribute[0] = ATTR0_BMP | ATTR0_SQUARE | (64 * y);
NE_Sprites[i].attribute[1] = ATTR1_SIZE_64 | (64 * x);
NE_Sprites[i].attribute[2] = ATTR2_ALPHA(1) | (8 * 32 * y)
| (8 * x);
i++;
}
}
ne_setup_sprites();
NE_DisplayListSetDefaultFunction(NE_DL_DMA_GFX_FIFO);
@ -380,9 +389,57 @@ int NE_InitDual3D(void)
int NE_InitDual3D_FB(void)
{
// TODO
NE_End();
return -1;
NE_Sprites = calloc(128, sizeof(SpriteEntry));
if (NE_Sprites == NULL)
{
NE_DebugPrint("Not enough memory");
return -1;
}
if (ne_systems_reset_all(NE_VRAM_AB) != 0)
return -2;
ne_setup_sprites();
NE_DisplayListSetDefaultFunction(NE_DL_DMA_GFX_FIFO);
NE_UpdateInput();
ne_init_registers();
videoSetModeSub(0);
REG_BG2CNT = BG_BMP16_256x256;
REG_BG2PA = 1 << 8;
REG_BG2PB = 0;
REG_BG2PC = 0;
REG_BG2PD = 1 << 8;
REG_BG2X = 0;
REG_BG2Y = 0;
REG_BG2CNT_SUB = BG_BMP16_256x256;
REG_BG2PA_SUB = 1 << 8;
REG_BG2PB_SUB = 0;
REG_BG2PC_SUB = 0;
REG_BG2PD_SUB = 1 << 8;
REG_BG2X_SUB = 0;
REG_BG2Y_SUB = 0;
vramSetBankC(VRAM_C_LCD);
vramSetBankD(VRAM_D_LCD);
videoSetMode(0);
videoSetModeSub(0);
ne_execution_mode = NE_ModeDual3D_FB;
NE_Screen = 0;
NE_DebugPrint("Nitro Engine initialized in dual 3D FB mode");
return 0;
}
int NE_InitDual3D_DMA(void)
@ -439,7 +496,7 @@ void NE_InitConsole(void)
case NE_ModeDual3D_FB:
{
// TODO
NE_Assert(false, "Debug console not supported in ModeDual3D_FB");
break;
}
@ -572,6 +629,61 @@ static void ne_process_dual_3d(NE_Voidfunc mainscreen, NE_Voidfunc subscreen)
NE_Screen ^= 1;
}
static void ne_process_dual_3d_fb(NE_Voidfunc mainscreen, NE_Voidfunc subscreen)
{
NE_UpdateInput();
if (NE_Screen == ne_main_screen)
lcdMainOnTop();
else
lcdMainOnBottom();
if (NE_Screen == 1)
{
videoSetMode(MODE_FB3);
videoSetModeSub(MODE_5_2D | DISPLAY_BG2_ACTIVE);
vramSetBankC(VRAM_C_SUB_BG);
vramSetBankD(VRAM_D_LCD);
REG_DISPCAPCNT = DCAP_SIZE(DCAP_SIZE_256x192)
| DCAP_BANK(DCAP_BANK_VRAM_D)
| DCAP_MODE(DCAP_MODE_A)
| DCAP_SRC_A(DCAP_SRC_A_3DONLY)
| DCAP_ENABLE;
}
else
{
videoSetMode(MODE_FB2);
videoSetModeSub(MODE_5_2D | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_2D_BMP_256);
vramSetBankC(VRAM_C_LCD);
vramSetBankD(VRAM_D_SUB_SPRITE);
REG_DISPCAPCNT = DCAP_SIZE(DCAP_SIZE_256x192)
| DCAP_BANK(DCAP_BANK_VRAM_C)
| DCAP_MODE(DCAP_MODE_A)
| DCAP_SRC_A(DCAP_SRC_A_3DONLY)
| DCAP_ENABLE;
}
NE_PolyFormat(31, 0, NE_LIGHT_ALL, NE_CULL_BACK, 0);
NE_Viewport(0, 0, 255, 191);
MATRIX_IDENTITY = 0;
if (NE_Screen == 1)
mainscreen();
else
subscreen();
GFX_FLUSH = GL_TRANS_MANUALSORT;
dmaCopy(NE_Sprites, OAM_SUB, 128 * sizeof(SpriteEntry));
NE_Screen ^= 1;
}
static void ne_do_dma(void)
{
@ -726,8 +838,8 @@ void NE_ProcessDual(NE_Voidfunc mainscreen, NE_Voidfunc subscreen)
case NE_ModeDual3D_FB:
{
// TODO
break;
ne_process_dual_3d_fb(mainscreen, subscreen);
return;
}
case NE_ModeDual3D_DMA: