From 3f57b7c7572ea799896aff4635510502f1eee499 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Fri, 13 Mar 2026 23:06:57 -0400 Subject: [PATCH 1/5] Fix GL splitscreen being broken Looks like I accidently removed forgot to update function args to prevent this issue. OOPS! Also rearragned some stuff back around to match the order it was before, seems fine asside from one other issue I found with GL shearing not matching software shearing. --- src/hardware/hw_main.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 71560d3a9..3dc3de91c 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1070,7 +1070,16 @@ void HWR_RenderPlayerView(void) ClearColor.blue = 0.0f; ClearColor.alpha = 1.0f; - GL_ClearBuffer(true, true, true, &ClearColor); + if (cv_glshaders.value) + GL_SetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime. + + if (viewssnum == 0) // Only do it if it's the first screen being rendered + GL_ClearBuffer(true, true, true, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs. + + ps_hw_skyboxtime = I_GetPreciseTime(); + if (skybox) // If there's a skybox and we should be drawing the sky, draw the skybox + HWR_RenderSkyboxView(player); // This is drawn before everything else so it is placed behind + ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime; if (!HWR_ShouldUsePaletteRendering()) { @@ -1087,26 +1096,15 @@ void HWR_RenderPlayerView(void) // set window position HWR_ShiftViewPort(); + // Reset the shader state. + HWR_SetShaderState(); + GL_GClipRect((INT32)gl_viewwindowx, (INT32)gl_viewwindowy, (INT32)(gl_viewwindowx + gl_viewwidth), (INT32)(gl_viewwindowy + gl_viewheight), ZCLIP_PLANE); - // Reset the shader state. - HWR_SetShaderState(); - - if (cv_glshaders.value) - GL_SetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime. - - if (viewssnum == 0) // Only do it if it's the first screen being rendered - GL_ClearBuffer(true, false, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs. - - ps_hw_skyboxtime = I_GetPreciseTime(); - if (skybox) // If there's a skybox and we should be drawing the sky, draw the skybox - HWR_RenderSkyboxView(player); // This is drawn before everything else so it is placed behind - ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime; - // note: sets viewangle, viewx, viewy, viewz R_SetupFrame(viewssnum, skybox); framecount++; // timedemo From 2b928de129fd52e2e9a4a5495858b8e14d6762b4 Mon Sep 17 00:00:00 2001 From: Alug Date: Sat, 14 Mar 2026 10:58:04 -0400 Subject: [PATCH 2/5] Convert FTRANSFORM flip booleans into flags and fix splitscreen and encore flipcam shearing Thanks to Hanicef as well for the calcs used in HWR_SetTransformAiming --- src/hardware/hw_defs.h | 12 +++++++--- src/hardware/hw_main.c | 26 ++++++++++---------- src/hardware/hw_md2.c | 3 +-- src/hardware/hw_sky.c | 30 ++++++++++++----------- src/hardware/r_opengl/r_opengl.c | 41 +++++++++++++++++++++----------- 5 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 381f13a57..cd02ad652 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -122,17 +122,23 @@ typedef struct FLOAT scalex,scaley,scalez; FLOAT fovxangle, fovyangle; UINT8 splitscreen; - boolean flip; // screenflip boolean shearing; // 14042019 float viewaiming; // 17052019 boolean roll; FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ FLOAT centerx, centery; FLOAT rollx, rollz; - boolean mirror; // SRB2Kart: Encore Mode - boolean mirrorflip; // Encore Mode with Flipcam + UINT8 fliptype; } FTransform; +enum +{ + TRANSFORM_NONE = 0, + TRANSFORM_FLIP = 1 << 0, // screenflip + TRANSFORM_MIRROR = 1 << 1, // SRB2Kart: Encore Mode + TRANSFORM_MIRRORFLIP = TRANSFORM_FLIP|TRANSFORM_MIRROR // SRB2Kart: Encore Mode with Flipcam +}; + // Transformed vector, as passed to HWR API typedef struct { diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3dc3de91c..933cf35eb 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -669,7 +669,9 @@ void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox, if (cv_glshearing.value == 1 || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox))) { fixed_t fixedaiming = AIMINGTODY(aimingangle); - trans->viewaiming = FIXED_TO_FLOAT(fixedaiming); + trans->viewaiming = FixedToFloat(fixedaiming) * ((float)vid.width / (float)vid.height) / ((float)BASEVIDWIDTH / (float)BASEVIDHEIGHT); + if (splitscreen == 1) // only for 2 player splitscreen + trans->viewaiming *= 2.125f; // splitscreen adjusts fov with 0.8, so compensate (but only halfway, since splitscreen means only half the screen is used) trans->shearing = true; temp_aimingangle = 0; } @@ -730,17 +732,17 @@ static void HWR_PrepareTransform(player_t *player, boolean is_skybox) gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT)); gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT)); - atransform.flip = false; - if ((thiscam->postimgflags & POSTIMG_FLIP) && !(thiscam->postimgflags & POSTIMG_MIRROR)) - atransform.flip = true; - - atransform.mirror = false; - if ((thiscam->postimgflags & POSTIMG_MIRROR) && !(thiscam->postimgflags & POSTIMG_FLIP)) - atransform.mirror = true; - - atransform.mirrorflip = false; - if ((thiscam->postimgflags & POSTIMG_FLIP) && (thiscam->postimgflags & POSTIMG_MIRROR)) - atransform.mirrorflip = true; + if (thiscam->postimgflags & POSTIMG_FLIP) + { + if (thiscam->postimgflags & POSTIMG_MIRROR) + atransform.fliptype = TRANSFORM_MIRRORFLIP; + else + atransform.fliptype = TRANSFORM_FLIP; + } + else if (thiscam->postimgflags & POSTIMG_MIRROR) + { + atransform.fliptype = TRANSFORM_MIRROR; + } atransform.x = gl_viewx; // FIXED_TO_FLOAT(viewx) atransform.y = gl_viewy; // FIXED_TO_FLOAT(viewy) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 0431b8875..b3ab2bdb1 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1717,8 +1717,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.anglez = FIXED_TO_FLOAT(AngleFixed(R_InterpolateAngle(spr->mobj->old_pitch, spr->mobj->pitch))); p.anglex = FIXED_TO_FLOAT(AngleFixed(R_InterpolateAngle(spr->mobj->old_roll, spr->mobj->roll))); - p.flip = atransform.flip; - p.mirror = atransform.mirror; + p.fliptype = atransform.fliptype; if (HWR_UseShader()) GL_SetShader(HWR_GetShaderFromTarget(SHADER_MODEL)); diff --git a/src/hardware/hw_sky.c b/src/hardware/hw_sky.c index fbd040a6e..47b8c9692 100644 --- a/src/hardware/hw_sky.c +++ b/src/hardware/hw_sky.c @@ -164,12 +164,13 @@ void HWR_BuildSkyDome(void) void HWR_DrawSkyBackground(player_t *player) { - UINT8 viewnum = R_GetViewNumber(); - camera_t *thiscam = &camera[viewnum]; GL_SetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated); if (cv_glskydome.value) { + UINT8 viewnum = R_GetViewNumber(); + camera_t *thiscam = &camera[viewnum]; + FTransform dometransform; const float fpov = FIXED_TO_FLOAT(cv_fov[viewssnum].value+player->fovadd); @@ -178,17 +179,17 @@ void HWR_DrawSkyBackground(player_t *player) HWR_SetTransformAiming(&dometransform, player, false, true); dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); - dometransform.flip = false; - if ((thiscam->postimgflags & POSTIMG_FLIP) && !(thiscam->postimgflags & POSTIMG_MIRROR)) - dometransform.flip = true; - - dometransform.mirror = false; - if ((thiscam->postimgflags & POSTIMG_MIRROR) && !(thiscam->postimgflags & POSTIMG_FLIP)) - dometransform.mirror = true; - - dometransform.mirrorflip = false; - if ((thiscam->postimgflags & POSTIMG_FLIP) && (thiscam->postimgflags & POSTIMG_MIRROR)) - dometransform.mirrorflip = true; + if (thiscam->postimgflags & POSTIMG_FLIP) + { + if (thiscam->postimgflags & POSTIMG_MIRROR) + dometransform.fliptype = TRANSFORM_MIRRORFLIP; + else + dometransform.fliptype = TRANSFORM_FLIP; + } + else if (thiscam->postimgflags & POSTIMG_MIRROR) + { + dometransform.fliptype = TRANSFORM_MIRROR; + } dometransform.scalex = 1; dometransform.scaley = (float)vid.width/vid.height; @@ -265,7 +266,8 @@ void HWR_DrawSkyBackground(player_t *player) // Middle of the sky should always be at angle 0 // need to keep correct aspect ratio with X - if (atransform.flip) + if (atransform.fliptype == TRANSFORM_FLIP || + atransform.fliptype == TRANSFORM_MIRRORFLIP) { // During vertical flip the sky should be flipped and it's y movement should also be flipped obviously v[3].t = v[2].t = -(0.5f-(0.5f/dimensionmultiply)); // top diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 1b1ae2b1a..4d74bfec6 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2740,7 +2740,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float // pos->mirror is if the screen is flipped horizontally // XOR all the flips together to figure out what culling to use! { - boolean reversecull = (flipped ^ hflipped ^ pos->flip ^ pos->mirror); + boolean reversecull = (flipped ^ hflipped ^ !!(pos->fliptype & TRANSFORM_FLIP) ^ !!(pos->fliptype & TRANSFORM_MIRROR)); if (reversecull) pglCullFace(GL_FRONT); else @@ -2935,14 +2935,21 @@ void GL_SetTransform(FTransform *stransform) if (stransform) { used_fov = stransform->fovxangle; - if (stransform->mirror) - pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez); - else if (stransform->mirrorflip) - pglScalef(-stransform->scalex, -stransform->scaley, -stransform->scalez); - else if (stransform->flip) - pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez); - else - pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez); + switch (stransform->fliptype) + { + case TRANSFORM_MIRROR: + pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez); + break; + case TRANSFORM_MIRRORFLIP: + pglScalef(-stransform->scalex, -stransform->scaley, -stransform->scalez); + break; + case TRANSFORM_FLIP: + pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez); + break; + default: // TRANSFORM_NONE + pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez); + break; + } if (stransform->roll) pglRotatef(stransform->rollangle, 0.0f, 0.0f, 1.0f); @@ -2962,23 +2969,29 @@ void GL_SetTransform(FTransform *stransform) pglMatrixMode(GL_PROJECTION); pglLoadIdentity(); + // jimita 14042019 // Simulate Software's y-shearing // https://zdoom.org/wiki/Y-shearing if (shearing) { - float fdy = stransform->viewaiming * 2 * ((float)vid.width / vid.height) / ((float)BASEVIDWIDTH / BASEVIDHEIGHT); //screen_width/BASEVIDWIDTH; - if (stransform->flip) - fdy *= -1.0f; - pglTranslatef(0.0f, -fdy/BASEVIDHEIGHT, 0.0f); + float dy = stransform->viewaiming * 2; + + if (stransform->fliptype == TRANSFORM_FLIP || + stransform->fliptype == TRANSFORM_MIRRORFLIP) + dy *= -1.0f; + + pglTranslatef(0.0f, -dy/BASEVIDHEIGHT, 0.0f); } if (special_splitscreen) { - used_fov = atan(tan(used_fov*M_PI/360)*0.8)*360/M_PI; + used_fov = (atanf(tanf(used_fov * (float)M_PI / 360.0f) * 0.8f) * 360.0f / (float)M_PI); GLPerspective(used_fov, 2*ASPECT_RATIO); } else + { GLPerspective(used_fov, ASPECT_RATIO); + } pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix); // added for new coronas' code (without depth buffer) pglMatrixMode(GL_MODELVIEW); From 8bbdf11b27f685e0c073e2a6931b06b41881b99e Mon Sep 17 00:00:00 2001 From: Alug Date: Sat, 14 Mar 2026 12:59:53 -0400 Subject: [PATCH 3/5] Fix portals and skyboxes in splitscreen in OpenGL --- src/hardware/hw_main.c | 32 ++++++++++++++++++++++---------- src/hardware/r_opengl/r_opengl.c | 16 +++++++++------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 933cf35eb..19f6382bf 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -989,7 +989,6 @@ static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolea if (timing) { - ps_hw_spritesorttime = I_GetPreciseTime(); } @@ -1059,6 +1058,23 @@ void HWR_RollTransform(FTransform *tr, angle_t roll) } } +// -----------------+ +// HWR_ClearView : clear the viewwindow, with maximum z value. also clears stencil buffer. +// -----------------+ +static inline void HWR_ClearView(void) +{ + // set window position + HWR_ShiftViewPort(); + + GL_GClipRect((INT32)gl_viewwindowx, + (INT32)gl_viewwindowy, + (INT32)(gl_viewwindowx + gl_viewwidth), + (INT32)(gl_viewwindowy + gl_viewheight), + ZCLIP_PLANE); + + GL_ClearBuffer(false, true, true, NULL); +} + void HWR_RenderPlayerView(void) { player_t * player = &players[displayplayers[viewssnum]]; @@ -1080,7 +1096,10 @@ void HWR_RenderPlayerView(void) ps_hw_skyboxtime = I_GetPreciseTime(); if (skybox) // If there's a skybox and we should be drawing the sky, draw the skybox + { + HWR_ClearView(); HWR_RenderSkyboxView(player); // This is drawn before everything else so it is placed behind + } ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime; if (!HWR_ShouldUsePaletteRendering()) @@ -1095,18 +1114,9 @@ void HWR_RenderPlayerView(void) #endif } - // set window position - HWR_ShiftViewPort(); - // Reset the shader state. HWR_SetShaderState(); - GL_GClipRect((INT32)gl_viewwindowx, - (INT32)gl_viewwindowy, - (INT32)(gl_viewwindowx + gl_viewwidth), - (INT32)(gl_viewwindowy + gl_viewheight), - ZCLIP_PLANE); - // note: sets viewangle, viewx, viewy, viewz R_SetupFrame(viewssnum, skybox); framecount++; // timedemo @@ -1114,6 +1124,8 @@ void HWR_RenderPlayerView(void) // Check for new console commands. NetUpdate(); + HWR_ClearView(); + HWR_RenderViewpoint(player, !skybox, // Don't draw the regular sky if there's a skybox false, diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 4d74bfec6..6da624800 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -923,7 +923,7 @@ static void SetNoTexture(GLenum texture) } } -static void GLPerspective(GLfloat fovy, GLfloat aspect) +static void GL_Perspective(GLfloat fovy, GLfloat aspect) { GLfloat m[4][4] = { @@ -1033,7 +1033,7 @@ void SetModelView(GLint w, GLint h) pglMatrixMode(GL_MODELVIEW); pglLoadIdentity(); - GLPerspective(fov, ASPECT_RATIO); + GL_Perspective(fov, ASPECT_RATIO); //pglScalef(1.0f, 320.0f/200.0f, 1.0f); // gl_scalefrustum (ORIGINAL_ASPECT) // added for new coronas' code (without depth buffer) @@ -1339,7 +1339,7 @@ void GL_GClipRect(INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip //pglScissor(minx, screen_height-maxy, maxx-minx, maxy-miny); pglMatrixMode(GL_PROJECTION); pglLoadIdentity(); - GLPerspective(fov, ASPECT_RATIO); + GL_Perspective(fov, ASPECT_RATIO); pglMatrixMode(GL_MODELVIEW); // added for new coronas' code (without depth buffer) @@ -1368,6 +1368,7 @@ void GL_ClearBuffer(FBOOLEAN ColorMask, ClearColor->alpha); ClearMask |= GL_COLOR_BUFFER_BIT; } + if (DepthMask) { pglClearDepth(1.0f); //Hurdler: all that are permanen states @@ -1375,6 +1376,7 @@ void GL_ClearBuffer(FBOOLEAN ColorMask, pglDepthFunc(GL_LEQUAL); ClearMask |= GL_DEPTH_BUFFER_BIT; } + if (StencilMask) ClearMask |= GL_STENCIL_BUFFER_BIT; @@ -2926,7 +2928,7 @@ void GL_DrawModel(model_t *model, INT32 frameIndex, float duration, float tics, // -----------------+ void GL_SetTransform(FTransform *stransform) { - static boolean special_splitscreen; + boolean special_splitscreen = false; boolean shearing = false; float used_fov; @@ -2986,11 +2988,11 @@ void GL_SetTransform(FTransform *stransform) if (special_splitscreen) { used_fov = (atanf(tanf(used_fov * (float)M_PI / 360.0f) * 0.8f) * 360.0f / (float)M_PI); - GLPerspective(used_fov, 2*ASPECT_RATIO); + GL_Perspective(used_fov, 2*ASPECT_RATIO); } else { - GLPerspective(used_fov, ASPECT_RATIO); + GL_Perspective(used_fov, ASPECT_RATIO); } pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix); // added for new coronas' code (without depth buffer) @@ -3000,7 +3002,7 @@ void GL_SetTransform(FTransform *stransform) } -INT32 GL_GetTextureUsed(void) +INT32 GL_GetTextureUsed(void) { FTextureInfo *tmp = TexCacheHead; INT32 res = 0; From a9f544bf019a53ff75c4b833f6a86e4c8f1b8f67 Mon Sep 17 00:00:00 2001 From: Alug Date: Sat, 14 Mar 2026 13:15:06 -0400 Subject: [PATCH 4/5] Kill some remaining unused dead code --- src/d_main.cpp | 13 ++++--- src/hardware/hw_main.c | 79 +++--------------------------------------- src/hardware/hw_main.h | 4 --- 3 files changed, 12 insertions(+), 84 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 3f6fedf33..a6c0391fc 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -346,11 +346,6 @@ boolean D_RenderLevel(void) { viewssnum = i; -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_RenderPlayerView(); - else -#endif if (rendermode != render_none) { if (i > 0) // Splitscreen-specific @@ -380,7 +375,15 @@ boolean D_RenderLevel(void) break; } } + } +#ifdef HWRENDER + if (rendermode == render_opengl) + HWR_RenderPlayerView(); + else +#endif + if (rendermode != render_none) + { R_RenderPlayerView(); } } diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 19f6382bf..fbb44a145 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -61,22 +61,6 @@ // GLOBALS // ========================================================================== -// base values set at SetViewSize -static float gl_basecentery; -static float gl_basecenterx; - -float gl_baseviewwindowy, gl_basewindowcentery; -float gl_baseviewwindowx, gl_basewindowcenterx; -float gl_viewwidth, gl_viewheight; // viewport clipping boundaries (screen coords) -float gl_viewwindowx; - -static float gl_centerx, gl_centery; -static float gl_viewwindowy; // top left corner of view window -static float gl_windowcenterx; // center of view window, for projection -static float gl_windowcentery; - -static float gl_pspritexscale, gl_pspriteyscale; - seg_t *gl_curline; side_t *gl_sidedef; line_t *gl_linedef; @@ -604,61 +588,9 @@ boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf) // -----------------+ void HWR_SetViewSize(void) { - // setup view size - gl_viewwidth = (float)vid.width; - gl_viewheight = (float)vid.height; - - if (r_splitscreen > 0) - { - gl_viewheight /= 2; - - if (r_splitscreen > 1) - { - gl_viewwidth /= 2; - } - } - - gl_basecenterx = gl_viewwidth / 2; - gl_basecentery = gl_viewheight / 2; - - gl_baseviewwindowx = 0; - gl_basewindowcenterx = gl_viewwidth / 2; - - gl_baseviewwindowy = 0; - gl_basewindowcentery = gl_viewheight / 2; - - gl_pspritexscale = gl_viewwidth / BASEVIDWIDTH; - gl_pspriteyscale = ((vid.height*gl_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width; - GL_FlushScreenTextures(); } -// -------------------+ -// HWR_ShiftViewPort : offset viewport according to current split -// -------------------+ -static void HWR_ShiftViewPort(void) -{ - gl_centerx = gl_basecenterx; - gl_viewwindowx = gl_baseviewwindowx; - gl_windowcenterx = gl_basewindowcenterx; - - gl_centery = gl_basecentery; - gl_viewwindowy = gl_baseviewwindowy; - gl_windowcentery = gl_basewindowcentery; - - if (viewssnum > ( r_splitscreen > 1 )) - { - gl_viewwindowy += gl_viewheight; - gl_windowcentery += gl_viewheight; - } - - if (r_splitscreen > 1 && viewssnum & 1) - { - gl_viewwindowx += gl_viewwidth; - gl_windowcenterx += gl_viewwidth; - } -} - // Set view aiming, for the sky dome, the skybox, // and the normal view, all with a single function. void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox, boolean side_effect) @@ -1063,13 +995,10 @@ void HWR_RollTransform(FTransform *tr, angle_t roll) // -----------------+ static inline void HWR_ClearView(void) { - // set window position - HWR_ShiftViewPort(); - - GL_GClipRect((INT32)gl_viewwindowx, - (INT32)gl_viewwindowy, - (INT32)(gl_viewwindowx + gl_viewwidth), - (INT32)(gl_viewwindowy + gl_viewheight), + GL_GClipRect(viewwindowx, + viewwindowy, + (viewwindowx + viewwidth), + (viewwindowy + viewheight), ZCLIP_PLANE); GL_ClearBuffer(false, true, true, NULL); diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 879f3c40b..cce9daf45 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -124,10 +124,6 @@ extern consvar_t cv_gldebugportal; extern consvar_t cv_glskydebug; -extern float gl_viewwidth, gl_viewheight, gl_baseviewwindowy; - -extern float gl_viewwindowx, gl_basewindowcentery; - extern seg_t *gl_curline; extern side_t *gl_sidedef; extern line_t *gl_linedef; From 40988ef4b5d90aab6f0cbfa65920cba1568a6e82 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sat, 14 Mar 2026 21:03:13 +0100 Subject: [PATCH 5/5] Some recovery spin tweaks * Charging during flashtics now has unique effects * Fixed full charge sound not playing in flashtics * kickstartaccel is now accounted for * Dedent (hint: git show -b) --- src/k_items.c | 2 +- src/k_kart.c | 255 +++++++++++++++++++++++++++----------------------- src/k_kart.h | 2 +- 3 files changed, 138 insertions(+), 121 deletions(-) diff --git a/src/k_items.c b/src/k_items.c index b67993b7d..4d179b28f 100644 --- a/src/k_items.c +++ b/src/k_items.c @@ -1127,7 +1127,7 @@ UINT32 K_GetCongaLineDistance(const player_t *player, UINT8 startPos) memset(sortedPlayers, -1, sizeof(sortedPlayers)); - if (player->mo != NULL && P_MobjWasRemoved(player->mo) == false) + if (player->mo != NULL && P_MobjWasRemoved(player->mo) == false && player->position > 0) { // Sort all of the players ahead of you. // Then tally up their distances in a conga line. diff --git a/src/k_kart.c b/src/k_kart.c index 55bb53246..0add2b200 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1803,7 +1803,7 @@ static void K_RespawnChecker(player_t *player) */ void K_KartMoveAnimation(player_t *player) { - const fixed_t fastspeed = (K_GetKartSpeed(player, false, true) * 17) / 20; // 85% + const fixed_t fastspeed = (K_GetKartSpeed(player, player->forcedtopspeed > 0, true) * 17) / 20; // 85% const fixed_t speedthreshold = player->mo->scale / 8; const boolean onground = P_IsObjectOnGround(player->mo); @@ -4428,7 +4428,7 @@ static void K_SpawnDraftDust(mobj_t *mo) } } -void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) +mobj_t *K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) { mobj_t *dust; angle_t aoff; @@ -4469,6 +4469,8 @@ void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) if (translucent) dust->renderflags |= RF_GHOSTLY; + + return dust; } // K_DriftDustHandling @@ -6793,6 +6795,9 @@ static void K_TireGreaseEffect(player_t *player) if (leveltime % 6 == 0) S_StartSound(player->mo, sfx_screec); + + if (!S_SoundPlaying(player->mo, sfx_ruburn)) + S_StartSound(player->mo, sfx_ruburn); } boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound) @@ -9828,9 +9833,19 @@ static void K_KartSlipdash(player_t *player, boolean onground) } } +static boolean K_CanPanicRecoverySpin(const player_t *player) +{ + return player->flashing > 0 && ( +#if 0 // skip the last flashtics? maybe not... + player->spinouttimer > 0 ? player->spinouttimer <= TICRATE/4 : +#endif + !K_IsPlayerDamaged(player) + ); +} + static boolean K_PlayerWantsRecoverySpin(player_t *player) { - return ((player->cmd.buttons & BT_ACCELERATE) && (player->cmd.buttons & BT_BRAKE) && (!(player->cmd.buttons & BT_DRIFT))); + return (K_GetKartButtons(player) & (BT_ACCELERATE|BT_BRAKE|BT_DRIFT)) == (BT_ACCELERATE|BT_BRAKE); } static boolean K_PlayerCanStartRecoverySpin(player_t *player) @@ -9842,159 +9857,161 @@ static boolean K_PlayerCanStartRecoverySpin(player_t *player) static boolean K_PlayerCanRecoverySpin(player_t *player) { return (K_RecoveryDashActive() && leveltime > starttime && (player->carry == CR_NONE) && - !(player->sneakertimer || K_IsPlayerDamaged(player) || player->squishedtimer || - player->exiting || (player->pflags & PF_STASIS) || player->dashpadcooldown || + !(player->sneakertimer || (K_IsPlayerDamaged(player) && !K_CanPanicRecoverySpin(player)) || + player->squishedtimer || player->exiting || (player->pflags & PF_STASIS) || player->dashpadcooldown || player->walltransferboost || player->loop.radius )); } static void K_RecoveryDash(player_t *player) { - if (K_PlayerWantsRecoverySpin(player) && (player->spinouttimer > 0 || player->flipovertimer > 0) && (!player->wipeoutslow)) + if (K_PlayerWantsRecoverySpin(player) && K_IsPlayerDamaged(player) && player->wipeoutslow == 0) { player->wipeoutslow = max(wipeoutslowtime + 1, player->spinouttimer + 4); } - if ((player->pflags & PF_RECOVERYSPIN) && player->forcedtopspeed == 0 && player->speed >= 10*player->mo->scale) + if (!K_PlayerCanRecoverySpin(player) + || ((player->pflags & PF_RECOVERYSPIN) && player->forcedtopspeed == 0 && player->speed >= 10*player->mo->scale)) { player->pflags &= ~PF_RECOVERYSPIN; player->forcedtopspeed = 0; player->recoverydashcharge = 0; + return; } - if (K_PlayerCanRecoverySpin(player)) + if (K_PlayerWantsRecoverySpin(player) && K_PlayerCanStartRecoverySpin(player)) { - if (K_PlayerWantsRecoverySpin(player) && K_PlayerCanStartRecoverySpin(player)) + player->pflags |= PF_RECOVERYSPIN; + player->forcedtopspeed = cv_kartrecoverydash_spinspeed.value + 8; + S_StartSound(player->mo, sfx_cdfm20); + + player->mo->momx = min(10*player->mo->scale, abs(player->mo->momx/2)) * intsign(player->mo->momx); + player->mo->momy = min(10*player->mo->scale, abs(player->mo->momy/2)) * intsign(player->mo->momy); + + player->driftboost = 0; + player->sneakertimer = 0; + player->ringboost = 0; + player->startboost = 0; + } + + if (player->pflags & PF_RECOVERYSPIN) + { + if ((K_GetKartButtons(player) & (BT_ACCELERATE|BT_BRAKE)) != (BT_ACCELERATE|BT_BRAKE)) { - player->pflags |= PF_RECOVERYSPIN; - player->forcedtopspeed = cv_kartrecoverydash_spinspeed.value + 8; - S_StartSound(player->mo, sfx_cdfm20); - - player->mo->momx = min(10*player->mo->scale, abs(player->mo->momx/2)) * intsign(player->mo->momx); - player->mo->momy = min(10*player->mo->scale, abs(player->mo->momy/2)) * intsign(player->mo->momy); - - player->driftboost = 0; - player->sneakertimer = 0; - player->ringboost = 0; - player->startboost = 0; + player->pflags &= ~PF_RECOVERYSPIN; + if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME && (K_GetKartButtons(player) & BT_ACCELERATE)) + { + K_SetTireGrease(player, 2*TICRATE); + player->outrun = TICRATE/4; + player->recoverydash = TICRATE; + player->flashing = 0; + S_StartSound(player->mo, sfx_s23c); + K_SpawnDashDustRelease(player, true); + } + player->recoverydashcharge = 0; + player->forcedtopspeed = 0; + return; } - if (player->pflags & PF_RECOVERYSPIN) + player->forcedtopspeed = cv_kartrecoverydash_spinspeed.value + 8; + if (P_IsObjectOnGround(player->mo)) { - if (!((player->cmd.buttons & BT_ACCELERATE) && (player->cmd.buttons & BT_BRAKE))) + tic_t oldcharge = player->recoverydashcharge; + player->recoverydashcharge += K_CanPanicRecoverySpin(player) ? (leveltime & 1) + 1 : 1; + if (oldcharge < RECOVERYDASHCHARGETIME && player->recoverydashcharge >= RECOVERYDASHCHARGETIME) + S_StartSound(player->mo, sfx_s3ka2); + + mobj_t *dust = K_SpawnWipeoutTrail(player->mo, !K_CanPanicRecoverySpin(player) + && player->recoverydashcharge < RECOVERYDASHWIPETIME); + + if (K_CanPanicRecoverySpin(player)) { - player->pflags &= ~PF_RECOVERYSPIN; - if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME && (player->cmd.buttons & BT_ACCELERATE)) - { - K_SetTireGrease(player, 2*TICRATE); - player->outrun = TICRATE/4; - player->recoverydash = TICRATE; - player->flashing = 0; - S_StartSound(player->mo, sfx_s23c); - K_SpawnDashDustRelease(player, true); - } - player->recoverydashcharge = 0; - player->forcedtopspeed = 0; - return; + dust->colorized = true; + dust->color = SKINCOLOR_KETCHUP; + if (!S_SoundPlaying(player->mo, sfx_s248)) + S_StartSound(player->mo, sfx_s248); } - player->forcedtopspeed = cv_kartrecoverydash_spinspeed.value + 8; - if (P_IsObjectOnGround(player->mo)) + if (player->recoverydashcharge < RECOVERYDASHCHARGETIME) { - player->recoverydashcharge += player->flashing ? ((leveltime & 1) + 1) : 1; - - K_SpawnWipeoutTrail(player->mo, (player->recoverydashcharge < RECOVERYDASHWIPETIME)); - if (leveltime % 6 == 0) { - if (player->recoverydashcharge < RECOVERYDASHCHARGETIME) - { - S_StartSound(player->mo, sfx_s225); - } - } - if (leveltime % 4 == 0) - { - fixed_t newx; - fixed_t newy; - mobj_t *skid; - angle_t travelangle; - travelangle = player->mo->angle; - for (INT32 i = 0; i < 2; i++) - { - newx = P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale)); - newy = P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale)); - skid = P_SpawnMobjFromMobj(player->mo, newx, newy, (10*player->mo->scale), MT_OVERLAY); - P_SetTarget(&skid->target, player->mo); - skid->sprxoff = newx; - skid->spryoff = newy; - skid->sprzoff = (10*player->mo->scale); - - P_SetScale(skid, player->mo->scale); - skid->destscale = player->mo->destscale; - skid->scalespeed = player->mo->scalespeed; - skid->movefactor = FRACUNIT; - skid->angle = travelangle; - - - P_SetMobjState(skid, S_RECSPIN_SKID); - K_MatchGenericExtraFlags(skid, player->mo); - if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME) - { - skid->renderflags |= RF_TRANS20; - } - else - { - skid->renderflags |= RF_TRANS40; - } - if (i) skid->renderflags |= RF_HORIZONTALFLIP; - } + S_StartSound(player->mo, sfx_s225); } } - if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME) + if (leveltime % 4 == 0) { - if (player->recoverydashcharge == RECOVERYDASHCHARGETIME && P_IsObjectOnGround(player->mo)) - S_StartSound(player->mo, sfx_s3ka2); - - if (leveltime & 1) + fixed_t newx; + fixed_t newy; + mobj_t *skid; + angle_t travelangle; + travelangle = player->mo->angle; + for (INT32 i = 0; i < 2; i++) { - fixed_t newx; - fixed_t newy; - mobj_t *spark; - angle_t travelangle, sparkangle; - travelangle = player->mo->angle; - sparkangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - for (INT32 i = 0; i < 2; i++) + newx = P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale)); + newy = P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale)); + skid = P_SpawnMobjFromMobj(player->mo, newx, newy, (10*player->mo->scale), MT_OVERLAY); + P_SetTarget(&skid->target, player->mo); + skid->sprxoff = newx; + skid->spryoff = newy; + skid->sprzoff = (10*player->mo->scale); + + P_SetScale(skid, player->mo->scale); + skid->destscale = player->mo->destscale; + skid->scalespeed = player->mo->scalespeed; + skid->movefactor = FRACUNIT; + skid->angle = travelangle; + + P_SetMobjState(skid, S_RECSPIN_SKID); + K_MatchGenericExtraFlags(skid, player->mo); + if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME) { - newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale)); - newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale)); - spark = P_SpawnMobj(newx, newy, player->mo->z, MT_DRIFTSPARK); - spark->momx = player->mo->momx/2; - spark->momy = player->mo->momy/2; - - P_SetTarget(&spark->target, player->mo); - spark->angle = sparkangle; - spark->color = SKINCOLOR_WHITE; - - if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME + TICRATE/4) - { - P_SetMobjState(spark, S_DRIFTSPARK_B1); - } - else - { - P_SetMobjState(spark, S_DRIFTSPARK_A1); - } - K_MatchGenericExtraFlags(spark, player->mo); + skid->renderflags |= RF_TRANS20; } + else + { + skid->renderflags |= RF_TRANS40; + } + if (i) skid->renderflags |= RF_HORIZONTALFLIP; + } + } + } + + if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME) + { + if (leveltime & 1) + { + fixed_t newx; + fixed_t newy; + mobj_t *spark; + angle_t travelangle, sparkangle; + travelangle = player->mo->angle; + sparkangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + for (INT32 i = 0; i < 2; i++) + { + newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale)); + newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale)); + spark = P_SpawnMobj(newx, newy, player->mo->z, MT_DRIFTSPARK); + spark->momx = player->mo->momx/2; + spark->momy = player->mo->momy/2; + + P_SetTarget(&spark->target, player->mo); + spark->angle = sparkangle; + spark->color = SKINCOLOR_WHITE; + + if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME + TICRATE/4) + { + P_SetMobjState(spark, S_DRIFTSPARK_B1); + } + else + { + P_SetMobjState(spark, S_DRIFTSPARK_A1); + } + K_MatchGenericExtraFlags(spark, player->mo); } } } - } - else - { - player->pflags &= ~PF_RECOVERYSPIN; - player->forcedtopspeed = 0; - player->recoverydashcharge = 0; } } diff --git a/src/k_kart.h b/src/k_kart.h index 4cd6d4305..07426d099 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -253,7 +253,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color); UINT16 K_DriftSparkColor(player_t *player, INT32 charge); void K_SpawnBoostTrail(player_t *player); void K_SpawnSparkleTrail(mobj_t *mo); -void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); +mobj_t *K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); void K_DriftDustHandling(mobj_t *spawner); mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow); void K_PuntMine(mobj_t *mine, mobj_t *punter);