]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/q3map2/light_bounce.c
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light_bounce.c
index f72653ab88fb21f849a820b341e1a6808a6e7931..b0b838b8ccea11094e34b50f3dc1745e0dc64384 100644 (file)
@@ -185,16 +185,33 @@ static void RadClipWindingEpsilon( radWinding_t *in, vec3_t normal, vec_t dist,
        }
 
        /* error check */
-       if ( front->numVerts > maxPoints || front->numVerts > maxPoints ) {
+       if ( front->numVerts > maxPoints ) {
                Error( "RadClipWindingEpsilon: points exceeded estimate" );
        }
-       if ( front->numVerts > MAX_POINTS_ON_WINDING || front->numVerts > MAX_POINTS_ON_WINDING ) {
+       if ( front->numVerts > MAX_POINTS_ON_WINDING ) {
                Error( "RadClipWindingEpsilon: MAX_POINTS_ON_WINDING" );
        }
 }
 
 
 
+/*
+   Modulo1IfNegative()
+   Previously the bias computation was doing:
+
+      while ( f < 0.0f ) {
+         f += 1.0f;
+      }
+
+   That may end in infinite loop in some case.
+   It may also be slower because of useless loops.
+   I don't know what that computation is for.
+   -- illwieckz
+*/
+float Modulo1IfNegative( float f ){
+       return f < 0.0f ? f - floor( f ) : f;
+}
+
 
 
 /*
@@ -204,10 +221,8 @@ static void RadClipWindingEpsilon( radWinding_t *in, vec3_t normal, vec_t dist,
  */
 
 qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] ){
-       float sto[ 2 ];
        int x, y;
 
-
        /* clear color first */
        color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255;
 
@@ -216,18 +231,10 @@ qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], flo
                return qfalse;
        }
 
-       /* bias st */
-       sto[ 0 ] = st[ 0 ];
-       while ( sto[ 0 ] < 0.0f )
-               sto[ 0 ] += 1.0f;
-       sto[ 1 ] = st[ 1 ];
-       while ( sto[ 1 ] < 0.0f )
-               sto[ 1 ] += 1.0f;
-
        /* get offsets */
-       x = ( (float) width * sto[ 0 ] ) + 0.5f;
+       x = ( (float) width * Modulo1IfNegative( st[ 0 ] ) ) + 0.5f;
        x %= width;
-       y = ( (float) height * sto[ 1 ] )  + 0.5f;
+       y = ( (float) height * Modulo1IfNegative( st[ 1 ] ) ) + 0.5f;
        y %= height;
 
        /* get pixel */
@@ -256,7 +263,7 @@ qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], flo
 #define SAMPLE_GRANULARITY  6
 
 static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si, radWinding_t *rw, vec3_t average, vec3_t gradient, int *style ){
-       int i, j, k, l, v, x, y, samples;
+       int i, j, k, l, v, x, y, samples, avgcolor, f_superSample;
        vec3_t color, mins, maxs;
        vec4_t textureColor;
        float alpha, alphaI, bf;
@@ -264,6 +271,8 @@ static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm,
        float st[ 2 ], lightmap[ 2 ], *radLuxel;
        radVert_t   *rv[ 3 ];
 
+       if (!bouncing)
+               Sys_Printf( "BUG: RadSample: !bouncing shouldn't happen\n" );
 
        /* initial setup */
        ClearBounds( mins, maxs );
@@ -286,10 +295,12 @@ static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm,
                        /* multiply by texture color */
                        if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) ) {
                                VectorCopy( si->averageColor, textureColor );
-                               textureColor[ 4 ] = 255.0f;
+                               textureColor[ 3 ] = 255.0f;
                        }
+                       avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
                        for ( i = 0; i < 3; i++ )
