From ff98d3b28af08ffdb2300bae1e7c05ee6086960a Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sun, 19 Apr 2020 18:19:16 +0300 Subject: [PATCH 01/12] Fix skywalls in ogl. Similar to c3f6f263 in master. --- src/hardware/hw_main.c | 238 ++++++++++++++++++++++++++--------------- src/hardware/hw_main.h | 2 +- 2 files changed, 152 insertions(+), 88 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index b41d2ff6..87d1f0a7 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -854,7 +854,7 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa // HWR_DrawSkyWalls // Draw walls into the depth buffer so that anything behind is culled properly -void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf, fixed_t bottom, fixed_t top) +void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf) { HWD.pfnSetTexture(NULL); // no texture @@ -863,12 +863,6 @@ void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf, fixed_t bottom, wallVerts[0].s = wallVerts[3].s = 0; wallVerts[2].s = wallVerts[1].s = 0; - if (bottom != 0 || top != 0) - { - // set top/bottom coords - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(top); // No real way to find the correct height of this - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(bottom); // worldlow/bottom because it needs to cover up the lower thok barrier wall - } HWR_ProjectWall(wallVerts, Surf, PF_Invisible|PF_NoTexture, 255, NULL); // PF_Invisible so it's not drawn into the colour buffer // PF_NoTexture for no texture @@ -976,6 +970,109 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom worldlow = gr_backsector->floorheight; #endif + // Sky culling + if (!gr_curline->polyseg) // Don't do it for polyobjects + { + // Sky Ceilings + wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(INT32_MAX); + + if (gr_frontsector->ceilingpic == skyflatnum) + { + if (gr_backsector->ceilingpic == skyflatnum) + { + // Both front and back sectors are sky, needs skywall from the frontsector's ceiling, but only if the + // backsector is lower + if ((worldhigh <= worldtop && worldhighslope <= worldtopslope)// Assuming ESLOPE is always on with my changes + && (worldhigh != worldtop || worldhighslope != worldtopslope)) + // Removing the second line above will render more rarely visible skywalls. Example: Cave garden ceiling in Dark race + { +#ifdef ESLOPE + wallVerts[0].y = FIXED_TO_FLOAT(worldhigh); + wallVerts[1].y = FIXED_TO_FLOAT(worldhighslope); +#else + wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldhigh); +#endif + HWR_DrawSkyWall(wallVerts, &Surf); + } + } + else + { + // Only the frontsector is sky, just draw a skywall from the front ceiling +#ifdef ESLOPE + wallVerts[0].y = FIXED_TO_FLOAT(worldtop); + wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope); +#else + wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldtop); +#endif + HWR_DrawSkyWall(wallVerts, &Surf); + } + } + else if (gr_backsector->ceilingpic == skyflatnum) + { + // Only the backsector is sky, just draw a skywall from the front ceiling +#ifdef ESLOPE + wallVerts[0].y = FIXED_TO_FLOAT(worldtop); + wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope); +#else + wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldtop); +#endif + HWR_DrawSkyWall(wallVerts, &Surf); + } + + + // Sky Floors + wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); + + if (gr_frontsector->floorpic == skyflatnum) + { + if (gr_backsector->floorpic == skyflatnum) + { + // Both front and back sectors are sky, needs skywall from the backsector's floor, but only if the + // it's higher, also needs to check for bottomtexture as the floors don't usually move down + // when both sides are sky floors + if ((worldlow >= worldbottom && worldlowslope >= worldbottomslope) + && (worldlow != worldbottom || worldlowslope != worldbottomslope) + // Removing the second line above will render more rarely visible skywalls. Example: Cave garden ceiling in Dark race + && !(gr_sidedef->bottomtexture)) + { +#ifdef ESLOPE + wallVerts[3].y = FIXED_TO_FLOAT(worldlow); + wallVerts[2].y = FIXED_TO_FLOAT(worldlowslope); +#else + wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(worldlow); +#endif + + HWR_DrawSkyWall(wallVerts, &Surf); + } + } + else + { + // Only the backsector has sky, just draw a skywall from the back floor +#ifdef ESLOPE + wallVerts[3].y = FIXED_TO_FLOAT(worldbottom); + wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope); +#else + wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(worldbottom); +#endif + + HWR_DrawSkyWall(wallVerts, &Surf); + } + } + else if ((gr_backsector->floorpic == skyflatnum) && !(gr_sidedef->bottomtexture)) + { + // Only the backsector has sky, just draw a skywall from the back floor if there's no bottomtexture +#ifdef ESLOPE + wallVerts[3].y = FIXED_TO_FLOAT(worldlow); + wallVerts[2].y = FIXED_TO_FLOAT(worldlowslope); +#else + wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(worldlow); +#endif + + HWR_DrawSkyWall(wallVerts, &Surf); + } + + } + // hack to allow height changes in outdoor areas // This is what gets rid of the upper textures if there should be sky if (gr_frontsector->ceilingpic == skyflatnum && @@ -1421,86 +1518,6 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom else HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap); } - - // Isn't this just the most lovely mess - if (!gr_curline->polyseg) // Don't do it for polyobjects - { - if (gr_frontsector->ceilingpic == skyflatnum || gr_backsector->ceilingpic == skyflatnum) - { - fixed_t depthwallheight; - - if (!gr_sidedef->toptexture || (gr_frontsector->ceilingpic == skyflatnum && gr_backsector->ceilingpic == skyflatnum)) // when both sectors are sky, the top texture isn't drawn - depthwallheight = gr_frontsector->ceilingheight < gr_backsector->ceilingheight ? gr_frontsector->ceilingheight : gr_backsector->ceilingheight; - else - depthwallheight = gr_frontsector->ceilingheight > gr_backsector->ceilingheight ? gr_frontsector->ceilingheight : gr_backsector->ceilingheight; - - if (gr_frontsector->ceilingheight-gr_frontsector->floorheight <= 0) // current sector is a thok barrier - { - if (gr_backsector->ceilingheight-gr_backsector->floorheight <= 0) // behind sector is also a thok barrier - { - if (!gr_sidedef->bottomtexture) // Only extend further down if there's no texture - HWR_DrawSkyWall(wallVerts, &Surf, worldbottom < worldlow ? worldbottom : worldlow, INT32_MAX); - else - HWR_DrawSkyWall(wallVerts, &Surf, worldbottom > worldlow ? worldbottom : worldlow, INT32_MAX); - } - // behind sector is not a thok barrier - else if (gr_backsector->ceilingheight <= gr_frontsector->ceilingheight) // behind sector ceiling is lower or equal to current sector - HWR_DrawSkyWall(wallVerts, &Surf, depthwallheight, INT32_MAX); - // gr_front/backsector heights need to be used here because of the worldtop being set to worldhigh earlier on - } - else if (gr_backsector->ceilingheight-gr_backsector->floorheight <= 0) // behind sector is a thok barrier, current sector is not - { - if (gr_backsector->ceilingheight >= gr_frontsector->ceilingheight // thok barrier ceiling height is equal to or greater than current sector ceiling height - || gr_backsector->floorheight <= gr_frontsector->floorheight // thok barrier ceiling height is equal to or less than current sector floor height - || gr_backsector->ceilingpic != skyflatnum) // thok barrier is not a sky - HWR_DrawSkyWall(wallVerts, &Surf, depthwallheight, INT32_MAX); - } - else // neither sectors are thok barriers - { - if ((gr_backsector->ceilingheight < gr_frontsector->ceilingheight && !gr_sidedef->toptexture) // no top texture and sector behind is lower - || gr_backsector->ceilingpic != skyflatnum) // behind sector is not a sky - HWR_DrawSkyWall(wallVerts, &Surf, depthwallheight, INT32_MAX); - } - } - // And now for sky floors! - if (gr_frontsector->floorpic == skyflatnum || gr_backsector->floorpic == skyflatnum) - { - fixed_t depthwallheight; - - if (!gr_sidedef->bottomtexture) - depthwallheight = worldbottom > worldlow ? worldbottom : worldlow; - else - depthwallheight = worldbottom < worldlow ? worldbottom : worldlow; - - if (gr_frontsector->ceilingheight-gr_frontsector->floorheight <= 0) // current sector is a thok barrier - { - if (gr_backsector->ceilingheight-gr_backsector->floorheight <= 0) // behind sector is also a thok barrier - { - if (!gr_sidedef->toptexture) // Only extend up if there's no texture - HWR_DrawSkyWall(wallVerts, &Surf, INT32_MIN, worldtop > worldhigh ? worldtop : worldhigh); - else - HWR_DrawSkyWall(wallVerts, &Surf, INT32_MIN, worldtop < worldhigh ? worldtop : worldhigh); - } - // behind sector is not a thok barrier - else if (gr_backsector->floorheight >= gr_frontsector->floorheight) // behind sector floor is greater or equal to current sector - HWR_DrawSkyWall(wallVerts, &Surf, INT32_MIN, depthwallheight); - } - else if (gr_backsector->ceilingheight-gr_backsector->floorheight <= 0) // behind sector is a thok barrier, current sector is not - { - if (gr_backsector->floorheight <= gr_frontsector->floorheight // thok barrier floor height is equal to or less than current sector floor height - || gr_backsector->ceilingheight >= gr_frontsector->ceilingheight // thok barrier floor height is equal to or greater than current sector ceiling height - || gr_backsector->floorpic != skyflatnum) // thok barrier is not a sky - HWR_DrawSkyWall(wallVerts, &Surf, INT32_MIN, depthwallheight); - } - else // neither sectors are thok barriers - { - if (((gr_backsector->floorheight > gr_frontsector->floorheight && !gr_sidedef->bottomtexture) // no bottom texture and sector behind is higher - || gr_backsector->floorpic != skyflatnum) // behind sector is not a sky - && ABS(gr_backsector->floorheight - gr_frontsector->floorheight) > FRACUNIT*3/2) // don't draw sky walls for VERY thin differences, this makes for horrible looking slopes sometimes! - HWR_DrawSkyWall(wallVerts, &Surf, INT32_MIN, depthwallheight); - } - } - } } else { @@ -1568,6 +1585,53 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap); } } + else + { +#ifdef ESLOPE + //Set textures properly on single sided walls that are sloped + wallVerts[3].y = FIXED_TO_FLOAT(worldtop); + wallVerts[0].y = FIXED_TO_FLOAT(worldbottom); + wallVerts[2].y = FIXED_TO_FLOAT(worldtopslope); + wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope); +#else + // set top/bottom coords + wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(worldtop); + wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldbottom); +#endif + + // When there's no midtexture, draw a skywall to prevent rendering behind it + HWR_DrawSkyWall(wallVerts, &Surf); + } + + + // Single sided lines are simple for skywalls, just need to draw from the top or bottom of the sector if there's + // a sky flat + if (!gr_curline->polyseg) + { + if (gr_frontsector->ceilingpic == skyflatnum) // It's a single-sided line with sky for its sector + { + wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(INT32_MAX); +#ifdef ESLOPE + wallVerts[0].y = FIXED_TO_FLOAT(worldtop); + wallVerts[1].y = FIXED_TO_FLOAT(worldtopslope); +#else + wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(worldtop); +#endif + HWR_DrawSkyWall(wallVerts, &Surf); + } + if (gr_frontsector->floorpic == skyflatnum) + { +#ifdef ESLOPE + wallVerts[3].y = FIXED_TO_FLOAT(worldbottom); + wallVerts[2].y = FIXED_TO_FLOAT(worldbottomslope); +#else + wallVerts[3].y = wallVerts[2].y = FIXED_TO_FLOAT(worldbottom); +#endif + wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); + + HWR_DrawSkyWall(wallVerts, &Surf); + } + } } diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 91a95a30..8ffb5890 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -102,7 +102,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap); void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo * pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap); void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor); -void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf, fixed_t bottom, fixed_t top); +void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf); void HWR_DrawSkyBackground(void); #ifdef POLYOBJECTS From 628bd27b88c06e912136a448f658a1ba1ebf103d Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sun, 19 Apr 2020 18:42:03 +0300 Subject: [PATCH 02/12] Fixed and faster transparency sorting for OGL. For easy comparison, check Ethereal Crystal in Abstraction Pack --- src/hardware/hw_main.c | 167 ++++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 93 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 87d1f0a7..106f2094 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -43,6 +43,8 @@ #include "../p_slopes.h" #endif +#include // qsort + #define ABS(x) ((x) < 0 ? -(x) : (x)) // ========================================================================== @@ -3897,27 +3899,65 @@ void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, numpolyplanes++; } +// putting sortindex and sortnode here so the comparator function can see them +gr_drawnode_t *sortnode; +size_t *sortindex; + +static int CompareDrawNodes(const void *p1, const void *p2) +{ + size_t n1 = *(const size_t*)p1; + size_t n2 = *(const size_t*)p2; + INT32 v1 = 0; + INT32 v2 = 0; + INT32 diff; + if (sortnode[n1].plane) + v1 = sortnode[n1].plane->drawcount; + else if (sortnode[n1].polyplane) + v1 = sortnode[n1].polyplane->drawcount; + else if (sortnode[n1].wall) + v1 = sortnode[n1].wall->drawcount; + else I_Error("n1 unknown"); + + if (sortnode[n2].plane) + v2 = sortnode[n2].plane->drawcount; + else if (sortnode[n2].polyplane) + v2 = sortnode[n2].polyplane->drawcount; + else if (sortnode[n2].wall) + v2 = sortnode[n2].wall->drawcount; + else I_Error("n2 unknown"); + + diff = v2 - v1; + if (diff == 0) I_Error("diff is zero"); + return diff; +} + +static int CompareDrawNodePlanes(const void *p1, const void *p2) +{ + size_t n1 = *(const size_t*)p1; + size_t n2 = *(const size_t*)p2; + if (!sortnode[n1].plane) I_Error("Uh.. This isn't a plane! (n1)"); + if (!sortnode[n2].plane) I_Error("Uh.. This isn't a plane! (n2)"); + return ABS(sortnode[n2].plane->fixedheight - viewz) - ABS(sortnode[n1].plane->fixedheight - viewz); +} + // HWR_RenderDrawNodes // Creates, sorts and renders a list of drawnodes for the current frame. void HWR_RenderDrawNodes(void) { - UINT32 i = 0, p = 0, prev = 0, loop; - const fixed_t pviewz = viewz; + UINT32 i = 0, p = 0; + size_t run_start = 0; // Dump EVERYTHING into a huge drawnode list. Then we'll sort it! // Could this be optimized into _AddTransparentWall/_AddTransparentPlane? // Hell yes! But sort algorithm must be modified to use a linked list. - gr_drawnode_t *sortnode = Z_Calloc((sizeof(planeinfo_t)*numplanes) + sortnode = Z_Calloc((sizeof(planeinfo_t)*numplanes) + (sizeof(polyplaneinfo_t)*numpolyplanes) + (sizeof(wallinfo_t)*numwalls) ,PU_STATIC, NULL); // todo: // However, in reality we shouldn't be re-copying and shifting all this information // that is already lying around. This should all be in some sort of linked list or lists. - size_t *sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL); - - // If true, swap the draw order. - boolean shift = false; + sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL); for (i = 0; i < numplanes; i++, p++) { @@ -3944,99 +3984,40 @@ void HWR_RenderDrawNodes(void) // through the lists of masked textures and // translucent ffloors being drawn. - // This is a bubble sort! Wahoo! + // im not sure if this sort on the next line is needed. + // it sorts the list based on the value of the 'drawcount' member of the drawnodes. + // im thinking the list might already be in that order, but i havent bothered to check yet. + // anyway doing this sort does not hurt and does not take much time. + // the while loop after this sort is important however! + qsort(sortindex, p, sizeof(size_t), CompareDrawNodes); - // Stuff is sorted: - // sortnode[sortindex[0]] = farthest away - // sortnode[sortindex[p-1]] = closest - // "i" should be closer. "prev" should be further. - // The lower drawcount is, the further it is from the screen. - - for (loop = 0; loop < p; loop++) + // try solving floor order here. for each consecutive run of floors in the list, sort that run. + while (run_start < p-1)// p-1 because a 1 plane run at the end of the list does not count { - for (i = 1; i < p; i++) + // locate run start + if (sortnode[sortindex[run_start]].plane) { - prev = i-1; - if (sortnode[sortindex[i]].plane) + // found it, now look for run end + size_t run_end;// (inclusive) + for (i = run_start+1; i < p; i++)// size_t and UINT32 being used mixed here... shouldnt break anything though.. { - // What are we comparing it with? - if (sortnode[sortindex[prev]].plane) - { - // Plane (i) is further away than plane (prev) - if (ABS(sortnode[sortindex[i]].plane->fixedheight - pviewz) > ABS(sortnode[sortindex[prev]].plane->fixedheight - pviewz)) - shift = true; - } - if (sortnode[sortindex[prev]].polyplane) - { - // Plane (i) is further away than polyplane (prev) - if (ABS(sortnode[sortindex[i]].plane->fixedheight - pviewz) > ABS(sortnode[sortindex[prev]].polyplane->fixedheight - pviewz)) - shift = true; - } - else if (sortnode[sortindex[prev]].wall) - { - // Plane (i) is further than wall (prev) - if (sortnode[sortindex[i]].plane->drawcount > sortnode[sortindex[prev]].wall->drawcount) - shift = true; - } + if (!sortnode[sortindex[i]].plane) break; } - else if (sortnode[sortindex[i]].polyplane) + run_end = i-1; + if (run_end > run_start)// if there are multiple consecutive planes, not just one { - // What are we comparing it with? - if (sortnode[sortindex[prev]].plane) - { - // Plane (i) is further away than plane (prev) - if (ABS(sortnode[sortindex[i]].polyplane->fixedheight - pviewz) > ABS(sortnode[sortindex[prev]].plane->fixedheight - pviewz)) - shift = true; - } - if (sortnode[sortindex[prev]].polyplane) - { - // Plane (i) is further away than polyplane (prev) - if (ABS(sortnode[sortindex[i]].polyplane->fixedheight - pviewz) > ABS(sortnode[sortindex[prev]].polyplane->fixedheight - pviewz)) - shift = true; - } - else if (sortnode[sortindex[prev]].wall) - { - // Plane (i) is further than wall (prev) - if (sortnode[sortindex[i]].polyplane->drawcount > sortnode[sortindex[prev]].wall->drawcount) - shift = true; - } + // consecutive run of planes found, now sort it + // not sure how long these runs can be in reality... + qsort(sortindex + run_start, run_end - run_start + 1, sizeof(size_t), CompareDrawNodePlanes); } - else if (sortnode[sortindex[i]].wall) - { - // What are we comparing it with? - if (sortnode[sortindex[prev]].plane) - { - // Wall (i) is further than plane(prev) - if (sortnode[sortindex[i]].wall->drawcount > sortnode[sortindex[prev]].plane->drawcount) - shift = true; - } - if (sortnode[sortindex[prev]].polyplane) - { - // Wall (i) is further than polyplane(prev) - if (sortnode[sortindex[i]].wall->drawcount > sortnode[sortindex[prev]].polyplane->drawcount) - shift = true; - } - else if (sortnode[sortindex[prev]].wall) - { - // Wall (i) is further than wall (prev) - if (sortnode[sortindex[i]].wall->drawcount > sortnode[sortindex[prev]].wall->drawcount) - shift = true; - } - } - - if (shift) - { - size_t temp; - - temp = sortindex[prev]; - sortindex[prev] = sortindex[i]; - sortindex[i] = temp; - - shift = false; - } - - } //i++ - } // loop++ + run_start = run_end + 1;// continue looking for runs coming right after this one + } + else + { + // this wasnt the run start, try next one + run_start++; + } + } // Okay! Let's draw it all! Woo! HWD.pfnSetTransform(&atransform); From b5fb88922a2d60638eb07d9163606e61ffcdc57b Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 21 Apr 2020 22:08:52 +0300 Subject: [PATCH 03/12] Faster sprite sorting algorithm --- src/hardware/hw_main.c | 160 +++++++++++++---------------------------- 1 file changed, 51 insertions(+), 109 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 106f2094..de100385 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3685,96 +3685,44 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) // -------------------------------------------------------------------------- // Sort vissprites by distance // -------------------------------------------------------------------------- -static gr_vissprite_t gr_vsprsortedhead; + +gr_vissprite_t* gr_vsprorder[MAXVISSPRITES]; + +// For more correct transparency the transparent sprites would need to be +// sorted and drawn together with transparent surfaces. +static int CompareVisSprites(const void *p1, const void *p2) +{ + gr_vissprite_t* spr1 = *(gr_vissprite_t*const*)p1; + gr_vissprite_t* spr2 = *(gr_vissprite_t*const*)p2; + int idiff; + float fdiff; + + // make transparent sprites last + // "boolean to int" + + int transparency1 = (spr1->mobj->flags2 & MF2_SHADOW) || (spr1->mobj->frame & FF_TRANSMASK); + int transparency2 = (spr2->mobj->flags2 & MF2_SHADOW) || (spr2->mobj->frame & FF_TRANSMASK); + idiff = transparency1 - transparency2; + if (idiff != 0) return idiff; + + fdiff = spr2->tz - spr1->tz;// this order seems correct when checking with apitrace. Back to front. + if (fabsf(fdiff) < 1.0E-36f) + return spr1->dispoffset - spr2->dispoffset;// smallest dispoffset first if sprites are at (almost) same location. + else if (fdiff > 0) + return 1; + else + return -1; +} + static void HWR_SortVisSprites(void) { UINT32 i; - gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst; - gr_vissprite_t *best = NULL; - gr_vissprite_t unsorted; - float bestdist = 0.0f; - INT32 bestdispoffset = 0; - - if (!gr_visspritecount) - return; - - dsfirst = HWR_GetVisSprite(0); - - for (i = 0, dsnext = dsfirst, ds = NULL; i < gr_visspritecount; i++) - { - dsprev = ds; - ds = dsnext; - if (i < gr_visspritecount - 1) dsnext = HWR_GetVisSprite(i + 1); - - ds->next = dsnext; - ds->prev = dsprev; - } - - // Fix first and last. ds still points to the last one after the loop - dsfirst->prev = &unsorted; - unsorted.next = dsfirst; - if (ds) - ds->next = &unsorted; - unsorted.prev = ds; - - // pull the vissprites out by scale - gr_vsprsortedhead.next = gr_vsprsortedhead.prev = &gr_vsprsortedhead; for (i = 0; i < gr_visspritecount; i++) { - best = NULL; - for (ds = unsorted.next; ds != &unsorted; ds = ds->next) - { - if (!best || ds->tz > bestdist) - { - bestdist = ds->tz; - bestdispoffset = ds->dispoffset; - best = ds; - } - // order visprites of same scale by dispoffset, smallest first - else if (fabsf(ds->tz - bestdist) < 1.0E-36f && ds->dispoffset < bestdispoffset) - { - bestdispoffset = ds->dispoffset; - best = ds; - } - } - if (best) - { - best->next->prev = best->prev; - best->prev->next = best->next; - best->next = &gr_vsprsortedhead; - best->prev = gr_vsprsortedhead.prev; - } - gr_vsprsortedhead.prev->next = best; - gr_vsprsortedhead.prev = best; - } - - // Sryder: Oh boy, while it's nice having ALL the sprites sorted properly, it fails when we bring MD2's into the - // mix and they want to be translucent. So let's place all the translucent sprites and MD2's AFTER - // everything else, but still ordered of course, the depth buffer can handle the opaque ones plenty fine. - // We just need to move all translucent ones to the end in order - // TODO: Fully sort all sprites and MD2s with walls and floors, this part will be unnecessary after that - best = gr_vsprsortedhead.next; - for (i = 0; i < gr_visspritecount; i++) - { - if ((best->mobj->flags2 & MF2_SHADOW) || (best->mobj->frame & FF_TRANSMASK)) - { - if (best == gr_vsprsortedhead.next) - { - gr_vsprsortedhead.next = best->next; - } - best->prev->next = best->next; - best->next->prev = best->prev; - best->prev = gr_vsprsortedhead.prev; - gr_vsprsortedhead.prev->next = best; - gr_vsprsortedhead.prev = best; - ds = best; - best = best->next; - ds->next = &gr_vsprsortedhead; - } - else - best = best->next; + gr_vsprorder[i] = HWR_GetVisSprite(i); } + qsort(gr_vsprorder, gr_visspritecount, sizeof(gr_vissprite_t*), CompareVisSprites); } // A drawnode is something that points to a 3D floor, 3D side, or masked @@ -4068,34 +4016,28 @@ void HWR_RenderDrawNodes(void) // -------------------------------------------------------------------------- void HWR_DrawSprites(void) { - if (gr_visspritecount > 0) + UINT32 i; + for (i = 0; i < gr_visspritecount; i++) { - gr_vissprite_t *spr; - - // draw all vissprites back to front - for (spr = gr_vsprsortedhead.next; - spr != &gr_vsprsortedhead; - spr = spr->next) - { - if (spr->precip) - HWR_DrawPrecipitationSprite(spr); - else - if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) - { - // 8/1/19: Only don't display player models if no default SPR_PLAY is found. - if (!cv_grmdls.value || ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) && ((!cv_grfallbackplayermodel.value) || md2_models[SPR_PLAY].notfound || md2_models[SPR_PLAY].scale < 0.0f))) - HWR_DrawSprite(spr); - else - HWR_DrawMD2(spr); - } + gr_vissprite_t *spr = gr_vsprorder[i]; + if (spr->precip) + HWR_DrawPrecipitationSprite(spr); + else + if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) + { + // 8/1/19: Only don't display player models if no default SPR_PLAY is found. + if (!cv_grmdls.value || ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) && ((!cv_grfallbackplayermodel.value) || md2_models[SPR_PLAY].notfound || md2_models[SPR_PLAY].scale < 0.0f))) + HWR_DrawSprite(spr); else - { - if (!cv_grmdls.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) - HWR_DrawSprite(spr); - else - HWR_DrawMD2(spr); - } - } + HWR_DrawMD2(spr); + } + else + { + if (!cv_grmdls.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) + HWR_DrawSprite(spr); + else + HWR_DrawMD2(spr); + } } } From 6cc1c5dd36d98aa27bd0d77630d04268a4f1eba4 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 21 Apr 2020 22:38:46 +0300 Subject: [PATCH 04/12] Make OpenGL texture filter config save --- src/hardware/hw_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index de100385..a3969ad1 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -69,10 +69,10 @@ CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NU consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -// Unfortunately, this can no longer be saved.. -consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL, grfiltermode_cons_t, + +consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL|CV_SAVE, grfiltermode_cons_t, CV_filtermode_ONChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t, +consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL|CV_SAVE, granisotropicmode_cons_t, CV_anisotropic_ONChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; From 43be277ac7ea89d7c1b9a2353e10f7f559b7824f Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 21 Apr 2020 23:15:44 +0300 Subject: [PATCH 05/12] Newer color tinting shaders ported from SRB2 shader branch --- src/hardware/hw_defs.h | 1 + src/hardware/hw_main.c | 171 ++++++++++++++++--------------- src/hardware/r_opengl/r_opengl.c | 165 +++++++++++++++++++++-------- 3 files changed, 214 insertions(+), 123 deletions(-) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index f5839520..129daa00 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -231,6 +231,7 @@ struct FSurfaceInfo { FUINT PolyFlags; RGBA_t PolyColor; + RGBA_t TintColor; RGBA_t FadeColor; FLightInfo LightInfo; // jimita 14032019 }; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a3969ad1..18cf3bb8 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -141,79 +141,87 @@ static INT32 drawcount = 0; void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mixcolor, UINT32 fadecolor) { - RGBA_t mix_color, fog_color, final_color; - INT32 mix; - float fog_alpha; - - mix_color.rgba = mixcolor; - fog_color.rgba = fadecolor; - - mix = mix_color.s.alpha*10/5; - if (mix > 25) mix = 25; - mix *= 255; - mix /= 25; - - // Modulate the colors by alpha. - mix_color.s.red = (UINT8)(CALCLIGHT(mix,mix_color.s.red)); - mix_color.s.green = (UINT8)(CALCLIGHT(mix,mix_color.s.green)); - mix_color.s.blue = (UINT8)(CALCLIGHT(mix,mix_color.s.blue)); - - // Set the surface colors and further modulate the colors by light. - final_color.s.red = (UINT8)(CALCLIGHT((0xFF-mix),0xFF)+CALCLIGHT(mix_color.s.red,0xFF)); - final_color.s.green = (UINT8)(CALCLIGHT((0xFF-mix),0xFF)+CALCLIGHT(mix_color.s.green,0xFF)); - final_color.s.blue = (UINT8)(CALCLIGHT((0xFF-mix),0xFF)+CALCLIGHT(mix_color.s.blue,0xFF)); - final_color.s.alpha = 0xFF; - - // Fog. - fog_alpha = (0xFF - fog_color.s.alpha) / 255.0f; - - // Set the surface colors and further modulate the colors by light. - fog_color.s.red = (UINT8)(((float)fog_color.s.red) * fog_alpha); - fog_color.s.green = (UINT8)(((float)fog_color.s.green) * fog_alpha); - fog_color.s.blue = (UINT8)(((float)fog_color.s.blue) * fog_alpha); - - if (cv_grfog.value) + if (!cv_grshaders.value || (cv_grshaders.value && !cv_grfog.value)) { - // be careful, this may get negative for high lightlevel values. - float fog = (fog_alpha - (light_level/255.0f))*3/2; - if (fog < 0) - fog = 0; + RGBA_t mix_color, fog_color, final_color; + INT32 mix; + float fog_alpha; - float red = ((fog_color.s.red/255.0f) * fog) + ((final_color.s.red/255.0f) * (1.0f - fog)); - float green = ((fog_color.s.green/255.0f) * fog) + ((final_color.s.green/255.0f) * (1.0f - fog)); - float blue = ((fog_color.s.blue/255.0f) * fog) + ((final_color.s.blue/255.0f) * (1.0f - fog)); - final_color.s.red = (UINT8)(red*255.0f); - final_color.s.green = (UINT8)(green*255.0f); - final_color.s.blue = (UINT8)(blue*255.0f); + mix_color.rgba = mixcolor; + fog_color.rgba = fadecolor; + + mix = mix_color.s.alpha*10/5; + if (mix > 25) mix = 25; + mix *= 255; + mix /= 25; + + // Modulate the colors by alpha. + mix_color.s.red = (UINT8)(CALCLIGHT(mix,mix_color.s.red)); + mix_color.s.green = (UINT8)(CALCLIGHT(mix,mix_color.s.green)); + mix_color.s.blue = (UINT8)(CALCLIGHT(mix,mix_color.s.blue)); + + // Set the surface colors and further modulate the colors by light. + final_color.s.red = (UINT8)(CALCLIGHT((0xFF-mix),0xFF)+CALCLIGHT(mix_color.s.red,0xFF)); + final_color.s.green = (UINT8)(CALCLIGHT((0xFF-mix),0xFF)+CALCLIGHT(mix_color.s.green,0xFF)); + final_color.s.blue = (UINT8)(CALCLIGHT((0xFF-mix),0xFF)+CALCLIGHT(mix_color.s.blue,0xFF)); + final_color.s.alpha = 0xFF; + + // Fog. + fog_alpha = (0xFF - fog_color.s.alpha) / 255.0f; + + // Set the surface colors and further modulate the colors by light. + fog_color.s.red = (UINT8)(((float)fog_color.s.red) * fog_alpha); + fog_color.s.green = (UINT8)(((float)fog_color.s.green) * fog_alpha); + fog_color.s.blue = (UINT8)(((float)fog_color.s.blue) * fog_alpha); + + if (cv_grfog.value) + { + // be careful, this may get negative for high lightlevel values. + float fog = (fog_alpha - (light_level/255.0f))*3/2; + if (fog < 0) + fog = 0; + + float red = ((fog_color.s.red/255.0f) * fog) + ((final_color.s.red/255.0f) * (1.0f - fog)); + float green = ((fog_color.s.green/255.0f) * fog) + ((final_color.s.green/255.0f) * (1.0f - fog)); + float blue = ((fog_color.s.blue/255.0f) * fog) + ((final_color.s.blue/255.0f) * (1.0f - fog)); + final_color.s.red = (UINT8)(red*255.0f); + final_color.s.green = (UINT8)(green*255.0f); + final_color.s.blue = (UINT8)(blue*255.0f); + } + + Surface->PolyColor.rgba = final_color.rgba; + Surface->FadeColor.rgba = fog_color.rgba; + Surface->LightInfo.light_level = light_level; + } + else + { + Surface->PolyColor.rgba = 0xFFFFFFFF; + Surface->TintColor.rgba = mixcolor; + Surface->FadeColor.rgba = fadecolor; + Surface->LightInfo.light_level = light_level; } - - Surface->PolyColor.rgba = final_color.rgba; - Surface->FadeColor.rgba = fog_color.rgba; - Surface->LightInfo.light_level = light_level; } void HWR_NoColormapLighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mixcolor, UINT32 fadecolor) { - RGBA_t mix_color, fog_color, final_color; - INT32 mix, fogmix, lightmix; - float fog_alpha; - - // You see the problem is that darker light isn't actually as dark as it SHOULD be. - lightmix = 255 - ((255 - light_level)*10/7); - - // Don't go out of bounds - if (lightmix < 0) - lightmix = 0; - else if (lightmix > 255) - lightmix = 255; - - mix_color.rgba = mixcolor; - fog_color.rgba = fadecolor; - - // if shaders are off, or shaders are on, but fog is off: - // modulate colors by light here if (!cv_grshaders.value || (cv_grshaders.value && !cv_grfog.value)) { + RGBA_t mix_color, fog_color, final_color; + INT32 mix, fogmix, lightmix; + float fog_alpha; + + // You see the problem is that darker light isn't actually as dark as it SHOULD be. + lightmix = 255 - ((255 - light_level)*10/7); + + // Don't go out of bounds + if (lightmix < 0) + lightmix = 0; + else if (lightmix > 255) + lightmix = 255; + + mix_color.rgba = mixcolor; + fog_color.rgba = fadecolor; + mix = (mix_color.s.alpha*255)/25; fogmix = (fog_color.s.alpha*255)/25; @@ -237,24 +245,27 @@ void HWR_NoColormapLighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mix final_color.s.green = final_color.s.green+((UINT8)(CALCLIGHT((0xFF-fogmix),(0xFF-lightmix))+CALCLIGHT(fog_color.s.green,(0xFF-lightmix)))); final_color.s.blue = final_color.s.blue+((UINT8)(CALCLIGHT((0xFF-fogmix),(0xFF-lightmix))+CALCLIGHT(fog_color.s.blue,(0xFF-lightmix)))); final_color.s.alpha = 0xFF; + + // Fog. + fog_color.rgba = fadecolor; + fog_alpha = (0xFF - fog_color.s.alpha*10/7) / 255.0f; + + // Set the surface colors and further modulate the colors by light. + fog_color.s.red = (UINT8)(((float)fog_color.s.red) * fog_alpha); + fog_color.s.green = (UINT8)(((float)fog_color.s.green) * fog_alpha); + fog_color.s.blue = (UINT8)(((float)fog_color.s.blue) * fog_alpha); + + Surface->PolyColor.rgba = final_color.rgba; + Surface->FadeColor.rgba = fog_color.rgba; + Surface->LightInfo.light_level = lightmix; } - // if shaders are on: - // modulate colors by light on the shader else - final_color.rgba = 0xFFFFFFFF; - - // Fog. - fog_color.rgba = fadecolor; - fog_alpha = (0xFF - fog_color.s.alpha*10/7) / 255.0f; - - // Set the surface colors and further modulate the colors by light. - fog_color.s.red = (UINT8)(((float)fog_color.s.red) * fog_alpha); - fog_color.s.green = (UINT8)(((float)fog_color.s.green) * fog_alpha); - fog_color.s.blue = (UINT8)(((float)fog_color.s.blue) * fog_alpha); - - Surface->PolyColor.rgba = final_color.rgba; - Surface->FadeColor.rgba = fog_color.rgba; - Surface->LightInfo.light_level = lightmix; + { + Surface->PolyColor.rgba = 0xFFFFFFFF; + Surface->TintColor.rgba = mixcolor; + Surface->FadeColor.rgba = fadecolor; + Surface->LightInfo.light_level = light_level; + } } UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color) // Let's see if this can work diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 659388d2..8d6ee3c7 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -552,7 +552,8 @@ static boolean gl_batching = false;// are we currently collecting batches? typedef enum { // lighting - gluniform_mix_color, + gluniform_poly_color, + gluniform_tint_color, gluniform_fade_color, gluniform_lighting, @@ -582,37 +583,80 @@ static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS]; // GLSL Software fragment shader // -#define GLSL_INTERNAL_FOG_FUNCTION \ - "float fog(const float dist, const float density, const float globaldensity) {\n" \ - "const float LOG2 = -1.442695;\n" \ - "float d = density * dist;\n" \ - "return 1.0 - clamp(exp2(d * sqrt(d) * globaldensity * LOG2), 0.0, 1.0);\n" \ +// (new shader stuff taken from srb2 shader branch) +// this is missing support for fade_start and fade_end + +#define GLSL_DOOM_COLORMAP \ + "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 - scale * 0.5;\n" \ "}\n" -// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_gpu_shader_fp64.txt -#define GLSL_INTERNAL_FOG_MIX \ - "float fog_distance = gl_FragCoord.z / gl_FragCoord.w;\n" \ - "float fog_attenuation = floor(fog(fog_distance, 0.0001 * ((256.0-lighting)/24.0), fog_density)*10.0)/10.0;\n" \ - "vec4 fog_color = vec4(fade_color[0], fade_color[1], fade_color[2], 1.0);\n" \ - "vec4 mixed_color = texel * mix_color;\n" \ - "vec4 fog_mix = mix(mixed_color, fog_color, fog_attenuation);\n" \ - "vec4 final_color = mix(fog_mix, fog_color, ((256.0-lighting)/256.0));\n" \ - "final_color[3] = mixed_color[3];\n" +#define GLSL_DOOM_LIGHT_EQUATION \ + "float R_DoomLightingEquation(float light)\n" \ + "{\n" \ + "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ + "float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \ + "return clamp(colormap, 0.0, 31.0) / 32.0;\n" \ + "}\n" + +#define GLSL_SOFTWARE_TINT_EQUATION \ + "if (tint_color.a > 0.0) {\n" \ + "float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \ + "float strength = sqrt(9.0 * tint_color.a);\n" \ + "final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \ + "final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \ + "final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \ + "}\n" + +#define GLSL_SOFTWARE_FADE_EQUATION \ + "float darkness = R_DoomLightingEquation(lighting);\n" \ + "final_color = mix(final_color, fade_color, darkness);\n" #define GLSL_SOFTWARE_FRAGMENT_SHADER \ "uniform sampler2D tex;\n" \ - "uniform vec4 mix_color;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ "uniform vec4 fade_color;\n" \ "uniform float lighting;\n" \ - "uniform int fog_mode;\n" \ - "uniform float fog_density;\n" \ - GLSL_INTERNAL_FOG_FUNCTION \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ "void main(void) {\n" \ "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ - GLSL_INTERNAL_FOG_MIX \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ "gl_FragColor = final_color;\n" \ "}\0" + +// +// Fog block shader (Taken from srb2 shader branch) +// +// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha +// + +#define GLSL_FOG_FRAGMENT_SHADER \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 base_color = gl_Color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "gl_FragColor = final_color;\n" \ + "}\0" + + // // GLSL generic fragment shader // @@ -644,9 +688,7 @@ static const char *fragment_shaders[] = { GLSL_SOFTWARE_FRAGMENT_SHADER, // Fog fragment shader - "void main(void) {\n" - "gl_FragColor = gl_Color;\n" - "}\0", + GLSL_FOG_FRAGMENT_SHADER, // Sky fragment shader "uniform sampler2D tex;\n" @@ -840,7 +882,8 @@ EXPORT void HWRAPI(LoadShaders) (void) #define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); // lighting - shader->uniforms[gluniform_mix_color] = GETUNI("mix_color"); + shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); + shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); shader->uniforms[gluniform_lighting] = GETUNI("lighting"); @@ -1626,7 +1669,7 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) } } -static void load_shaders(FSurfaceInfo *Surface, GLRGBAFloat *mix, GLRGBAFloat *fade) +static void load_shaders(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) { #ifdef GL_SHADERS if (gl_shadersenabled) @@ -1685,7 +1728,9 @@ static void load_shaders(FSurfaceInfo *Surface, GLRGBAFloat *mix, GLRGBAFloat *f function (uniform, a, b, c, d); // polygon - UNIFORM_4(shader->uniforms[gluniform_mix_color], mix->red, mix->green, mix->blue, mix->alpha, pglUniform4f); + UNIFORM_4(shader->uniforms[gluniform_poly_color], poly->red, poly->green, poly->blue, poly->alpha, pglUniform4f); + UNIFORM_4(shader->uniforms[gluniform_tint_color], tint->red, tint->green, tint->blue, tint->alpha, pglUniform4f); + // 13062019 // Check for fog @@ -1794,6 +1839,8 @@ static int comparePolygons(const void *p1, const void *p2) diff64 = poly1->surf.PolyColor.rgba - poly2->surf.PolyColor.rgba; if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + diff64 = poly1->surf.TintColor.rgba - poly2->surf.TintColor.rgba; + if (diff64 < 0) return -1; else if (diff64 > 0) return 1; diff64 = poly1->surf.FadeColor.rgba - poly2->surf.FadeColor.rgba; if (diff64 < 0) return -1; else if (diff64 > 0) return 1; @@ -1840,6 +1887,7 @@ EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCall FSurfaceInfo currentSurfaceInfo; GLRGBAFloat firstPoly = {0,0,0,0}; // may be misleading but this means first PolyColor + GLRGBAFloat firstTint = {0,0,0,0}; GLRGBAFloat firstFade = {0,0,0,0}; boolean needRebind = false; @@ -1901,6 +1949,11 @@ EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCall firstPoly.alpha = byte2float[currentSurfaceInfo.PolyColor.s.alpha]; pglColor4ubv((GLubyte*)¤tSurfaceInfo.PolyColor.s); } + // Tint color + firstTint.red = byte2float[currentSurfaceInfo.TintColor.s.red]; + firstTint.green = byte2float[currentSurfaceInfo.TintColor.s.green]; + firstTint.blue = byte2float[currentSurfaceInfo.TintColor.s.blue]; + firstTint.alpha = byte2float[currentSurfaceInfo.TintColor.s.alpha]; // Fade color firstFade.red = byte2float[currentSurfaceInfo.FadeColor.s.red]; firstFade.green = byte2float[currentSurfaceInfo.FadeColor.s.green]; @@ -1908,7 +1961,7 @@ EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCall firstFade.alpha = byte2float[currentSurfaceInfo.FadeColor.s.alpha]; if (gl_allowshaders) - load_shaders(¤tSurfaceInfo, &firstPoly, &firstFade); + load_shaders(¤tSurfaceInfo, &firstPoly, &firstTint, &firstFade); if (currentPolyFlags & PF_NoTexture) currentTexture = 0; @@ -2022,6 +2075,7 @@ EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCall if (gl_allowshaders) { 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) { @@ -2070,6 +2124,7 @@ EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCall if (changeShader) { GLRGBAFloat poly = {0,0,0,0}; + GLRGBAFloat tint = {0,0,0,0}; GLRGBAFloat fade = {0,0,0,0}; gl_currentshaderprogram = nextShader; gl_shaderprogramchanged = true; @@ -2081,13 +2136,18 @@ EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCall poly.blue = byte2float[nextSurfaceInfo.PolyColor.s.blue]; poly.alpha = byte2float[nextSurfaceInfo.PolyColor.s.alpha]; } + // Tint color + tint.red = byte2float[nextSurfaceInfo.TintColor.s.red]; + tint.green = byte2float[nextSurfaceInfo.TintColor.s.green]; + tint.blue = byte2float[nextSurfaceInfo.TintColor.s.blue]; + tint.alpha = byte2float[nextSurfaceInfo.TintColor.s.alpha]; // Fade color fade.red = byte2float[nextSurfaceInfo.FadeColor.s.red]; fade.green = byte2float[nextSurfaceInfo.FadeColor.s.green]; fade.blue = byte2float[nextSurfaceInfo.FadeColor.s.blue]; fade.alpha = byte2float[nextSurfaceInfo.FadeColor.s.alpha]; - load_shaders(&nextSurfaceInfo, &poly, &fade); + load_shaders(&nextSurfaceInfo, &poly, &tint, &fade); currentShader = nextShader; changeShader = false; @@ -2114,6 +2174,7 @@ EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCall if (changeSurfaceInfo) { GLRGBAFloat poly = {0,0,0,0}; + GLRGBAFloat tint = {0,0,0,0}; GLRGBAFloat fade = {0,0,0,0}; gl_shaderprogramchanged = false; if (nextPolyFlags & PF_Modulated) @@ -2127,13 +2188,18 @@ EXPORT void HWRAPI(RenderBatches) (int *sNumPolys, int *sNumVerts, int *sNumCall } if (gl_allowshaders) { + // Tint color + tint.red = byte2float[nextSurfaceInfo.TintColor.s.red]; + tint.green = byte2float[nextSurfaceInfo.TintColor.s.green]; + tint.blue = byte2float[nextSurfaceInfo.TintColor.s.blue]; + tint.alpha = byte2float[nextSurfaceInfo.TintColor.s.alpha]; // Fade color fade.red = byte2float[nextSurfaceInfo.FadeColor.s.red]; fade.green = byte2float[nextSurfaceInfo.FadeColor.s.green]; fade.blue = byte2float[nextSurfaceInfo.FadeColor.s.blue]; fade.alpha = byte2float[nextSurfaceInfo.FadeColor.s.alpha]; - load_shaders(&nextSurfaceInfo, &poly, &fade); + load_shaders(&nextSurfaceInfo, &poly, &tint, &fade); } currentSurfaceInfo = nextSurfaceInfo; changeSurfaceInfo = false; @@ -2199,7 +2265,8 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI } else { - static GLRGBAFloat mix = {0,0,0,0}; + static GLRGBAFloat poly = {0,0,0,0}; + static GLRGBAFloat tint = {0,0,0,0}; static GLRGBAFloat fade = {0,0,0,0}; SetBlend(PolyFlags); //TODO: inline (#pragma..) @@ -2210,14 +2277,20 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI // If Modulated, mix the surface colour to the texture if (CurrentPolyFlags & PF_Modulated) { - // Mix color - mix.red = byte2float[pSurf->PolyColor.s.red]; - mix.green = byte2float[pSurf->PolyColor.s.green]; - mix.blue = byte2float[pSurf->PolyColor.s.blue]; - mix.alpha = byte2float[pSurf->PolyColor.s.alpha]; + // Poly color + poly.red = byte2float[pSurf->PolyColor.s.red]; + poly.green = byte2float[pSurf->PolyColor.s.green]; + poly.blue = byte2float[pSurf->PolyColor.s.blue]; + poly.alpha = byte2float[pSurf->PolyColor.s.alpha]; pglColor4ubv((GLubyte*)&pSurf->PolyColor.s); } + + // Tint color + tint.red = byte2float[pSurf->TintColor.s.red]; + tint.green = byte2float[pSurf->TintColor.s.green]; + tint.blue = byte2float[pSurf->TintColor.s.blue]; + tint.alpha = byte2float[pSurf->TintColor.s.alpha]; // Fade color fade.red = byte2float[pSurf->FadeColor.s.red]; @@ -2226,7 +2299,7 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI fade.alpha = byte2float[pSurf->FadeColor.s.alpha]; } - load_shaders(pSurf, &mix, &fade); + load_shaders(pSurf, &poly, &tint, &fade); pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x); pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s); @@ -2526,7 +2599,8 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model) static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface) { - static GLRGBAFloat mix = {0,0,0,0}; + static GLRGBAFloat poly = {0,0,0,0}; + static GLRGBAFloat tint = {0,0,0,0}; static GLRGBAFloat fade = {0,0,0,0}; float pol = 0.0f; @@ -2555,24 +2629,29 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 pol = 0.0f; } - mix.red = byte2float[Surface->PolyColor.s.red]; - mix.green = byte2float[Surface->PolyColor.s.green]; - mix.blue = byte2float[Surface->PolyColor.s.blue]; - mix.alpha = byte2float[Surface->PolyColor.s.alpha]; + poly.red = byte2float[Surface->PolyColor.s.red]; + poly.green = byte2float[Surface->PolyColor.s.green]; + poly.blue = byte2float[Surface->PolyColor.s.blue]; + poly.alpha = byte2float[Surface->PolyColor.s.alpha]; - if (mix.alpha < 1) + if (poly.alpha < 1) SetBlend(PF_Translucent|PF_Modulated); else SetBlend(PF_Masked|PF_Modulated|PF_Occlude); pglColor4ubv((GLubyte*)&Surface->PolyColor.s); + tint.red = byte2float[Surface->TintColor.s.red]; + tint.green = byte2float[Surface->TintColor.s.green]; + tint.blue = byte2float[Surface->TintColor.s.blue]; + tint.alpha = byte2float[Surface->TintColor.s.alpha]; + fade.red = byte2float[Surface->FadeColor.s.red]; fade.green = byte2float[Surface->FadeColor.s.green]; fade.blue = byte2float[Surface->FadeColor.s.blue]; fade.alpha = byte2float[Surface->FadeColor.s.alpha]; - load_shaders(Surface, &mix, &fade); + load_shaders(Surface, &poly, &tint, &fade); pglEnable(GL_CULL_FACE); pglEnable(GL_NORMALIZE); From 4309908999a6f3c89df65d65e798c959cec773f8 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 21 Apr 2020 23:23:03 +0300 Subject: [PATCH 06/12] Fix race results screen showing wrong image on maps with skyboxes --- src/hardware/hw_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 18cf3bb8..acbc4357 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4850,7 +4850,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) } R_SetupFrame(player, false); // This can stay false because it is only used to set viewsky in r_main.c, which isn't used here - HWR_RenderFrame(viewnumber, player, skybox); + HWR_RenderFrame(viewnumber, player, false); } // ========================================================================== From 2fdb7627b7d1095e48ac03d46ec003ece31450e7 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 21 Apr 2020 23:24:32 +0300 Subject: [PATCH 07/12] Fix wrong behaviour and lack of animation in ogl sky background --- src/hardware/hw_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index acbc4357..a222cdcd 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4524,7 +4524,7 @@ void HWR_DrawSkyBackground(void) if (drewsky) return; - HWR_GetTexture(skytexture); + HWR_GetTexture(texturetranslation[skytexture]); aspectratio = (float)vid.width/(float)vid.height; //Hurdler: the sky is the only texture who need 4.0f instead of 1.0 @@ -4549,8 +4549,8 @@ void HWR_DrawSkyBackground(void) // software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly // The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture - angle = (viewangle/2 + xtoviewangle[0]); - dimensionmultiply = ((float)textures[skytexture]->width/256.0f); + angle = (viewangle + xtoviewangle[0]); + dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f); if (atransform.mirror) { @@ -4563,7 +4563,7 @@ void HWR_DrawSkyBackground(void) // Y angle = aimingangle; - dimensionmultiply = ((float)textures[skytexture]->height/(128.0f*aspectratio)); + dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio)); if (splitscreen == 1) { From 812cceb53f6745554158829c98157d13d49749e1 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 21 Apr 2020 23:32:31 +0300 Subject: [PATCH 08/12] Remove sometimes harmful NetUpdate call from HWR_RenderFrame --- src/hardware/hw_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a222cdcd..4ac026de 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4792,7 +4792,8 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox) } // Check for new console commands. - NetUpdate(); + // this was removed since it caused crashes on leaving record attack with models on since it was removing mobjs that were about to be rendered + //NetUpdate(); // Draw MD2 and sprites HWR_SortVisSprites(); From e45295f1ead0e0e7314d9afd9231255b270c935a Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 21 Apr 2020 23:45:48 +0300 Subject: [PATCH 09/12] Don't crash if shaders are unavailable --- src/hardware/r_opengl/r_opengl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 8d6ee3c7..4e5114e8 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -790,6 +790,8 @@ EXPORT void HWRAPI(LoadShaders) (void) #ifdef GL_SHADERS GLuint gl_vertShader, gl_fragShader; GLint i, result; + + if (!pglUseProgram) return; gl_customvertexshaders[0] = NULL; gl_customfragmentshaders[0] = NULL; @@ -902,6 +904,7 @@ EXPORT void HWRAPI(LoadShaders) (void) EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment) { #ifdef GL_SHADERS + if (!pglUseProgram) return; if (number < 1 || number > MAXSHADERS) I_Error("LoadCustomShader(): cannot load shader %d (max %d)", number, MAXSHADERS); @@ -951,6 +954,7 @@ EXPORT void HWRAPI(UnSetShader) (void) gl_shadersenabled = false; gl_currentshaderprogram = 0; gl_shaderprogramchanged = true;// not sure if this is needed + if (!pglUseProgram) return; pglUseProgram(0); #endif } @@ -1672,7 +1676,7 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) static void load_shaders(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) { #ifdef GL_SHADERS - if (gl_shadersenabled) + if (gl_shadersenabled && pglUseProgram) { gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; if (shader->program) @@ -1760,9 +1764,7 @@ static void load_shaders(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat * else pglUseProgram(0); } - else #endif - pglUseProgram(0); } // unfinished draw call batching From ce1d017a73d0171d7a38814610bb06ea1018b766 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Wed, 22 Apr 2020 00:18:58 +0300 Subject: [PATCH 10/12] Sky dome from SRB2 --- src/hardware/hw_drv.h | 4 + src/hardware/hw_main.c | 193 +++++++++++++---------- src/hardware/hw_main.h | 2 +- src/hardware/r_opengl/r_opengl.c | 259 +++++++++++++++++++++++++++++++ src/sdl/hwsym_sdl.c | 2 + src/sdl/i_video.c | 2 + 6 files changed, 381 insertions(+), 81 deletions(-) diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index d6ad26c0..b2f79782 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -51,6 +51,8 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model); EXPORT void HWRAPI(SetTransform) (FTransform *stransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); +EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform); + EXPORT void HWRAPI(FlushScreenTextures) (void); EXPORT void HWRAPI(StartScreenWipe) (void); EXPORT void HWRAPI(EndScreenWipe) (void); @@ -111,6 +113,8 @@ struct hwdriver_s MakeScreenFinalTexture pfnMakeScreenFinalTexture; DrawScreenFinalTexture pfnDrawScreenFinalTexture; + RenderSkyDome pfnRenderSkyDome; + LoadShaders pfnLoadShaders; KillShaders pfnKillShaders; SetShader pfnSetShader; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4ac026de..9b7a3523 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -78,6 +78,7 @@ consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, consvar_t cv_grsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static void CV_filtermode_ONChange(void) { @@ -4513,105 +4514,136 @@ void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) static boolean drewsky = false; -void HWR_DrawSkyBackground(void) +void HWR_DrawSkyBackground(float fpov) { - FOutVector v[4]; - angle_t angle; - float dimensionmultiply; - float aspectratio; - float angleturn; - if (drewsky) return; - - HWR_GetTexture(texturetranslation[skytexture]); - aspectratio = (float)vid.width/(float)vid.height; - - //Hurdler: the sky is the only texture who need 4.0f instead of 1.0 - // because it's called just after clearing the screen - // and thus, the near clipping plane is set to 3.99 - // Sryder: Just use the near clipping plane value then - - // 3--2 - // | /| - // |/ | - // 0--1 - v[0].x = v[3].x = -ZCLIP_PLANE-1; - v[1].x = v[2].x = ZCLIP_PLANE+1; - v[0].y = v[1].y = -ZCLIP_PLANE-1; - v[2].y = v[3].y = ZCLIP_PLANE+1; - - v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1; - - // X - - // NOTE: This doesn't work right with texture widths greater than 1024 - // software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly - // The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture - - angle = (viewangle + xtoviewangle[0]); - dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f); - - if (atransform.mirror) + if (cv_grskydome.value) { - angle = InvAngle(angle); - dimensionmultiply *= -1; - } + FTransform dometransform; - v[0].s = v[3].s = ((float) angle / ((ANGLE_90-1)*dimensionmultiply)); - v[2].s = v[1].s = (-1.0f/dimensionmultiply)+((float) angle / ((ANGLE_90-1)*dimensionmultiply)); + memset(&dometransform, 0x00, sizeof(FTransform)); - // Y - angle = aimingangle; - dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio)); + //04/01/2000: Hurdler: added for T&L + // It should replace all other gr_viewxxx when finished + if (!atransform.shearing) + dometransform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); + dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); - if (splitscreen == 1) - { - dimensionmultiply *= 2; - angle *= 2; - } + dometransform.flip = atransform.flip; + dometransform.mirror = atransform.mirror; + dometransform.shearing = atransform.shearing; + dometransform.viewaiming = atransform.viewaiming; - // Middle of the sky should always be at angle 0 - // need to keep correct aspect ratio with X - if (atransform.flip) - { - // 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)); - v[0].t = v[1].t = (-1.0f/dimensionmultiply)-(0.5f-(0.5f/dimensionmultiply)); + dometransform.scalex = 1; + dometransform.scaley = (float)vid.width/vid.height; + dometransform.scalez = 1; + dometransform.fovxangle = fpov; // Tails + dometransform.fovyangle = fpov; // Tails + dometransform.splitscreen = splitscreen; + + HWR_GetTexture(texturetranslation[skytexture]); + HWD.pfnSetShader(7); // sky shader + HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, dometransform); + HWD.pfnSetShader(0); } else { - v[3].t = v[2].t = (-1.0f/dimensionmultiply)-(0.5f-(0.5f/dimensionmultiply)); - v[0].t = v[1].t = -(0.5f-(0.5f/dimensionmultiply)); - } + FOutVector v[4]; + angle_t angle; + float dimensionmultiply; + float aspectratio; + float angleturn; - angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply; + HWR_GetTexture(texturetranslation[skytexture]); + aspectratio = (float)vid.width/(float)vid.height; - if (cv_grshearing.value) - { - // Doesn't really make sense, but what can I do? - angle_t dy = FixedAngle(FixedMul(360*FRACUNIT, FixedDiv(AIMINGTODY(aimingangle), 900*FRACUNIT))); - v[3].t = v[2].t -= ((float) dy / angleturn); - v[0].t = v[1].t -= ((float) dy / angleturn); - } - else - { - if (angle > ANGLE_180) // Do this because we don't want the sky to suddenly teleport when crossing over 0 to 360 and vice versa + //Hurdler: the sky is the only texture who need 4.0f instead of 1.0 + // because it's called just after clearing the screen + // and thus, the near clipping plane is set to 3.99 + // Sryder: Just use the near clipping plane value then + + // 3--2 + // | /| + // |/ | + // 0--1 + v[0].x = v[3].x = -ZCLIP_PLANE-1; + v[1].x = v[2].x = ZCLIP_PLANE+1; + v[0].y = v[1].y = -ZCLIP_PLANE-1; + v[2].y = v[3].y = ZCLIP_PLANE+1; + + v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1; + + // X + + // NOTE: This doesn't work right with texture widths greater than 1024 + // software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly + // The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture + + angle = (viewangle + xtoviewangle[0]); + dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f); + + if (atransform.mirror) { angle = InvAngle(angle); - v[3].t = v[2].t += ((float) angle / angleturn); - v[0].t = v[1].t += ((float) angle / angleturn); + dimensionmultiply *= -1; + } + + v[0].s = v[3].s = ((float) angle / ((ANGLE_90-1)*dimensionmultiply)); + v[2].s = v[1].s = (-1.0f/dimensionmultiply)+((float) angle / ((ANGLE_90-1)*dimensionmultiply)); + + // Y + angle = aimingangle; + dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio)); + + if (splitscreen == 1) + { + dimensionmultiply *= 2; + angle *= 2; + } + + // Middle of the sky should always be at angle 0 + // need to keep correct aspect ratio with X + if (atransform.flip) + { + // 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)); + v[0].t = v[1].t = (-1.0f/dimensionmultiply)-(0.5f-(0.5f/dimensionmultiply)); } else { - v[3].t = v[2].t -= ((float) angle / angleturn); - v[0].t = v[1].t -= ((float) angle / angleturn); + v[3].t = v[2].t = (-1.0f/dimensionmultiply)-(0.5f-(0.5f/dimensionmultiply)); + v[0].t = v[1].t = -(0.5f-(0.5f/dimensionmultiply)); } - } - HWD.pfnSetShader(7); // sky shader - HWD.pfnDrawPolygon(NULL, v, 4, 0); - HWD.pfnSetShader(0); + angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply; + + if (cv_grshearing.value) + { + // Doesn't really make sense, but what can I do? + angle_t dy = FixedAngle(FixedMul(360*FRACUNIT, FixedDiv(AIMINGTODY(aimingangle), 900*FRACUNIT))); + v[3].t = v[2].t -= ((float) dy / angleturn); + v[0].t = v[1].t -= ((float) dy / angleturn); + } + else + { + if (angle > ANGLE_180) // Do this because we don't want the sky to suddenly teleport when crossing over 0 to 360 and vice versa + { + angle = InvAngle(angle); + v[3].t = v[2].t += ((float) angle / angleturn); + v[0].t = v[1].t += ((float) angle / angleturn); + } + else + { + v[3].t = v[2].t -= ((float) angle / angleturn); + v[0].t = v[1].t -= ((float) angle / angleturn); + } + } + + HWD.pfnSetShader(7); // sky shader + HWD.pfnDrawPolygon(NULL, v, 4, 0); + HWD.pfnSetShader(0); + } } @@ -4751,7 +4783,7 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox) ST_doPaletteStuff(); // Draw the sky background. - HWR_DrawSkyBackground(); + HWR_DrawSkyBackground(fpov); if (skybox) drewsky = true; @@ -4885,6 +4917,7 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_grsolvetjoin); CV_RegisterVar(&cv_grbatching); + CV_RegisterVar(&cv_grskydome); } // -------------------------------------------------------------------------- diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 8ffb5890..1dba6bba 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -103,7 +103,7 @@ void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo * pSurf, INT32 texnum, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap); void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor); void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf); -void HWR_DrawSkyBackground(void); +void HWR_DrawSkyBackground(float fpov); #ifdef POLYOBJECTS void HWR_AddPolyObjectSegs(void); diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 4e5114e8..2285107d 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -388,6 +388,10 @@ static PFNglMultiTexCoord2fv pglMultiTexCoord2fv; typedef void (APIENTRY *PFNglClientActiveTexture) (GLenum); static PFNglClientActiveTexture pglClientActiveTexture; +// sky dome needs this +typedef void (APIENTRY *PFNglColorPointer) (GLint, GLenum, GLsizei, const GLvoid*); +static PFNglColorPointer pglColorPointer; + /* 1.2 Parms */ /* GL_CLAMP_TO_EDGE_EXT */ #ifndef GL_CLAMP_TO_EDGE @@ -756,6 +760,7 @@ void SetupGLFunc4(void) pglBindBuffer = GetGLFunc("glBindBuffer"); pglBufferData = GetGLFunc("glBufferData"); pglDeleteBuffers = GetGLFunc("glDeleteBuffers"); + pglColorPointer = GetGLFunc("glColorPointer"); #ifdef GL_SHADERS pglCreateShader = GetGLFunc("glCreateShader"); @@ -2318,6 +2323,260 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI } } +// Sky dome code, taken/backported from SRB2 + +typedef struct vbo_vertex_s +{ + float x, y, z; + float u, v; + unsigned char r, g, b, a; +} vbo_vertex_t; + +typedef struct +{ + int mode; + int vertexcount; + int vertexindex; + int use_texture; +} GLSkyLoopDef; + +typedef struct +{ + unsigned int id; + int rows, columns; + int loopcount; + GLSkyLoopDef *loops; + vbo_vertex_t *data; +} GLSkyVBO; + +static const boolean gl_ext_arb_vertex_buffer_object = true; + +#define NULL_VBO_VERTEX ((vbo_vertex_t*)NULL) +#define sky_vbo_x (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->x : &vbo->data[0].x) +#define sky_vbo_u (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->u : &vbo->data[0].u) +#define sky_vbo_r (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->r : &vbo->data[0].r) + +// The texture offset to be applied to the texture coordinates in SkyVertex(). +static int rows, columns; +static signed char yflip; +static int texw, texh; +static boolean foglayer; +static float delta = 0.0f; + +static int gl_sky_detail = 16; + +static INT32 lasttex = -1; + +#define MAP_COEFF 128.0f + +static void SkyVertex(vbo_vertex_t *vbo, int r, int c) +{ + const float radians = (float)(M_PIl / 180.0f); + const float scale = 10000.0f; + const float maxSideAngle = 60.0f; + + float topAngle = (c / (float)columns * 360.0f); + float sideAngle = (maxSideAngle * (rows - r) / rows); + float height = (float)(sin(sideAngle * radians)); + float realRadius = (float)(scale * cos(sideAngle * radians)); + float x = (float)(realRadius * cos(topAngle * radians)); + float y = (!yflip) ? scale * height : -scale * height; + float z = (float)(realRadius * sin(topAngle * radians)); + float timesRepeat = (4 * (256.0f / texw)); + if (fpclassify(timesRepeat) == FP_ZERO) + timesRepeat = 1.0f; + + if (!foglayer) + { + vbo->r = 255; + vbo->g = 255; + vbo->b = 255; + vbo->a = (r == 0 ? 0 : 255); + + // And the texture coordinates. + //vbo->u = (-timesRepeat * c / (float)columns); + vbo->u = (timesRepeat * c / (float)columns);// TEST + if (!yflip) // Flipped Y is for the lower hemisphere. + vbo->v = (r / (float)rows) + 0.5f; + else + vbo->v = 1.0f + ((rows - r) / (float)rows) + 0.5f; + } + + if (r != 4) + { + y += 300.0f; + } + + // And finally the vertex. + vbo->x = x; + vbo->y = y + delta; + vbo->z = z; +} + +static GLSkyVBO sky_vbo; + +static void gld_BuildSky(int row_count, int col_count) +{ + int c, r; + vbo_vertex_t *vertex_p; + int vertex_count = 2 * row_count * (col_count * 2 + 2) + col_count * 2; + + GLSkyVBO *vbo = &sky_vbo; + + if ((vbo->columns != col_count) || (vbo->rows != row_count)) + { + free(vbo->loops); + free(vbo->data); + memset(vbo, 0, sizeof(&vbo)); + } + + if (!vbo->data) + { + memset(vbo, 0, sizeof(&vbo)); + vbo->loops = malloc((row_count * 2 + 2) * sizeof(vbo->loops[0])); + // create vertex array + vbo->data = malloc(vertex_count * sizeof(vbo->data[0])); + } + + vbo->columns = col_count; + vbo->rows = row_count; + + vertex_p = &vbo->data[0]; + vbo->loopcount = 0; + + for (yflip = 0; yflip < 2; yflip++) + { + vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_FAN; + vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0]; + vbo->loops[vbo->loopcount].vertexcount = col_count; + vbo->loops[vbo->loopcount].use_texture = false; + vbo->loopcount++; + + delta = 0.0f; + foglayer = true; + for (c = 0; c < col_count; c++) + { + SkyVertex(vertex_p, 1, c); + vertex_p->r = 255; + vertex_p->g = 255; + vertex_p->b = 255; + vertex_p->a = 255; + vertex_p++; + } + foglayer = false; + + delta = (yflip ? 5.0f : -5.0f) / MAP_COEFF; + + for (r = 0; r < row_count; r++) + { + vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_STRIP; + vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0]; + vbo->loops[vbo->loopcount].vertexcount = 2 * col_count + 2; + vbo->loops[vbo->loopcount].use_texture = true; + vbo->loopcount++; + + for (c = 0; c <= col_count; c++) + { + SkyVertex(vertex_p++, r + (yflip ? 1 : 0), (c ? c : 0)); + SkyVertex(vertex_p++, r + (yflip ? 0 : 1), (c ? c : 0)); + } + } + } +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +static void RenderDome(INT32 skytexture) +{ + int i, j; + int vbosize; + GLSkyVBO *vbo = &sky_vbo; + + rows = 4; + columns = 4 * gl_sky_detail; + + vbosize = 2 * rows * (columns * 2 + 2) + columns * 2; + + // Build the sky dome! Yes! + if (lasttex != skytexture) + { + // delete VBO when already exists + if (gl_ext_arb_vertex_buffer_object) + { + if (vbo->id) + pglDeleteBuffers(1, &vbo->id); + } + + lasttex = skytexture; + gld_BuildSky(rows, columns); + + if (gl_ext_arb_vertex_buffer_object) + { + // generate a new VBO and get the associated ID + pglGenBuffers(1, &vbo->id); + + // bind VBO in order to use + pglBindBuffer(GL_ARRAY_BUFFER, vbo->id); + + // upload data to VBO + pglBufferData(GL_ARRAY_BUFFER, vbosize * sizeof(vbo->data[0]), vbo->data, GL_STATIC_DRAW); + } + } + + // bind VBO in order to use + if (gl_ext_arb_vertex_buffer_object) + pglBindBuffer(GL_ARRAY_BUFFER, vbo->id); + + // activate and specify pointers to arrays + pglVertexPointer(3, GL_FLOAT, sizeof(vbo->data[0]), sky_vbo_x); + pglTexCoordPointer(2, GL_FLOAT, sizeof(vbo->data[0]), sky_vbo_u); + pglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vbo->data[0]), sky_vbo_r); + + // activate color arrays + pglEnableClientState(GL_COLOR_ARRAY); + + // set transforms + pglScalef(1.0f, (float)texh / 230.0f, 1.0f); + pglRotatef(270.0f, 0.0f, 1.0f, 0.0f); + + for (j = 0; j < 2; j++) + { + for (i = 0; i < vbo->loopcount; i++) + { + GLSkyLoopDef *loop = &vbo->loops[i]; + + if (j == 0 ? loop->use_texture : !loop->use_texture) + continue; + + pglDrawArrays(loop->mode, loop->vertexindex, loop->vertexcount); + } + } + + pglScalef(1.0f, 1.0f, 1.0f); + pglColor4ubv(white); + + // bind with 0, so, switch back to normal pointer operation + if (gl_ext_arb_vertex_buffer_object) + pglBindBuffer(GL_ARRAY_BUFFER, 0); + + // deactivate color array + pglDisableClientState(GL_COLOR_ARRAY); +} + +EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform) +{ + SetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated); + SetTransform(&transform); + texw = texture_width; + texh = texture_height; + RenderDome(tex); + SetBlend(0); +} + // ========================================================================== // // ========================================================================== diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 51426184..2627c3fd 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -100,6 +100,8 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(MakeScreenTexture); GETFUNC(MakeScreenFinalTexture); GETFUNC(DrawScreenFinalTexture); + + GETFUNC(RenderSkyDome); GETFUNC(LoadShaders); GETFUNC(KillShaders); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 064fba6f..1e6a5cc1 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1871,6 +1871,8 @@ void I_StartupGraphics(void) HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); + + HWD.pfnRenderSkyDome = hwSym("RenderSkyDome",NULL); HWD.pfnLoadShaders = hwSym("LoadShaders",NULL); HWD.pfnKillShaders = hwSym("KillShaders",NULL); From 4e8349fcccc5e2cf9384813421ab1c4f28f8fd3a Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Wed, 22 Apr 2020 23:50:14 +0300 Subject: [PATCH 11/12] Fix lighting breaking if trying to use unavailable shaders --- src/hardware/hw_drv.h | 2 +- src/hardware/hw_main.c | 9 ++++++--- src/hardware/r_opengl/r_opengl.c | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index b2f79782..45346226 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -66,7 +66,7 @@ EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height); EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); // jimita -EXPORT void HWRAPI(LoadShaders) (void); +EXPORT boolean HWRAPI(LoadShaders) (void); EXPORT void HWRAPI(KillShaders) (void); EXPORT void HWRAPI(SetShader) (int shader); EXPORT void HWRAPI(UnSetShader) (void); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 9b7a3523..4b03767d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -119,6 +119,8 @@ static line_t *gr_linedef; static sector_t *gr_frontsector; static sector_t *gr_backsector; +boolean gr_shadersavailable = true; + // ========================================================================== // View position // ========================================================================== @@ -142,7 +144,7 @@ static INT32 drawcount = 0; void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mixcolor, UINT32 fadecolor) { - if (!cv_grshaders.value || (cv_grshaders.value && !cv_grfog.value)) + if (!cv_grshaders.value || (cv_grshaders.value && !cv_grfog.value) || !gr_shadersavailable) { RGBA_t mix_color, fog_color, final_color; INT32 mix; @@ -205,7 +207,7 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mixcolor, UIN void HWR_NoColormapLighting(FSurfaceInfo *Surface, INT32 light_level, UINT32 mixcolor, UINT32 fadecolor) { - if (!cv_grshaders.value || (cv_grshaders.value && !cv_grfog.value)) + if (!cv_grshaders.value || (cv_grshaders.value && !cv_grfog.value) || !gr_shadersavailable) { RGBA_t mix_color, fog_color, final_color; INT32 mix, fogmix, lightmix; @@ -4947,7 +4949,8 @@ void HWR_Startup(void) // jimita HWD.pfnKillShaders(); - HWD.pfnLoadShaders(); + if (!HWD.pfnLoadShaders()) + gr_shadersavailable = false; } diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 2285107d..64861336 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -796,7 +796,7 @@ EXPORT void HWRAPI(LoadShaders) (void) GLuint gl_vertShader, gl_fragShader; GLint i, result; - if (!pglUseProgram) return; + if (!pglUseProgram) return false; gl_customvertexshaders[0] = NULL; gl_customfragmentshaders[0] = NULL; @@ -904,6 +904,7 @@ EXPORT void HWRAPI(LoadShaders) (void) #undef GETUNI } #endif + return true; } EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment) From 957768efd1a4d15bf8452f6e248c6bcf4eecbacc Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Wed, 22 Apr 2020 23:50:50 +0300 Subject: [PATCH 12/12] Fix mistake in previous commit --- src/hardware/r_opengl/r_opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 64861336..c88badde 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -790,7 +790,7 @@ void SetupGLFunc4(void) } // jimita -EXPORT void HWRAPI(LoadShaders) (void) +EXPORT boolean HWRAPI(LoadShaders) (void) { #ifdef GL_SHADERS GLuint gl_vertShader, gl_fragShader;