2023-05-08 14:57:51 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
2024-04-22 23:38:45 +02:00
|
|
|
Copyright (C) 2024 the OpenMoHAA team
|
2023-05-08 14:57:51 +02:00
|
|
|
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// tr_sphere_shade.cpp -- sphere shade
|
|
|
|
|
|
|
|
#include "tr_local.h"
|
|
|
|
|
2023-07-25 22:01:28 +02:00
|
|
|
typedef struct gatheredLight_s {
|
2023-12-31 21:53:13 +01:00
|
|
|
spherel_t *pLight;
|
|
|
|
float fIntensity;
|
|
|
|
gatheredLight_s *pPrev;
|
|
|
|
gatheredLight_s *pNext;
|
2023-07-25 22:01:28 +02:00
|
|
|
} gatheredLight_t;
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
vec3_t spheredef[6];
|
|
|
|
suninfo_t s_sun;
|
|
|
|
static vec3_t ambientlight;
|
2023-05-20 17:01:42 +02:00
|
|
|
static qboolean bEntityOverbright;
|
2023-12-31 21:53:13 +01:00
|
|
|
static int iEntityLightingMax;
|
|
|
|
static int light_reference_count = 0;
|
2023-05-20 17:01:42 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
const float one_half_root = 0.70710678118654752440084436210485f;
|
2023-07-25 22:01:28 +02:00
|
|
|
const float one_third_root = 0.57735026918962576450914878050196f;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
static vec3_t offsets[26] = {
|
|
|
|
{1.0, 0.0, 0.0 },
|
|
|
|
{-1.0, 0.0, 0.0 },
|
|
|
|
{0.0, 1.0, 0.0 },
|
|
|
|
{0.0, -1.0, 0.0 },
|
|
|
|
{0.0, 0.0, 1.0 },
|
|
|
|
{0.0, 0.0, -1.0 },
|
|
|
|
{one_half_root, one_half_root, 0.0 },
|
|
|
|
{one_half_root, -one_half_root, 0.0 },
|
|
|
|
{-one_half_root, one_half_root, 0.0 },
|
|
|
|
{-one_half_root, -one_half_root, 0.0 },
|
|
|
|
{one_half_root, 0.0, one_half_root },
|
|
|
|
{one_half_root, 0.0, -one_half_root },
|
|
|
|
{-one_half_root, 0.0, one_half_root },
|
|
|
|
{-one_half_root, 0.0, -one_half_root },
|
|
|
|
{0.0, one_half_root, one_half_root },
|
|
|
|
{0.0, one_half_root, -one_half_root },
|
|
|
|
{0.0, -one_half_root, one_half_root },
|
|
|
|
{0.0, -one_half_root, -one_half_root },
|
|
|
|
{one_third_root, one_third_root, one_third_root },
|
|
|
|
{one_third_root, one_third_root, -one_third_root},
|
|
|
|
{one_third_root, -one_third_root, one_third_root },
|
|
|
|
{one_third_root, -one_third_root, -one_third_root},
|
|
|
|
{-one_third_root, one_third_root, one_third_root },
|
|
|
|
{-one_third_root, one_third_root, -one_third_root},
|
|
|
|
{-one_third_root, -one_third_root, one_third_root },
|
|
|
|
{-one_third_root, -one_third_root, -one_third_root}
|
2023-07-24 20:14:39 +02:00
|
|
|
};
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
int compare_light_intensities(const void *p1, const void *p2)
|
2023-05-20 17:01:42 +02:00
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
return ((const reallightinfo_t *)p2)->fIntensity - ((const reallightinfo_t *)p1)->fIntensity;
|
2023-05-20 17:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void RB_OptimizeLights()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
static int iCubeBuildInfo[24][9];
|
|
|
|
int i, j;
|
|
|
|
int nCubeMapLights;
|
|
|
|
float fMaxIntensity;
|
|
|
|
vec3_t cubecolor[256];
|
|
|
|
vec3_t colorout;
|
|
|
|
float(*cube)[3][4];
|
|
|
|
reallightinfo_t *pLight;
|
|
|
|
|
|
|
|
nCubeMapLights = 0;
|
|
|
|
|
|
|
|
if (backEnd.currentSphere->numRealLights > 2) {
|
|
|
|
qsort(
|
|
|
|
backEnd.currentSphere->light,
|
|
|
|
backEnd.currentSphere->numRealLights,
|
|
|
|
sizeof(reallightinfo_t),
|
|
|
|
compare_light_intensities
|
2023-07-24 20:14:39 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
for (i = 0; i < backEnd.currentSphere->numRealLights && i < r_entlight_maxcalc->integer; i++) {
|
|
|
|
pLight = &backEnd.currentSphere->light[i];
|
|
|
|
|
|
|
|
if (pLight->fIntensity < r_entlight_cubelevel->value
|
2023-12-31 21:53:13 +01:00
|
|
|
|| pLight->fIntensity * r_entlight_cubefraction->value > pLight->fIntensity) {
|
|
|
|
break;
|
2023-07-24 20:14:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nCubeMapLights = backEnd.currentSphere->numRealLights - i;
|
2023-12-31 21:53:13 +01:00
|
|
|
if (nCubeMapLights <= 1) {
|
|
|
|
nCubeMapLights = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
backEnd.currentSphere->bUsesCubeMap = nCubeMapLights > 0;
|
|
|
|
if (backEnd.currentSphere->bUsesCubeMap) {
|
|
|
|
for (i = 0; i < 26; i++) {
|
|
|
|
float fDot;
|
|
|
|
vec3_t v;
|
|
|
|
|
|
|
|
colorout[0] = backEnd.currentSphere->ambient.level[0];
|
|
|
|
colorout[1] = backEnd.currentSphere->ambient.level[1];
|
|
|
|
colorout[2] = backEnd.currentSphere->ambient.level[2];
|
|
|
|
|
|
|
|
for (j = backEnd.currentSphere->numRealLights - nCubeMapLights; j < backEnd.currentSphere->numRealLights;
|
|
|
|
j++) {
|
|
|
|
pLight = &backEnd.currentSphere->light[j];
|
|
|
|
|
|
|
|
switch (pLight->eType) {
|
2023-07-24 20:14:39 +02:00
|
|
|
case LIGHT_SPOT:
|
2023-12-31 21:53:13 +01:00
|
|
|
{
|
|
|
|
fDot = DotProduct(pLight->vDirection, offsets[i]);
|
2023-07-24 20:14:39 +02:00
|
|
|
if (fDot > 0) {
|
|
|
|
float fProjSquared;
|
|
|
|
float fDistSquared;
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorSubtract(pLight->vOrigin, backEnd.currentSphere->origin, v);
|
|
|
|
fProjSquared = DotProduct(v, pLight->vDirection) * DotProduct(v, pLight->vDirection);
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
|
|
|
fMaxIntensity = (pLight->fSpotConst - fDistSquared / fProjSquared) * pLight->fSpotScale;
|
|
|
|
if (fMaxIntensity > 0) {
|
|
|
|
fDot /= fDistSquared;
|
|
|
|
if (fMaxIntensity < 1) {
|
|
|
|
fDot *= fMaxIntensity;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorMA(colorout, fDot, pLight->color, colorout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LIGHT_SPOT_FAST:
|
|
|
|
fDot = DotProduct(pLight->vDirection, offsets[i]);
|
2023-07-24 20:14:39 +02:00
|
|
|
if (fDot > 0) {
|
|
|
|
float fDistSquared;
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorSubtract(pLight->vOrigin, backEnd.currentSphere->origin, v);
|
2023-07-24 20:14:39 +02:00
|
|
|
fDistSquared = VectorLengthSquared(v);
|
|
|
|
|
|
|
|
fDot /= fDistSquared;
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorMA(colorout, fDot, pLight->color, colorout);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LIGHT_DIRECTIONAL:
|
|
|
|
fDot = DotProduct(pLight->vDirection, offsets[i]);
|
|
|
|
if (fDot > 0) {
|
|
|
|
VectorMA(colorout, fDot, pLight->color, colorout);
|
|
|
|
}
|
|
|
|
break;
|
2023-07-24 20:14:39 +02:00
|
|
|
case LIGHT_POINT:
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorSubtract(pLight->vOrigin, backEnd.currentSphere->origin, v);
|
|
|
|
fDot = DotProduct(v, offsets[i]);
|
|
|
|
if (fDot > 0) {
|
|
|
|
fDot /= VectorLengthSquared(v);
|
|
|
|
VectorMA(colorout, fDot, pLight->color, colorout);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(!"unhandled light type");
|
|
|
|
break;
|
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
cubecolor[i][0] = colorout[0];
|
|
|
|
if (cubecolor[i][0] > 255.f) {
|
|
|
|
cubecolor[i][0] = 255.f;
|
2023-07-24 20:14:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cubecolor[i][1] = colorout[1];
|
|
|
|
if (cubecolor[i][1] > 255.f) {
|
|
|
|
cubecolor[i][1] = 255.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
cubecolor[i][2] = colorout[2];
|
|
|
|
if (cubecolor[i][2] > 255.f) {
|
|
|
|
cubecolor[i][2] = 255.f;
|
|
|
|
}
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
cube = backEnd.currentSphere->cubemap;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
for (i = 0; i < 24; i++) {
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
|
|
vec4_t f;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
f[0] = cubecolor[iCubeBuildInfo[i][5]][j];
|
|
|
|
f[1] = cubecolor[iCubeBuildInfo[i][6]][j];
|
2023-12-31 21:53:13 +01:00
|
|
|
f[2] = cubecolor[iCubeBuildInfo[i][7]][j];
|
|
|
|
f[3] = cubecolor[iCubeBuildInfo[i][8]][j];
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
cube[i][j][0] = f[0];
|
|
|
|
cube[i][j][1] = (f[1] - f[0]) * iCubeBuildInfo[i][3];
|
|
|
|
cube[i][j][2] = (f[2] - f[0]) * iCubeBuildInfo[i][4];
|
|
|
|
cube[i][j][3] = (f[0] - f[1] - f[2] + f[3]) * iCubeBuildInfo[i][3] * iCubeBuildInfo[i][4];
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
backEnd.currentSphere->numRealLights -= nCubeMapLights;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < backEnd.currentSphere->numRealLights; i++) {
|
|
|
|
float fDistParallel;
|
|
|
|
float fDistPerp;
|
|
|
|
float fDistSquared;
|
|
|
|
float fRadiusSquared;
|
|
|
|
float fSlope;
|
|
|
|
vec3_t v;
|
|
|
|
|
|
|
|
pLight = &backEnd.currentSphere->light[i];
|
|
|
|
|
|
|
|
switch (pLight->eType) {
|
|
|
|
case LIGHT_SPOT:
|
|
|
|
VectorSubtract(pLight->vOrigin, backEnd.currentSphere->origin, v);
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
|
|
|
fSlope = DotProduct(v, pLight->vDirection);
|
|
|
|
fDistPerp = sqrt(fDistSquared - fSlope * fSlope);
|
|
|
|
fRadiusSquared = backEnd.currentSphere->radius * backEnd.currentSphere->radius;
|
|
|
|
fDistParallel = fDistPerp + fSlope * (pLight->fSpotSlope * 0.9f);
|
|
|
|
if (fDistParallel * fDistParallel
|
|
|
|
>= fRadiusSquared + pLight->fSpotSlope * 0.9f * (pLight->fSpotSlope * 0.9f) * fRadiusSquared) {
|
|
|
|
pLight->eType = LIGHT_SPOT_FAST;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LIGHT_POINT:
|
|
|
|
if ((pLight->fDist - backEnd.currentSphere->radius) * r_entlight_errbound->value * pLight->fDist
|
|
|
|
> backEnd.currentSphere->radius * pLight->fIntensity) {
|
|
|
|
pLight->color[0] *= 1.f / pLight->fDist;
|
|
|
|
pLight->color[1] *= 1.f / pLight->fDist;
|
|
|
|
pLight->color[2] *= 1.f / pLight->fDist;
|
|
|
|
pLight->eType = LIGHT_DIRECTIONAL;
|
|
|
|
VectorNormalize2(pLight->vOrigin, pLight->vDirection);
|
|
|
|
}
|
|
|
|
break;
|
2024-06-07 20:34:13 +02:00
|
|
|
default:
|
|
|
|
break;
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
|
|
|
}
|
2023-05-20 17:01:42 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
static void RB_Light_CubeMap(unsigned char *colors)
|
2023-05-15 14:21:16 +02:00
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
int i, j;
|
|
|
|
float *normal;
|
|
|
|
float *xyz;
|
|
|
|
unsigned char *color;
|
|
|
|
vec3_t colorout;
|
|
|
|
reallightinfo_t *pLight;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
color = colors;
|
|
|
|
normal = (float *)tess.normal;
|
|
|
|
xyz = (float *)tess.xyz;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
for (i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4, color += 4) {
|
2023-12-31 21:53:13 +01:00
|
|
|
unsigned int components[3];
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (normal[1] == -1) {
|
|
|
|
components[0] = 1;
|
|
|
|
components[1] = 0;
|
|
|
|
components[2] = 2;
|
2023-07-24 20:14:39 +02:00
|
|
|
} else if (normal[1] == 1 && !normal[0] && !normal[2]) {
|
2023-12-31 21:53:13 +01:00
|
|
|
components[0] = 1;
|
|
|
|
components[1] = 0;
|
|
|
|
components[2] = 2;
|
|
|
|
} else if (Q_fabs(normal[0]) >= Q_fabs(normal[2])) {
|
|
|
|
components[0] = 0;
|
|
|
|
components[1] = 1;
|
|
|
|
components[2] = 2;
|
|
|
|
} else {
|
|
|
|
components[0] = 2;
|
|
|
|
components[1] = 1;
|
|
|
|
components[2] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int cubeIndex =
|
|
|
|
(normal[2] < 0 ? 1 : 0) | (normal[1] < 0 ? 2 : 0) | (normal[0] < 0 ? 4 : 0) | (components[0] << 3);
|
|
|
|
float newnorms[3];
|
|
|
|
float mapping[3];
|
|
|
|
float(*cube)[3][4];
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
newnorms[0] = normal[components[0]];
|
|
|
|
newnorms[1] = normal[components[1]];
|
|
|
|
newnorms[2] = normal[components[2]];
|
|
|
|
|
|
|
|
mapping[0] = 1.f / newnorms[0] * newnorms[1];
|
|
|
|
mapping[1] = 1.f / newnorms[0] * newnorms[2];
|
|
|
|
mapping[2] = mapping[0] * mapping[1];
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
cube = &backEnd.currentSphere->cubemap[cubeIndex];
|
|
|
|
colorout[0] =
|
|
|
|
(*cube)[0][0] + (*cube)[0][1] * mapping[1] + (*cube)[0][2] * mapping[1] + (*cube)[0][3] * mapping[2];
|
|
|
|
colorout[1] =
|
|
|
|
(*cube)[1][0] + (*cube)[1][1] * mapping[1] + (*cube)[1][2] * mapping[1] + (*cube)[1][3] * mapping[2];
|
|
|
|
colorout[2] =
|
|
|
|
(*cube)[2][0] + (*cube)[2][1] * mapping[1] + (*cube)[2][2] * mapping[1] + (*cube)[2][3] * mapping[2];
|
|
|
|
|
|
|
|
for (j = 0; j < backEnd.currentSphere->numRealLights; j++) {
|
|
|
|
float fDistSquared;
|
|
|
|
float fProjSquared;
|
|
|
|
float fMaxIntensity;
|
|
|
|
float fDot;
|
|
|
|
vec3_t v;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
pLight = &backEnd.currentSphere->light[j];
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
switch (pLight->eType) {
|
2023-07-24 20:14:39 +02:00
|
|
|
case LIGHT_DIRECTIONAL:
|
|
|
|
fDot = DotProduct(pLight->vDirection, normal);
|
|
|
|
if (fDot > 0) {
|
|
|
|
VectorMA(colorout, fDot, pLight->color, colorout);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LIGHT_SPOT:
|
|
|
|
fDot = DotProduct(pLight->vDirection, normal);
|
|
|
|
if (fDot > 0) {
|
|
|
|
VectorSubtract(pLight->vOrigin, xyz, v);
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
fProjSquared = DotProduct(v, pLight->vDirection) * DotProduct(v, pLight->vDirection);
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
2023-07-24 20:14:39 +02:00
|
|
|
fMaxIntensity = (pLight->fSpotConst - fDistSquared / fProjSquared) * pLight->fSpotScale;
|
|
|
|
if (fMaxIntensity > 0) {
|
|
|
|
fDot /= fDistSquared;
|
|
|
|
if (fMaxIntensity < 1) {
|
|
|
|
fDot *= fMaxIntensity;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorMA(colorout, fDot, pLight->color, colorout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LIGHT_SPOT_FAST:
|
|
|
|
fDot = DotProduct(pLight->vDirection, normal);
|
|
|
|
if (fDot > 0) {
|
|
|
|
VectorSubtract(pLight->vOrigin, xyz, v);
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
|
|
|
VectorMA(colorout, fDot / fDistSquared, pLight->color, colorout);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LIGHT_POINT:
|
|
|
|
VectorSubtract(pLight->vOrigin, xyz, v);
|
|
|
|
fDot = DotProduct(v, normal);
|
|
|
|
if (fDot > 0) {
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
|
|
|
VectorMA(colorout, fDot / fDistSquared, pLight->color, colorout);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
color[0] = Q_clamp_int(colorout[0], 0, 255);
|
|
|
|
color[1] = Q_clamp_int(colorout[1], 0, 255);
|
|
|
|
color[2] = Q_clamp_int(colorout[2], 0, 255);
|
|
|
|
}
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
void RB_Light_Real(unsigned char *colors)
|
2023-05-15 14:21:16 +02:00
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
int i, j;
|
|
|
|
float *normal;
|
|
|
|
float *xyz;
|
|
|
|
unsigned char *color;
|
|
|
|
vec3_t v;
|
|
|
|
vec3_t colorout;
|
|
|
|
float fDot;
|
|
|
|
reallightinfo_t *pLight;
|
|
|
|
|
|
|
|
color = colors;
|
2023-07-24 20:14:39 +02:00
|
|
|
if (backEnd.currentSphere->bUsesCubeMap) {
|
|
|
|
RB_Light_CubeMap(colors);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (!backEnd.currentSphere->numRealLights) {
|
|
|
|
for (i = 0; i < tess.numVertexes; i++, color += 4) {
|
2023-07-24 20:14:39 +02:00
|
|
|
color[0] = backEnd.currentSphere->ambient.level[0];
|
|
|
|
color[1] = backEnd.currentSphere->ambient.level[1];
|
|
|
|
color[2] = backEnd.currentSphere->ambient.level[2];
|
|
|
|
color[3] = backEnd.currentSphere->ambient.level[3];
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (backEnd.currentSphere->numRealLights != 1) {
|
|
|
|
normal = (float *)tess.normal;
|
|
|
|
xyz = (float *)tess.xyz;
|
|
|
|
|
|
|
|
for (i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4, color += 4) {
|
|
|
|
colorout[0] = colorout[1] = colorout[2] = 0;
|
|
|
|
|
|
|
|
for (j = 0; j < backEnd.currentSphere->numRealLights; j++) {
|
|
|
|
float fDistSquared;
|
|
|
|
float fProjSquared;
|
|
|
|
float fMaxIntensity;
|
|
|
|
|
|
|
|
pLight = &backEnd.currentSphere->light[j];
|
|
|
|
|
|
|
|
switch (pLight->eType) {
|
|
|
|
case LIGHT_DIRECTIONAL:
|
|
|
|
fDot = DotProduct(pLight->vDirection, normal);
|
|
|
|
if (fDot > 0) {
|
|
|
|
VectorMA(colorout, fDot, pLight->color, colorout);
|
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
break;
|
|
|
|
case LIGHT_SPOT:
|
|
|
|
fDot = DotProduct(pLight->vDirection, normal);
|
|
|
|
if (fDot > 0) {
|
|
|
|
VectorSubtract(pLight->vOrigin, xyz, v);
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
fProjSquared = DotProduct(v, pLight->vDirection) * DotProduct(v, pLight->vDirection);
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
2023-07-24 20:14:39 +02:00
|
|
|
fMaxIntensity = (pLight->fSpotConst - fDistSquared / fProjSquared) * pLight->fSpotScale;
|
|
|
|
if (fMaxIntensity > 0) {
|
|
|
|
fDot /= fDistSquared;
|
|
|
|
if (fMaxIntensity < 1) {
|
|
|
|
fDot *= fMaxIntensity;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorMA(colorout, fDot, pLight->color, colorout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LIGHT_SPOT_FAST:
|
2023-12-31 21:53:13 +01:00
|
|
|
fDot = DotProduct(pLight->vDirection, normal);
|
2023-07-24 20:14:39 +02:00
|
|
|
if (fDot > 0) {
|
|
|
|
VectorSubtract(pLight->vOrigin, xyz, v);
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorMA(colorout, fDot / fDistSquared, pLight->color, colorout);
|
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
break;
|
|
|
|
case LIGHT_POINT:
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorSubtract(pLight->vOrigin, xyz, v);
|
|
|
|
fDot = DotProduct(v, normal);
|
|
|
|
if (fDot > 0) {
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
|
|
|
VectorMA(colorout, fDot / fDistSquared, pLight->color, colorout);
|
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
break;
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
color[0] = Q_clamp_int((int)colorout[0] + backEnd.currentSphere->ambient.level[0], 0, 255);
|
|
|
|
color[1] = Q_clamp_int((int)colorout[1] + backEnd.currentSphere->ambient.level[1], 0, 255);
|
|
|
|
color[2] = Q_clamp_int((int)colorout[2] + backEnd.currentSphere->ambient.level[2], 0, 255);
|
|
|
|
color[3] = 0xff;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
normal = (float *)tess.normal;
|
|
|
|
xyz = (float *)tess.xyz;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
pLight = &backEnd.currentSphere->light[0];
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
switch (backEnd.currentSphere->light[0].eType) {
|
|
|
|
case LIGHT_DIRECTIONAL:
|
|
|
|
for (i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4, color += 4) {
|
2023-07-24 20:14:39 +02:00
|
|
|
fDot = DotProduct(pLight->vDirection, normal);
|
|
|
|
if (fDot > 0) {
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorScale(pLight->color, fDot, colorout);
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
color[0] = Q_clamp_int((int)colorout[0] + backEnd.currentSphere->ambient.level[0], 0, 255);
|
|
|
|
color[1] = Q_clamp_int((int)colorout[1] + backEnd.currentSphere->ambient.level[1], 0, 255);
|
|
|
|
color[2] = Q_clamp_int((int)colorout[2] + backEnd.currentSphere->ambient.level[2], 0, 255);
|
2023-12-31 21:53:13 +01:00
|
|
|
color[3] = 0xff;
|
2023-07-24 20:14:39 +02:00
|
|
|
} else {
|
|
|
|
color[0] = backEnd.currentSphere->ambient.level[0];
|
|
|
|
color[1] = backEnd.currentSphere->ambient.level[1];
|
|
|
|
color[2] = backEnd.currentSphere->ambient.level[2];
|
|
|
|
color[3] = backEnd.currentSphere->ambient.level[3];
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2023-07-24 20:14:39 +02:00
|
|
|
case LIGHT_SPOT:
|
2023-12-31 21:53:13 +01:00
|
|
|
for (i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4, color += 4) {
|
2023-07-24 20:14:39 +02:00
|
|
|
float fDistSquared;
|
|
|
|
float fProjSquared;
|
|
|
|
float fMaxIntensity;
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
color[0] = backEnd.currentSphere->ambient.level[0];
|
|
|
|
color[1] = backEnd.currentSphere->ambient.level[1];
|
|
|
|
color[2] = backEnd.currentSphere->ambient.level[2];
|
|
|
|
color[3] = backEnd.currentSphere->ambient.level[3];
|
|
|
|
|
|
|
|
fDot = DotProduct(pLight->vDirection, normal);
|
2023-07-24 20:14:39 +02:00
|
|
|
if (fDot > 0) {
|
|
|
|
VectorSubtract(pLight->vOrigin, xyz, v);
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
fProjSquared = DotProduct(v, pLight->vDirection) * DotProduct(v, pLight->vDirection);
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
2023-07-24 20:14:39 +02:00
|
|
|
fMaxIntensity = (pLight->fSpotConst - fDistSquared / fProjSquared) * pLight->fSpotScale;
|
|
|
|
if (fMaxIntensity > 0) {
|
|
|
|
fDot /= fDistSquared;
|
|
|
|
if (fMaxIntensity < 1) {
|
|
|
|
fDot *= fMaxIntensity;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorScale(pLight->color, fDot, colorout);
|
2023-12-31 21:53:13 +01:00
|
|
|
|
|
|
|
color[0] = Q_clamp_int((int)colorout[0] + backEnd.currentSphere->ambient.level[0], 0, 255);
|
2023-07-24 20:14:39 +02:00
|
|
|
color[1] = Q_clamp_int((int)colorout[1] + backEnd.currentSphere->ambient.level[1], 0, 255);
|
|
|
|
color[2] = Q_clamp_int((int)colorout[2] + backEnd.currentSphere->ambient.level[2], 0, 255);
|
|
|
|
color[3] = 0xff;
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
}
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
|
|
|
break;
|
2023-07-24 20:14:39 +02:00
|
|
|
case LIGHT_SPOT_FAST:
|
|
|
|
for (i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4, color += 4) {
|
|
|
|
color[0] = backEnd.currentSphere->ambient.level[0];
|
|
|
|
color[1] = backEnd.currentSphere->ambient.level[1];
|
|
|
|
color[2] = backEnd.currentSphere->ambient.level[2];
|
|
|
|
color[3] = backEnd.currentSphere->ambient.level[3];
|
2023-12-31 21:53:13 +01:00
|
|
|
|
|
|
|
fDot = DotProduct(pLight->vDirection, normal);
|
2023-07-24 20:14:39 +02:00
|
|
|
if (fDot > 0) {
|
2023-12-31 21:53:13 +01:00
|
|
|
float fDistSquared;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
VectorSubtract(pLight->vOrigin, xyz, v);
|
|
|
|
fDistSquared = VectorLengthSquared(v);
|
|
|
|
VectorScale(pLight->color, fDot / fDistSquared, colorout);
|
|
|
|
|
|
|
|
color[0] = Q_clamp_int((int)colorout[0] + backEnd.currentSphere->ambient.level[0], 0, 255);
|
|
|
|
color[1] = Q_clamp_int((int)colorout[1] + backEnd.currentSphere->ambient.level[1], 0, 255);
|
|
|
|
color[2] = Q_clamp_int((int)colorout[2] + backEnd.currentSphere->ambient.level[2], 0, 255);
|
|
|
|
color[3] = 0xff;
|
|
|
|
}
|
|
|
|
}
|
2023-12-31 21:53:13 +01:00
|
|
|
break;
|
2023-07-24 20:14:39 +02:00
|
|
|
case LIGHT_POINT:
|
2023-12-31 21:53:13 +01:00
|
|
|
for (i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4, color += 4) {
|
|
|
|
VectorSubtract(pLight->vOrigin, xyz, v);
|
|
|
|
fDot = DotProduct(v, normal);
|
|
|
|
if (fDot > 0) {
|
|
|
|
float fDistSquared;
|
2023-05-20 17:01:42 +02:00
|
|
|
|
2023-07-24 20:14:39 +02:00
|
|
|
fDistSquared = VectorLengthSquared(v);
|
|
|
|
VectorScale(pLight->color, fDot / fDistSquared, colorout);
|
|
|
|
|
|
|
|
color[0] = Q_clamp_int((int)colorout[0] + backEnd.currentSphere->ambient.level[0], 0, 255);
|
|
|
|
color[1] = Q_clamp_int((int)colorout[1] + backEnd.currentSphere->ambient.level[1], 0, 255);
|
|
|
|
color[2] = Q_clamp_int((int)colorout[2] + backEnd.currentSphere->ambient.level[2], 0, 255);
|
|
|
|
color[3] = 0xff;
|
2023-12-31 21:53:13 +01:00
|
|
|
} else {
|
|
|
|
color[0] = backEnd.currentSphere->ambient.level[0];
|
|
|
|
color[1] = backEnd.currentSphere->ambient.level[1];
|
|
|
|
color[2] = backEnd.currentSphere->ambient.level[2];
|
|
|
|
color[3] = backEnd.currentSphere->ambient.level[3];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void RB_Sphere_Light_Sun()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
int curleaf;
|
|
|
|
qboolean hitSun;
|
|
|
|
vec3_t end;
|
|
|
|
mnode_t *leaf;
|
|
|
|
trace_t trace;
|
|
|
|
|
|
|
|
if (!s_sun.exists) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tr.world->vis && backEnd.currentSphere->leaves[0] && tr.sSunLight.leaf == (struct mnode_s *)-1) {
|
|
|
|
vec3_t transpos;
|
|
|
|
vec3_t temppos;
|
|
|
|
|
2024-09-17 20:51:00 +02:00
|
|
|
for (curleaf = 0; curleaf < 8; curleaf++) {
|
|
|
|
leaf = backEnd.currentSphere->leaves[curleaf];
|
|
|
|
if (!leaf) {
|
2023-12-31 21:53:13 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-09-17 20:51:00 +02:00
|
|
|
if (leaf->numlights && leaf->lights[0] == &tr.sSunLight) {
|
2023-12-31 21:53:13 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!leaf || (leaf->lights && leaf->lights[0] != &tr.sSunLight)) {
|
|
|
|
if (r_light_sun_line->integer) {
|
|
|
|
VectorMA(backEnd.currentSphere->worldOrigin, 16384.0, s_sun.direction, end);
|
|
|
|
|
|
|
|
VectorCopy(backEnd.currentEntity->e.origin, temppos);
|
|
|
|
MatrixTransformVectorRight(backEnd.currentEntity->e.axis, temppos, transpos);
|
|
|
|
|
|
|
|
GL_State(GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE);
|
|
|
|
|
|
|
|
qglPushMatrix();
|
|
|
|
|
|
|
|
qglLoadMatrixf(backEnd.ori.modelMatrix);
|
|
|
|
// Clear the depth range
|
|
|
|
qglDepthRange(0.0, 0.0);
|
|
|
|
|
|
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
qglBegin(GL_LINES);
|
|
|
|
qglColor3f(0.0, 0.0, 0.0);
|
|
|
|
qglVertex3fv(backEnd.currentSphere->origin);
|
|
|
|
qglColor3f(0.5, 0.5, 0.5);
|
|
|
|
qglVertex3fv(transpos);
|
|
|
|
qglEnd();
|
|
|
|
|
|
|
|
qglEnable(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
// Bring the depth range back
|
|
|
|
qglDepthRange(0.0, 1.0);
|
|
|
|
|
|
|
|
qglPopMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorMA(backEnd.currentSphere->traceOrigin, 16384.0, s_sun.direction, end);
|
2024-09-17 20:51:00 +02:00
|
|
|
ri.CM_BoxTrace(&trace, backEnd.currentSphere->traceOrigin, end, vec3_origin, vec3_origin, 0, CONTENTS_SOLID | CONTENTS_FENCE, 0);
|
2023-12-31 21:53:13 +01:00
|
|
|
|
|
|
|
hitSun = (trace.surfaceFlags >> 2) & 1;
|
2023-07-24 20:14:39 +02:00
|
|
|
if (r_light_sun_line->integer) {
|
|
|
|
vec3_t transpos;
|
|
|
|
vec3_t temppos;
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorSubtract(trace.endpos, backEnd.currentEntity->e.origin, temppos);
|
2023-07-24 20:14:39 +02:00
|
|
|
MatrixTransformVectorRight(backEnd.currentEntity->e.axis, temppos, transpos);
|
|
|
|
|
|
|
|
GL_State(GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE);
|
|
|
|
|
|
|
|
qglPushMatrix();
|
|
|
|
|
|
|
|
qglLoadMatrixf(backEnd.ori.modelMatrix);
|
|
|
|
// Clear the depth range
|
|
|
|
qglDepthRange(0.0, 0.0);
|
|
|
|
|
|
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
qglBegin(GL_LINES);
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (hitSun) {
|
|
|
|
qglColor3f(1.0, 1.0, 0.0);
|
|
|
|
} else {
|
|
|
|
qglColor3f(0.0, 0.0, 0.0);
|
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
qglVertex3fv(backEnd.currentSphere->origin);
|
|
|
|
qglColor3f(0.5, 0.5, 0.5);
|
|
|
|
qglVertex3fv(transpos);
|
|
|
|
qglEnd();
|
|
|
|
|
|
|
|
qglEnable(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
// Bring the depth range back
|
|
|
|
qglDepthRange(0.0, 1.0);
|
|
|
|
|
|
|
|
qglPopMatrix();
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (hitSun) {
|
|
|
|
vec3_t sunnormal;
|
|
|
|
sphereor_t *pSphere;
|
|
|
|
reallightinfo_t *pLight;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
pSphere = backEnd.currentSphere;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
MatrixTransformVectorRight(backEnd.currentEntity->e.axis, s_sun.direction, sunnormal);
|
2023-12-31 21:53:13 +01:00
|
|
|
|
2024-09-17 20:51:00 +02:00
|
|
|
pLight = &pSphere->light[pSphere->numRealLights];
|
|
|
|
VectorScale(s_sun.color, r_entlight_scale->value, pLight->color);
|
|
|
|
//VectorScale(s_sun.color, r_entlight_scale->value * tr.overbrightMult, pLight->color);
|
2023-12-31 21:53:13 +01:00
|
|
|
|
|
|
|
VectorCopy(sunnormal, pLight->vDirection);
|
|
|
|
pLight->eType = LIGHT_DIRECTIONAL;
|
|
|
|
pLight->fIntensity = pLight->color[0] * 0.299f + pLight->color[1] * 0.587f + pLight->color[2] * 0.114f;
|
|
|
|
|
|
|
|
pSphere->numRealLights++;
|
|
|
|
}
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static qboolean RB_Sphere_CalculateSphereOrigin()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
vec3_t *axis;
|
|
|
|
vec3_t sphereOrigin;
|
|
|
|
trRefEntity_t *refent;
|
|
|
|
trRefEntity_t *newref;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
axis = backEnd.currentEntity->e.axis;
|
2023-12-31 21:53:13 +01:00
|
|
|
if (!backEnd.currentEntity->e.tiki) {
|
|
|
|
return qfalse;
|
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
backEnd.currentSphere->radius = backEnd.currentEntity->e.radius;
|
|
|
|
VectorCopy(backEnd.currentEntity->e.lightingOrigin, backEnd.currentSphere->worldOrigin);
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorSubtract(backEnd.currentSphere->worldOrigin, backEnd.currentEntity->e.origin, sphereOrigin);
|
|
|
|
MatrixTransformVectorRight(axis, sphereOrigin, backEnd.currentSphere->origin);
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
for (refent = backEnd.currentEntity;; refent = newref) {
|
2023-07-24 20:14:39 +02:00
|
|
|
if (refent->e.parentEntity == ENTITYNUM_NONE) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
newref = &backEnd.refdef.entities[refent->e.parentEntity];
|
|
|
|
if (refent == newref) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorCopy(refent->e.lightingOrigin, backEnd.currentSphere->traceOrigin);
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
return qtrue;
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool RB_Sphere_SetupGlobals()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if ((backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && !(backEnd.refdef.rdflags & RDF_HUD)) {
|
|
|
|
backEnd.currentSphere->TessFunction = &RB_Light_Fullbright;
|
|
|
|
return false;
|
|
|
|
}
|
2024-09-17 20:51:00 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (backEnd.refdef.rdflags & RDF_HUD) {
|
2024-09-17 20:51:00 +02:00
|
|
|
if (!backEnd.refdef.vieworg[0] && !backEnd.refdef.vieworg[1] && !backEnd.refdef.vieworg[2]) {
|
2023-12-31 21:53:13 +01:00
|
|
|
backEnd.currentSphere->TessFunction = &RB_Light_Fullbright;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorCopy(backEnd.refdef.vieworg, backEnd.currentSphere->worldOrigin);
|
|
|
|
VectorClear(backEnd.currentSphere->origin);
|
|
|
|
backEnd.currentSphere->radius = 2.0;
|
|
|
|
} else if (!RB_Sphere_CalculateSphereOrigin()) {
|
|
|
|
backEnd.currentSphere->TessFunction = &RB_CalcLightGridColor;
|
|
|
|
|
|
|
|
if (!backEnd.currentEntity->bLightGridCalculated) {
|
|
|
|
RB_SetupEntityGridLighting();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
light_reference_count++;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
backEnd.currentSphere->leaves[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_SphereInLeafs(
|
|
|
|
backEnd.currentSphere->worldOrigin, backEnd.currentSphere->radius, backEnd.currentSphere->leaves, 8
|
|
|
|
);
|
|
|
|
|
|
|
|
backEnd.currentSphere->TessFunction = &RB_Light_Real;
|
|
|
|
return true;
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool RB_Sphere_ResetPointColors()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
vec3_t light_offset, amb;
|
|
|
|
|
|
|
|
R_GetLightingGridValue(backEnd.currentSphere->worldOrigin, light_offset);
|
|
|
|
light_offset[0] = ambientlight[0] + light_offset[0] * 0.18;
|
|
|
|
light_offset[1] = ambientlight[1] + light_offset[1] * 0.18;
|
|
|
|
light_offset[2] = ambientlight[2] + light_offset[2] * 0.18;
|
|
|
|
if (tr.refdef.rdflags & RDF_FULLBRIGHT) {
|
|
|
|
float fMin = tr.identityLight * 20.0;
|
|
|
|
|
|
|
|
if (fMin <= light_offset[0] || fMin <= light_offset[1] || fMin <= light_offset[2]) {
|
|
|
|
light_offset[0] += fMin;
|
|
|
|
light_offset[1] += fMin;
|
|
|
|
light_offset[2] += fMin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-17 20:51:00 +02:00
|
|
|
VectorScale(light_offset, tr.overbrightMult * r_entlight_scale->value, amb);
|
|
|
|
backEnd.currentSphere->ambient.level[0] = Q_min(amb[0], 0xff);
|
|
|
|
backEnd.currentSphere->ambient.level[1] = Q_min(amb[1], 0xff);
|
|
|
|
backEnd.currentSphere->ambient.level[2] = Q_min(amb[2], 0xff);
|
2023-12-31 21:53:13 +01:00
|
|
|
backEnd.currentSphere->ambient.level[3] = 0xff;
|
2023-05-20 17:01:42 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
return true;
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
static void RB_Sphere_DrawDebugLine(const spherel_t *thislight, float falloff, const vec3_t origin)
|
2023-05-15 14:21:16 +02:00
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
int i;
|
|
|
|
vec3_t newColor;
|
|
|
|
vec3_t fakeLine, fakeLine2;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (!r_light_lines->integer) {
|
|
|
|
return;
|
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
qglPushMatrix();
|
|
|
|
|
|
|
|
qglLoadMatrixf(backEnd.ori.modelMatrix);
|
|
|
|
// Clear the depth range
|
|
|
|
qglDepthRange(0.0, 0.0);
|
|
|
|
|
|
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (r_light_lines->integer == 2) {
|
|
|
|
newColor[0] = thislight->color[0] * (falloff * r_entlight_scale->value / 255.0);
|
|
|
|
newColor[1] = thislight->color[1] * (falloff * r_entlight_scale->value / 255.0);
|
|
|
|
newColor[2] = thislight->color[2] * (falloff * r_entlight_scale->value / 255.0);
|
|
|
|
|
|
|
|
if (newColor[0] > 1 || newColor[1] > 1 || newColor[2] > 1) {
|
|
|
|
NormalizeColor(newColor, newColor);
|
|
|
|
}
|
|
|
|
} else if (thislight->spot_light) {
|
2023-07-24 20:14:39 +02:00
|
|
|
newColor[0] = 1.0;
|
|
|
|
newColor[1] = 0.7;
|
|
|
|
newColor[2] = 0.7;
|
2023-12-31 21:53:13 +01:00
|
|
|
} else {
|
2023-07-24 20:14:39 +02:00
|
|
|
newColor[0] = 1.0;
|
|
|
|
newColor[1] = 1.0;
|
|
|
|
newColor[2] = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
qglColor3f(newColor[0], newColor[1], newColor[2]);
|
|
|
|
|
|
|
|
qglBegin(GL_LINES);
|
|
|
|
qglVertex3fv(origin);
|
|
|
|
qglVertex3fv(backEnd.currentSphere->origin);
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
for (i = 0; i < 5; i += 2) {
|
|
|
|
VectorMA(origin, 16.0, spheredef[i], fakeLine);
|
|
|
|
VectorMA(origin, -16.0, spheredef[i], fakeLine2);
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
qglVertex3fv(fakeLine);
|
|
|
|
qglVertex3fv(fakeLine2);
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (thislight->spot_light) {
|
|
|
|
qglColor3f(0.7, 1.0, 0.7);
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
MatrixTransformVectorRight(backEnd.currentEntity->e.axis, thislight->spot_dir, fakeLine);
|
|
|
|
VectorMA(origin, 32.0, fakeLine, fakeLine);
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
qglVertex3fv(origin);
|
|
|
|
qglVertex3fv(fakeLine);
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
qglEnd();
|
|
|
|
qglEnable(GL_TEXTURE_2D);
|
2023-12-31 21:53:13 +01:00
|
|
|
// Restore depth
|
2023-07-24 20:14:39 +02:00
|
|
|
qglDepthRange(0.0, 1.0);
|
|
|
|
qglPopMatrix();
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
static void RB_Sphere_AddSpotLight(const spherel_t *thislight)
|
2023-05-15 14:21:16 +02:00
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
vec3_t lightorigin;
|
|
|
|
vec3_t newlight;
|
|
|
|
vec3_t lightline;
|
|
|
|
vec3_t newdir;
|
|
|
|
float falloff;
|
|
|
|
float dot;
|
|
|
|
float radiusByDistance;
|
|
|
|
float radiusAtDist;
|
|
|
|
float sampleRadius;
|
|
|
|
vec3_t pointAtDist;
|
|
|
|
|
|
|
|
radiusByDistance = thislight->spot_radiusbydistance;
|
|
|
|
if (radiusByDistance < 0) {
|
|
|
|
vec3_t proj;
|
|
|
|
vec3_t delta;
|
|
|
|
float distfromcentroid;
|
|
|
|
|
|
|
|
dot =
|
|
|
|
-(DotProduct(backEnd.currentSphere->worldOrigin, thislight->spot_dir)
|
|
|
|
- DotProduct(thislight->origin, thislight->spot_dir));
|
|
|
|
VectorMA(thislight->origin, dot, thislight->spot_dir, proj);
|
|
|
|
VectorSubtract(proj, thislight->origin, delta);
|
|
|
|
|
|
|
|
distfromcentroid = VectorLengthSquared(delta);
|
|
|
|
if (distfromcentroid > radiusByDistance * radiusByDistance) {
|
|
|
|
VectorScale(delta, -radiusByDistance / sqrt(distfromcentroid), delta);
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorSubtract(thislight->origin, backEnd.currentEntity->e.origin, lightorigin);
|
|
|
|
VectorAdd(lightorigin, delta, lightorigin);
|
2023-07-24 20:14:39 +02:00
|
|
|
} else {
|
|
|
|
VectorSubtract(thislight->origin, backEnd.currentEntity->e.origin, lightorigin);
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
MatrixTransformVectorRight(backEnd.currentEntity->e.axis, lightorigin, lightline);
|
|
|
|
VectorSubtract(lightline, backEnd.currentSphere->origin, newlight);
|
|
|
|
|
|
|
|
falloff = thislight->intensity * 7500.0 / VectorLengthSquared(newlight);
|
|
|
|
if (falloff >= 5.0) {
|
|
|
|
reallightinfo_t *pLight;
|
|
|
|
float fMinDist;
|
|
|
|
float fRadByDistSquared;
|
|
|
|
|
|
|
|
MatrixTransformVectorRight(backEnd.currentEntity->e.axis, thislight->spot_dir, newdir);
|
|
|
|
dot = DotProduct(newlight, newdir);
|
|
|
|
if (dot > 0) {
|
|
|
|
fMinDist = sqrt(
|
|
|
|
(newlight[0] + newdir[0] * dot) * (newlight[0] + newdir[0] * dot)
|
|
|
|
+ (newlight[1] + newdir[1] * dot) * (newlight[1] + newdir[1] * dot)
|
|
|
|
+ (newlight[2] + newdir[2] * dot) * (newlight[2] + newdir[2] * dot)
|
|
|
|
);
|
|
|
|
|
|
|
|
if (fMinDist < radiusByDistance * dot) {
|
|
|
|
if (backEnd.currentSphere->numRealLights < MAX_REAL_LIGHTS) {
|
|
|
|
pLight = &backEnd.currentSphere->light[backEnd.currentSphere->numRealLights];
|
2023-07-24 20:14:39 +02:00
|
|
|
pLight->eType = LIGHT_SPOT;
|
2023-12-31 21:53:13 +01:00
|
|
|
pLight->color[0] *= thislight->intensity * 7500.0 * tr.overbrightMult;
|
|
|
|
pLight->color[1] *= thislight->intensity * 7500.0 * tr.overbrightMult;
|
|
|
|
pLight->color[2] *= thislight->intensity * 7500.0 * tr.overbrightMult;
|
|
|
|
pLight->fDist = VectorLength(newlight);
|
|
|
|
pLight->fIntensity =
|
|
|
|
(pLight->color[0] * 0.299f + pLight->color[1] * 0.587f + pLight->color[2] * 0.114f)
|
|
|
|
* (thislight->intensity * 7500.0 * tr.overbrightMult);
|
|
|
|
|
|
|
|
sampleRadius = pLight->fDist - backEnd.currentSphere->radius;
|
|
|
|
if (sampleRadius > 0) {
|
|
|
|
pLight->fIntensity /= (sampleRadius * sampleRadius);
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorCopy(lightline, pLight->vOrigin);
|
|
|
|
VectorNegate(newdir, pLight->vDirection);
|
|
|
|
fRadByDistSquared = radiusByDistance * radiusByDistance;
|
|
|
|
pLight->fSpotConst = fRadByDistSquared + 1.0;
|
|
|
|
pLight->fSpotScale = 1.0 / (fRadByDistSquared * 0.19);
|
|
|
|
pLight->fSpotSlope = radiusByDistance;
|
|
|
|
|
|
|
|
backEnd.currentSphere->numRealLights++;
|
|
|
|
}
|
|
|
|
|
|
|
|
RB_Sphere_DrawDebugLine(thislight, falloff, lightline);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
static void RB_Sphere_AddLight(const spherel_t *thislight)
|
2023-05-15 14:21:16 +02:00
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
vec3_t lightorigin;
|
|
|
|
vec3_t newlight;
|
|
|
|
vec3_t lightline;
|
|
|
|
float intensity;
|
|
|
|
float falloff;
|
|
|
|
|
|
|
|
if (thislight->intensity > 0 && (backEnd.currentEntity->e.renderfx & RF_INVISIBLE)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thislight->intensity < 0 && !(backEnd.currentEntity->e.renderfx & RF_INVISIBLE)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thislight->needs_trace) {
|
2023-07-24 20:14:39 +02:00
|
|
|
trace_t trace;
|
2023-12-31 21:53:13 +01:00
|
|
|
ri.CM_BoxTrace(
|
|
|
|
&trace,
|
|
|
|
backEnd.currentSphere->traceOrigin,
|
|
|
|
thislight->origin,
|
|
|
|
vec3_origin,
|
|
|
|
vec3_origin,
|
|
|
|
0,
|
|
|
|
CONTENTS_SOLID,
|
|
|
|
0
|
|
|
|
);
|
|
|
|
|
|
|
|
if (trace.fraction < 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!thislight->spot_light) {
|
|
|
|
reallightinfo_t *pLight;
|
|
|
|
float fDist;
|
|
|
|
float fRadius;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
|
|
|
VectorSubtract(thislight->origin, backEnd.currentEntity->e.origin, lightorigin);
|
|
|
|
MatrixTransformVectorRight(backEnd.currentEntity->e.axis, lightorigin, lightline);
|
|
|
|
VectorSubtract(lightline, backEnd.currentSphere->origin, newlight);
|
2023-12-31 21:53:13 +01:00
|
|
|
|
|
|
|
intensity = thislight->intensity * 7500.0;
|
|
|
|
falloff = 1.f / VectorLengthSquared(newlight) * intensity;
|
|
|
|
if (falloff >= 5.0) {
|
|
|
|
RB_Sphere_DrawDebugLine(thislight, falloff, lightline);
|
|
|
|
if (backEnd.currentSphere->numRealLights < MAX_REAL_LIGHTS) {
|
|
|
|
pLight = &backEnd.currentSphere->light[backEnd.currentSphere->numRealLights];
|
|
|
|
|
|
|
|
fDist = VectorLength(newlight);
|
|
|
|
pLight->color[0] = thislight->color[0] * falloff * tr.overbrightMult * r_entlight_scale->value * fDist;
|
|
|
|
pLight->color[1] = thislight->color[1] * falloff * tr.overbrightMult * r_entlight_scale->value * fDist;
|
2023-07-24 20:14:39 +02:00
|
|
|
pLight->color[2] = thislight->color[2] * falloff * tr.overbrightMult * r_entlight_scale->value * fDist;
|
2023-12-31 21:53:13 +01:00
|
|
|
|
|
|
|
VectorCopy(lightline, pLight->vOrigin);
|
|
|
|
pLight->fDist = fDist;
|
|
|
|
pLight->eType = LIGHT_POINT;
|
|
|
|
pLight->fIntensity = pLight->color[0] * 0.299f + pLight->color[1] * 0.587f + pLight->color[2] * 0.114f;
|
|
|
|
|
|
|
|
fRadius = fDist - backEnd.currentSphere->radius;
|
|
|
|
if (fRadius > 0) {
|
|
|
|
pLight->fIntensity /= fRadius;
|
|
|
|
}
|
|
|
|
|
|
|
|
backEnd.currentSphere->numRealLights++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2023-07-24 20:14:39 +02:00
|
|
|
RB_Sphere_AddSpotLight(thislight);
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void RB_Sphere_BuildStaticLights()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
int i;
|
|
|
|
int curleaf;
|
|
|
|
mnode_t *leaf;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (tr.world->vis) {
|
|
|
|
int cntarea;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2024-08-13 20:38:39 +02:00
|
|
|
for (curleaf = 0; curleaf < 8; curleaf++) {
|
|
|
|
leaf = backEnd.currentSphere->leaves[curleaf];
|
|
|
|
if (!leaf) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
cntarea = leaf->numlights;
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (cntarea) {
|
|
|
|
for (i = (*leaf->lights == &tr.sSunLight ? 1 : 0); i < cntarea; i++) {
|
|
|
|
spherel_t *pLight = leaf->lights[i];
|
|
|
|
byte mask = backEnd.refdef.areamask[pLight->leaf->area >> 3];
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (!(mask & (1 << (pLight->leaf->area & 7))) && pLight->reference_count != light_reference_count) {
|
2023-07-24 20:14:39 +02:00
|
|
|
RB_Sphere_AddLight(pLight);
|
2023-12-31 21:53:13 +01:00
|
|
|
pLight->reference_count = light_reference_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < tr.numSLights; i++) {
|
|
|
|
RB_Sphere_AddLight(&tr.sLights[i]);
|
|
|
|
}
|
|
|
|
}
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RB_Sphere_BuildDLights()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
int i;
|
|
|
|
float length;
|
|
|
|
vec3_t lightorigin;
|
|
|
|
vec3_t delta;
|
|
|
|
float scale;
|
|
|
|
float fRadius;
|
|
|
|
sphereor_t *pSphere;
|
|
|
|
reallightinfo_t *pLight;
|
|
|
|
|
|
|
|
pSphere = backEnd.currentSphere;
|
2023-07-24 20:14:39 +02:00
|
|
|
backEnd.currentSphere->TessFunction = RB_Light_Real;
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
for (i = 0; i < backEnd.refdef.num_dlights && pSphere->numRealLights < MAX_REAL_LIGHTS; i++) {
|
|
|
|
VectorSubtract(backEnd.refdef.dlights[i].origin, pSphere->worldOrigin, delta);
|
|
|
|
length = VectorLength(delta);
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
fRadius = backEnd.refdef.dlights[i].radius + pSphere->radius;
|
|
|
|
if (fRadius < length) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-07-24 20:14:39 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorSubtract(backEnd.refdef.dlights[i].origin, backEnd.currentEntity->e.origin, lightorigin);
|
|
|
|
scale = r_entlight_scale->value * tr.overbrightMult * 7500.0 * backEnd.refdef.dlights[i].radius / length;
|
2023-07-24 20:14:39 +02:00
|
|
|
pLight = &pSphere->light[pSphere->numRealLights];
|
|
|
|
pLight->color[0] = scale * backEnd.refdef.dlights[i].color[0];
|
|
|
|
pLight->color[1] = scale * backEnd.refdef.dlights[i].color[1];
|
|
|
|
pLight->color[2] = scale * backEnd.refdef.dlights[i].color[2];
|
2023-12-31 21:53:13 +01:00
|
|
|
MatrixTransformVectorRight(backEnd.currentEntity->e.axis, lightorigin, pLight->vOrigin);
|
|
|
|
|
|
|
|
pLight->eType = LIGHT_POINT;
|
|
|
|
pLight->fDist = length;
|
|
|
|
pLight->fIntensity = pLight->color[0] * 0.299f + pLight->color[1] * 0.587f + pLight->color[2] * 0.114f;
|
|
|
|
|
|
|
|
if (pLight->fDist - backEnd.currentSphere->radius >= 0.f) {
|
|
|
|
pLight->fIntensity /= pLight->fDist - backEnd.currentSphere->radius;
|
|
|
|
}
|
|
|
|
|
|
|
|
backEnd.currentSphere->numRealLights++;
|
|
|
|
}
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RB_Sphere_SetupEntity()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
if (r_light_nolight->integer) {
|
|
|
|
backEnd.currentSphere->TessFunction = &RB_Light_Fullbright;
|
|
|
|
} else if (RB_Sphere_SetupGlobals() && RB_Sphere_ResetPointColors()) {
|
|
|
|
backEnd.currentSphere->numRealLights = 0;
|
|
|
|
RB_Sphere_Light_Sun();
|
|
|
|
RB_Sphere_BuildStaticLights();
|
|
|
|
RB_Sphere_BuildDLights();
|
|
|
|
backEnd.pc.c_characterlights += backEnd.currentSphere->numRealLights;
|
|
|
|
RB_OptimizeLights();
|
|
|
|
}
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RB_Grid_SetupEntity()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
trRefEntity_t *refent;
|
|
|
|
trRefEntity_t *newref;
|
|
|
|
|
|
|
|
for (refent = backEnd.currentEntity;; refent = newref) {
|
|
|
|
if (refent->e.parentEntity == ENTITYNUM_NONE) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
newref = &backEnd.refdef.entities[refent->e.parentEntity];
|
|
|
|
if (refent == newref) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorCopy(refent->e.lightingOrigin, backEnd.currentSphere->traceOrigin);
|
|
|
|
RB_SetupEntityGridLighting();
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RB_Grid_SetupStaticModel()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
RB_SetupStaticModelGridLighting(&tr.refdef, backEnd.currentStaticModel, backEnd.currentStaticModel->origin);
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
void RB_Light_Fullbright(unsigned char *colors)
|
2023-05-15 14:21:16 +02:00
|
|
|
{
|
2023-12-31 22:15:19 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < tess.numVertexes; i++) {
|
|
|
|
colors[i * 4] = 0xFF;
|
|
|
|
colors[i * 4 + 1] = 0xFF;
|
|
|
|
colors[i * 4 + 2] = 0xFF;
|
|
|
|
colors[i * 4 + 3] = 0xFF;
|
|
|
|
}
|
2023-05-15 14:21:16 +02:00
|
|
|
}
|
|
|
|
|
2023-05-09 20:49:04 +02:00
|
|
|
void R_Sphere_InitLights()
|
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
const char *ents;
|
|
|
|
const char *ret;
|
|
|
|
qboolean bFlareDirSet;
|
2024-09-17 20:29:52 +02:00
|
|
|
qboolean bIsWorld;
|
|
|
|
qboolean bWorldProcessed;
|
|
|
|
|
|
|
|
ents = ri.CM_EntityString();
|
|
|
|
bFlareDirSet = qfalse;
|
|
|
|
bIsWorld = qfalse;
|
|
|
|
bWorldProcessed = qfalse;
|
2023-12-31 21:53:13 +01:00
|
|
|
|
|
|
|
s_sun.szFlareName[0] = 0;
|
|
|
|
s_sun.exists = qfalse;
|
|
|
|
|
2024-09-17 20:05:51 +02:00
|
|
|
for (int i = 0; i < MAX_SPHERE_LIGHTS; i++) {
|
2023-12-31 21:53:13 +01:00
|
|
|
backEnd.spheres[i].TessFunction = &RB_Light_Real;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorClear(ambientlight);
|
|
|
|
backEnd.spareSphere.TessFunction = &RB_Light_Real;
|
|
|
|
backEnd.currentSphere = &backEnd.spareSphere;
|
|
|
|
bEntityOverbright = qfalse;
|
|
|
|
iEntityLightingMax = tr.identityLightByte;
|
|
|
|
s_sun.color[0] = s_sun.color[1] = s_sun.color[2] = tr.overbrightMult * 70;
|
|
|
|
|
|
|
|
while (ents) {
|
|
|
|
ret = COM_Parse((char **)&ents);
|
|
|
|
if (*ret == '{' || *ret == '}') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-09-17 20:29:52 +02:00
|
|
|
if (!bWorldProcessed && !strcmp(ret, "classname")) {
|
|
|
|
//
|
|
|
|
// Added in 2.0
|
|
|
|
// Make sure that the world's properties are not overridden
|
|
|
|
// by some random entities
|
|
|
|
//
|
|
|
|
if (!strcmp(COM_Parse((char **)&ents), "worldspawn")) {
|
|
|
|
bIsWorld = qtrue;
|
|
|
|
} else {
|
|
|
|
bWorldProcessed = qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
if (!strcmp(ret, "suncolor") || !strcmp(ret, "sunlight")) {
|
2024-09-17 20:29:52 +02:00
|
|
|
if (bWorldProcessed) {
|
|
|
|
ri.Printf(PRINT_WARNING, "Multiple suncolors defined in map\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
sscanf(COM_Parse((char **)&ents), "%f %f %f", &s_sun.color[0], &s_sun.color[1], &s_sun.color[2]);
|
|
|
|
s_sun.color[0] *= tr.overbrightMult;
|
|
|
|
s_sun.color[1] *= tr.overbrightMult;
|
|
|
|
s_sun.color[2] *= tr.overbrightMult;
|
|
|
|
s_sun.exists = qtrue;
|
|
|
|
} else if (!strcmp(ret, "sundirection")) {
|
|
|
|
vec3_t dir;
|
|
|
|
|
2024-09-17 20:29:52 +02:00
|
|
|
if (bWorldProcessed) {
|
|
|
|
ri.Printf(PRINT_WARNING, "Multiple sundirections defined in map\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
sscanf(COM_Parse((char **)&ents), "%f %f %f", &dir[0], &dir[1], &dir[2]);
|
|
|
|
AngleVectorsLeft(dir, s_sun.direction, 0, 0);
|
|
|
|
|
|
|
|
s_sun.exists = qtrue;
|
|
|
|
if (!bFlareDirSet) {
|
|
|
|
s_sun.flaredirection[0] = s_sun.direction[0];
|
|
|
|
s_sun.flaredirection[1] = s_sun.direction[1];
|
|
|
|
s_sun.flaredirection[2] = s_sun.direction[2];
|
|
|
|
}
|
|
|
|
} else if (!strcmp(ret, "sunflaredirection")) {
|
|
|
|
vec3_t dir;
|
|
|
|
|
2024-09-17 20:29:52 +02:00
|
|
|
if (bWorldProcessed) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
sscanf(COM_Parse((char **)&ents), "%f %f %f", &dir[0], &dir[1], &dir[2]);
|
|
|
|
AngleVectorsLeft(dir, s_sun.flaredirection, 0, 0);
|
|
|
|
bFlareDirSet = qtrue;
|
|
|
|
} else if (!strcmp(ret, "sunflarename")) {
|
2024-09-17 20:29:52 +02:00
|
|
|
if (bWorldProcessed) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
strcpy(s_sun.szFlareName, COM_Parse((char **)&ents));
|
|
|
|
} else if (!strcmp(ret, "ambientlight")) {
|
2024-09-17 20:29:52 +02:00
|
|
|
if (bWorldProcessed) {
|
|
|
|
ri.Printf(PRINT_WARNING, "Multiple ambientlights defined in map\n");
|
|
|
|
continue;
|
|
|
|
}
|
2023-12-31 21:53:13 +01:00
|
|
|
sscanf(COM_Parse((char **)&ents), "%f %f %f", &ambientlight[0], &ambientlight[1], &ambientlight[2]);
|
|
|
|
} else if (!strcmp(ret, "overbright")) {
|
2024-09-17 20:29:52 +02:00
|
|
|
if (bWorldProcessed) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
ret = COM_Parse((char **)&ents);
|
|
|
|
if (strcmp(ret, "world") || strcmp(ret, "none")) {
|
|
|
|
bEntityOverbright = qtrue;
|
|
|
|
iEntityLightingMax = 0xFF;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
COM_Parse((char **)&ents);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-17 20:29:52 +02:00
|
|
|
if (s_sun.exists && !s_sun.szFlareName[0]) {
|
|
|
|
strcpy(s_sun.szFlareName, "sun");
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
2023-05-09 20:49:04 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
static qboolean R_CheckAddLightToList(spherel_t *pLight, const vec3_t vPos, float *pfFalloff)
|
|
|
|
{
|
2023-07-25 22:01:28 +02:00
|
|
|
vec3_t vDelta;
|
|
|
|
|
|
|
|
if (pLight->intensity < 0) {
|
|
|
|
return qfalse;
|
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
VectorSubtract(pLight->origin, vPos, vDelta);
|
|
|
|
*pfFalloff = pLight->intensity * 7500.0 / VectorLengthSquared(vDelta);
|
2023-07-25 22:01:28 +02:00
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
return *pfFalloff >= 5.0;
|
2023-07-25 22:01:28 +02:00
|
|
|
}
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
static void R_InsertLightIntoList(spherel_t *pLight, float fIntensity, gatheredLight_t **pLightsList)
|
|
|
|
{
|
|
|
|
gatheredLight_t *pCurrLight;
|
|
|
|
gatheredLight_t *pLastLight;
|
|
|
|
|
|
|
|
if (pLightsList[0]->pPrev->fIntensity >= fIntensity) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fIntensity > pLightsList[0]->fIntensity) {
|
|
|
|
pLightsList[0] = pLightsList[0]->pPrev;
|
|
|
|
pLightsList[0]->pLight = pLight;
|
|
|
|
pLightsList[0]->fIntensity = fIntensity;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pCurrLight = pLightsList[0]->pNext;
|
|
|
|
if (!pCurrLight) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (pCurrLight->fIntensity >= fIntensity) {
|
|
|
|
pCurrLight = pCurrLight->pNext;
|
|
|
|
if (!pCurrLight) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pLastLight = pLightsList[0]->pPrev->pPrev;
|
|
|
|
pCurrLight->pPrev->pNext = pLightsList[0]->pPrev;
|
|
|
|
pLightsList[0]->pPrev->pPrev = pCurrLight->pPrev;
|
|
|
|
pLightsList[0]->pPrev->pNext = pCurrLight;
|
|
|
|
pCurrLight->pPrev = pLightsList[0]->pPrev;
|
|
|
|
pLastLight->pNext = pLightsList[0];
|
|
|
|
pLightsList[0]->pPrev = pLastLight;
|
|
|
|
pCurrLight = pCurrLight->pPrev;
|
|
|
|
pCurrLight->fIntensity = fIntensity;
|
|
|
|
pCurrLight->pLight = pLight;
|
2023-07-25 22:01:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_GATHERED_LIGHTS 8
|
|
|
|
|
2023-12-31 21:53:13 +01:00
|
|
|
int R_GatherLightSources(const vec3_t vPos, vec3_t *pvLightPos, vec3_t *pvLightIntensity, int iMaxLights)
|
2023-05-08 14:57:51 +02:00
|
|
|
{
|
2023-12-31 21:53:13 +01:00
|
|
|
int i, j;
|
|
|
|
int iLightCount;
|
|
|
|
vec3_t vEnd;
|
|
|
|
vec3_t vDelta;
|
|
|
|
spherel_t *pCurrLight;
|
|
|
|
gatheredLight_t lights[MAX_GATHERED_LIGHTS];
|
|
|
|
gatheredLight_t *pLightsHead;
|
|
|
|
gatheredLight_t *pLightsCurr;
|
|
|
|
float fFalloff;
|
|
|
|
trace_t trace;
|
|
|
|
mnode_t *leaf;
|
|
|
|
|
|
|
|
fFalloff = 0;
|
|
|
|
leaf = NULL;
|
|
|
|
|
|
|
|
if (iMaxLights <= 0 || !r_drawspherelights->integer) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(lights, 0, sizeof(lights));
|
2023-08-27 17:01:53 +02:00
|
|
|
|
|
|
|
for (j = 0; j < MAX_GATHERED_LIGHTS - 2; j++) {
|
|
|
|
lights[j + 1].pNext = &lights[j + 2];
|
2023-12-31 21:53:13 +01:00
|
|
|
lights[j + 1].pPrev = &lights[j];
|
|
|
|
}
|
|
|
|
|
|
|
|
lights[0].pNext = &lights[1];
|
|
|
|
lights[0].pPrev = &lights[MAX_GATHERED_LIGHTS - 1];
|
|
|
|
lights[MAX_GATHERED_LIGHTS - 1].pNext = &lights[0];
|
|
|
|
lights[MAX_GATHERED_LIGHTS - 1].pPrev = &lights[MAX_GATHERED_LIGHTS - 2];
|
|
|
|
pLightsHead = &lights[0];
|
|
|
|
|
|
|
|
if (tr.world->vis) {
|
|
|
|
leaf = R_PointInLeaf(vPos);
|
|
|
|
if (leaf->area == -1 || !leaf->numlights) {
|
|
|
|
leaf = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (leaf) {
|
|
|
|
if (leaf->numlights) {
|
|
|
|
light_reference_count++;
|
|
|
|
|
|
|
|
for (i = (leaf->lights[0] == &tr.sSunLight ? 1 : 0); i < leaf->numlights; i++) {
|
|
|
|
pCurrLight = leaf->lights[i];
|
|
|
|
if (pCurrLight->leaf != (mnode_t *)-1) {
|
|
|
|
byte mask = backEnd.refdef.areamask[pCurrLight->leaf->area >> 3];
|
|
|
|
|
|
|
|
if (!(mask & (1 << (pCurrLight->leaf->area & 7)))
|
|
|
|
&& pCurrLight->reference_count != light_reference_count) {
|
|
|
|
if (R_CheckAddLightToList(pCurrLight, vPos, &fFalloff)) {
|
|
|
|
R_InsertLightIntoList(pCurrLight, fFalloff, &pLightsHead);
|
|
|
|
}
|
|
|
|
|
|
|
|
pCurrLight->reference_count = light_reference_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < tr.numSLights; i++) {
|
|
|
|
pCurrLight = &tr.sLights[i];
|
|
|
|
|
|
|
|
if (R_CheckAddLightToList(pCurrLight, vPos, &fFalloff)) {
|
|
|
|
R_InsertLightIntoList(pCurrLight, fFalloff, &pLightsHead);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
iLightCount = 0;
|
|
|
|
|
|
|
|
if (s_sun.exists) {
|
2024-06-05 21:21:35 +02:00
|
|
|
if (leaf && leaf->lights[0] == &tr.sSunLight) {
|
|
|
|
VectorMA(vPos, 16384.0, s_sun.direction, vEnd);
|
|
|
|
ri.CM_BoxTrace(&trace, vPos, vEnd, vec3_origin, vec3_origin, 0, CONTENTS_SOLID, 0);
|
|
|
|
|
|
|
|
if (trace.surfaceFlags & SURF_SKY) {
|
|
|
|
VectorMA(vPos, 16384.0, s_sun.direction, pvLightPos[0]);
|
|
|
|
pvLightIntensity[0][0] = s_sun.color[0] * (1.0 / 510.0);
|
|
|
|
pvLightIntensity[0][1] = s_sun.color[1] * (1.0 / 510.0);
|
|
|
|
pvLightIntensity[0][2] = s_sun.color[2] * (1.0 / 510.0);
|
|
|
|
iLightCount = 1;
|
2023-12-31 21:53:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pLightsCurr = pLightsHead;
|
|
|
|
|
|
|
|
for (; iLightCount < iMaxLights && iLightCount < MAX_GATHERED_LIGHTS && pLightsCurr->pLight;
|
|
|
|
iLightCount++, pLightsCurr = pLightsCurr->pNext) {
|
|
|
|
VectorCopy(pLightsCurr->pLight->origin, pvLightPos[iLightCount]);
|
|
|
|
vDelta[0] = pLightsCurr->fIntensity / 200.0 * pLightsCurr->pLight->color[0];
|
|
|
|
vDelta[1] = pLightsCurr->fIntensity / 200.0 * pLightsCurr->pLight->color[1];
|
|
|
|
vDelta[2] = pLightsCurr->fIntensity / 200.0 * pLightsCurr->pLight->color[2];
|
|
|
|
|
|
|
|
if (vDelta[0] > 1.0 || vDelta[1] > 1.0 || vDelta[2] > 1.0) {
|
|
|
|
NormalizeColor(vDelta, vDelta);
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorCopy(vDelta, pvLightIntensity[iLightCount]);
|
|
|
|
pLightsCurr = pLightsCurr->pNext;
|
|
|
|
if (pLightsCurr == pLightsHead) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return iLightCount;
|
2023-05-08 14:57:51 +02:00
|
|
|
}
|