-                               color[ i ] = ( textureColor[ i ] / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
+                               color[ i ] = ( ( textureColor[ i ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
+//                             color[ i ] = ( textureColor[ i ] / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
 
                        AddPointToBounds( color, mins, maxs );
                        VectorAdd( average, color, average );
@@ -305,6 +316,7 @@ static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm,
        /* sample lightmap */
        else
        {
+               f_superSample = (float)superSample;
                /* fracture the winding into a fan (including degenerate tris) */
                for ( v = 1; v < ( rw->numVerts - 1 ) && samples < MAX_SAMPLES; v++ )
                {
@@ -324,7 +336,7 @@ static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm,
                                                blend[ 0 ] = i;
                                                blend[ 1 ] = j;
                                                blend[ 2 ] = k;
-                                               bf = ( 1.0 / ( blend[ 0 ] + blend[ 1 ] + blend[ 2 ] ) );
+                                               bf = ( 1.0f / ( blend[ 0 ] + blend[ 1 ] + blend[ 2 ] ) );
                                                VectorScale( blend, bf, blend );
 
                                                /* create a blended sample */
@@ -341,8 +353,10 @@ static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm,
                                                }
 
                                                /* get lightmap xy coords */
-                                               x = lightmap[ 0 ] / (float) superSample;
-                                               y = lightmap[ 1 ] / (float) superSample;
+                                               /* xy = clamp(lightmap/superSample, 0, lm - 1)*/
+                                               x = lightmap[ 0 ] / f_superSample;
+                                               y = lightmap[ 1 ] / f_superSample;
+
                                                if ( x < 0 ) {
                                                        x = 0;
                                                }
@@ -370,11 +384,20 @@ static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm,
                                                /* multiply by texture color */
                                                if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) ) {
                                                        VectorCopy( si->averageColor, textureColor );
-                                                       textureColor[ 4 ] = 255;
+                                                       textureColor[ 3 ] = 255;
+                                               }
+                                               avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
+                                               for ( i = 0; i < 3; i++ ){
+                                                       color[ i ] = ( ( textureColor[ i ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( radLuxel[ i ] / 255 );
+                                               /*
+                                                  Workaround for https://gitlab.com/xonotic/netradiant/-/issues/182
+                                                  This loop normally uses the l iterator instead of i:
+                                                  for ( l = 0; l < 3; l++ ){
+                                                       color[ l ] = ( ( textureColor[ l ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( radLuxel[ l ] / 255 );
+                                                       }
+                                               */
+                                               //Sys_Printf( "%i %i %i %i %i \n", (int) textureColor[ 0 ], (int) textureColor[ 1 ], (int) textureColor[ 2 ], (int) avgcolor, (int) color[ i ] );
                                                }
-                                               for ( i = 0; i < 3; i++ )
-                                                       color[ i ] = ( textureColor[ i ] / 255 ) * ( radLuxel[ i ] / 255 );
-
                                                AddPointToBounds( color, mins, maxs );
                                                VectorAdd( average, color, average );
 
@@ -422,13 +445,15 @@ static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm,
 #define RADIOSITY_MIN               0.0001f
 #define RADIOSITY_CLIP_EPSILON      0.125f
 
+
+
 static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si,
-                                                                         float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw ){
+                                                                         float scale, float subdivide, radWinding_t *rw, clipWork_t *cw ){
        int i, style = 0;
        float dist, area, value;
        vec3_t mins, maxs, normal, d1, d2, cross, color, gradient;
        light_t         *light, *splash;
-       winding_t       *w;
+       winding_t       *w, *splash_w;
 
 
        /* dummy check */
@@ -457,8 +482,8 @@ static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, raw
                        RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw );
 
                        /* recurse */
-                       RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &front, cw );
-                       RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &back, cw );
+                       RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &front, cw );
+                       RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &back, cw );
                        return;
                }
        }
@@ -484,7 +509,7 @@ static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, raw
                /* if color gradient is too high, subdivide again */
                if ( subdivide > minDiffuseSubdivide &&
                         ( gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT ) ) {
-                       RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, ( subdivide / 2.0f ), qfalse, rw, cw );
+                       RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, ( subdivide / 2.0f ), rw, cw );
                        return;
                }
        }
@@ -530,8 +555,7 @@ static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, raw
        }
 
        /* create a light */
-       light = safe_malloc( sizeof( *light ) );
-       memset( light, 0, sizeof( *light ) );
+       light = safe_malloc0( sizeof( *light ) );
 
        /* attach it */
        ThreadLock();
@@ -550,7 +574,10 @@ static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, raw
        light->falloffTolerance = falloffTolerance;
 
        /* bouncing light? */
