ref: 5c840ffec2b14ebf8ccede0f837c34b7eb159274
parent: 3a83bca01f54db3fdbde78658787664968b04aab
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Thu Jan 4 11:17:00 EST 2024
more precise alpha/fog blending
--- a/d_alpha.c
+++ b/d_alpha.c
@@ -5,21 +5,21 @@
{
int a, b, c;
- if(ca == 0 || (ca >> 24) != 0)
- alpha = (ca >> 24)*alpha >> 8;
+ if(ca == 0 || (ca >> 24) != 0){
+ alpha = alpha*(ca >> 24) + 0x80;
+ alpha = ((alpha>>8) + alpha) >> 8;
+ }
+ ca = mulalpha(ca, alpha);
+
if(currententity != nil && currententity->effects & EF_ADDITIVE){
- a = (alpha*((ca>> 0)&0xff) + 255*((cb>> 0)&0xff))>> 8;
- b = (alpha*((ca>> 8)&0xff) + 255*((cb>> 8)&0xff))>> 8;
- c = (alpha*((ca>>16)&0xff) + 255*((cb>>16)&0xff))>> 8;
+ a = ((ca>> 0)&0xff) + ((cb>> 0)&0xff);
+ b = ((ca>> 8)&0xff) + ((cb>> 8)&0xff);
+ c = ((ca>>16)&0xff) + ((cb>>16)&0xff);
return (cb & 0xff000000) | min(a, 255) | min(b, 255)<<8 | min(c, 255)<<16;
}
- return
- (cb & 0xff000000) |
- ((alpha*((ca>> 0)&0xff) + (255-alpha)*((cb>> 0)&0xff))>> 8) << 0 |
- ((alpha*((ca>> 8)&0xff) + (255-alpha)*((cb>> 8)&0xff))>> 8) << 8 |
- ((alpha*((ca>>16)&0xff) + (255-alpha)*((cb>>16)&0xff))>> 8) << 16;
+ return ca + mulalpha(cb, 255-alpha);
}
float
--- a/d_local.h
+++ b/d_local.h
@@ -83,5 +83,21 @@
extern int d_minmip;
extern float d_scalemip[3];
+static inline pixel_t
+mulalpha(pixel_t ca, int alpha)
+{
+ pixel_t a, b;
+
+ a = ((ca >> 0) & 0xff00ff)*alpha + 0x800080;
+ a = (a + ((a >> 8) & 0xff00ff)) >> 8;
+ a &= 0x00ff00ff;
+
+ b = ((ca >> 8) & 0xff00ff)*alpha + 0x800080;
+ b = (b + ((b >> 8) & 0xff00ff)) >> 0;
+ b &= 0xff00ff00;
+
+ return a | b;
+}
+
pixel_t blendalpha(pixel_t ca, pixel_t cb, int alpha);
float alphafor(int flags);
--- a/d_scan.c
+++ b/d_scan.c
@@ -165,7 +165,8 @@
sturb = ((s + r_turb_turb[(t>>16)&(CYCLE-1)])>>16)&63;
tturb = ((t + r_turb_turb[(s>>16)&(CYCLE-1)])>>16)&63;
*pdest = blendalpha(*(pbase + (tturb<<6) + sturb), *pdest, alpha);
- *pz = izi; // FIXME(sigrid): can always update this one?
+ if(noblend)
+ *pz = izi;
}
s += sstep;
t += tstep;
@@ -191,7 +192,8 @@
sturb = ((s + r_turb_turb[(t>>16)&(CYCLE-1)])>>16)&63;
tturb = ((t + r_turb_turb[(s>>16)&(CYCLE-1)])>>16)&63;
*pdest = blendalpha(blendfog(*(pbase + (tturb<<6) + sturb), *fog), *pdest, alpha);
- *pz = izi; // FIXME(sigrid): can always update this one?
+ if(noblend)
+ *pz = izi;
}
s += sstep;
t += tstep;
@@ -213,7 +215,7 @@
float sdivz, tdivz, zi, z, du, dv;
float sdivzstepu, tdivzstepu, zistepu;
fog_t fog;
- bool fogged;
+ bool fogged, fogenabled;
sstep = 0; // keep compiler happy
tstep = 0; // ditto
@@ -224,6 +226,8 @@
zistepu = dvars.zistepu * 16;
izistep = (int)(dvars.zistepu * 0x8000 * 0x10000);
+ fogenabled = isfogged();
+
do{
pdest = dvars.viewbuffer + pspan->v*dvars.width + pspan->u;
pz = dvars.zbuffer + pspan->v*dvars.width + pspan->u;
@@ -249,6 +253,7 @@
// calculate s and t at the far end of the span
spancount = min(count, 16);
count -= spancount;
+ fogged = fogenabled && fogcalc(izi, izi + izistep*spancount, spancount, &fog);
if(count){
// calculate s/z, t/z, zi->fixed s and t at far end of span,
@@ -296,7 +301,6 @@
}
}
- fogged = isfogged() ? fogcalc(izi, izi + izistep*spancount, spancount, &fog) : false;
if(fogged){
switch(spanfunc){
case SPAN_SOLID:
--- a/r_fog.c
+++ b/r_fog.c
@@ -43,6 +43,7 @@
fogvars.enabled = x > 0 ? (Enfog | Enskyfog) : 0;
setcvar("r_skyfog", x > 0 ? "1" : "0");
}
+ fogvars.pix = 0xff<<24 | fogvars.c2<<16 | fogvars.c1<<8 | fogvars.c0;
return;
}
fogvars.density = clamp(x, 0.0, 1.0) * 0.016;
@@ -57,6 +58,7 @@
x = atof(Cmd_Argv(i));
fogvars.c0 = 0xff * clamp(x, 0.0, 1.0);
r_skyfog_cb(&r_skyfog); /* recalculate sky fog */
+ fogvars.pix = 0xff<<24 | fogvars.c2<<16 | fogvars.c1<<8 | fogvars.c0;
break;
}
if(fogvars.density > 0.0)
@@ -70,6 +72,7 @@
{
memset(&fogvars, 0, sizeof(fogvars));
fogvars.c0 = fogvars.c1 = fogvars.c2 = 0x80;
+ fogvars.pix = 0xff808080;
fogvars.allowed = r_fog.value > 0.0;
setcvar("r_skyfog", "0");
}
--- a/r_fog.h
+++ b/r_fog.h
@@ -1,13 +1,14 @@
-#define fogstep(f) \
- do{ \
- (f).v[0] += (f).d[0]; \
- (f).v[1] += (f).d[1]; \
- (f).v[2] += (f).d[2]; \
- (f).v[3] += (f).d[3]; \
- }while(0)
+typedef struct fog_t fog_t;
-#define fogshift 8
+struct fog_t {
+ pixel64_t v;
+ pixel64_t d;
+};
+#define fogstep(f) do{ \
+ (f).v += (f).d; \
+ }while(0)
+
static inline byte
z2foga(uzint z)
{
@@ -20,39 +21,48 @@
return 255*d;
}
+static inline pixel64_t
+pixto64(pixel_t p)
+{
+ return
+ (pixel64_t)((p>>24)&0xff)<<56 |
+ (pixel64_t)((p>>16)&0xff)<<40 |
+ (pixel64_t)((p>> 8)&0xff)<<24 |
+ (pixel64_t)((p>> 0)&0xff)<< 8;
+}
+
static inline pixel_t
+pixfrom64(pixel64_t p)
+{
+ return ((p>>56)&0xff)<<24 | ((p>>40)&0xff)<<16 | ((p>>24)&0xff)<<8 | ((p>>8)&0xff)<<0;
+}
+
+static inline pixel_t
blendfog(pixel_t pix, fog_t fog)
{
- byte inva = 0xff - (fog.v[3]>>fogshift);
- return
- ((fog.v[0] + ((inva*((pix>> 0)&0xff))<<fogshift)) >> (8 + fogshift)) << 0 |
- ((fog.v[1] + ((inva*((pix>> 8)&0xff))<<fogshift)) >> (8 + fogshift)) << 8 |
- ((fog.v[2] + ((inva*((pix>>16)&0xff))<<fogshift)) >> (8 + fogshift)) << 16|
- (pix & (0xff<<24));
+ pixel_t a = pixfrom64(fog.v);
+ pixel_t b = mulalpha(pix, 0xff - (fog.v>>56));
+ return a + b;
}
static inline bool
fogcalc(uzint zi0, uzint zi1, int cnt, fog_t *f)
{
- int end[3], v, e;
+ int v, e;
+ pixel64_t x;
if((v = z2foga(zi0)) == 0 || (e = z2foga(zi1)) == 0)
return false;
- v <<= fogshift;
- e <<= fogshift;
-
- end[0] = e * fogvars.c0;
- end[1] = e * fogvars.c1;
- end[2] = e * fogvars.c2;
- f->v[0] = v * fogvars.c0;
- f->v[1] = v * fogvars.c1;
- f->v[2] = v * fogvars.c2;
- f->v[3] = v;
- f->d[0] = (end[0] - f->v[0])/cnt;
- f->d[1] = (end[1] - f->v[1])/cnt;
- f->d[2] = (end[2] - f->v[2])/cnt;
- f->d[3] = (e - v)/cnt;
+ f->v = pixto64(mulalpha(fogvars.pix, v));
+ x = pixto64(mulalpha(fogvars.pix, (e<v ? v-e : e-v)));
+ f->d =
+ (((x & (0xffffULL<<48))/cnt) & (0xffffULL<<48)) |
+ (((x & (0xffffULL<<32))/cnt) & (0xffffULL<<32)) |
+ (((x & (0xffffULL<<16))/cnt) & (0xffffULL<<16)) |
+ (((x & (0xffffULL<< 0))/cnt) & (0xffffULL<< 0));
+ if(e < v)
+ f->d = -f->d;
return true;
}
--- a/r_shared.h
+++ b/r_shared.h
@@ -8,20 +8,15 @@
Enskyfog = 1<<1,
};
-typedef struct fog_t fog_t;
typedef struct fogvars_t fogvars_t;
-struct fog_t {
- int v[4];
- int d[4];
-};
-
struct fogvars_t {
+ pixel_t pix;
float density;
- byte c0, c1, c2, sky;
- bool allowed;
- int enabled;
int skyc0, skyc1, skyc2;
+ int enabled;
+ byte sky, c0, c1, c2;
+ bool allowed;
};
extern fogvars_t fogvars;
--- a/vid.h
+++ b/vid.h
@@ -4,6 +4,7 @@
#define VID_GRADES (1 << VID_CBITS)
typedef u32int pixel_t;
+typedef u64int pixel64_t;
typedef struct vrect_s
{