diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index c27e17a16..bfd5fa26d 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -576,7 +576,6 @@ void HWR_SetPalette(RGBA_t *palette) Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRCACHE_UNLOCKED); } } - // -------------------------------------------------------------------------- // Make sure texture is downloaded and set it as the source // -------------------------------------------------------------------------- diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 294e4e791..6002fcf18 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -224,6 +224,7 @@ struct FSurfaceInfo RGBA_t PolyColor; RGBA_t TintColor; RGBA_t FadeColor; + UINT32 LightTableId; FLightInfo LightInfo; // jimita 14032019 }; typedef struct FSurfaceInfo FSurfaceInfo; @@ -231,6 +232,7 @@ typedef struct FSurfaceInfo FSurfaceInfo; enum hwdsetspecialstate { HWD_SET_SHADERS, + HWD_SET_PALETTE_SHADER_ENABLED, HWD_SET_TEXTUREFILTERMODE, HWD_SET_TEXTUREANISOTROPICMODE, diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 204c79dc1..d00055d59 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -80,6 +80,9 @@ EXPORT void HWRAPI(InitCustomShaders) (void); EXPORT void HWRAPI(StartBatching) (void); EXPORT void HWRAPI(RenderBatches) (precise_t *sSortTime, precise_t *sDrawTime, int *sNumPolys, int *sNumVerts, int *sNumCalls, int *sNumShaders, int *sNumTextures, int *sNumPolyFlags, int *sNumColors); +EXPORT UINT32 HWRAPI(AddLightTable) (UINT8 *lighttable); +EXPORT void HWRAPI(ClearLightTableCache) (void); + // ========================================================================== // HWR DRIVER OBJECT, FOR CLIENT PROGRAM // ========================================================================== @@ -126,6 +129,9 @@ struct hwdriver_s StartBatching pfnStartBatching; RenderBatches pfnRenderBatches; + + AddLightTable pfnAddLightTable; + ClearLightTableCache pfnClearLightTableCache; }; extern struct hwdriver_s hwdriver; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 66adf3522..f5dec1d58 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -30,6 +30,7 @@ #include "../r_fps.h" #include "../r_state.h" #include "../r_local.h" +#include "../r_data.h" #include "../r_patch.h" // a mystery as to what this is for #include "../r_bsp.h" // R_NoEncore #include "../r_main.h" // cv_fov @@ -60,10 +61,14 @@ struct hwdriver_s hwdriver; // Commands and console variables // ========================================================================== +// keep the state here instead of in the cv var, so it always matches the state in r_opengl.c +int gr_use_palette_shader = 0; + static void CV_filtermode_ONChange(void); static void CV_anisotropic_ONChange(void); static void CV_screentextures_ONChange(void); -static void CV_useCustomShaders_ONChange(void); +static void CV_useCustomShaders_ONChange(void); +static void CV_grpaletteshader_OnChange(void); static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, {HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"}, @@ -115,7 +120,11 @@ static INT32 current_bsp_culling_distance = 0; consvar_t cv_grscreentextures = {"gr_screentextures", "On", CV_CALL, CV_OnOff, CV_screentextures_ONChange, 0, NULL, NULL, 0, 0, NULL}; - consvar_t cv_grusecustomshaders = {"gr_usecustomshaders", "Yes", CV_CALL|CV_SAVE, CV_OnOff, CV_useCustomShaders_ONChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_grusecustomshaders = {"gr_usecustomshaders", "Yes", CV_CALL|CV_SAVE, CV_OnOff, CV_useCustomShaders_ONChange, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_grpaletteshader = {"gr_paletteshader", "Off", CV_CALL|CV_SAVE, CV_OnOff, CV_grpaletteshader_OnChange, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_grflashpal = {"gr_flashpal", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static void CV_filtermode_ONChange(void) { @@ -138,6 +147,16 @@ static void CV_useCustomShaders_ONChange(void) HWD.pfnInitCustomShaders(); } +static void CV_grpaletteshader_OnChange(void) +{ + if (rendermode == render_opengl) + { + HWD.pfnSetSpecialState(HWD_SET_PALETTE_SHADER_ENABLED, cv_grpaletteshader.value); + gr_use_palette_shader = cv_grpaletteshader.value; + V_SetPalette(0); + } +} + // ========================================================================== // Globals // ========================================================================== @@ -400,6 +419,7 @@ static size_t gr_numportalcullsectors = 0; void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap) { RGBA_t poly_color, tint_color, fade_color; + boolean default_colormap = false; poly_color.rgba = 0xFFFFFFFF; tint_color.rgba = (colormap != NULL) ? (UINT32)colormap->rgba : GL_DEFAULTMIX; @@ -451,6 +471,37 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col Surface->LightInfo.light_level = light_level; Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0; Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31; + + if (gr_use_palette_shader) + { + if (!colormap) + { + colormap = &extra_colormaps[num_extra_colormaps]; + default_colormap = true; + } + if (!colormap->gl_lighttable_id) + { + UINT8 *colormap_pointer; + + if (default_colormap) + { + colormap_pointer = colormaps; + } + else + { + colormap_pointer = colormap->colormap; + } + colormap->gl_lighttable_id = HWD.pfnAddLightTable(colormap_pointer); + } + + Surface->LightTableId = colormap->gl_lighttable_id; + } +} + +void HWR_ClearLightTableCache() +{ + if (rendermode == render_opengl) + HWD.pfnClearLightTableCache(); } UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work @@ -723,7 +774,7 @@ void HWR_RenderPlane(extrasubsector_t *xsub, boolean isceiling, fixed_t fixedhei else if (PolyFlags & PF_Ripple) HWD.pfnSetShader(5); // water shader else - HWD.pfnSetShader(1); // floor shader + HWD.pfnSetShader(gr_use_palette_shader ? 9 : 1); // floor shader HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, false); @@ -861,7 +912,7 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) break; } - HWD.pfnSetShader(2); // wall shader + HWD.pfnSetShader(gr_use_palette_shader ? 10 : 2); // wall shader HWD.pfnDrawPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal, false); } } @@ -895,7 +946,7 @@ void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend { HWR_Lighting(pSurf, lightlevel, wallcolormap); - HWD.pfnSetShader(2); // wall shader + HWD.pfnSetShader(gr_use_palette_shader ? 10 : 2); // wall shader // don't draw to color buffer when drawing to stencil if (gl_drawing_stencil) @@ -951,6 +1002,9 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa pegb = wallVerts[0].t; pegmul = (pegb - pegt) / (top - bot); + if (fpclassify(pegmul) == FP_NAN) + pegmul = 0.0; + #ifdef ESLOPE endrealtop = endtop = wallVerts[2].y; endrealbot = endbot = wallVerts[1].y; @@ -959,6 +1013,8 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa endpegmul = (endpegb - endpegt) / (endtop - endbot); #endif + if (fpclassify(endpegmul) == FP_NAN) + endpegmul = 0.0; for (i = 0; i < sector->numlights; i++) { @@ -972,13 +1028,15 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa { if (pfloor && (pfloor->flags & FF_FOG)) { - lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y); colormap = pfloor->master->frontsector->extra_colormap; + lightnum = pfloor->master->frontsector->lightlevel; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); } else { - lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y); colormap = list[i].extra_colormap; + lightnum = *list[i].lightlevel; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); } } @@ -1070,7 +1128,8 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa #endif #ifdef ESLOPE - if (endbheight >= endtop) + if (endbheight > endtop) + endbot = endtop; #endif if (bheight >= top) continue; @@ -1080,13 +1139,11 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa if (bot < realbot) bot = realbot; - -#ifdef ESLOPE - endbot = endbheight; - if (endbot < endrealbot) - endbot = endrealbot; +#ifdef ESLOPE + endbot = min(max(endbheight, endrealbot), endtop); #endif + Surf->PolyColor.s.alpha = alpha; #ifdef ESLOPE @@ -1379,8 +1436,9 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT)); } - lightnum = HWR_CalcWallLight(gr_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); colormap = gr_frontsector->extra_colormap; + lightnum = gr_frontsector->lightlevel; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); if (gr_frontsector) Surf.PolyColor.s.alpha = 255; @@ -1680,10 +1738,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture); if (gr_midtexture || gr_portal == GRPORTAL_STENCIL || gr_portal == GRPORTAL_DEPTH || gl_drawing_stencil) { - FBITFIELD blendmode; sector_t *front, *back; - fixed_t popentop, popenbottom, polytop, polybottom, lowcut, highcut; - fixed_t texturevpeg = 0; INT32 repeats; if (gr_linedef->frontsector->heightsec != -1) @@ -1719,6 +1774,10 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom else repeats = 1; + fixed_t midtexheight = textureheight[gr_midtexture] * repeats; + fixed_t popentop, popenbottom, polytop, polybottom, lowcut, highcut; + fixed_t popentopslope, popenbottomslope, polytopslope, polybottomslope, lowcutslope, highcutslope; + // SoM: a little note: This code re-arranging will // fix the bug in Nimrod map02. popentop and popenbottom // record the limits the texture can be displayed in. @@ -1732,8 +1791,8 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // From CB if (gr_curline->polyseg) { - popentop = back->ceilingheight; - popenbottom = back->floorheight; + popentop = popentopslope = back->ceilingheight; + popenbottom = popenbottomslope = back->floorheight; } else #endif @@ -1741,10 +1800,9 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom #ifdef ESLOPE popentop = min(worldtop, worldhigh); popenbottom = max(worldbottom, worldlow); -#else - popentop = min(front->ceilingheight, back->ceilingheight); - popenbottom = max(front->floorheight, back->floorheight); -#endif + + popentopslope = min(worldtopslope, worldhighslope); + popenbottomslope = max(worldbottomslope, worldlowslope); } #ifdef ESLOPE @@ -1753,12 +1811,16 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) { polybottom = max(front->floorheight, back->floorheight) + gr_sidedef->rowoffset; - polytop = polybottom + textureheight[gr_midtexture]*repeats; + polybottomslope = polybottom; + polytop = polybottom + midtexheight; + polytopslope = polytop; } else { polytop = min(front->ceilingheight, back->ceilingheight) + gr_sidedef->rowoffset; - polybottom = polytop - textureheight[gr_midtexture]*repeats; + polytopslope = polytop; + polybottom = polytop - midtexheight; + polybottomslope = polybottom; } } else if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) @@ -1767,12 +1829,17 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom #endif { polybottom = popenbottom + gr_sidedef->rowoffset; - polytop = polybottom + textureheight[gr_midtexture]*repeats; + polytop = polybottom + midtexheight; + polybottomslope = popenbottomslope + gr_sidedef->rowoffset; + polytopslope = polybottomslope + midtexheight; } else { polytop = popentop + gr_sidedef->rowoffset; polybottom = polytop - textureheight[gr_midtexture]*repeats; + polybottom = polytop - midtexheight; + polytopslope = popentopslope + gr_sidedef->rowoffset; + polybottomslope = polytopslope - midtexheight; } // CB @@ -1783,6 +1850,8 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { lowcut = polybottom; highcut = polytop; + lowcutslope = polybottomslope; + highcutslope = polytopslope; } #endif else @@ -1790,83 +1859,49 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector lowcut = popenbottom; highcut = popentop; + lowcutslope = popenbottomslope; + highcutslope = popentopslope; } h = min(highcut, polytop); l = max(polybottom, lowcut); + hS = min(highcutslope, polytopslope); + lS = max(polybottomslope, lowcutslope); + // PEGGING + fixed_t texturevpeg, texturevpegslope; + + if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) { - // PEGGING -#ifdef ESLOPE - if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) -#else - if (gr_linedef->flags & ML_DONTPEGBOTTOM) -#endif - texturevpeg = textureheight[gr_sidedef->midtexture]*repeats - h + polybottom; - else - texturevpeg = polytop - h; + texturevpeg = midtexheight - h + polybottom; + texturevpegslope = midtexheight - hS + polybottomslope; + } + else + { + texturevpeg = polytop - h; + texturevpegslope = polytopslope - hS; + } grTex = HWR_GetTexture(gr_midtexture); - wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; - wallVerts[0].t = wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY; - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; - } + wallVerts[3].t = texturevpeg * grTex->scaleY; + wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY; + wallVerts[2].t = texturevpegslope * grTex->scaleY; + wallVerts[1].t = (hS - lS + texturevpegslope) * grTex->scaleY; + wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; // set top/bottom coords // Take the texture peg into account, rather than changing the offsets past // where the polygon might not be. - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(h); - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(l); - -#ifdef ESLOPE - // Correct to account for slopes - { - fixed_t midtextureslant; - - if (gr_linedef->flags & ML_EFFECT2) - midtextureslant = 0; - else if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) - midtextureslant = worldlow < worldbottom - ? worldbottomslope-worldbottom - : worldlowslope-worldlow; - else - midtextureslant = worldtop < worldhigh - ? worldtopslope-worldtop - : worldhighslope-worldhigh; - - polytop += midtextureslant; - polybottom += midtextureslant; - - highcut += worldtop < worldhigh - ? worldtopslope-worldtop - : worldhighslope-worldhigh; - lowcut += worldlow < worldbottom - ? worldbottomslope-worldbottom - : worldlowslope-worldlow; - - // Texture stuff - h = min(highcut, polytop); - l = max(polybottom, lowcut); - - { - // PEGGING - if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) - texturevpeg = textureheight[gr_sidedef->midtexture]*repeats - h + polybottom; - else - texturevpeg = polytop - h; - wallVerts[2].t = texturevpeg * grTex->scaleY; - wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY; - } - - wallVerts[2].y = FIXED_TO_FLOAT(h); - wallVerts[1].y = FIXED_TO_FLOAT(l); - } + wallVerts[3].y = FIXED_TO_FLOAT(h); + wallVerts[0].y = FIXED_TO_FLOAT(l); + wallVerts[2].y = FIXED_TO_FLOAT(hS); + wallVerts[1].y = FIXED_TO_FLOAT(lS); #endif // set alpha for transparent walls (new boom and legacy linedef types) - // ooops ! this do not work at all because render order we should render it in backtofront order + FBITFIELD blendmode; switch (gr_linedef->special) { @@ -2224,8 +2259,10 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode = PF_Fog|PF_NoTexture; - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); colormap = rover->master->frontsector->extra_colormap; + lightnum = rover->master->frontsector->lightlevel; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); + Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); @@ -2347,8 +2384,9 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode = PF_Fog|PF_NoTexture; - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); colormap = rover->master->frontsector->extra_colormap; + lightnum = rover->master->frontsector->lightlevel; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); @@ -3055,7 +3093,7 @@ void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t else blendmode |= PF_Masked|PF_Modulated; - HWD.pfnSetShader(1); // floor shader + HWD.pfnSetShader(gr_use_palette_shader ? 9 : 1); // floor shader HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, false); } @@ -3854,7 +3892,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t if (sSurf.PolyColor.s.alpha > floorheight/4) { sSurf.PolyColor.s.alpha = (UINT8)(sSurf.PolyColor.s.alpha - floorheight/4); - HWD.pfnSetShader(1); // floor shader + HWD.pfnSetShader(gr_use_palette_shader ? 9 : 1); // floor shader HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated, false); } } @@ -4221,7 +4259,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWD.pfnSetShader(3); // sprite shader + HWD.pfnSetShader(gr_use_palette_shader ? 10 : 3); // sprite shader HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); top = bot; @@ -4261,7 +4299,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWD.pfnSetShader(3); // sprite shader + HWD.pfnSetShader(gr_use_palette_shader ? 10 : 3); // sprite shader HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); } @@ -4414,7 +4452,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) blend = PF_Translucent|PF_Occlude; } - HWD.pfnSetShader(3); // sprite shader + HWD.pfnSetShader(gr_use_palette_shader ? 10 : 3); // sprite shader HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); } } @@ -4508,7 +4546,7 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) blend = PF_Translucent|PF_Occlude; } - HWD.pfnSetShader(3); // sprite shader + HWD.pfnSetShader(gr_use_palette_shader ? 10 : 3); // sprite shader HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); } @@ -6056,6 +6094,8 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_portalline); CV_RegisterVar(&cv_portalonly); CV_RegisterVar(&cv_secbright); + CV_RegisterVar(&cv_grpaletteshader); + CV_RegisterVar(&cv_grflashpal); } // -------------------------------------------------------------------------- @@ -6097,7 +6137,6 @@ void HWR_Startup(void) } } - // -------------------------------------------------------------------------- // Free resources allocated by the hardware renderer // -------------------------------------------------------------------------- @@ -6119,8 +6158,6 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, pSurf->PolyColor.s.alpha = alpha; // put the alpha back after lighting - HWD.pfnSetShader(2); // wall shader - if (blend & PF_Environment) blendmode |= PF_Occlude; // PF_Occlude must be used for solid objects @@ -6132,6 +6169,8 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency + if (!fogwall) + HWD.pfnSetShader(gr_use_palette_shader ? 10 : 2); // wall shader HWD.pfnDrawPolygon(pSurf, wallVerts, 4, blendmode, false); #ifdef WALLSPLATS @@ -6163,7 +6202,7 @@ void HWR_DoPostProcessor(player_t *player) // Armageddon Blast Flash! // Could this even be considered postprocessor? - if (player->flashcount) + if (player->flashcount && !cv_grpaletteshader.value || player->flashcount && cv_grpaletteshader.value && !cv_grflashpal.value) { FOutVector v[4]; FSurfaceInfo Surf; @@ -6292,6 +6331,8 @@ void HWR_MakeScreenFinalTexture(void) void HWR_DrawScreenFinalTexture(int width, int height) { + if (gr_use_palette_shader) + HWD.pfnSetShader(11); //post processing HWD.pfnDrawScreenFinalTexture(width, height); } diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 51a362c9e..5098c754e 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -142,6 +142,8 @@ void HWR_AddLine(seg_t *line); boolean HWR_CheckBBox(fixed_t *bspcoord); void HWR_RenderDrawNodes(void); +void HWR_ClearLightTableCache(void); + // hw_main.c: Sprites void HWR_AddSprites(sector_t *sec); void HWR_ProjectSprite(mobj_t *thing); @@ -179,6 +181,8 @@ extern consvar_t cv_grfallbackplayermodel; extern consvar_t cv_grbatching; extern consvar_t cv_grrenderdistance; extern consvar_t cv_grusecustomshaders; +extern consvar_t cv_grpaletteshader; +extern consvar_t cv_grflashpal; extern consvar_t cv_grportals; extern consvar_t cv_nostencil; extern consvar_t cv_secbright; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index b0c6ec8f6..67eec5058 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -26,10 +26,15 @@ #include "r_opengl.h" #include "r_vbo.h" +#include "../../v_video.h" // pLocalPalette +#include "../../r_data.h" // NearestColor + #include "../../p_tick.h" // for leveltime (NOTE: THIS IS BAD, FIGURE OUT HOW TO PROPERLY IMPLEMENT gl_leveltime) #include "../../i_system.h" // for I_GetPreciseTime (batching time measurements) -// Eeeeh not sure is this right way, but it works +#include "../hw_main.h" + +// Eeeeh not sure is this right way, but it works < sry :c extern consvar_t cv_grusecustomshaders; extern fixed_t fovtan; // also extremely bad, I'm just too lazy!!! @@ -44,12 +49,15 @@ struct GLRGBAFloat GLfloat alpha; }; typedef struct GLRGBAFloat GLRGBAFloat; + static const GLubyte white[4] = { 255, 255, 255, 255 }; // ========================================================================== // CONSTANTS // ========================================================================== + + // With OpenGL 1.1+, the first texture should be 1 #define NOTEXTURE_NUM 0 @@ -70,8 +78,17 @@ static GLuint tex_downloaded = 0; static GLfloat fov = 90.0f; static FBITFIELD CurrentPolyFlags; -static FTextureInfo* gr_cachetail = NULL; -static FTextureInfo* gr_cachehead = NULL; +static FTextureInfo *gr_cachetail = NULL; +static FTextureInfo *gr_cachehead = NULL; + +typedef struct LightTableCacheEntry_s +{ + GLuint id; + struct LightTableCacheEntry_s *next; +} LightTableCacheEntry_t; + +LightTableCacheEntry_t *ltcachehead = NULL; +LightTableCacheEntry_t *ltcachetail = NULL; RGBA_t myPaletteData[256]; GLint screen_width = 0; // used by Draw2DLine() @@ -235,6 +252,7 @@ FUNCPRINTF void GL_DBG_Printf(const char *format, ...) #define pglTexEnvi glTexEnvi #define pglTexParameteri glTexParameteri #define pglTexImage2D glTexImage2D +#define pglTexImage3D glTexImage3D /* Fog */ #define pglFogf glFogf @@ -355,6 +373,8 @@ typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint static PFNglTexParameteri pglTexParameteri; typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); static PFNglTexImage2D pglTexImage2D; +typedef void (APIENTRY * PFNglTexImage3D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static PFNglTexImage3D pglTexImage3D; /* Fog */ typedef void (APIENTRY * PFNglFogf) (GLenum pname, GLfloat param); @@ -511,6 +531,7 @@ typedef void (APIENTRY *PFNglLinkProgram) (GLuint); typedef void (APIENTRY *PFNglGetProgramiv) (GLuint, GLenum, GLint*); typedef void (APIENTRY *PFNglUseProgram) (GLuint); typedef void (APIENTRY *PFNglUniform1i) (GLint, GLint); +typedef void (APIENTRY *PFNglUniform1iv) (GLint, GLsizei, const GLint*); typedef void (APIENTRY *PFNglUniform1f) (GLint, GLfloat); typedef void (APIENTRY *PFNglUniform2f) (GLint, GLfloat, GLfloat); typedef void (APIENTRY *PFNglUniform3f) (GLint, GLfloat, GLfloat, GLfloat); @@ -532,6 +553,7 @@ static PFNglLinkProgram pglLinkProgram; static PFNglGetProgramiv pglGetProgramiv; static PFNglUseProgram pglUseProgram; static PFNglUniform1i pglUniform1i; +static PFNglUniform1iv pglUniform1iv; static PFNglUniform1f pglUniform1f; static PFNglUniform2f pglUniform2f; static PFNglUniform3f pglUniform3f; @@ -555,6 +577,10 @@ static boolean gl_shaderprogramchanged = true; static boolean gl_batching = false;// are we currently collecting batches? +static GLint gl_palette[768]; +static INT32 gl_use_palette_shader = 0; +boolean gl_palette_initialized = false; + static INT32 gl_enable_screen_textures = 1; static GLint gl_portal_stencil_level = 0; @@ -571,10 +597,15 @@ typedef enum gluniform_lighting, gluniform_fade_start, gluniform_fade_end, - - // misc. (custom shaders) + + // palette rendering + gluniform_palette, + gluniform_color_lookup, + gluniform_lighttable_tex, + + // misc. gluniform_leveltime, - + gluniform_max, } gluniform_t; @@ -594,6 +625,18 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS]; // GLSL Software fragment shader // +#define GLSL_DOOM_COLORMAP_floors \ + "float R_DoomColormap(float light, float z)\n" \ + "{\n" \ + "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \ + "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ + "float startmap = (15.0 - lightnum) * 4.0;\n" \ + "float scale = 160.0 / (lightz + 1.0);\n" \ + "return startmap * 1.06 - scale * 0.5 * 1.15;\n" \ + "}\n" + +// 1.06 and 1.15 were chosen when trying to match software lighting in a test map + #define GLSL_DOOM_COLORMAP \ "float R_DoomColormap(float light, float z)\n" \ "{\n" \ @@ -604,6 +647,16 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS]; "return startmap - scale * 0.5;\n" \ "}\n" +#define GLSL_DOOM_COLORMAP_walls \ + "float R_DoomColormap(float light, float z)\n" \ + "{\n" \ + "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \ + "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ + "float startmap = (15.0 - lightnum) * 4.0;\n" \ + "float scale = 160.0 / (lightz + 1.0);\n" \ + "return startmap * 1.05 - scale * 1.0 * 1.1;\n" \ + "}\n" + #define GLSL_DOOM_LIGHT_EQUATION \ "float R_DoomLightingEquation(float light)\n" \ "{\n" \ @@ -631,16 +684,16 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS]; "}\n" \ "final_color = mix(final_color, fade_color, darkness);\n" -#define GLSL_SOFTWARE_FRAGMENT_SHADER \ +#define GLSL_SOFTWARE_UNIFORMS \ "uniform sampler2D tex;\n" \ "uniform vec4 poly_color;\n" \ "uniform vec4 tint_color;\n" \ "uniform vec4 fade_color;\n" \ "uniform float lighting;\n" \ "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ + "uniform float fade_end;\n" + +#define GLSL_SOFTWARE_MAIN \ "void main(void) {\n" \ "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ "vec4 base_color = texel * poly_color;\n" \ @@ -649,7 +702,59 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS]; GLSL_SOFTWARE_FADE_EQUATION \ "final_color.a = texel.a * poly_color.a;\n" \ "gl_FragColor = final_color;\n" \ - "}\0" + "}\n" + +#define GLSL_SOFTWARE_FRAGMENT_SHADER_FLOORS \ + GLSL_SOFTWARE_UNIFORMS \ + GLSL_DOOM_COLORMAP_floors \ + GLSL_DOOM_LIGHT_EQUATION \ + GLSL_SOFTWARE_MAIN \ + "\0" + +#define GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS \ + GLSL_SOFTWARE_UNIFORMS \ + GLSL_DOOM_COLORMAP_walls \ + GLSL_DOOM_LIGHT_EQUATION \ + GLSL_SOFTWARE_MAIN \ + "\0" + +#define GLSL_SOFTWARE_PAL_UNIFORMS \ + "uniform sampler2D tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + "uniform sampler3D lookup_tex;\n" \ + "uniform int palette[768];\n" \ + "uniform vec4 poly_color;\n" \ + "uniform float lighting;\n" \ + +#define GLSL_SOFTWARE_PAL_MAIN \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "int tex_pal_idx = int(texture3D(lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0);\n" \ + "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ + "int light_y = int(clamp(floor(R_DoomColormap(lighting, z)), 0.0, 31.0));\n" \ + "vec2 lighttable_coord = vec2((float(tex_pal_idx) + 0.5) / 256.0, (float(light_y) + 0.5) / 32.0);\n" \ + "int final_idx = int(texture2D(lighttable_tex, lighttable_coord)[0] * 255.0);\n" \ + "vec4 final_color = vec4(float(palette[final_idx*3])/255.0, float(palette[final_idx*3+1])/255.0, float(palette[final_idx*3+2])/255.0, 1.0);\n" \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\n" + +#define GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_FLOORS \ + GLSL_SOFTWARE_PAL_UNIFORMS \ + GLSL_DOOM_COLORMAP_floors \ + GLSL_SOFTWARE_PAL_MAIN \ + "\0" + +#define GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_WALLS \ + GLSL_SOFTWARE_PAL_UNIFORMS \ + GLSL_DOOM_COLORMAP_walls \ + GLSL_SOFTWARE_PAL_MAIN \ + "\0" + +#define GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_POSTPROCESS \ + GLSL_SOFTWARE_PAL_UNIFORMS \ + GLSL_SOFTWARE_PAL_MAIN \ + "\0" // // Water surface shader @@ -708,6 +813,20 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS]; GLSL_SOFTWARE_FADE_EQUATION \ "gl_FragColor = final_color;\n" \ "}\0" + +// +// Palette color quantization shader +// + +#define GLSL_PALETTE_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D lookup_tex;\n" \ + "uniform int palette[768];\n" \ + "void main(void) {\n" \ + "vec3 texel = vec3(texture2D(tex, gl_TexCoord[0].st));\n" \ + "int pal_idx = int(texture3D(lookup_tex, vec3((63.0/64.0) * texel + 1.0 / 128.0))[0] * 255.0);\n" \ + "gl_FragColor = vec4(float(palette[pal_idx*3])/255.0, float(palette[pal_idx*3+1])/255.0, float(palette[pal_idx*3+2])/255.0, 1.0);\n" \ + "}\0" // // GLSL generic fragment shader @@ -725,16 +844,16 @@ static const char *fragment_shaders[] = { GLSL_DEFAULT_FRAGMENT_SHADER, // Floor fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER, + GLSL_SOFTWARE_FRAGMENT_SHADER_FLOORS, // Wall fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER, + GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS, // Sprite fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER, + GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS, // Model fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER, + GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS, // Water fragment shader GLSL_WATER_FRAGMENT_SHADER, @@ -747,6 +866,15 @@ static const char *fragment_shaders[] = { "void main(void) {\n" "gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" "}\0", + + // Palette fragment shader + GLSL_PALETTE_FRAGMENT_SHADER, + + GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_FLOORS, + + GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_WALLS, + + GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_POSTPROCESS, NULL, }; @@ -792,6 +920,13 @@ static const char *vertex_shaders[] = { // Sky vertex shader GLSL_DEFAULT_VERTEX_SHADER, + + // Palette vertex shader + GLSL_DEFAULT_VERTEX_SHADER, + + GLSL_DEFAULT_VERTEX_SHADER, + + GLSL_DEFAULT_VERTEX_SHADER, NULL, }; @@ -800,6 +935,7 @@ static const char *vertex_shaders[] = { void SetupGLFunc4(void) { + pglTexImage3D = GetGLFunc("glTexImage3D"); pglActiveTexture = GetGLFunc("glActiveTexture"); pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f"); pglClientActiveTexture = GetGLFunc("glClientActiveTexture"); @@ -826,6 +962,7 @@ void SetupGLFunc4(void) pglGetProgramiv = GetGLFunc("glGetProgramiv"); pglUseProgram = GetGLFunc("glUseProgram"); pglUniform1i = GetGLFunc("glUniform1i"); + pglUniform1iv = GetGLFunc("glUniform1iv"); pglUniform1f = GetGLFunc("glUniform1f"); pglUniform2f = GetGLFunc("glUniform2f"); pglUniform3f = GetGLFunc("glUniform3f"); @@ -858,12 +995,13 @@ EXPORT boolean HWRAPI(LoadShaders) (void) const GLchar* vert_shader = vertex_shaders[i]; const GLchar* frag_shader = fragment_shaders[i]; boolean custom = cv_grusecustomshaders.value && ((gl_customvertexshaders[i] || gl_customfragmentshaders[i]) && (i > 0)); - + // 18032019 if (cv_grusecustomshaders.value && gl_customvertexshaders[i]) vert_shader = gl_customvertexshaders[i]; if (cv_grusecustomshaders.value && gl_customfragmentshaders[i]) frag_shader = gl_customfragmentshaders[i]; + if (i >= MAXSHADERS) break; @@ -946,11 +1084,38 @@ EXPORT boolean HWRAPI(LoadShaders) (void) shader->uniforms[gluniform_lighting] = GETUNI("lighting"); shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); - + + // palette rendering + shader->uniforms[gluniform_palette] = GETUNI("palette"); + shader->uniforms[gluniform_color_lookup] = GETUNI("lookup_tex"); + shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex"); + // misc. (custom shaders) shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); - + #undef GETUNI + +// set permanent uniform values +#define UNIFORM_1(uniform, a, function) \ + if (uniform != -1) \ + function (uniform, a); + +#define UNIFORM_2(uniform, a, b, function) \ + if (uniform != -1) \ + function (uniform, a, b); + + pglUseProgram(shader->program); + + // texture unit numbers for the samplers used for palette rendering + UNIFORM_2(shader->uniforms[gluniform_palette], 768, gl_palette, pglUniform1iv); + UNIFORM_1(shader->uniforms[gluniform_color_lookup], 1, pglUniform1i); + UNIFORM_1(shader->uniforms[gluniform_lighttable_tex], 2, pglUniform1i); + + pglUseProgram(0); + +#undef UNIFORM_1 +#undef UNIFORM_2 + } #endif return true; @@ -962,7 +1127,9 @@ EXPORT boolean HWRAPI(LoadShaders) (void) EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment) { #ifdef GL_SHADERS - if (!pglUseProgram) return; + if (!pglUseProgram) + return; + if (number < 1 || number > MAXSHADERS) I_Error("LoadCustomShader(): cannot load shader %d (max %d)", number, MAXSHADERS); @@ -984,8 +1151,14 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boo EXPORT void HWRAPI(InitCustomShaders) (void) { #ifdef GL_SHADERS + KillShaders(); LoadShaders(); + + if (gl_use_palette_shader) + { + InitPalette(0, false); + } #endif } @@ -1022,6 +1195,105 @@ EXPORT void HWRAPI(KillShaders) (void) // unused......................... } +GLuint palette_tex_num; +// length of one side of lookup texture +// smallest separation between all the colors in the srb2 palette is 6, so +// possibly a 64x64x64 lookup texture might be enough for 100% correct colors +// (min separation for 64^3 size is 4) +#define LUT_SIZE 64 +#define STEP_SIZE (256/LUT_SIZE) +// the +2 in the NearestColor call also needs to be adjusted if LUT_SIZE is changed! +// the hardcoded values in the shader also need to be adjusted if LUT_SIZE is changed! + +void InitPalette(int flashnum, boolean skiplut) +{ + int i, r, g, b; + + //Hudler: 16/10/99: added for OpenGL gamma correction + RGBA_t gamma_correction = {0x7F7F7F7F}; + + //Hurdler 16/10/99: added for OpenGL gamma correction + gamma_correction.s.red = (UINT8)cv_grgammared.value; + gamma_correction.s.green = (UINT8)cv_grgammagreen.value; + gamma_correction.s.blue = (UINT8)cv_grgammablue.value; + + // init the palette + int flashoffset = flashnum*256; + for (i = 0+flashoffset; i < 256+flashoffset; i++) + { + int fi = i-flashoffset; + + // gamma correction + int pr, pg, pb; + pr = (UINT8)MIN((pLocalPalette[i].s.red*gamma_correction.s.red)/127, 255); + pg = (UINT8)MIN((pLocalPalette[i].s.green*gamma_correction.s.green)/127, 255); + pb = (UINT8)MIN((pLocalPalette[i].s.blue*gamma_correction.s.blue)/127, 255); + + // crush to 16-bit rgb565, like software currently does + float fred = (float)(pr >> 3); + float fgreen = (float)(pg >> 2); + float fblue = (float)(pb >> 3); + // restore to rgb888 + gl_palette[fi*3] = (GLint)(fred / 31.0f * 255.0f); + gl_palette[fi*3+1] = (GLint)(fgreen / 63.0f * 255.0f); + gl_palette[fi*3+2] = (GLint)(fblue / 31.0f * 255.0f); + } + + if (!skiplut) + { + // init the palette conversion lookup texture + GLubyte *pal_lookup_tex = malloc(LUT_SIZE*LUT_SIZE*LUT_SIZE*sizeof(GLubyte)); + + if (!pal_lookup_tex) + I_Error("Failed to allocate memory for generating palette lookup texture."); + + for (b = 0; b < LUT_SIZE; b++) + { + for (g = 0; g < LUT_SIZE; g++) + { + for (r = 0; r < LUT_SIZE; r++) + { + pal_lookup_tex[b*LUT_SIZE*LUT_SIZE+g*LUT_SIZE+r] = NearestColor(r*STEP_SIZE+0, g*STEP_SIZE+0, b*STEP_SIZE+0); + } + } + } + + pglGenTextures(1, &palette_tex_num); + pglBindTexture(GL_TEXTURE_3D, palette_tex_num); + pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + if (!pglTexImage3D) + I_Error("pglTexImage3D is NULL!"); + pglTexImage3D(GL_TEXTURE_3D, 0, GL_R8, LUT_SIZE, LUT_SIZE, LUT_SIZE, 0, GL_RED, GL_UNSIGNED_BYTE, pal_lookup_tex); + free(pal_lookup_tex); + } +#undef STEP_SIZE + + pglUseProgram(gl_shaderprograms[8].program); + pglUniform1i(gl_shaderprograms[8].uniforms[gluniform_color_lookup], 1); // bind sampler to second texture unit + pglUniform1iv(gl_shaderprograms[8].uniforms[gluniform_palette], 768, gl_palette); + // bind the palette to the fancy shader here + pglUseProgram(gl_shaderprograms[9].program); + pglUniform1iv(gl_shaderprograms[9].uniforms[gluniform_palette], 768, gl_palette); + // bind tex unit 2 to lighttable tex + pglUniform1i(gl_shaderprograms[9].uniforms[gluniform_lighttable_tex], 2); + pglUniform1i(gl_shaderprograms[9].uniforms[gluniform_color_lookup], 1); + // bind the palette to the fancy shader here + pglUseProgram(gl_shaderprograms[10].program); + pglUniform1iv(gl_shaderprograms[10].uniforms[gluniform_palette], 768, gl_palette); + // bind tex unit 2 to lighttable tex + pglUniform1i(gl_shaderprograms[10].uniforms[gluniform_lighttable_tex], 2); + pglUniform1i(gl_shaderprograms[10].uniforms[gluniform_color_lookup], 1); + pglUseProgram(0); + pglBindTexture(GL_TEXTURE_3D, 0); + + // bind 3d lookup to unit 1, maybe it can stay there + pglActiveTexture(GL_TEXTURE1); + pglBindTexture(GL_TEXTURE_3D, palette_tex_num); + pglActiveTexture(GL_TEXTURE0); + gl_palette_initialized = true; +} + // -----------------+ // SetNoTexture : Disable texture // -----------------+ @@ -1201,6 +1473,46 @@ EXPORT void HWRAPI(ClearMipMapCache) (void) Flush(); } +EXPORT UINT32 HWRAPI(AddLightTable) (UINT8 *lighttable) +{ + LightTableCacheEntry_t *cache_entry = malloc(sizeof(LightTableCacheEntry_t)); + if (!ltcachetail) + { + ltcachehead = ltcachetail = cache_entry; + } + else + { + ltcachetail->next = cache_entry; + ltcachetail = cache_entry; + } + ltcachetail->next = NULL; + pglGenTextures(1, <cachetail->id); + if (!ltcachetail->id) + I_Error("hwr lighttable cache entry id is zero"); + pglBindTexture(GL_TEXTURE_2D, ltcachetail->id); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 256, 32, 0, GL_RED, GL_UNSIGNED_BYTE, lighttable); + + // restore previously bound texture + if (!gl_batching) + pglBindTexture(GL_TEXTURE_2D, tex_downloaded); + + return ltcachetail->id; +} + +// Delete light table textures, ids given before become invalid and must not be used. +EXPORT void HWRAPI(ClearLightTableCache) (void) +{ + while (ltcachehead) + { + pglDeleteTextures(1, <cachehead->id); + LightTableCacheEntry_t *next = ltcachehead->next; + free(ltcachehead); + ltcachehead = next; + } + ltcachetail = NULL; +} // -----------------+ // ReadRect : Read a rectangle region of the truecolor framebuffer @@ -1312,6 +1624,9 @@ EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, pglClear(ClearMask); pglEnableClientState(GL_VERTEX_ARRAY); // We always use this one pglEnableClientState(GL_TEXTURE_COORD_ARRAY); // And mostly this one, too + + if (!gl_palette_initialized) + InitPalette(0, false); // just gonna put this here for now } @@ -1886,6 +2201,12 @@ static int comparePolygons(const void *p1, const void *p2) diff = poly1->texNum - poly2->texNum; if (diff != 0) return diff; + + if (gl_use_palette_shader) + { + diff = poly1->surf.LightTableId - poly2->surf.LightTableId; + if (diff != 0) return diff; + } diff = poly1->polyFlags - poly2->polyFlags; if (diff != 0) return diff; @@ -2024,7 +2345,15 @@ EXPORT void HWRAPI(RenderBatches) (precise_t *sSortTime, precise_t *sDrawTime, i firstFade.alpha = byte2float[currentSurfaceInfo.FadeColor.s.alpha]; if (gl_allowshaders) + { load_shaders(¤tSurfaceInfo, &firstPoly, &firstTint, &firstFade); + if (gl_use_palette_shader) + { + pglActiveTexture(GL_TEXTURE2);// this stuff could be done better but gonna do it quick like this for now + pglBindTexture(GL_TEXTURE_2D, currentSurfaceInfo.LightTableId); + pglActiveTexture(GL_TEXTURE0); + } + } if (currentPolyFlags & PF_NoTexture) currentTexture = 0; @@ -2135,7 +2464,21 @@ EXPORT void HWRAPI(RenderBatches) (precise_t *sSortTime, precise_t *sDrawTime, i changeState = true; changePolyFlags = true; } - if (gl_allowshaders) + if ((gl_allowshaders) && (gl_use_palette_shader)) + { + if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba || + currentSurfaceInfo.TintColor.rgba != nextSurfaceInfo.TintColor.rgba || + currentSurfaceInfo.FadeColor.rgba != nextSurfaceInfo.FadeColor.rgba || + currentSurfaceInfo.LightInfo.light_level != nextSurfaceInfo.LightInfo.light_level || + currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start || + currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end || + currentSurfaceInfo.LightTableId != nextSurfaceInfo.LightTableId) + { + changeState = true; + changeSurfaceInfo = true; + } + } + else if ((gl_allowshaders) && (!gl_use_palette_shader)) { if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba || currentSurfaceInfo.TintColor.rgba != nextSurfaceInfo.TintColor.rgba || @@ -2265,7 +2608,15 @@ EXPORT void HWRAPI(RenderBatches) (precise_t *sSortTime, precise_t *sDrawTime, i fade.alpha = byte2float[nextSurfaceInfo.FadeColor.s.alpha]; load_shaders(&nextSurfaceInfo, &poly, &tint, &fade); + + if (gl_use_palette_shader) + { + pglActiveTexture(GL_TEXTURE2);// this stuff could be done better but gonna do it quick like this for now + pglBindTexture(GL_TEXTURE_2D, nextSurfaceInfo.LightTableId); + pglActiveTexture(GL_TEXTURE0); + } } + currentSurfaceInfo = nextSurfaceInfo; changeSurfaceInfo = false; @@ -2365,6 +2716,13 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI fade.green = byte2float[pSurf->FadeColor.s.green]; fade.blue = byte2float[pSurf->FadeColor.s.blue]; fade.alpha = byte2float[pSurf->FadeColor.s.alpha]; + + if (gl_use_palette_shader && gl_allowshaders) + { + pglActiveTexture(GL_TEXTURE2); + pglBindTexture(GL_TEXTURE_2D, pSurf->LightTableId); + pglActiveTexture(GL_TEXTURE0); + } } load_shaders(pSurf, &poly, &tint, &fade); @@ -2707,6 +3065,10 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) break; } break; + + case HWD_SET_PALETTE_SHADER_ENABLED: + gl_use_palette_shader = Value; + break; case HWD_SET_TEXTUREFILTERMODE: switch (Value) @@ -3775,6 +4137,12 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) clearColour.alpha = 1; ClearBuffer(true, false, false, &clearColour); pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); + + if (gl_use_palette_shader && cv_grshaders.value) + { + pglUseProgram(gl_shaderprograms[8].program); // palette shader + pglActiveTexture(GL_TEXTURE1); + } pglColor4ubv(white); pglTexCoordPointer(2, GL_FLOAT, 0, fix); @@ -3783,6 +4151,12 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); tex_downloaded = finalScreenTexture; + + if (gl_use_palette_shader && cv_grshaders.value) + { + pglUseProgram(0); + pglActiveTexture(GL_TEXTURE0); + } } #endif //HWRENDER diff --git a/src/hardware/r_opengl/r_opengl.h b/src/hardware/r_opengl/r_opengl.h index 6d11bf4e3..8bce7d15b 100644 --- a/src/hardware/r_opengl/r_opengl.h +++ b/src/hardware/r_opengl/r_opengl.h @@ -133,4 +133,8 @@ typedef enum GLF_NOTEXENV = 0x02, } oglflags_t; +// in order for custom playpals n shit to work properly +extern boolean gl_palette_initialized; +void InitPalette(int flashnum, boolean skiplut); + #endif diff --git a/src/m_menu.c b/src/m_menu.c index 980a4c694..86759d8dc 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1347,7 +1347,8 @@ static menuitem_t OP_OpenGLOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "3D Models", &cv_grmdls, 5}, {IT_STRING | IT_CVAR, NULL, "Fallback Player 3D Model", &cv_grfallbackplayermodel, 15}, {IT_STRING|IT_CVAR, NULL, "Shaders", &cv_grshaders, 25}, - {IT_STRING|IT_CVAR, NULL, "Use custom Shaders", &cv_grusecustomshaders, 35}, + //{IT_STRING|IT_CVAR, NULL, "Use custom Shaders", &cv_grusecustomshaders, 35}, + {IT_STRING|IT_CVAR, NULL, "Palette Rendering", &cv_grpaletteshader, 35}, {IT_STRING | IT_CVAR, NULL, "Min Shader Brightness", &cv_secbright, 45}, {IT_STRING|IT_CVAR, NULL, "Texture Quality", &cv_scr_depth, 65}, @@ -1407,7 +1408,6 @@ static menuitem_t OP_SoundOptionsMenu[] = {IT_STRING|IT_SUBMENU, NULL, "Advanced Settings...", &OP_SoundAdvancedDef, 155} }; - static menuitem_t OP_SoundAdvancedMenu[] = { #ifdef HAVE_OPENMPT @@ -1706,8 +1706,9 @@ static menuitem_t OP_SaturnMenu[] = {IT_STRING | IT_CVAR, NULL, "Show Minimap Names", &cv_showminimapnames, 80}, {IT_STRING | IT_CVAR, NULL, "Small Minimap Players", &cv_minihead, 90}, {IT_STRING | IT_CVAR, NULL, "Less Midnight Channel Flicker", &cv_lessflicker, 110}, - {IT_SUBMENU|IT_STRING, NULL, "Player distortion...", &OP_PlayerDistortDef, 130}, - {IT_SUBMENU|IT_STRING, NULL, "Hud Offsets...", &OP_HudOffsetDef, 145}, + {IT_STRING | IT_CVAR, NULL, "Flashpals in Palette Renderer", &cv_grflashpal, 120}, + {IT_SUBMENU|IT_STRING, NULL, "Player distortion...", &OP_PlayerDistortDef, 140}, + {IT_SUBMENU|IT_STRING, NULL, "Hud Offsets...", &OP_HudOffsetDef, 155}, {IT_SUBMENU|IT_STRING, NULL, "Saturn Credits", &OP_SaturnCreditsDef, 170}, // uwu }; diff --git a/src/r_data.c b/src/r_data.c index f982b0366..45c1da6cc 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -26,6 +26,10 @@ #include "v_video.h" // pLocalPalette #include "dehacked.h" +#ifdef HWRENDER +#include "hardware/hw_main.h" +#endif + #if defined (_WIN32) || defined (_WIN32_WCE) #include // alloca(sizeof) #endif @@ -1137,6 +1141,10 @@ void R_ClearColormaps(void) foundcolormaps[i] = LUMPERROR; memset(extra_colormaps, 0, sizeof (extra_colormaps)); + +#ifdef HWRENDER + HWR_ClearLightTableCache(); +#endif } /*INT32 R_ColormapNumForName(char *name) @@ -1316,13 +1324,13 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) extra_colormaps[mapnum].fadestart = (UINT16)fadestart; extra_colormaps[mapnum].fadeend = (UINT16)fadeend; extra_colormaps[mapnum].fog = fog; - - if (rendermode == render_soft) - { + + if (rendermode == render_soft || rendermode == render_opengl) + { double r, g, b, cbrightness; int p; lighttable_t *colormap_p; - + // Initialise the map and delta arrays // map[i] stores an RGB color (as double) for index i, // which is then converted to SRB2's palette later @@ -1402,7 +1410,7 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) } } } - + return (INT32)mapnum; } diff --git a/src/r_data.h b/src/r_data.h index f371d40d7..6a8806988 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -104,6 +104,4 @@ UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); extern INT32 numtextures; -UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); - #endif diff --git a/src/r_defs.h b/src/r_defs.h index 559e3646b..7254a6289 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -62,6 +62,12 @@ typedef struct INT32 fadergba; // The colour the colourmaps fade to lighttable_t *colormap; + + +#ifdef HWRENDER + // The id of the hardware lighttable. Zero means it does not exist yet. + UINT32 gl_lighttable_id; +#endif } extracolormap_t; // diff --git a/src/r_main.c b/src/r_main.c index dc914e79a..34efa13b8 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1955,6 +1955,8 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_grshearing); CV_RegisterVar(&cv_grshaders); CV_RegisterVar(&cv_grusecustomshaders); + CV_RegisterVar(&cv_grpaletteshader); + CV_RegisterVar(&cv_grflashpal); #endif #ifdef HWRENDER diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 2627c3fdb..dcaaa7f51 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -113,6 +113,9 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(StartBatching); GETFUNC(RenderBatches); + + GETFUNC(AddLightTable); + GETFUNC(ClearLightTableCache); #else //HWRENDER if (0 == strcmp("FinishUpdate", funcName)) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index d08b267f0..16dfc716a 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -2148,6 +2148,9 @@ void I_StartupGraphics(void) HWD.pfnStartBatching = hwSym("StartBatching",NULL); HWD.pfnRenderBatches = hwSym("RenderBatches",NULL); + + HWD.pfnAddLightTable = hwSym("AddLightTable",NULL); + HWD.pfnClearLightTableCache = hwSym("ClearLightTableCache",NULL); if (!HWD.pfnInit()) // load the OpenGL library rendermode = render_soft; diff --git a/src/st_stuff.c b/src/st_stuff.c index 966a0c9c6..10be523aa 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -232,18 +232,22 @@ void ST_doPaletteStuff(void) else palette = 0; + palette = min(max(palette, 0), 13); + #ifdef HWRENDER - if (rendermode == render_opengl) + if (rendermode == render_opengl && !cv_grpaletteshader.value || rendermode == render_opengl && cv_grpaletteshader.value && !cv_grflashpal.value) palette = 0; // No flashpals here in OpenGL #endif - palette = min(max(palette, 0), 13); - if (palette != st_palette) { st_palette = palette; - if (rendermode == render_soft) +#ifdef HWRENDER + if (rendermode != render_none && cv_grpaletteshader.value && cv_grflashpal.value) +#else + if (rendermode != render_none) +#endif { //V_SetPaletteLump(GetPalette()); // Reset the palette -- is this needed? if (!splitscreen) @@ -2167,9 +2171,9 @@ void ST_Drawer(void) //25/08/99: Hurdler: palette changes is done for all players, // not only player1! That's why this part // of code is moved somewhere else. - if (rendermode == render_soft) + if (rendermode == render_soft || rendermode == render_opengl && cv_grpaletteshader.value && cv_grflashpal.value) #endif - if (rendermode != render_none) ST_doPaletteStuff(); + if (rendermode != render_none) ST_doPaletteStuff(); if (st_overlay) { diff --git a/src/v_video.c b/src/v_video.c index 602e89248..dbe26a001 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -28,6 +28,7 @@ #ifdef HWRENDER #include "hardware/hw_main.h" +#include "hardware/r_opengl/r_opengl.h" #endif // Each screen is [vid.width*vid.height]; @@ -224,8 +225,17 @@ void V_SetPalette(INT32 palettenum) LoadMapPalette(); #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) - HWR_SetPalette(&pLocalPalette[palettenum*256]); + if (rendermode != render_soft && rendermode != render_none) { + // in palette rendering mode, we already manage our palette ourselves + if (cv_grpaletteshader.value == 1) + { + // reset our palette lookups n shit + gl_palette_initialized = false; + InitPalette(palettenum, true); + } + else + HWR_SetPalette(pLocalPalette); + } #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) else #endif @@ -238,8 +248,16 @@ void V_SetPaletteLump(const char *pal) { LoadPalette(pal); #ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) - HWR_SetPalette(pLocalPalette); + if (rendermode != render_soft && rendermode != render_none) { + if (cv_grpaletteshader.value == 1) + { + // reset our palette lookups n shit + gl_palette_initialized = false; + InitPalette(0, false); + } + else + HWR_SetPalette(pLocalPalette); + } #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) else #endif