From b925cabee9236112a65ba3bdaf38d0b718a79387 Mon Sep 17 00:00:00 2001 From: Sonic Dreamcaster Date: Tue, 15 Oct 2024 13:30:42 -0300 Subject: [PATCH] new starfield (not working for now) --- src/engine/fox_bg.c | 239 ++++++++++++++++++++++++++++++++++-------- src/engine/fox_play.c | 95 +++++++++++++++-- src/sys/sys_memory.c | 4 +- 3 files changed, 282 insertions(+), 56 deletions(-) diff --git a/src/engine/fox_bg.c b/src/engine/fox_bg.c index 3ca59718..a7122565 100644 --- a/src/engine/fox_bg.c +++ b/src/engine/fox_bg.c @@ -100,11 +100,46 @@ f32 sGroundPositions360z[4] = { -6000.0f, }; +// Declare global variables for screen dimensions +float gCurrentScreenWidth = 320.0f * 3; // Default width +float gCurrentScreenHeight = 240.0f * 3; // Default height + +// Custom floating-point modulo function (replaces fmodf) +float FloatMod(float a, float b) { + float result = a - ((int) (a / b)) * b; + if (result < 0.0f) { + result += b; + } + return result; +} + +// Define a single 1x1 star as two triangles +static Vtx starVerts[4] = { + // Format: VTX(x, y, z, s, t, r, g, b, a) + VTX(0, 0, 0, 0, 0, 255, 255, 255, 255), // Bottom-left + VTX(0, 1, 0, 0, 0, 255, 255, 255, 255), // Top-left + VTX(1, 0, 0, 0, 0, 255, 255, 255, 255), // Bottom-right + VTX(1, 1, 0, 0, 0, 255, 255, 255, 255), // Top-right +}; + +// Display list to render the two triangles forming the star quad +static Gfx starDL[] = { + gsSPVertex(starVerts, ARRAY_COUNT(starVerts), 0), + gsSP2Triangles(0, 1, 2, 0, 1, 2, 3, 0), + gsSPEndDisplayList(), +}; + +// Display list to render the two triangles forming the partial star quad +static Gfx starDLPartial[] = { + gsSPVertex(starVerts, ARRAY_COUNT(starVerts), 0), + gsSP2Triangles(0, 1, 2, 0, 1, 2, 3, 0), + gsSPEndDisplayList(), +}; + +// @port: Starfield drawn with triangles, re-engineered by @Tharo & @TheBoy181 void Background_DrawStarfield(void) { f32 by; f32 bx; - s16 vy; - s16 vx; s32 i; s32 starCount; f32 zCos; @@ -114,24 +149,52 @@ void Background_DrawStarfield(void) { f32* xStar; f32* yStar; u32* color; + float currentScreenWidth; + float currentScreenHeight; + float starfieldWidth; + float starfieldHeight; + float vx; + float vy; + const float STAR_MARGIN = 10.0f; // Margin to hide seam stars + + // Set projection to orthographic before drawing stars + Lib_InitOrtho(&gMasterDisp); + + // Setup render state for stars + static Gfx starSetupDL[] = { + gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF), // Disable texturing + gsSPClearGeometryMode(G_ZBUFFER | G_SHADE | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_CULL_BACK | + G_SHADING_SMOOTH), + gsDPPipeSync(), + gsDPSetCombineMode(G_CC_PRIMITIVE, G_CC_PRIMITIVE), // Use primitive color + gsDPSetOtherMode(G_AD_NOTPATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE | + G_TD_CLAMP | G_TP_PERSP | G_CYC_1CYCLE | G_PM_NPRIMITIVE, + G_AC_NONE | G_ZS_PIXEL | G_RM_OPA_SURF | G_RM_OPA_SURF2), + gsSPEndDisplayList(), + }; + gSPDisplayList(gMasterDisp++, starSetupDL); + + // Get current screen dimensions + currentScreenWidth = gCurrentScreenWidth; + currentScreenHeight = gCurrentScreenHeight; + starfieldWidth = 1.0f * currentScreenWidth; + starfieldHeight = 1.0f * currentScreenHeight; - gDPPipeSync(gMasterDisp++); - gDPSetCycleType(gMasterDisp++, G_CYC_FILL); - gDPSetCombineMode(gMasterDisp++, G_CC_SHADE, G_CC_SHADE); - gDPSetRenderMode(gMasterDisp++, G_RM_OPA_SURF, G_RM_OPA_SURF2); starCount = gStarCount; + if (starCount != 0) { - if (gStarfieldX >= 1.5f * SCREEN_WIDTH) { - gStarfieldX -= 1.5f * SCREEN_WIDTH; + // Wrapping logic for starfield positions + if (gStarfieldX >= starfieldWidth) { + gStarfieldX -= starfieldWidth; } - if (gStarfieldY >= 1.5f * SCREEN_HEIGHT) { - gStarfieldY -= 1.5f * SCREEN_HEIGHT; + if (gStarfieldY >= starfieldHeight) { + gStarfieldY -= starfieldHeight; } if (gStarfieldX < 0.0f) { - gStarfieldX += 1.5f * SCREEN_WIDTH; + gStarfieldX += starfieldWidth; } if (gStarfieldY < 0.0f) { - gStarfieldY += 1.5f * SCREEN_HEIGHT; + gStarfieldY += starfieldHeight; } xField = gStarfieldX; yField = gStarfieldY; @@ -143,35 +206,86 @@ void Background_DrawStarfield(void) { if (gGameState != GSTATE_PLAY) { starCount = 1000; } + + starCount = starCount * 3; // Adjust multiplier as needed + zCos = __cosf(gStarfieldRoll); zSin = __sinf(gStarfieldRoll); + for (i = 0; i < starCount; i++, yStar++, xStar++, color++) { + // Adjust star positions with field offsets bx = *xStar + xField; by = *yStar + yField; - if (bx >= 1.25f * SCREEN_WIDTH) { - bx -= 1.5f * SCREEN_WIDTH; - } - bx -= SCREEN_WIDTH / 2.0f; - if (by >= 1.25f * SCREEN_HEIGHT) { - by -= 1.5f * SCREEN_HEIGHT; + // Wrapping logic for individual stars along X-axis + if (bx >= starfieldWidth) { + bx -= starfieldWidth; + } + if (bx < 0.0f) { + bx += starfieldWidth; } - by -= SCREEN_HEIGHT / 2.0f; - vx = (zCos * bx) + (zSin * by) + SCREEN_WIDTH / 2.0f; - vy = (-zSin * bx) + (zCos * by) + SCREEN_HEIGHT / 2.0f; - if ((vx >= 0) && (vx < SCREEN_WIDTH) && (vy > 0) && (vy < SCREEN_HEIGHT)) { - gDPPipeSync(gMasterDisp++); - gDPSetFillColor(gMasterDisp++, *color); - gDPFillRectangle(gMasterDisp++, vx, vy, vx, vy); + // Wrapping logic for individual stars along Y-axis + if (by >= starfieldHeight) { + by -= starfieldHeight; + } + if (by < 0.0f) { + by += starfieldHeight; + } + + // Center the positions + bx -= starfieldWidth / 2.0f; + by -= starfieldHeight / 2.0f; + + // Apply rotation + vx = (zCos * bx) + (zSin * by) + currentScreenWidth / 2.0f; + vy = (-zSin * bx) + (zCos * by) + currentScreenHeight / 2.0f; + + // Check if the star is within the visible screen area with margin + if ((vx >= STAR_MARGIN) && (vx < currentScreenWidth - STAR_MARGIN) && (vy >= STAR_MARGIN) && + (vy < currentScreenHeight - STAR_MARGIN)) { + // @recomp Tag the transform. + // gEXMatrixGroupDecomposed(gMasterDisp++, TAG_STARFIELD + i, G_EX_PUSH, G_MTX_MODELVIEW, + // G_EX_COMPONENT_AUTO, G_EX_COMPONENT_AUTO, G_EX_COMPONENT_AUTO, + // G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, + // G_EX_COMPONENT_INTERPOLATE, G_EX_ORDER_AUTO, G_EX_EDIT_ALLOW); + + // Translate to (vx, vy) in ortho coordinates + Matrix_Push(&gGfxMatrix); + Matrix_Translate(gGfxMatrix, vx - (currentScreenWidth / 2.0f), -(vy - (currentScreenHeight / 2.0f)), + 0.0f, MTXF_NEW); + Matrix_SetGfxMtx(&gMasterDisp); + Matrix_Pop(&gGfxMatrix); + + // Convert color from fill color (assuming RGB5A1) to RGBA8 + u8 r = ((*color >> 11) & 0x1F); + r = (r << 3) | (r >> 2); // Convert 5-bit to 8-bit + u8 g = ((*color >> 6) & 0x1F); + g = (g << 3) | (g >> 2); // Convert 5-bit to 8-bit + u8 b = ((*color >> 1) & 0x1F); + b = (b << 3) | (b >> 2); // Convert 5-bit to 8-bit + u8 a = 255; // Fully opaque + + gDPSetPrimColor(gMasterDisp++, 0, 0, r, g, b, a); + + // Draw the star using the predefined display list + gSPDisplayList(gMasterDisp++, starDL); + + // Pop the transform id + // gEXPopMatrixGroup(gMasterDisp++, G_MTX_MODELVIEW); } } } + + // Restore original perspective after drawing stars + Lib_InitPerspective(&gMasterDisp); + + // Finalize rendering state gDPPipeSync(gMasterDisp++); gDPSetColorDither(gMasterDisp++, G_CD_MAGICSQ); } -void Background_DrawPartialStarfield(s32 yMin, s32 yMax) { +void Background_DrawPartialStarfield(s32 yMin, s32 yMax) { // Stars that are in the Epilogue f32 by; f32 bx; s16 vy; @@ -185,22 +299,30 @@ void Background_DrawPartialStarfield(s32 yMin, s32 yMax) { f32* sp60; f32* sp5C; u32* sp58; + + // Get current screen dimensions + float currentScreenWidth = gCurrentScreenWidth; + float currentScreenHeight = gCurrentScreenHeight; + float starfieldWidth = 1.0f * currentScreenWidth; + float starfieldHeight = 1.0f * currentScreenHeight; + + // Graphics pipeline setup gDPPipeSync(gMasterDisp++); gDPSetCycleType(gMasterDisp++, G_CYC_FILL); gDPSetCombineMode(gMasterDisp++, G_CC_SHADE, G_CC_SHADE); gDPSetRenderMode(gMasterDisp++, G_RM_OPA_SURF, G_RM_OPA_SURF2); - if (gStarfieldX >= 1.5f * SCREEN_WIDTH) { - gStarfieldX -= 1.5f * SCREEN_WIDTH; + if (gStarfieldX >= 1.5f * currentScreenWidth) { + gStarfieldX -= 1.5f * currentScreenWidth; } - if (gStarfieldY >= 1.5f * SCREEN_HEIGHT) { - gStarfieldY -= 1.5f * SCREEN_HEIGHT; + if (gStarfieldY >= 1.5f * currentScreenHeight) { + gStarfieldY -= 1.5f * currentScreenHeight; } if (gStarfieldX < 0.0f) { - gStarfieldX += 1.5f * SCREEN_WIDTH; + gStarfieldX += 1.5f * currentScreenWidth; } if (gStarfieldY < 0.0f) { - gStarfieldY += 1.5f * SCREEN_HEIGHT; + gStarfieldY += 1.5f * currentScreenHeight; } spf68 = gStarfieldX; @@ -216,21 +338,50 @@ void Background_DrawPartialStarfield(s32 yMin, s32 yMax) { for (i = 0; i < var_s2; i++, sp5C++, sp60++, sp58++) { bx = *sp60 + spf68; by = *sp5C + spf64; - if (bx >= SCREEN_WIDTH * 1.25f) { - bx -= 1.5f * SCREEN_WIDTH; + if (bx >= starfieldWidth * 1.25f) { + bx -= 1.5f * starfieldWidth; } - bx -= SCREEN_WIDTH / 2.0f; - if (by >= SCREEN_HEIGHT * 1.25f) { - by -= 1.5f * SCREEN_HEIGHT; + bx -= starfieldWidth / 2.0f; + if (by >= starfieldHeight * 1.25f) { + by -= 1.5f * starfieldHeight; } - by -= SCREEN_HEIGHT / 2.0f; + by -= starfieldHeight / 2.0f; - vx = (cos * bx) + (sin * by) + SCREEN_WIDTH / 2.0f; - vy = (-sin * bx) + (cos * by) + SCREEN_HEIGHT / 2.0f; - if ((vx >= 0) && (vx < SCREEN_WIDTH) && (yMin < vy) && (vy < yMax)) { - gDPPipeSync(gMasterDisp++); - gDPSetFillColor(gMasterDisp++, *sp58); - gDPFillRectangle(gMasterDisp++, vx, vy, vx, vy); + // Apply rotation + vx = (cos * bx) + (sin * by) + currentScreenWidth / 2.0f; + vy = (-sin * bx) + (cos * by) + currentScreenHeight / 2.0f; + + // Check if the star is within the visible screen area + if ((vx >= 0) && (vx < currentScreenWidth) && (yMin < vy) && (vy < yMax)) { + // Tag the transform. Assuming TAG_STARFIELD is a defined base tag value + // @recomp Tag the transform. + // gEXMatrixGroupDecomposed(gMasterDisp++, TAG_STARFIELD + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_COMPONENT_AUTO, + // G_EX_COMPONENT_AUTO, G_EX_COMPONENT_AUTO, G_EX_COMPONENT_INTERPOLATE, + // G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE, + // G_EX_ORDER_AUTO, G_EX_EDIT_ALLOW); + // Translate to (vx, vy) in ortho coordinates + Matrix_Push(&gGfxMatrix); + Matrix_Translate(gGfxMatrix, vx - (currentScreenWidth / 2.0f), -(vy - (currentScreenHeight / 2.0f)), 0.0f, + MTXF_NEW); + Matrix_SetGfxMtx(&gMasterDisp); + Matrix_Pop(&gGfxMatrix); + + // Convert color from fill color (assuming RGB5A1) to RGBA8 + u8 r = ((*sp58 >> 11) & 0x1F); + r = (r << 3) | (r >> 2); // Convert 5-bit to 8-bit + u8 g = ((*sp58 >> 6) & 0x1F); + g = (g << 3) | (g >> 2); // Convert 5-bit to 8-bit + u8 b = ((*sp58 >> 1) & 0x1F); + b = (b << 3) | (b >> 2); // Convert 5-bit to 8-bit + u8 a = 255; // Fully opaque + + gDPSetPrimColor(gMasterDisp++, 0, 0, r, g, b, a); + + // Draw the star using the predefined display list + gSPDisplayList(gMasterDisp++, starDLPartial); + + // Pop the transform id + // gEXPopMatrixGroup(gMasterDisp++, G_MTX_MODELVIEW); } } gDPPipeSync(gMasterDisp++); diff --git a/src/engine/fox_play.c b/src/engine/fox_play.c index c38ef870..3e423881 100644 --- a/src/engine/fox_play.c +++ b/src/engine/fox_play.c @@ -22,6 +22,9 @@ #include "assets/ast_area_6.h" #include "assets/ast_zoness.h" +extern float gCurrentScreenWidth; +extern float gCurrentScreenHeight; + UNK_TYPE D_800D2F50 = 0; // unused s32 sOverheadCam = 0; f32 sOverheadCamDist = 0.0f; @@ -559,7 +562,7 @@ void Play_InitEnvironment(void) { D_ctx_80178544 = 40; gFovY = 45.0f; } - +/* void Play_GenerateStarfield(void) { u32 i; @@ -574,34 +577,92 @@ void Play_GenerateStarfield(void) { gStarFillColors[i] = FILL_COLOR(gStarColors[i % ARRAY_COUNT(gStarColors)]); } } +*/ +void Play_GenerateStarfield(void) { + u32 i; + float currentScreenWidth = gCurrentScreenWidth; + float currentScreenHeight = gCurrentScreenHeight; + float starfieldWidth = 1.0f * currentScreenWidth; + float starfieldHeight = 1.0f * currentScreenHeight; + + MEM_ARRAY_ALLOCATE(gStarOffsetsX, 3000); + MEM_ARRAY_ALLOCATE(gStarOffsetsY, 3000); + MEM_ARRAY_ALLOCATE(gStarFillColors, 3000); + + Rand_SetSeed(1, 29000, 9876); + + for (i = 0; i < 3000; i++) { + gStarOffsetsX[i] = RAND_FLOAT_SEEDED(starfieldWidth); + gStarOffsetsY[i] = RAND_FLOAT_SEEDED(starfieldHeight); + gStarFillColors[i] = FILL_COLOR(gStarColors[i % ARRAY_COUNT(gStarColors)]); + } +} void Play_SetupStarfield(void) { + // Get current screen dimensions + float currentScreenWidth = gCurrentScreenWidth; + float currentScreenHeight = gCurrentScreenHeight; + float baseAspectRatio = 4.0f / 3.0f; // Original aspect ratio + float baseScreenWidth = gCurrentScreenHeight * baseAspectRatio; + float baseArea = baseScreenWidth * gCurrentScreenHeight; + float currentArea = currentScreenWidth * currentScreenHeight; + float areaRatio = currentArea / baseArea; + Play_GenerateStarfield(); gGroundHeight = -25000.0f; - gStarCount = 600; + + // Base star count adjusted for screen area + gStarCount = (s32) (600 * areaRatio); + if (gStarCount > 1000) { + gStarCount = 1000; // Cap the star count to 1000 + } + + // Adjust star count based on the current level if (gCurrentLevel == LEVEL_AREA_6) { - gStarCount = 300; + gStarCount = (s32) (300 * areaRatio); + if (gStarCount > 1000) { + gStarCount = 1000; + } } if (gCurrentLevel == LEVEL_UNK_15) { - gStarCount = 400; + gStarCount = (s32) (400 * areaRatio); + if (gStarCount > 1000) { + gStarCount = 1000; + } } if (gGameState != GSTATE_PLAY) { - gStarCount = 800; + gStarCount = (s32) (800 * areaRatio); + if (gStarCount > 1000) { + gStarCount = 1000; + } } if (gCurrentLevel == LEVEL_FORTUNA) { - gStarCount = 500; + gStarCount = (s32) (500 * areaRatio); + if (gStarCount > 1000) { + gStarCount = 1000; + } } if (gVersusMode) { - gStarCount = 0; + gStarCount = 0; // No stars in versus mode } if (gCurrentLevel == LEVEL_BOLSE) { - gStarCount = 300; + gStarCount = (s32) (300 * areaRatio); + if (gStarCount > 1000) { + gStarCount = 1000; + } gGroundHeight = -0.0f; } if (gCurrentLevel == LEVEL_TRAINING) { - gStarCount = 800; + gStarCount = (s32) (800 * areaRatio); + if (gStarCount > 1000) { + gStarCount = 1000; + } gGroundHeight = -0.0f; } + + // Initialize starfield position with dynamic screen dimensions + gStarfieldX = currentScreenWidth; + gStarfieldY = currentScreenHeight; } void Player_PlaySfx(f32* sfxSrc, u32 sfxId, s32 mode) { @@ -6370,27 +6431,39 @@ void Camera_SetStarfieldPos(f32 xEye, f32 yEye, f32 zEye, f32 xAt, f32 yAt, f32 f32 tempf; f32 sp20; + // Get current screen dimensions + float currentScreenWidth = gCurrentScreenWidth; + float currentScreenHeight = gCurrentScreenHeight; + float starfieldWidth = 1.0f * currentScreenWidth; + float starfieldHeight = 1.0f * currentScreenHeight; + yaw = -Math_Atan2F(xEye - xAt, zEye - zAt); tempf = sqrtf(SQ(zEye - zAt) + SQ(xEye - xAt)); pitch = -Math_Atan2F(yEye - yAt, tempf); + + // Adjust yaw to stay within the range [-π/2, π/2] if (yaw >= M_PI / 2) { yaw -= M_PI; } if (yaw <= -M_PI / 2) { yaw += M_PI; } + tempf = 0.0f; if (gCurrentLevel == LEVEL_UNK_15) { tempf = gPlayer[0].cam.eye.y * 0.03f; } + // Calculate new starfield positions sp30 = (-pitch * (-8.0f / 3.0f * M_RTOD) * 2.0f) + 3000.0f + gStarfieldScrollY + tempf; sp34 = (yaw * (-8.0f / 3.0f * M_RTOD) * 2.0f) + 3000.0f + gStarfieldScrollX; sp20 = gStarfieldX; - gStarfieldX = Math_ModF(sp34, SCREEN_WIDTH * 1.5f); - gStarfieldY = Math_ModF(sp30, SCREEN_HEIGHT * 1.5f); + // Wrap the starfield positions within the starfield dimensions + gStarfieldX = FloatMod(sp34, starfieldWidth); + gStarfieldY = FloatMod(sp30, starfieldHeight); + // Special case handling for specific game state and level if ((gGameState == GSTATE_PLAY) && (gPlayer[0].state_1C8 == PLAYERSTATE_1C8_LEVEL_INTRO) && (gCurrentLevel == LEVEL_METEO)) { if (fabsf(gStarfieldX - sp20) < 50.0f) { diff --git a/src/sys/sys_memory.c b/src/sys/sys_memory.c index 12954908..1525ee95 100644 --- a/src/sys/sys_memory.c +++ b/src/sys/sys_memory.c @@ -1,6 +1,8 @@ #include "sys.h" -s32 sMemoryBuffer[0x8800]; +// s32 sMemoryBuffer[0x8800]; +// @ port: Increase memory buffer size. +s32 sMemoryBuffer[1000000]; s32* sMemoryPtr; void Memory_FreeAll(void) {