Compare commits

..
2 Commits
Author SHA1 Message Date
alufolie91 59a4627911 gl: use shaders for vhs effect
this is a fuckton faster lol
the old one did a gazillion draw calls now we do two, one for the fuzzy and the 2nd for the bars as both are handled within a single shader
thanks to RRs heat effect being super similar to the vhs bars lul
2026-11-12 21:02:07 +01:00
alufolie91 ecab383078 gl: use shaders for underwater / heatwave effect
basically ported over from RR
water was massively toned down and adjusted, it visually almost matches software at default res (note that the software effects are not properly scaled lol)
the heat effect is just the water effect adjusted to look like the fixed function version from before but slightly slower to accomidate the slower water effect here

this should speed things up a little since we now only need ONE draw call instead of 20 per effect
small note: this does not zoom into the image like the shaderless version, which was quite jarring tbh but there can be some very slight "stretch" marks at screen border, but theyre extremely unnoticable
2026-11-12 20:32:38 +01:00
16 changed files with 1859 additions and 1780 deletions

No files matched your search

+2
View File
@@ -292,6 +292,7 @@ if(${SRB2_CONFIG_HAVE_BLUA})
lua_script.c
lua_skinlib.c
lua_thinkerlib.c
lua_udatalib.c
lua_glib.c
)
set(SRB2_LUA_HEADERS
@@ -301,6 +302,7 @@ if(${SRB2_CONFIG_HAVE_BLUA})
lua_profile.h
lua_libs.h
lua_script.h
lua_udatalib.h
lua_glib.h
)
+1
View File
@@ -97,5 +97,6 @@ lua_playerlib.c
lua_script.c
lua_skinlib.c
lua_thinkerlib.c
lua_udatalib.c
lua_glib.c
lua_profile.cpp
+6
View File
@@ -196,6 +196,12 @@ enum
SHADER_PALETTE_POSTPROCESS,
SHADER_UI_COLORMAP_FADE,
SHADER_POSTPROCESS_WATER,
SHADER_POSTPROCESS_HEAT,
SHADER_VHS_FUZZ,
SHADER_VHS_BAR,
NUMSHADERTARGETS
};
+2 -1
View File
@@ -66,10 +66,11 @@ void GL_FlushScreenTextures(void);
void GL_DrawScreenTexture(int tex, FSurfaceInfo *surf, FBITFIELD polyflags);
void GL_DoScreenWipe(int wipeStart, int wipeEnd);
void GL_RenderVhsEffect(fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize);
void GL_RenderVhsEffect(fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize, boolean rewind);
void GL_DrawScreenFinalTexture(int tex, INT32 width, INT32 height);
void GL_PostImgRedraw(float points[SCREENVERTS][SCREENVERTS][2]);
void GL_DoPostProcessor(INT32 type);
boolean GL_InitShaders(void);
void GL_LoadShader(int slot, char *code, hwdshaderstage_t stage);
+44 -29
View File
@@ -5992,8 +5992,7 @@ void HWR_RenderPlayerView(void)
if (HWR_UseShader())
{
if (cv_ripplewater.value)
GL_SetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime.
GL_SetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime.
if (cv_glmdls.value)
{
@@ -6002,7 +6001,7 @@ void HWR_RenderPlayerView(void)
const angle_t light_angle = maplighting.angle - viewangle + ANGLE_90; // I fucking hate OGL's coordinate system
GL_SetShaderInfo(HWD_SHADERINFO_LIGHT_X, FINECOSINE(light_angle >> ANGLETOFINESHIFT));
GL_SetShaderInfo(HWD_SHADERINFO_LIGHT_Y, 0);
GL_SetShaderInfo(HWD_SHADERINFO_LIGHT_Z, -FINESINE(light_angle >> ANGLETOFINESHIFT));
GL_SetShaderInfo(HWD_SHADERINFO_LIGHT_Z, -FINESINE(light_angle >> ANGLETOFINESHIFT));
}
GL_SetShaderInfo(HWD_SHADERINFO_LIGHT_CONTRAST, maplighting.contrast);
@@ -6352,42 +6351,58 @@ static void HWR_DoPostProcessor(void)
GL_MakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1);
// Drunken vision! WooOOooo~
// 10 by 10 grid. 2 coordinates (xy)
float v[SCREENVERTS][SCREENVERTS][2];
float disStart = (leveltime-1) + FixedToFloat(R_GetTimeFrac(RTF_LEVEL));
UINT8 x, y;
float WAVELENGTH;
float AMPLITUDE;
float FREQUENCY;
// Modifies the wave.
if (thiscam->postimg & POSTIMG_WATER)
// shader based, should be a bit faster!
if (HWR_UseShader())
{
WAVELENGTH = 5.0f;
AMPLITUDE = 40.0f;
FREQUENCY = 8.0f;
if (thiscam->postimg & POSTIMG_WATER)
{
GL_DoPostProcessor(POSTIMG_WATER);
}
else if (thiscam->postimg & POSTIMG_HEAT)
{
GL_DoPostProcessor(POSTIMG_HEAT);
}
}
else
{
WAVELENGTH = 10.0f;
AMPLITUDE = 60.0f;
FREQUENCY = 4.0f;
}
// 10 by 10 grid. 2 coordinates (xy)
float v[SCREENVERTS][SCREENVERTS][2];
float disStart = (leveltime-1) + FixedToFloat(R_GetTimeFrac(RTF_LEVEL));
//static constexpr float scale = ((float)SCREENVERTS - 1.0f) / 9.0f; // well this evals to just 1.0f and what is x / 1? kek
UINT8 x, y;
float WAVELENGTH;
float AMPLITUDE;
float FREQUENCY;
for (x = 0; x < SCREENVERTS; x++)
{
for (y = 0; y < SCREENVERTS; y++)
// Modifies the wave.
if (thiscam->postimg & POSTIMG_WATER)
{
// Change X position based on its Y position.
v[x][y][0] = x-4.5f + sinf(((disStart+(static_cast<float>(y) * WAVELENGTH)) / FREQUENCY)) / AMPLITUDE; // (x / scale)
v[x][y][1] = y-4.5f; // (y / scale)
WAVELENGTH = 5.0f;
AMPLITUDE = 40.0f;
FREQUENCY = 8.0f;
}
else
{
WAVELENGTH = 10.0f;
AMPLITUDE = 60.0f;
FREQUENCY = 4.0f;
}
}
GL_PostImgRedraw(v);
//static constexpr float scale = ((float)SCREENVERTS - 1.0f) / 9.0f; // well this evals to just 1.0f and what is x / 1? kek
for (x = 0; x < SCREENVERTS; x++)
{
for (y = 0; y < SCREENVERTS; y++)
{
// Change X position based on its Y position.
v[x][y][0] = x-4.5f + sinf(((disStart+(static_cast<float>(y) * WAVELENGTH)) / FREQUENCY)) / AMPLITUDE; // (x / scale)
v[x][y][1] = y-4.5f; // (y / scale)
}
}
GL_PostImgRedraw(v);
}
// Capture the screen again for screen waving on the intermission
if (gamestate != GS_INTERMISSION)
+2 -2
View File
@@ -145,9 +145,9 @@ FUNCINLINE static ATTRINLINE void HWR_DrawIntermissionBG(void)
GL_DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC1, NULL, 0);
}
FUNCINLINE static ATTRINLINE void HWR_RenderVhsEffect(fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize)
FUNCINLINE static ATTRINLINE void HWR_RenderVhsEffect(fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize, boolean rewind)
{
GL_RenderVhsEffect(upbary, downbary, updistort, downdistort, barsize);
GL_RenderVhsEffect(upbary, downbary, updistort, downdistort, barsize, rewind);
}
FUNCINLINE static ATTRINLINE void HWR_MakeScreenTexture(void)
+16
View File
@@ -53,6 +53,18 @@ static struct {
// UI colormap fade shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_COLORMAP_FADE_FRAGMENT_SHADER},
// water postprocess shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_POSTPROCESS_FRAGMENT_WATER},
// heat postprocess shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_POSTPROCESS_FRAGMENT_HEAT},
// vhs fuzz
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_VHS_FUZZ_SHADER},
// vhs bars
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_VHS_BAR_SHADER},
{NULL, NULL},
};
@@ -444,6 +456,10 @@ customshaderxlat_t shaderxlat[] =
{"Sky", SHADER_SKY},
{"PalettePostprocess", SHADER_PALETTE_POSTPROCESS},
{"UIColormapFade", SHADER_UI_COLORMAP_FADE},
{"PostProcessWater", SHADER_POSTPROCESS_WATER},
{"PostProcessHeat", SHADER_POSTPROCESS_HEAT},
{"VHSFuzz", SHADER_VHS_FUZZ},
{"VHSBar", SHADER_VHS_BAR},
{NULL, 0},
};
+119
View File
@@ -337,6 +337,125 @@
"gl_FragColor = texture2D(lighttable_tex, lighttable_coord);\n" \
"}\0" \
// these are RRs postprocess shaders
// for water and heat
/*
#define GLSL_POSTPROCESS_FRAGMENT_WATER \
"uniform sampler2D tex;\n" \
"uniform float leveltime;\n" \
"void main(void) {\n" \
"vec2 uv = gl_TexCoord[0].st;\n" \
"float y = 1.0 - uv.y;\n" \
"uv.x += sin(leveltime * 2.0 + y * 20.0) * 0.01;\n" \
"uv = clamp(uv, vec2(0.0), vec2(0.9999));\n" \
"gl_FragColor = texture2D(tex, uv);\n" \
"}\0"
#define GLSL_POSTPROCESS_FRAGMENT_HEAT \
"uniform sampler2D tex;\n" \
"uniform float leveltime;\n" \
"void main(void) {\n" \
"vec2 uv = gl_TexCoord[0].st;\n" \
"float y = 1.0 - uv.y;\n" \
"float time = leveltime * 35.0;\n" \
"uv.x += max(sin((time / 35.0) * 1.2 - y * 5.0) - 0.995, 0.0);\n" \
"uv.x -= max(sin(((time + 24.0) / 35.0) * 0.2 - y * 1.5) - 0.990, 0.0);\n" \
"uv = clamp(uv, vec2(0.0), vec2(0.9999));\n" \
"gl_FragColor = texture2D(tex, uv);\n" \
"}\0"
*/
// for reference
// sin(leveltime * X + (y) + Y) * Z
// X = Speed, Y = Vertical phase, Z = Amplitude
// this matches software at 720p wonderfully
#define GLSL_POSTPROCESS_FRAGMENT_WATER \
"#version 120\n" \
"uniform sampler2D tex;\n" \
"uniform vec2 scr_resolution;\n" \
"uniform vec2 scr_tex_size;\n" \
"uniform float leveltime;\n" \
"void main(void) {\n" \
"vec2 uv = gl_TexCoord[0].st;\n" \
"vec2 maxuv = scr_resolution / scr_tex_size;\n" \
"float y = 1.0 - uv.y;\n" \
"uv.x += sin(leveltime * 3.0 + y * 15.0) * 0.0025;\n" \
"uv = clamp(uv, vec2(0.0), maxuv - vec2(0.0001));\n" \
"gl_FragColor = texture2D(tex, uv);\n" \
"}\0"
// like the fixed function version, this is just the water wave again
// a bit readjusted since the shader wave is more lean
// makes it less neausiating anyways :p
#define GLSL_POSTPROCESS_FRAGMENT_HEAT \
"#version 120\n" \
"uniform sampler2D tex;\n" \
"uniform vec2 scr_resolution;\n" \
"uniform vec2 scr_tex_size;\n" \
"uniform float leveltime;\n" \
"void main(void) {\n" \
"vec2 uv = gl_TexCoord[0].st;\n" \
"vec2 maxuv = scr_resolution / scr_tex_size;\n" \
"float y = 1.0 - uv.y;\n" \
"uv.x += sin(leveltime * 6.0 + y * 22.5) * 0.00125;\n" \
"uv = clamp(uv, vec2(0.0), maxuv - vec2(0.0001));\n" \
"gl_FragColor = texture2D(tex, uv);\n" \
"}\0"
// screen fuzzyness
// basically just what we did before as a shader lul
// thanks https://stackoverflow.com/a/4275343 for the pseudo random stuff for glsl
#define GLSL_VHS_FUZZ_SHADER \
"#version 120\n" \
"uniform sampler2D tex;\n" \
"uniform vec2 scr_resolution;\n" \
"uniform vec2 scr_tex_size;\n" \
"uniform float vhs_time;\n" \
"uniform float scr_dup;\n" \
"void main(void) {\n" \
"vec2 uv = gl_TexCoord[0].st;\n" \
"vec2 maxuv = scr_resolution / scr_tex_size;\n" \
"float y = 1.0 - uv.y;\n" \
"float ystep = (2.0 / scr_resolution.y) * scr_dup / 4.0;\n" \
"float rand = fract(sin((floor(y / ystep) + vhs_time) * 12.9898 + 78.233) * 43758.5453);\n" \
"uv.x += floor(rand * 128.0) / -22000.0;\n" \
"uv = clamp(uv, vec2(0.0), maxuv - vec2(0.0001));\n" \
"gl_FragColor = texture2D(tex, uv);\n" \
"}\0"
// repurposed the RR heat shader
// since it kinda matched the vhs bars lul
#define GLSL_VHS_BAR_SHADER \
"#version 120\n" \
"uniform sampler2D tex;\n" \
"uniform vec2 scr_resolution;\n" \
"uniform vec2 scr_tex_size;\n" \
"uniform float vhs_time;\n" \
"uniform float vhs_rewind;\n" \
"void main(void) {\n" \
"vec2 uv = gl_TexCoord[0].st;\n" \
"vec2 maxuv = scr_resolution / scr_tex_size;\n" \
"float y = 1.0 - uv.y;\n" \
"float downspd = (vhs_rewind > 0.5) ? 2.0 : 1.0;\n" \
"float downbar = max(sin(vhs_time * downspd - y * 5.0) - 0.95, 0.0);\n" \
"float upspd = (vhs_rewind > 0.5) ? 3.0 : 1.8;\n" \
"float upbar = max(sin((vhs_time * -1.0) * upspd - y * 5.0) - 0.95, 0.0);\n" \
"uv.x += (downbar) * 0.25;\n" \
"float updistort = (vhs_rewind > 0.5) ? 0.4125: 0.25;\n" \
"uv.x -= (upbar) * updistort;\n" \
"uv = clamp(uv, vec2(0.0), maxuv - vec2(0.0001));\n" \
"vec4 color = texture2D(tex, uv);\n" \
"float downcol = step(0.00001, downbar);\n" \
"float upcol = step(0.00001, upbar);\n" \
"color.rgb = mix(color.rgb, color.rgb * (190.0 / 255.0), downcol);\n" \
"color.rgb = mix(color.rgb, color.rgb * (190.0 / 255.0), upcol);\n" \
"color.a = mix(color.a, color.a * (250.0 / 255.0), downcol);\n" \
"color.a = mix(color.a, color.a * (250.0 / 255.0), upcol);\n" \
"gl_FragColor = color;\n" \
"}\0"
// ================
// Fallback shaders
// ================
+233 -94
View File
@@ -761,6 +761,14 @@ typedef enum
gluniform_scr_resolution,
// postprocess stuff
gluniform_scr_dup,
gluniform_scr_tex_size,
// vhs
gluniform_vhs_rewind,
gluniform_vhs_time,
gluniform_max,
} gluniform_t;
@@ -793,6 +801,9 @@ static float shader_light_z = 0.0f;
static INT32 shader_light_contrast = 0;
static INT32 shader_light_backlight = 0;
static float shader_vhs_rewind = 1.0f;
static float shader_vhs_time = 0.0f;
// Lactozilla: Shader functions
static boolean GL_Shader_CompileProgram(gl_shader_t *shader, GLint i);
static void GL_Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade);
@@ -2329,6 +2340,13 @@ static void GL_Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRG
UNIFORM_1(shader->uniforms[gluniform_leveltime], shader_leveltime, pglUniform1f);
UNIFORM_2(shader->uniforms[gluniform_scr_resolution], (GLfloat)screen_width, (GLfloat)screen_height, pglUniform2f);
// udup is before highres scale adjustments
UNIFORM_1(shader->uniforms[gluniform_scr_dup], (GLfloat)vid.udup, pglUniform1f);
// grrrrr stupid 2.0 support.. used similar to yfix, xfix
UNIFORM_2(shader->uniforms[gluniform_scr_tex_size], (GLfloat)screen_texsizew, (GLfloat)screen_texsizeh, pglUniform2f);
UNIFORM_1(shader->uniforms[gluniform_vhs_rewind], shader_vhs_rewind, pglUniform1f);
UNIFORM_1(shader->uniforms[gluniform_vhs_time], shader_vhs_time, pglUniform1f);
#undef UNIFORM_1
#undef UNIFORM_2
@@ -2461,6 +2479,15 @@ static boolean GL_Shader_CompileProgram(gl_shader_t *shader, GLint i)
// misc.
shader->uniforms[gluniform_leveltime] = GETUNI("leveltime");
// postprocessor stuff (water/heat effect)
shader->uniforms[gluniform_scr_dup] = GETUNI("scr_dup");
shader->uniforms[gluniform_scr_tex_size] = GETUNI("scr_tex_size");
// vhs stuff
shader->uniforms[gluniform_vhs_rewind] = GETUNI("vhs_rewind");
shader->uniforms[gluniform_vhs_time] = GETUNI("vhs_time");
#undef GETUNI
// set permanent uniform values
@@ -3597,6 +3624,55 @@ INT32 GL_GetTextureUsed(void)
return res;
}
void GL_DoPostProcessor(INT32 type)
{
float fix[8];
float xfix, yfix;
if (gl_enable_screen_textures != 2)
return;
xfix = 1/((float)screen_texsizew/(float)screen_width);
yfix = 1/((float)screen_texsizeh/(float)screen_height);
fix[0] = fix[1] =
fix[2] = fix[7] = 0.0f;
fix[3] = fix[5] = yfix;
fix[4] = fix[6] = xfix;
// this shouldnt be necessary, since this comes after level draw
// but somehow it breaks without this??
pglMatrixMode(GL_PROJECTION);
pglPushMatrix();
pglLoadIdentity();
pglMatrixMode(GL_MODELVIEW);
pglPushMatrix();
pglLoadIdentity();
GL_SetBlend(PF_NoDepthTest);
pglActiveTexture(GL_TEXTURE0);
pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_GENERIC1]);
tex_downloaded = screenTextures[HWD_SCREENTEXTURE_GENERIC1];
int shader = (type == POSTIMG_WATER) ? SHADER_POSTPROCESS_WATER : SHADER_POSTPROCESS_HEAT;
GL_SetShader(HWR_GetShaderFromTarget(shader));
GL_Shader_SetUniforms(NULL, NULL, NULL, NULL);
pglColor4ubv(white);
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, defaultscreenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
GL_UnSetShader();
pglMatrixMode(GL_PROJECTION);
pglPopMatrix();
pglMatrixMode(GL_MODELVIEW);
pglPopMatrix();
}
void GL_PostImgRedraw(float points[SCREENVERTS][SCREENVERTS][2])
{
INT32 x, y;
@@ -3716,7 +3792,6 @@ void GL_DrawScreenTexture(int tex, FSurfaceInfo *surf, FBITFIELD polyflags)
tex_downloaded = screenTextures[tex];
}
// Do screen fades!
void GL_DoScreenWipe(int wipeStart, int wipeEnd)
{
@@ -3791,120 +3866,184 @@ void GL_DoScreenWipe(int wipeStart, int wipeEnd)
tex_downloaded = screenTextures[wipeEnd];
}
void GL_RenderVhsEffect(fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize)
void GL_RenderVhsEffect(fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize, boolean rewind)
{
float xfix, yfix;
float fix[8];
float i;
if (gl_enable_screen_textures != 2)
return;
GLubyte color[4] = {255, 255, 255, 255};
float screenVerts[12] =
{
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f
};
const GLfloat scrwf = (float)screen_width;
const GLfloat scrwh = (float)screen_height;
const GLfloat scrhf = (float)screen_height;
xfix = 1/((float)screen_texsizew/scrwf);
yfix = 1/((float)screen_texsizeh/scrwh);
yfix = 1/((float)screen_texsizeh/scrhf);
GL_SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest);
// Slight fuzziness
GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS);
pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]);
uint32_t r = rand();
const float ystep = 2.f/scrwh * (float)vid.udup/4.f;
for (i = 0; i < 1; i += ystep)
// uses shaders to replicate the effect
// thanks RR for their heat effect being basically the vhs bars, made this lots easier lul
if (HWR_UseShader())
{
// avoid calling rand thousands of times
r ^= r >> 13;
r ^= r >> 11;
r ^= r << 21;
// leveltime pauses with the game so we need to keep our own ticker here
static tic_t lleveltime = 0;
if (renderisnewtic) lleveltime++;
shader_vhs_time = (((float)(lleveltime-1)) + FIXED_TO_FLOAT(R_GetTimeFrac(RTF_CAMERA))) / TICRATE; // RTF_CAMERA interpolates during pause gladly...
fix[2] = (float)(r & 127) / -22000.f * xfix;
fix[0] = fix[2];
fix[6] = fix[0] + xfix;
fix[4] = fix[2] + xfix;
fix[1] = fix[7] = i*yfix;
fix[3] = fix[5] = (i+0.015f)*yfix;
// easier to account for within the shader
shader_vhs_rewind = rewind ? 1.0f : 0.0f;
screenVerts[1] = screenVerts[10] = 2*i - 1.0f;
screenVerts[4] = screenVerts[7] = screenVerts[1] + 0.03f;
fix[0] = fix[1] =
fix[2] = fix[7] = 0.0f;
fix[3] = fix[5] = yfix;
fix[4] = fix[6] = xfix;
GL_SetBlend(PF_NoDepthTest);
// Slight fuzziness
GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS);
pglActiveTexture(GL_TEXTURE0);
pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]);
tex_downloaded = screenTextures[HWD_SCREENTEXTURE_VHS];
GL_SetShader(HWR_GetShaderFromTarget(SHADER_VHS_FUZZ));
GL_Shader_SetUniforms(NULL, NULL, NULL, NULL);
pglColor4ubv(white);
pglEnableClientState(GL_TEXTURE_COORD_ARRAY);
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, defaultscreenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
GL_UnSetShader();
// Upward and Downward bars
// theyre combined since the original shader also did this
// also saves us another screen copy + draw anyways
GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS);
pglActiveTexture(GL_TEXTURE0);
pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]);
tex_downloaded = screenTextures[HWD_SCREENTEXTURE_VHS];
GL_SetShader(HWR_GetShaderFromTarget(SHADER_VHS_BAR));
GL_Shader_SetUniforms(NULL, NULL, NULL, NULL);
pglColor4ubv(white);
pglEnableClientState(GL_TEXTURE_COORD_ARRAY);
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, defaultscreenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
GL_UnSetShader();
}
else // fallback fixed function version, this is quite slow
{
float i;
GLubyte color[4] = {255, 255, 255, 255};
float screenVerts[12] =
{
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f
};
xfix = 1/((float)screen_texsizew/scrwf);
yfix = 1/((float)screen_texsizeh/scrhf);
GL_SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest);
// Slight fuzziness
GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS);
pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]);
uint32_t r = rand();
const float ystep = 2.f/scrhf * (float)vid.udup/4.f;
for (i = 0; i < 1; i += ystep)
{
// avoid calling rand thousands of times
r ^= r >> 13;
r ^= r >> 11;
r ^= r << 21;
fix[2] = (float)(r & 127) / -22000.f * xfix;
fix[0] = fix[2];
fix[6] = fix[0] + xfix;
fix[4] = fix[2] + xfix;
fix[1] = fix[7] = i*yfix;
fix[3] = fix[5] = (i+0.015f)*yfix;
screenVerts[1] = screenVerts[10] = 2*i - 1.0f;
screenVerts[4] = screenVerts[7] = screenVerts[1] + 0.03f;
pglColor4ubv(color);
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
// Upward bar
GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS);
pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]);
color[0] = color[1] = color[2] = 190;
color[3] = 250;
pglColor4ubv(color);
fix[0] = 0.0f;
fix[6] = xfix;
fix[2] = (float)updistort / scrwf * xfix;
fix[4] = fix[2] + fix[6];
screenVerts[1] = screenVerts[10] = 2.0f*upbary/scrhf - 1.0f;
screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/scrhf;
fix[1] = fix[7] = (float)upbary/scrhf * yfix;
fix[3] = fix[5] = fix[1] + (float)barsize/2/scrhf * yfix;
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
fix[1] = fix[7] += (fix[3] - fix[7])*2;
screenVerts[1] = screenVerts[10] += (screenVerts[4] - screenVerts[1])*2;
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Downward bar
GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS);
pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]);
fix[0] = 0.0f;
fix[6] = xfix;
fix[2] = (float)downdistort / scrwf * -xfix;
fix[4] = fix[2] + fix[6];
screenVerts[1] = screenVerts[10] = 2.0f*downbary/scrhf - 1.0f;
screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/scrhf;
fix[1] = fix[7] = (float)downbary/scrhf * yfix;
fix[3] = fix[5] = fix[1] + (float)barsize/2/scrhf * yfix;
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
fix[1] = fix[7] += (fix[3] - fix[7])*2;
screenVerts[1] = screenVerts[10] += (screenVerts[4] - screenVerts[1])*2;
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
// Upward bar
GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS);
pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]);
color[0] = color[1] = color[2] = 190;
color[3] = 250;
pglColor4ubv(color);
fix[0] = 0.0f;
fix[6] = xfix;
fix[2] = (float)updistort / scrwf * xfix;
fix[4] = fix[2] + fix[6];
screenVerts[1] = screenVerts[10] = 2.0f*upbary/scrwh - 1.0f;
screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/scrwh;
fix[1] = fix[7] = (float)upbary/scrwh * yfix;
fix[3] = fix[5] = fix[1] + (float)barsize/2/scrwh * yfix;
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
fix[1] = fix[7] += (fix[3] - fix[7])*2;
screenVerts[1] = screenVerts[10] += (screenVerts[4] - screenVerts[1])*2;
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Downward bar
GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS);
pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]);
fix[0] = 0.0f;
fix[6] = xfix;
fix[2] = (float)downdistort / scrwf * -xfix;
fix[4] = fix[2] + fix[6];
screenVerts[1] = screenVerts[10] = 2.0f*downbary/scrwh - 1.0f;
screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/scrwh;
fix[1] = fix[7] = (float)downbary/scrwh * yfix;
fix[3] = fix[5] = fix[1] + (float)barsize/2/scrwh * yfix;
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
fix[1] = fix[7] += (fix[3] - fix[7])*2;
screenVerts[1] = screenVerts[10] += (screenVerts[4] - screenVerts[1])*2;
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
// Create a texture from the screen.
+4 -34
View File
@@ -752,14 +752,9 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr
static void SOCK_Send(void)
{
ssize_t c = ERRSOCKET;
int e = 0; // save error code so it can't be modified later code and avoid calling WSAGetLastError() more then once
size_t i, j;
int retrycount = 0;
ssize_t c;
int e; // save error code so it can't be modified later code and avoid calling WSAGetLastError() more then once
retry:
c = ERRSOCKET;
e = 0;
if (doomcom->remotenode < 0 || !nodeconnected[doomcom->remotenode])
return;
@@ -813,35 +808,10 @@ retry:
if (c == ERRSOCKET && e != 0) // 0 means no socket for the address family was found
{
if (ALLOWEDERROR(e))
return;
//if (!ALLOWEDERROR(e))
//I_Error("SOCK_Send, error sending to node %d (%s) #%u, %s", doomcom->remotenode,
//SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e));
// no need to spam this on retries
if (retrycount == 0)
CONS_Alert(CONS_ERROR, "SOCK_Send, error sending to node %d (%s) #%u, %s\n", doomcom->remotenode,
SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e));
// retry sending it
if (retrycount <= 3)
{
CONS_Printf("SOCK_Send: retrying... Attempt %d\n", retrycount+1);
retrycount++;
// wait quarter of a second or smth
I_Sleep(250);
goto retry;
}
// no recovery, guess we die
I_Error("SOCK_Send, error sending to node %d (%s) #%u, %s", doomcom->remotenode,
if (!ALLOWEDERROR(e))
I_Error("SOCK_Send, error sending to node %d (%s) #%u, %s", doomcom->remotenode,
SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e));
}
if (retrycount > 0)
CONS_Alert(CONS_NOTICE, "SOCK_Send: successfully reconnected on Attempt %d\n", retrycount);
}
#undef ALLOWEDERROR
+10
View File
@@ -18,6 +18,7 @@
#include "p_slopes.h"
#include "r_main.h"
#include "lua_udatalib.h"
#include "lua_script.h"
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
@@ -255,6 +256,15 @@ static const char *const vector_opt[] = {
static const char *const array_opt[] ={"iterate",NULL};
static const char *const valid_opt[] ={"valid",NULL};
#define pushsubsector(L, subsector) LUA_PushUserdata(L, subsector, META_SUBSECTOR)
int udatalib_getter_subsector(lua_State *L)
UDATALIB_SIMPLE_GETTER(subsector_t*, pushsubsector)
#undef pushsubsector
#define pushslope(L, slope) LUA_PushUserdata(L, slope, META_SLOPE)
int udatalib_getter_slope(lua_State *L)
UDATALIB_SIMPLE_GETTER(pslope_t*, pushslope)
#undef pushslope
// iterates through a sector's thinglist!
static int lib_iterateSectorThinglist(lua_State *L)
{
+743 -769
View File
File diff suppressed because it is too large. Load diff
+422 -847
View File
File diff suppressed because it is too large. Load diff
+137
View File
@@ -0,0 +1,137 @@
// SONIC ROBO BLAST 2 KART SATURN
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Indev.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file lua_udatalib.c
/// \brief Implementation of lua userdata object metatables based on getter/setter functions
#include "doomtype.h"
#include "m_fixed.h"
#include "lua_udatalib.h"
// Getters
int udatalib_getter_fixed(lua_State *L)
UDATALIB_SIMPLE_GETTER(fixed_t, lua_pushinteger)
int udatalib_getter_angle(lua_State *L)
UDATALIB_SIMPLE_GETTER(angle_t, lua_pushangle)
int udatalib_getter_uint8(lua_State *L)
UDATALIB_SIMPLE_GETTER(UINT8, lua_pushinteger)
int udatalib_getter_sint8(lua_State *L)
UDATALIB_SIMPLE_GETTER(SINT8, lua_pushinteger)
int udatalib_getter_uint16(lua_State *L)
UDATALIB_SIMPLE_GETTER(UINT16, lua_pushinteger)
int udatalib_getter_int16(lua_State *L)
UDATALIB_SIMPLE_GETTER(INT16, lua_pushinteger)
int udatalib_getter_uint32(lua_State *L)
UDATALIB_SIMPLE_GETTER(UINT32, lua_pushinteger)
int udatalib_getter_int32(lua_State *L)
UDATALIB_SIMPLE_GETTER(INT32, lua_pushinteger)
int udatalib_getter_uint64(lua_State *L)
UDATALIB_SIMPLE_GETTER(UINT64, lua_pushinteger)
int udatalib_getter_int64(lua_State *L)
UDATALIB_SIMPLE_GETTER(INT64, lua_pushinteger)
int udatalib_getter_string(lua_State *L)
UDATALIB_SIMPLE_GETTER(const char*, lua_pushstring)
int udatalib_getter_boolean(lua_State *L)
UDATALIB_SIMPLE_GETTER(boolean, lua_pushboolean)
int udatalib_getter_spritenum(lua_State *L)
UDATALIB_SIMPLE_GETTER(spritenum_t, lua_pushinteger)
int udatalib_getter_tic(lua_State *L)
UDATALIB_SIMPLE_GETTER(tic_t, lua_pushinteger)
// Setters
int udatalib_setter_fixed(lua_State *L)
UDATALIB_SIMPLE_SETTER(fixed_t, luaL_checkfixed)
int udatalib_setter_angle(lua_State *L)
UDATALIB_SIMPLE_SETTER(angle_t, luaL_checkangle)
int udatalib_setter_uint8(lua_State *L)
UDATALIB_SIMPLE_SETTER(UINT8, (UINT8)luaL_checkinteger)
int udatalib_setter_sint8(lua_State *L)
UDATALIB_SIMPLE_SETTER(SINT8, luaL_checkinteger)
int udatalib_setter_uint16(lua_State *L)
UDATALIB_SIMPLE_SETTER(UINT16, (UINT16)luaL_checkinteger)
int udatalib_setter_int16(lua_State *L)
UDATALIB_SIMPLE_SETTER(INT16, luaL_checkinteger)
int udatalib_setter_uint32(lua_State *L)
UDATALIB_SIMPLE_SETTER(UINT32, (UINT32)luaL_checkinteger)
int udatalib_setter_int32(lua_State *L)
UDATALIB_SIMPLE_SETTER(INT32, luaL_checkinteger)
int udatalib_setter_uint64(lua_State *L)
UDATALIB_SIMPLE_SETTER(UINT64, (UINT64)luaL_checkinteger)
int udatalib_setter_int64(lua_State *L)
UDATALIB_SIMPLE_SETTER(INT64, luaL_checkinteger)
int udatalib_setter_string(lua_State *L)
UDATALIB_SIMPLE_SETTER(const char*, luaL_checkstring)
int udatalib_setter_boolean(lua_State *L)
UDATALIB_SIMPLE_SETTER(boolean, luaL_checkboolean)
// ffs
int udatalib_setter_boolean_nocheck(lua_State *L)
UDATALIB_SIMPLE_SETTER(boolean, lua_toboolean)
int udatalib_setter_spritenum(lua_State *L)
UDATALIB_SIMPLE_SETTER(spritenum_t, luaL_checkinteger)
int udatalib_setter_tic(lua_State *L)
UDATALIB_SIMPLE_SETTER(tic_t, (tic_t)luaL_checkinteger)
void udatalib_addfield(lua_State *L, int mt, udata_field_t field)
{
int idx = abs_index(L, mt);
lua_createtable(L, 2, 0); // Push table
lua_pushinteger(L, field.offset); // Push offset
lua_pushcclosure(L, field.getter, 1); // Pop offset, push closure
lua_rawseti(L, -2, UDATALIB_GETTER); // Pop closure, add to table
lua_pushinteger(L, field.offset); // Push offset
lua_pushcclosure(L, field.setter, 1); // Pop offset, push closure
lua_rawseti(L, -2, UDATALIB_SETTER); // Pop closure, add to table
lua_pushstring(L, field.name); // Push field name
lua_pushvalue(L, -2); // Copy table
lua_rawset(L, idx); // Pop field name and table, add to metatable
lua_pop(L, 1); // Pop field table
}
void udatalib_addfields(lua_State *L, int mt, const udata_field_t fields[])
{
for (unsigned i = 0; fields[i].name != NULL; ++i)
{
udatalib_addfield(L, mt, fields[i]);
//CONS_Printf("Add field name=%s, offset=%d, getter=%p, setter=%p\n", fields[i].name, fields[i].offset, fields[i].getter, fields[i].setter);
}
}
+114
View File
@@ -0,0 +1,114 @@
// SONIC ROBO BLAST 2 KART SATURN
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Indev.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file lua_udatalib.h
/// \brief Implementation of lua userdata object metatables based on getter/setter functions
#ifndef __LUA_UDATALIB_H__
#define __LUA_UDATALIB_H__
#include "doomdef.h"
#include "lua_script.h"
#include "lua_libs.h"
#include "fastcmp.h"
// Indices in getter/setter tables for fields
#define UDATALIB_GETTER 1
#define UDATALIB_SETTER 2
typedef struct udata_field_s {
const char *name;
size_t offset;
lua_CFunction getter;
lua_CFunction setter;
} udata_field_t;
// Simple setters and getters, for situations where getter is simply
// "return obj.field" and setter is "obj.field = value"
int udatalib_getter_fixed(lua_State *L);
int udatalib_getter_angle(lua_State *L);
int udatalib_getter_uint8(lua_State *L);
int udatalib_getter_sint8(lua_State *L);
int udatalib_getter_uint16(lua_State *L);
int udatalib_getter_int16(lua_State *L);
int udatalib_getter_uint32(lua_State *L);
int udatalib_getter_int32(lua_State *L);
int udatalib_getter_uint64(lua_State *L);
int udatalib_getter_int64(lua_State *L);
int udatalib_getter_string(lua_State *L);
int udatalib_getter_boolean(lua_State *L);
int udatalib_getter_spritenum(lua_State *L);
int udatalib_getter_mobj(lua_State *L);
int udatalib_getter_subsector(lua_State *L);
int udatalib_getter_mobjtype(lua_State *L);
int udatalib_getter_player(lua_State *L);
int udatalib_getter_mapthing(lua_State *L);
int udatalib_getter_slope(lua_State *L);
int udatalib_getter_cmd(lua_State *L);
int udatalib_getter_playerstate(lua_State *L);
int udatalib_getter_powers(lua_State *L);
int udatalib_getter_kartstuff(lua_State *L);
int udatalib_getter_pflags(lua_State *L);
int udatalib_getter_panim(lua_State *L);
int udatalib_getter_tic(lua_State *L);
int udatalib_setter_fixed(lua_State *L);
int udatalib_setter_angle(lua_State *L);
int udatalib_setter_uint8(lua_State *L);
int udatalib_setter_sint8(lua_State *L);
int udatalib_setter_uint16(lua_State *L);
int udatalib_setter_int16(lua_State *L);
int udatalib_setter_uint32(lua_State *L);
int udatalib_setter_int32(lua_State *L);
int udatalib_setter_uint64(lua_State *L);
int udatalib_setter_int64(lua_State *L);
int udatalib_setter_string(lua_State *L);
int udatalib_setter_boolean(lua_State *L);
int udatalib_setter_boolean_nocheck(lua_State *L);
int udatalib_setter_spritenum(lua_State *L);
int udatalib_setter_mobj(lua_State *L);
int udatalib_setter_playerstate(lua_State *L);
int udatalib_setter_pflags(lua_State *L);
int udatalib_setter_panim(lua_State *L);
int udatalib_setter_tic(lua_State *L);
// Adds setter and getter for field and stores it as field.name..".get" and
// field.name..".set" in table at index mt. (metatable, usually)
void udatalib_addfield(lua_State *L, int mt, udata_field_t field);
// Convinience function to add array of fields at once.
void udatalib_addfields(lua_State *L, int mt, const udata_field_t fields[]);
// I miss C++ template functons :(
// Get pointer to field value within getter or setter
#define UDATALIB_GETFIELD(type, field) \
{ \
size_t offset = lua_tointeger(L, lua_upvalueindex(1)); \
field = (type*)((uint8_t*)lua_touserdata(L, 1) + offset); \
}
// Creates implementation for simple getter and setter. Super lazy, yes.
// Assumes userdata is a pointer to actual data. Maybe not really safe.
#define UDATALIB_SIMPLE_GETTER(type, pushf) \
{ \
type *field; \
UDATALIB_GETFIELD(type, field) \
pushf(L, *field); \
return 1; \
}
#define UDATALIB_SIMPLE_SETTER(type, checkf) \
{ \
type *field; \
UDATALIB_GETFIELD(type, field) \
*field = checkf(L, 2); \
return 0; \
}
#endif
+4 -4
View File
@@ -1882,7 +1882,7 @@ void V_DrawVhsEffect(boolean rewind)
#ifdef HWRENDER
if (rendermode == render_opengl)
{
HWR_RenderVhsEffect(uby, dby, updistort, downdistort, barsize);
HWR_RenderVhsEffect(uby, dby, updistort, downdistort, barsize, rewind);
return;
}
#endif
@@ -3619,7 +3619,7 @@ void V_DoPostProcessor(INT32 view, INT32 param)
for (y = yoffset; y < yoffset+viewheight; y++)
{
sine = (FINESINE(disStart)*5)>>FRACBITS;
sine = (FINESINE(disStart) * 5) >> FRACBITS;
newpix = abs(sine);
if (sine < 0)
@@ -3659,8 +3659,8 @@ void V_DoPostProcessor(INT32 view, INT32 param)
tmpscr[y*vid.width + x] = srcscr[y*vid.width+newpix]; // *(transme + (srcscr[y*vid.width+x]<<8) + srcscr[y*vid.width+newpix]);
}*/
disStart += 22;//the offset into the displacement map, increment each game loop
disStart &= FINEMASK; //clip it to FINEMASK
disStart += 22; // the offset into the displacement map, increment each game loop
disStart &= FINEMASK; // clip it to FINEMASK
}
UINT8 *tmp = tmpscr;