mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-23 04:12:42 +00:00
dynamic lights apply to even more surfaces and have a nicer fall-off
- ditched vertex colors (not wanted) and alpha tests (not needed) in the shaders - using a Bezier fall-off to get much softer edges - added no-depth-write transparent surfaces support by adjusting the depth test - multiplying the diffuse texture's color by its alpha in non-opaque passes - fixed triangle rejection based on cull type and normal direction - reflecting normals in shaders to support two-sided surfaces - rejecting surfaces with no diffuse stage or bad blend states as early as possible - liquids get lit weaker than other surfaces
This commit is contained in:
parent
8ef496d22b
commit
85583acc9c
9 changed files with 128 additions and 73 deletions
|
@ -89,13 +89,15 @@ add: r_mapBrightness now works on q3map2's external lightmap atlas images
|
|||
add: the renderer can now batch surfaces with different (but sufficiently similar) shaders
|
||||
this new optimization works with the output of "Frozen Sand Particle Studio"
|
||||
|
||||
add: /modellist /skinlist /imagelist /shaderlist can now filter results with pattern matching
|
||||
|
||||
chg: dynamic lights now use a softer fall-off curve to create softer edges
|
||||
|
||||
chg: reverted an old change to the Escape key handling for cgame
|
||||
this fixes demo playback behavior in CPMA, which enables custom binds after pressing Escape once
|
||||
|
||||
chg: searching for valid sample counts for MSAA in GL2 and GL3 instead of failing right away
|
||||
|
||||
add: /modellist /skinlist /imagelist /shaderlist can now filter results with pattern matching
|
||||
|
||||
chg: switched away from stb_image for .tga file loading and now using an updated version of the old code
|
||||
this lowers the chances of a fatal error from the zone memory allocator when reading large images
|
||||
|
||||
|
@ -106,8 +108,8 @@ chg: removed FreeType 2 and the unused R_REGISTERFONT syscalls that were using i
|
|||
chg: removed light flares and all related cvars (r_flare*)
|
||||
|
||||
chg: r_textureMode <filter> (default: "best") is now latched and only supports 2 modes:
|
||||
r_textureMode GL_NEAREST = LEGO(R) mode - nearest-neighbor filtering for a subset of surfaces
|
||||
r_textureMode anything else = normal mode - the engine picks the most appropriate filters
|
||||
r_textureMode GL_NEAREST = LEGO(R) mode - nearest-neighbor filtering for a subset of surfaces
|
||||
r_textureMode anything else = normal mode - the engine picks the most appropriate filters
|
||||
|
||||
chg: r_measureOverdraw was removed
|
||||
|
||||
|
@ -140,7 +142,7 @@ fix: broken face normals get fixed up on map load, which helps with dynamic ligh
|
|||
|
||||
fix: classes of transparent surfaces (sprites, beams, etc) now get drawn in the right order
|
||||
|
||||
fix: dynamic lights can now affect transparent surfaces
|
||||
fix: dynamic lights can now affect transparent surfaces and double-sided surfaces on both sides
|
||||
|
||||
fix: dynamic lights no longer "reveal" the diffuse texture when r_lightmap is 1
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ struct VIn
|
|||
{
|
||||
float4 position : POSITION;
|
||||
float4 normal : NORMAL;
|
||||
float4 color : COLOR0;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
};
|
||||
|
||||
|
@ -41,7 +40,6 @@ struct VOut
|
|||
{
|
||||
float4 position : SV_Position;
|
||||
float3 normal : NORMAL;
|
||||
float4 color : COLOR0;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float3 osLightVec : TEXCOORD1;
|
||||
float3 osEyeVec : TEXCOORD2;
|
||||
|
@ -55,7 +53,6 @@ VOut vs_main(VIn input)
|
|||
VOut output;
|
||||
output.position = mul(projectionMatrix, positionVS);
|
||||
output.normal = input.normal.xyz;
|
||||
output.color = input.color;
|
||||
output.texCoords = input.texCoords;
|
||||
output.osLightVec = osLightPos.xyz - input.position.xyz;
|
||||
output.osEyeVec = osEyePos.xyz - input.position.xyz;
|
||||
|
@ -68,36 +65,39 @@ cbuffer PixelShaderBuffer
|
|||
{
|
||||
float3 lightColor;
|
||||
float lightRadius;
|
||||
uint alphaTest;
|
||||
uint dummy[3];
|
||||
float opaque;
|
||||
float intensity;
|
||||
float dummy[2];
|
||||
};
|
||||
|
||||
Texture2D texture0 : register(t0);
|
||||
SamplerState sampler0 : register(s0);
|
||||
|
||||
float BezierEase(float t)
|
||||
{
|
||||
return t * t * (3.0 - 2.0 * t);
|
||||
}
|
||||
|
||||
float4 ps_main(VOut input) : SV_TARGET
|
||||
{
|
||||
float4 base = texture0.Sample(sampler0, input.texCoords) * input.color;
|
||||
if((alphaTest == 1 && base.a == 0.0) ||
|
||||
(alphaTest == 2 && base.a >= 0.5) ||
|
||||
(alphaTest == 3 && base.a < 0.5))
|
||||
discard;
|
||||
|
||||
float4 base = texture0.Sample(sampler0, input.texCoords);
|
||||
float3 nL = normalize(input.osLightVec); // normalized object-space light vector
|
||||
float3 nV = normalize(input.osEyeVec); // normalized object-space view vector
|
||||
float3 nN = input.normal; // normalized object-space normal vector
|
||||
|
||||
// light intensity
|
||||
float intensFactor = dot(input.osLightVec, input.osLightVec) * lightRadius;
|
||||
float3 intens = lightColor * (1.0 - intensFactor);
|
||||
float intensFactor = min(dot(input.osLightVec, input.osLightVec) * lightRadius, 1.0);
|
||||
float3 intens = lightColor * BezierEase(1.0 - sqrt(intensFactor));
|
||||
|
||||
// specular reflection term (N.H)
|
||||
float specFactor = clamp(dot(nN, normalize(nL + nV)), 0.0, 1.0);
|
||||
float specFactor = min(abs(dot(nN, normalize(nL + nV))), 1.0);
|
||||
float spec = pow(specFactor, 16.0) * 0.25;
|
||||
|
||||
// Lambertian diffuse reflection term (N.L)
|
||||
float diffuse = clamp(dot(nN, nL), 0.0, 1.0);
|
||||
float4 final = (base * float4(diffuse.rrr, 1.0) + float4(spec.rrr, 1.0)) * float4(intens.rgb, 1.0);
|
||||
float diffuse = min(abs(dot(nN, nL)), 1.0);
|
||||
float3 color = (base.rgb * diffuse.rrr + spec.rrr) * intens * intensity;
|
||||
float alpha = lerp(opaque, 1.0, base.a);
|
||||
float4 final = float4(color.rgb * alpha, alpha);
|
||||
|
||||
return final;
|
||||
}
|
||||
|
|
|
@ -390,8 +390,10 @@ static void RB_RenderLitSurfList( dlight_t* dl, qbool opaque )
|
|||
double originalTime = backEnd.refdef.floatTime;
|
||||
|
||||
// draw everything
|
||||
const int liquidFlags = CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER;
|
||||
oldEntityNum = -1;
|
||||
backEnd.currentEntity = &tr.worldEntity;
|
||||
backEnd.dlOpaque = opaque;
|
||||
oldDepthRange = qfalse;
|
||||
depthRange = qfalse;
|
||||
tess.light = dl;
|
||||
|
@ -418,6 +420,15 @@ static void RB_RenderLitSurfList( dlight_t* dl, qbool opaque )
|
|||
RB_EndSurface();
|
||||
RB_BeginSurface( shader, fogNum );
|
||||
|
||||
// stage index is guaranteed valid by R_AddLitSurface
|
||||
const int stageIndex = tess.shader->lightingStages[ST_DIFFUSE];
|
||||
const shaderStage_t* const stage = tess.xstages[stageIndex];
|
||||
backEnd.dlIntensity = (shader->contentFlags & liquidFlags) != 0 ? 0.5f : 1.0f;
|
||||
backEnd.dlStateBits =
|
||||
(opaque || (stage->stateBits & GLS_ATEST_BITS) != 0) ?
|
||||
(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL):
|
||||
(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
|
||||
|
||||
sort = litSurf->sort;
|
||||
|
||||
//
|
||||
|
|
|
@ -177,8 +177,9 @@ struct DynamicLightPSData
|
|||
{
|
||||
float lightColor[3];
|
||||
float lightRadius;
|
||||
uint32_t alphaTest; // AlphaTest enum
|
||||
uint32_t dummy[3];
|
||||
float opaque;
|
||||
float intensity;
|
||||
float dummy[2];
|
||||
};
|
||||
|
||||
struct PostVSData
|
||||
|
@ -673,9 +674,10 @@ static void UploadPendingShaderData()
|
|||
memcpy(vsData.clipPlane, d3d.clipPlane, sizeof(vsData.clipPlane));
|
||||
memcpy(vsData.osEyePos, d3d.osEyePos, sizeof(vsData.osEyePos));
|
||||
memcpy(vsData.osLightPos, d3d.osLightPos, sizeof(vsData.osLightPos));
|
||||
psData.alphaTest = d3d.alphaTest;
|
||||
memcpy(psData.lightColor, d3d.lightColor, sizeof(psData.lightColor));
|
||||
psData.lightRadius = d3d.lightRadius;
|
||||
psData.opaque = backEnd.dlOpaque ? 1.0f : 0.0f;
|
||||
psData.intensity = backEnd.dlIntensity;
|
||||
ResetShaderData(pipeline->vertexBuffer, &vsData, sizeof(vsData));
|
||||
ResetShaderData(pipeline->pixelBuffer, &psData, sizeof(psData));
|
||||
}
|
||||
|
@ -2268,7 +2270,6 @@ static void DrawDynamicLight()
|
|||
AppendVertexData(&d3d.vertexBuffers[VB_POSITION], tess.xyz, tess.numVertexes);
|
||||
AppendVertexData(&d3d.vertexBuffers[VB_NORMAL], tess.normal, tess.numVertexes);
|
||||
AppendVertexData(&d3d.vertexBuffers[VB_TEXCOORD], tess.svars[stageIndex].texcoordsptr, tess.numVertexes);
|
||||
AppendVertexData(&d3d.vertexBuffers[VB_COLOR], tess.svars[stageIndex].colors, tess.numVertexes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2277,13 +2278,11 @@ static void DrawDynamicLight()
|
|||
pointers[VB_NORMAL] = tess.normal;
|
||||
pointers[VB_TEXCOORD] = tess.svars[stageIndex].texcoordsptr;
|
||||
pointers[VB_TEXCOORD2] = NULL;
|
||||
pointers[VB_COLOR] = tess.svars[stageIndex].colors;
|
||||
pointers[VB_COLOR] = NULL;
|
||||
AppendVertexDataGroup(pointers, tess.numVertexes);
|
||||
}
|
||||
|
||||
const int oldAlphaTestBits = stage->stateBits & GLS_ATEST_BITS;
|
||||
const int newBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL;
|
||||
ApplyState(oldAlphaTestBits | newBits, tess.shader->cullType, tess.shader->polygonOffset);
|
||||
ApplyState(backEnd.dlStateBits, tess.shader->cullType, tess.shader->polygonOffset);
|
||||
BindBundle(0, &stage->bundle);
|
||||
|
||||
UploadPendingShaderData();
|
||||
|
|
|
@ -93,6 +93,7 @@ struct GLSL_DynLightProgramAttribs {
|
|||
// pixel shader:
|
||||
GLint texture; // 2D texture
|
||||
GLint lightColorRadius; // 4f, w = 1 / (r^2)
|
||||
GLint opaqueIntensity; // 2f
|
||||
};
|
||||
|
||||
static GLSL_DynLightProgramAttribs dynLightProgAttribs;
|
||||
|
@ -120,6 +121,8 @@ static void DrawDynamicLight()
|
|||
if ( tess.shader->polygonOffset )
|
||||
glEnable( GL_POLYGON_OFFSET_FILL );
|
||||
|
||||
glUniform2f( dynLightProgAttribs.opaqueIntensity, backEnd.dlOpaque ? 1.0f : 0.0f, backEnd.dlIntensity );
|
||||
|
||||
const int stage = tess.shader->lightingStages[ST_DIFFUSE];
|
||||
const shaderStage_t* pStage = tess.xstages[ stage ];
|
||||
|
||||
|
@ -136,9 +139,7 @@ static void DrawDynamicLight()
|
|||
glVertexPointer( 3, GL_FLOAT, 16, tess.xyz );
|
||||
glLockArraysEXT( 0, tess.numVertexes );
|
||||
|
||||
const int oldAlphaTestBits = pStage->stateBits & GLS_ATEST_BITS;
|
||||
const int newBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL;
|
||||
GL_State( oldAlphaTestBits | newBits );
|
||||
GL_State( backEnd.dlStateBits );
|
||||
|
||||
GL_SelectTexture( 0 );
|
||||
R_BindAnimatedImage( &pStage->bundle );
|
||||
|
@ -300,25 +301,33 @@ static const char* dynLightVS =
|
|||
|
||||
static const char* dynLightFS =
|
||||
"uniform sampler2D texture;\n"
|
||||
"uniform vec4 lightColorRadius;" // w = 1 / (r^2)
|
||||
"uniform vec4 lightColorRadius;\n" // w = 1 / (r^2)
|
||||
"uniform vec2 opaqueIntensity;\n"
|
||||
"varying vec4 L;\n" // object-space light vector
|
||||
"varying vec4 V;\n" // object-space view vector
|
||||
"varying vec3 nN;\n" // normalized object-space normal vector
|
||||
"\n"
|
||||
"float BezierEase(float t)\n"
|
||||
"{\n"
|
||||
" return t * t * (3.0 - 2.0 * t);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 base = texture2D(texture, gl_TexCoord[0].xy);\n"
|
||||
" vec3 nL = normalize(L.xyz);\n" // normalized light vector
|
||||
" vec3 nV = normalize(V.xyz);\n" // normalized view vector
|
||||
// light intensity
|
||||
" float intensFactor = dot(L.xyz, L.xyz) * lightColorRadius.w;"
|
||||
" vec3 intens = lightColorRadius.rgb * (1.0 - intensFactor);\n"
|
||||
" float intensFactor = min(dot(L.xyz, L.xyz) * lightColorRadius.w, 1.0);"
|
||||
" vec3 intens = lightColorRadius.rgb * BezierEase(1.0 - sqrt(intensFactor));\n"
|
||||
// specular reflection term (N.H)
|
||||
" float specFactor = clamp(dot(nN, normalize(nL + nV)), 0.0, 1.0);\n"
|
||||
" float specFactor = min(abs(dot(nN, normalize(nL + nV))), 1.0);\n"
|
||||
" float spec = pow(specFactor, 16.0) * 0.25;\n"
|
||||
// Lambertian diffuse reflection term (N.L)
|
||||
" float diffuse = clamp(dot(nN, nL), 0.0, 1.0);\n"
|
||||
" gl_FragColor = vec4((base.rgb * vec3(diffuse) + vec3(spec)) * vec3(intens), base.a);\n"
|
||||
" float diffuse = min(abs(dot(nN, nL)), 1.0);\n"
|
||||
" vec3 color = (base.rgb * vec3(diffuse) + vec3(spec)) * intens * opaqueIntensity.y;\n"
|
||||
" float alpha = mix(opaqueIntensity.x, 1.0, base.a);\n"
|
||||
" gl_FragColor = vec4(color.rgb * alpha, alpha);\n"
|
||||
"}\n"
|
||||
"";
|
||||
|
||||
|
@ -696,6 +705,7 @@ static qbool GL2_Init()
|
|||
dynLightProgAttribs.osLightPos = glGetUniformLocation( dynLightProg.p, "osLightPos" );
|
||||
dynLightProgAttribs.texture = glGetUniformLocation( dynLightProg.p, "texture" );
|
||||
dynLightProgAttribs.lightColorRadius = glGetUniformLocation( dynLightProg.p, "lightColorRadius" );
|
||||
dynLightProgAttribs.opaqueIntensity = glGetUniformLocation( dynLightProg.p, "opaqueIntensity" );
|
||||
|
||||
if ( !GL2_CreateProgram( gammaProg, gammaVS, gammaFS ) ) {
|
||||
ri.Printf( PRINT_ERROR, "Failed to compile gamma correction shaders\n" );
|
||||
|
|
|
@ -161,7 +161,8 @@ enum DynamicLightUniform
|
|||
DU_LIGHT_POS,
|
||||
DU_EYE_POS,
|
||||
DU_LIGHT_COLOR_RADIUS,
|
||||
DU_ALPHA_TEST,
|
||||
DU_OPAQUE,
|
||||
DU_INTENSITY,
|
||||
DU_COUNT
|
||||
};
|
||||
|
||||
|
@ -233,6 +234,8 @@ struct OpenGL3
|
|||
qbool enableClipPlane;
|
||||
qbool prevEnableClipPlane;
|
||||
AlphaTest alphaTest;
|
||||
qbool dlOpaque;
|
||||
float dlIntensity;
|
||||
|
||||
ArrayBuffer arrayBuffers[VB_COUNT];
|
||||
ArrayBuffer indexBuffer;
|
||||
|
@ -400,11 +403,9 @@ static const char* dl_vs =
|
|||
"in vec4 position;\n"
|
||||
"in vec4 normal;\n"
|
||||
"in vec2 texCoords1;\n"
|
||||
"in vec4 color;\n"
|
||||
"\n"
|
||||
"out vec3 normalFS;\n"
|
||||
"out vec2 texCoords1FS;\n"
|
||||
"out vec4 colorFS;\n"
|
||||
"out vec3 L;\n"
|
||||
"out vec3 V;\n"
|
||||
"\n"
|
||||
|
@ -415,7 +416,6 @@ static const char* dl_vs =
|
|||
" gl_ClipDistance[0] = dot(positionVS, clipPlane);\n"
|
||||
" normalFS = normal.xyz;\n"
|
||||
" texCoords1FS = texCoords1;\n"
|
||||
" colorFS = color;\n"
|
||||
" L = osLightPos - position.xyz;\n"
|
||||
" V = osEyePos - position.xyz;\n"
|
||||
"}\n";
|
||||
|
@ -424,40 +424,41 @@ static const char* dl_fs =
|
|||
"uniform sampler2D texture1;\n"
|
||||
"\n"
|
||||
"uniform vec4 lightColorRadius;\n"
|
||||
"uniform uint alphaTest;\n"
|
||||
"uniform float opaque;\n"
|
||||
"uniform float intensity;\n"
|
||||
"\n"
|
||||
"in vec3 normalFS;\n"
|
||||
"in vec2 texCoords1FS;\n"
|
||||
"in vec4 colorFS;\n"
|
||||
"in vec3 L;\n"
|
||||
"in vec3 V;\n"
|
||||
"\n"
|
||||
"out vec4 fragColor;\n"
|
||||
"\n"
|
||||
"float BezierEase(float t)\n"
|
||||
"{\n"
|
||||
" return t * t * (3.0 - 2.0 * t);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 base = colorFS * texture2D(texture1, texCoords1FS);\n"
|
||||
" vec4 base = texture2D(texture1, texCoords1FS);\n"
|
||||
" vec3 nL = normalize(L);\n"
|
||||
" vec3 nV = normalize(V);\n"
|
||||
"\n"
|
||||
" // light intensity\n"
|
||||
" float intensFactor = dot(L, L) * lightColorRadius.w;\n"
|
||||
" vec3 intens = lightColorRadius.rgb * (1.0 - intensFactor);\n"
|
||||
" float intensFactor = min(dot(L, L) * lightColorRadius.w, 1.0);\n"
|
||||
" vec3 intens = lightColorRadius.rgb * BezierEase(1.0 - sqrt(intensFactor));\n"
|
||||
"\n"
|
||||
" // specular reflection term (N.H)\n"
|
||||
" float specFactor = clamp(dot(normalFS, normalize(nL + nV)), 0.0, 1.0);\n"
|
||||
" float specFactor = min(abs(dot(normalFS, normalize(nL + nV))), 1.0);\n"
|
||||
" float spec = pow(specFactor, 16.0) * 0.25;\n"
|
||||
"\n"
|
||||
" // Lambertian diffuse reflection term (N.L)\n"
|
||||
" float diffuse = clamp(dot(normalFS, nL), 0.0, 1.0);\n"
|
||||
" vec4 r = vec4((base.rgb * vec3(diffuse) + vec3(spec)) * intens, base.a);\n"
|
||||
" float diffuse = min(abs(dot(normalFS, nL)), 1.0);\n"
|
||||
" vec3 color = (base.rgb * vec3(diffuse) + vec3(spec)) * intens * intensity;\n"
|
||||
" float alpha = mix(opaque, 1.0, base.a);\n"
|
||||
"\n"
|
||||
" if( (alphaTest == uint(1) && r.a == 0.0) ||\n"
|
||||
" (alphaTest == uint(2) && r.a >= 0.5) ||\n"
|
||||
" (alphaTest == uint(3) && r.a < 0.5))\n"
|
||||
" discard;\n"
|
||||
"\n"
|
||||
" fragColor = r;\n"
|
||||
" fragColor = vec4(color.rgb * alpha, alpha);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* sprite_vs =
|
||||
|
@ -1412,10 +1413,6 @@ static void ApplyAlphaTest(AlphaTest alphaTest)
|
|||
{
|
||||
gl.pipelines[PID_GENERIC].uniformsDirty[GU_ALPHA_TEX] = qtrue;
|
||||
}
|
||||
else if(gl.pipelineId == PID_DYNAMIC_LIGHT)
|
||||
{
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformsDirty[DU_ALPHA_TEST] = qtrue;
|
||||
}
|
||||
else if(gl.pipelineId == PID_SOFT_SPRITE)
|
||||
{
|
||||
gl.pipelines[PID_SOFT_SPRITE].uniformsDirty[SU_ALPHA_TEST] = qtrue;
|
||||
|
@ -1884,15 +1881,14 @@ static void Init()
|
|||
gl.pipelines[PID_DYNAMIC_LIGHT].arrayBuffers[VB_NORMAL].attribName = "normal";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].arrayBuffers[VB_TEXCOORD].enabled = qtrue;
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].arrayBuffers[VB_TEXCOORD].attribName = "texCoords1";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].arrayBuffers[VB_COLOR].enabled = qtrue;
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].arrayBuffers[VB_COLOR].attribName = "color";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformNames[DU_MODELVIEW] = "modelView";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformNames[DU_PROJECTION] = "projection";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformNames[DU_CLIP_PLANE] = "clipPlane";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformNames[DU_LIGHT_POS] = "osLightPos";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformNames[DU_EYE_POS] = "osEyePos";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformNames[DU_LIGHT_COLOR_RADIUS] = "lightColorRadius";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformNames[DU_ALPHA_TEST] = "alphaTest";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformNames[DU_OPAQUE] = "opaque";
|
||||
gl.pipelines[PID_DYNAMIC_LIGHT].uniformNames[DU_INTENSITY] = "intensity";
|
||||
|
||||
gl.pipelines[PID_SOFT_SPRITE].arrayBuffers[VB_POSITION].enabled = qtrue;
|
||||
gl.pipelines[PID_SOFT_SPRITE].arrayBuffers[VB_POSITION].attribName = "position";
|
||||
|
@ -2209,14 +2205,23 @@ static void DrawDynamicLight()
|
|||
UploadVertexArray(VB_POSITION, tess.xyz);
|
||||
UploadVertexArray(VB_NORMAL, tess.normal);
|
||||
UploadVertexArray(VB_TEXCOORD, tess.svars[stageIndex].texcoordsptr);
|
||||
UploadVertexArray(VB_COLOR, tess.svars[stageIndex].colors);
|
||||
UploadIndices(tess.dlIndexes, tess.dlNumIndexes);
|
||||
|
||||
const int oldAlphaTestBits = stage->stateBits & GLS_ATEST_BITS;
|
||||
const int newBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL;
|
||||
ApplyState(oldAlphaTestBits | newBits, tess.shader->cullType, tess.shader->polygonOffset);
|
||||
ApplyState(backEnd.dlStateBits, tess.shader->cullType, tess.shader->polygonOffset);
|
||||
BindBundle(0, &stage->bundle);
|
||||
|
||||
if(backEnd.dlOpaque != gl.dlOpaque)
|
||||
{
|
||||
gl.dlOpaque = backEnd.dlOpaque;
|
||||
pipeline->uniformsDirty[DU_OPAQUE] = qtrue;
|
||||
}
|
||||
|
||||
if(backEnd.dlIntensity != gl.dlIntensity)
|
||||
{
|
||||
gl.dlIntensity = backEnd.dlIntensity;
|
||||
pipeline->uniformsDirty[DU_INTENSITY] = qtrue;
|
||||
}
|
||||
|
||||
if(pipeline->uniformsDirty[DU_MODELVIEW])
|
||||
{
|
||||
glUniformMatrix4fv(pipeline->uniformLocations[DU_MODELVIEW], 1, GL_FALSE, gl.modelViewMatrix);
|
||||
|
@ -2229,9 +2234,13 @@ static void DrawDynamicLight()
|
|||
{
|
||||
glUniform4fv(pipeline->uniformLocations[DU_CLIP_PLANE], 1, gl.clipPlane);
|
||||
}
|
||||
if(pipeline->uniformsDirty[DU_ALPHA_TEST])
|
||||
if(pipeline->uniformsDirty[DU_OPAQUE])
|
||||
{
|
||||
glUniform1ui(pipeline->uniformLocations[DU_ALPHA_TEST], gl.alphaTest);
|
||||
glUniform1f(pipeline->uniformLocations[DU_OPAQUE], gl.dlOpaque ? 1.0f : 0.0f);
|
||||
}
|
||||
if(pipeline->uniformsDirty[DU_INTENSITY])
|
||||
{
|
||||
glUniform1f(pipeline->uniformLocations[DU_INTENSITY], gl.dlIntensity);
|
||||
}
|
||||
|
||||
memset(pipeline->uniformsDirty, 0, sizeof(pipeline->uniformsDirty));
|
||||
|
|
|
@ -815,6 +815,15 @@ typedef struct {
|
|||
byte color2D[4];
|
||||
trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
|
||||
|
||||
// dynamic lights data set by the back-end for the GAL
|
||||
qbool dlOpaque; // qtrue when drawing an opaque surface
|
||||
float dlIntensity; // 1 for most surfaces, but can be scaled down for liquids etc.
|
||||
unsigned int dlStateBits; // the state bits to apply for this draw call
|
||||
// quick explanation on why dlOpaque is useful in the first place:
|
||||
// - opaque surfaces can have a diffuse texture whose alpha isn't 255 everywhere
|
||||
// - when that happens and we multiply the color by the the alpha (DL uses additive blending),
|
||||
// we get "light holes" in opaque surfaces, which is not what we want
|
||||
|
||||
int* pc; // current stats set, depending on projection2D
|
||||
int pc2D[RB_STATS_MAX];
|
||||
int pc3D[RB_STATS_MAX];
|
||||
|
|
|
@ -57,19 +57,19 @@ void RB_BeginSurface( const shader_t* shader, int fogNum )
|
|||
|
||||
static void RB_DrawDynamicLight()
|
||||
{
|
||||
if (tess.shader->lightingStages[ST_DIFFUSE] == -1)
|
||||
return;
|
||||
|
||||
backEnd.pc[RB_LIT_VERTICES_LATECULLTEST] += tess.numVertexes;
|
||||
|
||||
static byte clipBits[SHADER_MAX_VERTEXES];
|
||||
const dlight_t* dl = tess.light;
|
||||
const cullType_t cullType = tess.shader->cullType;
|
||||
|
||||
for (int i = 0; i < tess.numVertexes; ++i) {
|
||||
vec3_t dist;
|
||||
VectorSubtract(dl->transformed, tess.xyz[i], dist);
|
||||
|
||||
if (DotProduct(dist, tess.normal[i]) <= 0.0f) {
|
||||
const float dp = DotProduct(dist, tess.normal[i]);
|
||||
if (cullType == CT_FRONT_SIDED && dp <= 0.0f ||
|
||||
cullType == CT_BACK_SIDED && dp >= 0.0f) {
|
||||
clipBits[i] = byte(-1);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -331,12 +331,27 @@ static void R_AddLitSurface( msurface_t* surf, const dlight_t* light )
|
|||
if ( surf->shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) )
|
||||
return;
|
||||
|
||||
// reject mirrors, portals, sky boxes, etc.
|
||||
if ( surf->shader->sort < SS_OPAQUE )
|
||||
return;
|
||||
|
||||
if ( surf->lightCount == tr.lightCount )
|
||||
return; // already in the lit list (or already culled) for this light
|
||||
|
||||
const int stageIndex = surf->shader->lightingStages[ST_DIFFUSE];
|
||||
if ( stageIndex < 0 )
|
||||
return;
|
||||
|
||||
const shaderStage_t* const stage = surf->shader->stages[stageIndex];
|
||||
const int srcBits = stage->stateBits & GLS_SRCBLEND_BITS;
|
||||
const int dstBits = stage->stateBits & GLS_DSTBLEND_BITS;
|
||||
|
||||
// we can't use a texture that was used with such a blend mode
|
||||
// since the final color could look nothing like the texture itself
|
||||
if ( srcBits == GLS_SRCBLEND_ONE_MINUS_DST_COLOR ||
|
||||
dstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR )
|
||||
return;
|
||||
|
||||
surf->lightCount = tr.lightCount;
|
||||
|
||||
if ( R_LightCullSurface( surf->data, light ) ) {
|
||||
|
|
Loading…
Reference in a new issue