-       if ( !bouncing ) {
+       if ( bouncing == qfalse ) {
+               /* This is weird. This actually handles surfacelight and not
+                * bounces. */
+
                /* handle first-pass lights in normal q3a style */
                value = si->value;
                light->photons = value * area * areaScale;
@@ -571,28 +598,77 @@ static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, raw
                VectorMA( light->origin, 1.0f, light->normal, light->origin );
                light->dist = DotProduct( light->origin, normal );
 
-               /* optionally create a point splashsplash light for first pass */
-               if ( original && si->backsplashFraction > 0 ) {
+#if 0
+               /* optionally create a point backsplash light */
+               if ( si->backsplashFraction > 0 ) {
+
                        /* allocate a new point light */
-                       splash = safe_malloc( sizeof( *splash ) );
-                       memset( splash, 0, sizeof( *splash ) );
+                       splash = safe_malloc0( sizeof( *splash ) );
+
                        splash->next = lights;
                        lights = splash;
 
+
                        /* set it up */
                        splash->flags = LIGHT_Q3A_DEFAULT;
                        splash->type = EMIT_POINT;
                        splash->photons = light->photons * si->backsplashFraction;
+
                        splash->fade = 1.0f;
                        splash->si = si;
                        VectorMA( light->origin, si->backsplashDistance, normal, splash->origin );
                        VectorCopy( si->color, splash->color );
+
                        splash->falloffTolerance = falloffTolerance;
                        splash->style = noStyles ? LS_NORMAL : light->style;
 
                        /* add to counts */
                        numPointLights++;
                }
+#endif
+
+#if 1
+               /* optionally create area backsplash light */
+               //if ( original && si->backsplashFraction > 0 ) {
+               if ( si->backsplashFraction > 0 && !( si->compileFlags & C_SKY ) ) {
+                       /* allocate a new area light */
+                       splash = safe_malloc( sizeof( *splash ) );
+                       memset( splash, 0, sizeof( *splash ) );
+                       ThreadLock();
+                       splash->next = lights;
+                       lights = splash;
+                       ThreadUnlock();
+
+                       /* set it up */
+                       splash->flags = LIGHT_AREA_DEFAULT;
+                       splash->type = EMIT_AREA;
+                       splash->photons = light->photons * 7.0f * si->backsplashFraction;
+                       splash->add = light->add * 7.0f * si->backsplashFraction;
+                       splash->fade = 1.0f;
+                       splash->si = si;
+                       VectorCopy( si->color, splash->color );
+                       VectorScale( splash->color, splash->add, splash->emitColor );
+                       splash->falloffTolerance = falloffTolerance;
+                       splash->style = noStyles ? LS_NORMAL : si->lightStyle;
+                       if ( splash->style < LS_NORMAL || splash->style >= LS_NONE ) {
+                               splash->style = LS_NORMAL;
+                       }
+
+                       /* create a regular winding */
+                       splash_w = AllocWinding( rw->numVerts );
+                       splash_w->numpoints = rw->numVerts;
+                       for ( i = 0; i < rw->numVerts; i++ )
+                               VectorMA( rw->verts[rw->numVerts - 1 - i].xyz, si->backsplashDistance, normal, splash_w->p[ i ] );
+                       splash->w = splash_w;
+
+                       VectorMA( light->origin, si->backsplashDistance, normal, splash->origin );
+                       VectorNegate( normal, splash->normal );
+            splash->dist = DotProduct( splash->origin, splash->normal );
+
+//                     splash->flags |= LIGHT_TWOSIDED;
+               }
+#endif
+
        }
        else
        {
@@ -616,6 +692,9 @@ static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, raw
                light->dist = DotProduct( light->origin, normal );
        }
 
+       if (light->photons < 0 || light->add < 0 || light->color[0] < 0 || light->color[1] < 0 || light->color[2] < 0)
+               Sys_Printf( "BUG: RadSubdivideDiffuseLight created a darkbulb\n" );
+
        /* emit light from both sides? */
        if ( si->compileFlags & C_FOG || si->twoSided ) {
                light->flags |= LIGHT_TWOSIDED;
@@ -628,7 +707,6 @@ static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, raw
 }
 
 
-
 /*
    RadLightForTriangles()
    creates unbounced diffuse lights for triangle soup (misc_models, etc)
@@ -667,7 +745,7 @@ void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderIn
                }
 
                /* subdivide into area lights */
-               RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
+               RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &rw, cw );
        }
 }
 
@@ -776,7 +854,7 @@ void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t
                                }
 
                                /* subdivide into area lights */
-                               RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
+                               RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &rw, cw );
                        }
 
                        /* generate 2 tris */
@@ -805,7 +883,7 @@ void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t
                                        }
 
                                        /* subdivide into area lights */
-                                       RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
+                                       RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &rw, cw );
                                }
                        }
                }