Merge branch 'master' into sdl2
Conflicts: Makefile code/renderercommon/qgl.h code/renderergl1/tr_local.h code/sdl/sdl_glimp.c
This commit is contained in:
commit
d9d52f0306
427 changed files with 66082 additions and 14083 deletions
70
code/renderergl2/glsl/bokeh_fp.glsl
Normal file
70
code/renderergl2/glsl/bokeh_fp.glsl
Normal file
|
@ -0,0 +1,70 @@
|
|||
uniform sampler2D u_TextureMap;
|
||||
|
||||
uniform vec4 u_Color;
|
||||
|
||||
uniform vec2 u_InvTexRes;
|
||||
varying vec2 var_TexCoords;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color;
|
||||
vec2 tc;
|
||||
|
||||
#if 0
|
||||
float c[7] = float[7](1.0, 0.9659258263, 0.8660254038, 0.7071067812, 0.5, 0.2588190451, 0.0);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[6]); color = texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[5]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[2], c[4]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[3], c[3]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[4], c[2]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[5], c[1]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[6], c[0]); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[1], -c[5]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[2], -c[4]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[3], -c[3]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[4], -c[2]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[5], -c[1]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[6], -c[0]); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[0], c[6]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[1], c[5]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[2], c[4]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[3], c[3]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[4], c[2]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[5], c[1]); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[1], -c[5]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[2], -c[4]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[3], -c[3]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[4], -c[2]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[5], -c[1]); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
gl_FragColor = color * 0.04166667 * u_Color;
|
||||
#endif
|
||||
|
||||
float c[5] = float[5](1.0, 0.9238795325, 0.7071067812, 0.3826834324, 0.0);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[4]); color = texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[3]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[2], c[2]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[3], c[1]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[4], c[0]); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[1], -c[3]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[2], -c[2]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[3], -c[1]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( c[4], -c[0]); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[0], c[4]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[1], c[3]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[2], c[2]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[3], c[1]); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[1], -c[3]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[2], -c[2]); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( -c[3], -c[1]); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
gl_FragColor = color * 0.0625 * u_Color;
|
||||
}
|
13
code/renderergl2/glsl/bokeh_vp.glsl
Normal file
13
code/renderergl2/glsl/bokeh_vp.glsl
Normal file
|
@ -0,0 +1,13 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
|
||||
varying vec2 var_TexCoords;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_ModelViewProjectionMatrix * attr_Position;
|
||||
var_TexCoords = attr_TexCoord0.st;
|
||||
}
|
55
code/renderergl2/glsl/calclevels4x_fp.glsl
Normal file
55
code/renderergl2/glsl/calclevels4x_fp.glsl
Normal file
|
@ -0,0 +1,55 @@
|
|||
uniform sampler2D u_TextureMap;
|
||||
|
||||
uniform vec4 u_Color;
|
||||
|
||||
uniform vec2 u_InvTexRes;
|
||||
varying vec2 var_TexCoords;
|
||||
|
||||
const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721); //vec3(0.299, 0.587, 0.114);
|
||||
|
||||
vec3 GetValues(vec2 offset, vec3 current)
|
||||
{
|
||||
vec3 minAvgMax;
|
||||
vec2 tc = var_TexCoords + u_InvTexRes * offset; minAvgMax = texture2D(u_TextureMap, tc).rgb;
|
||||
|
||||
#ifdef FIRST_PASS
|
||||
float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001);
|
||||
float loglumi = clamp(log2(lumi), -10.0, 10.0);
|
||||
minAvgMax = vec3(loglumi * 0.05 + 0.5);
|
||||
#endif
|
||||
|
||||
return vec3(min(current.x, minAvgMax.x), current.y + minAvgMax.y, max(current.z, minAvgMax.z));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 current = vec3(1.0, 0.0, 0.0);
|
||||
|
||||
#ifdef FIRST_PASS
|
||||
current = GetValues(vec2( 0.0, 0.0), current);
|
||||
#else
|
||||
current = GetValues(vec2(-1.5, -1.5), current);
|
||||
current = GetValues(vec2(-0.5, -1.5), current);
|
||||
current = GetValues(vec2( 0.5, -1.5), current);
|
||||
current = GetValues(vec2( 1.5, -1.5), current);
|
||||
|
||||
current = GetValues(vec2(-1.5, -0.5), current);
|
||||
current = GetValues(vec2(-0.5, -0.5), current);
|
||||
current = GetValues(vec2( 0.5, -0.5), current);
|
||||
current = GetValues(vec2( 1.5, -0.5), current);
|
||||
|
||||
current = GetValues(vec2(-1.5, 0.5), current);
|
||||
current = GetValues(vec2(-0.5, 0.5), current);
|
||||
current = GetValues(vec2( 0.5, 0.5), current);
|
||||
current = GetValues(vec2( 1.5, 0.5), current);
|
||||
|
||||
current = GetValues(vec2(-1.5, 1.5), current);
|
||||
current = GetValues(vec2(-0.5, 1.5), current);
|
||||
current = GetValues(vec2( 0.5, 1.5), current);
|
||||
current = GetValues(vec2( 1.5, 1.5), current);
|
||||
|
||||
current.y *= 0.0625;
|
||||
#endif
|
||||
|
||||
gl_FragColor = vec4(current, 1.0f);
|
||||
}
|
13
code/renderergl2/glsl/calclevels4x_vp.glsl
Normal file
13
code/renderergl2/glsl/calclevels4x_vp.glsl
Normal file
|
@ -0,0 +1,13 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
|
||||
varying vec2 var_TexCoords;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_ModelViewProjectionMatrix * attr_Position;
|
||||
var_TexCoords = attr_TexCoord0.st;
|
||||
}
|
58
code/renderergl2/glsl/depthblur_fp.glsl
Normal file
58
code/renderergl2/glsl/depthblur_fp.glsl
Normal file
|
@ -0,0 +1,58 @@
|
|||
uniform sampler2D u_ScreenImageMap;
|
||||
uniform sampler2D u_ScreenDepthMap;
|
||||
|
||||
uniform vec4 u_ViewInfo; // zfar / znear, zfar
|
||||
varying vec2 var_ScreenTex;
|
||||
|
||||
//float gauss[5] = float[5](0.30, 0.23, 0.097, 0.024, 0.0033);
|
||||
float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044);
|
||||
//float gauss[3] = float[3](0.60, 0.19, 0.0066);
|
||||
#define GAUSS_SIZE 4
|
||||
|
||||
float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
|
||||
{
|
||||
float sampleZDivW = texture2D(depthMap, tex).r;
|
||||
return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
|
||||
}
|
||||
|
||||
vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar)
|
||||
{
|
||||
float scale = 1.0 / 256.0;
|
||||
|
||||
#if defined(USE_HORIZONTAL_BLUR)
|
||||
vec2 direction = vec2(1.0, 0.0) * scale;
|
||||
#else // if defined(USE_VERTICAL_BLUR)
|
||||
vec2 direction = vec2(0.0, 1.0) * scale;
|
||||
#endif
|
||||
|
||||
float depthCenter = zFar * getLinearDepth(depthMap, tex, zFarDivZNear);
|
||||
vec2 centerSlope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y));
|
||||
|
||||
vec4 result = texture2D(imageMap, tex) * gauss[0];
|
||||
float total = gauss[0];
|
||||
|
||||
int i, j;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
for (j = 1; j < GAUSS_SIZE; j++)
|
||||
{
|
||||
vec2 offset = direction * j;
|
||||
float depthSample = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear);
|
||||
float depthExpected = depthCenter + dot(centerSlope, offset);
|
||||
if(abs(depthSample - depthExpected) < 5.0)
|
||||
{
|
||||
result += texture2D(imageMap, tex + offset) * gauss[j];
|
||||
total += gauss[j];
|
||||
}
|
||||
}
|
||||
|
||||
direction = -direction;
|
||||
}
|
||||
|
||||
return result / total;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y);
|
||||
}
|
12
code/renderergl2/glsl/depthblur_vp.glsl
Normal file
12
code/renderergl2/glsl/depthblur_vp.glsl
Normal file
|
@ -0,0 +1,12 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
varying vec2 var_ScreenTex;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = attr_Position;
|
||||
var_ScreenTex = attr_TexCoord0.xy;
|
||||
//vec2 screenCoords = gl_Position.xy / gl_Position.w;
|
||||
//var_ScreenTex = screenCoords * 0.5 + 0.5;
|
||||
}
|
12
code/renderergl2/glsl/dlight_fp.glsl
Normal file
12
code/renderergl2/glsl/dlight_fp.glsl
Normal file
|
@ -0,0 +1,12 @@
|
|||
uniform sampler2D u_DiffuseMap;
|
||||
|
||||
varying vec2 var_Tex1;
|
||||
varying vec4 var_Color;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture2D(u_DiffuseMap, var_Tex1);
|
||||
|
||||
gl_FragColor = color * var_Color;
|
||||
}
|
92
code/renderergl2/glsl/dlight_vp.glsl
Normal file
92
code/renderergl2/glsl/dlight_vp.glsl
Normal file
|
@ -0,0 +1,92 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
attribute vec3 attr_Normal;
|
||||
|
||||
uniform vec4 u_DlightInfo;
|
||||
|
||||
#if defined(USE_DEFORM_VERTEXES)
|
||||
uniform int u_DeformGen;
|
||||
uniform float u_DeformParams[5];
|
||||
uniform float u_Time;
|
||||
#endif
|
||||
|
||||
uniform vec4 u_Color;
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
|
||||
varying vec2 var_Tex1;
|
||||
varying vec4 var_Color;
|
||||
|
||||
#if defined(USE_DEFORM_VERTEXES)
|
||||
vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
|
||||
{
|
||||
if (u_DeformGen == 0)
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
float base = u_DeformParams[0];
|
||||
float amplitude = u_DeformParams[1];
|
||||
float phase = u_DeformParams[2];
|
||||
float frequency = u_DeformParams[3];
|
||||
float spread = u_DeformParams[4];
|
||||
|
||||
if (u_DeformGen == DGEN_BULGE)
|
||||
{
|
||||
phase *= M_PI * 0.25 * st.x;
|
||||
}
|
||||
else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)
|
||||
{
|
||||
phase += dot(pos.xyz, vec3(spread));
|
||||
}
|
||||
|
||||
float value = phase + (u_Time * frequency);
|
||||
float func;
|
||||
|
||||
if (u_DeformGen == DGEN_WAVE_SIN)
|
||||
{
|
||||
func = sin(value * 2.0 * M_PI);
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_SQUARE)
|
||||
{
|
||||
func = sign(sin(value * 2.0 * M_PI));
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_TRIANGLE)
|
||||
{
|
||||
func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0;
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_SAWTOOTH)
|
||||
{
|
||||
func = fract(value);
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)
|
||||
{
|
||||
func = (1.0 - fract(value));
|
||||
}
|
||||
else if (u_DeformGen == DGEN_BULGE)
|
||||
{
|
||||
func = sin(value);
|
||||
}
|
||||
|
||||
return pos + normal * (base + func * amplitude);
|
||||
}
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = attr_Position;
|
||||
vec3 normal = attr_Normal;
|
||||
|
||||
#if defined(USE_DEFORM_VERTEXES)
|
||||
position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st);
|
||||
#endif
|
||||
|
||||
gl_Position = u_ModelViewProjectionMatrix * position;
|
||||
|
||||
vec3 dist = u_DlightInfo.xyz - position.xyz;
|
||||
|
||||
var_Tex1 = dist.xy * u_DlightInfo.a + vec2(0.5);
|
||||
float dlightmod = step(0.0, dot(dist, normal));
|
||||
dlightmod *= clamp(2.0 * (1.0 - abs(dist.z) * u_DlightInfo.a), 0.0, 1.0);
|
||||
|
||||
var_Color = u_Color * dlightmod;
|
||||
}
|
34
code/renderergl2/glsl/down4x_fp.glsl
Normal file
34
code/renderergl2/glsl/down4x_fp.glsl
Normal file
|
@ -0,0 +1,34 @@
|
|||
uniform sampler2D u_TextureMap;
|
||||
|
||||
uniform vec2 u_InvTexRes;
|
||||
varying vec2 var_TexCoords;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color;
|
||||
vec2 tc;
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2(-1.5, -1.5); color = texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2(-0.5, -1.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( 0.5, -1.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( 1.5, -1.5); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2(-1.5, -0.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2(-0.5, -0.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( 0.5, -0.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( 1.5, -0.5); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2(-1.5, 0.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2(-0.5, 0.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( 0.5, 0.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( 1.5, 0.5); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
tc = var_TexCoords + u_InvTexRes * vec2(-1.5, 1.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2(-0.5, 1.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( 0.5, 1.5); color += texture2D(u_TextureMap, tc);
|
||||
tc = var_TexCoords + u_InvTexRes * vec2( 1.5, 1.5); color += texture2D(u_TextureMap, tc);
|
||||
|
||||
color *= 0.0625;
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
13
code/renderergl2/glsl/down4x_vp.glsl
Normal file
13
code/renderergl2/glsl/down4x_vp.glsl
Normal file
|
@ -0,0 +1,13 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
|
||||
varying vec2 var_TexCoords;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_ModelViewProjectionMatrix * attr_Position;
|
||||
var_TexCoords = attr_TexCoord0.st;
|
||||
}
|
9
code/renderergl2/glsl/fogpass_fp.glsl
Normal file
9
code/renderergl2/glsl/fogpass_fp.glsl
Normal file
|
@ -0,0 +1,9 @@
|
|||
uniform vec4 u_Color;
|
||||
|
||||
varying float var_Scale;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = u_Color;
|
||||
gl_FragColor.a *= sqrt(clamp(var_Scale, 0.0, 1.0));
|
||||
}
|
117
code/renderergl2/glsl/fogpass_vp.glsl
Normal file
117
code/renderergl2/glsl/fogpass_vp.glsl
Normal file
|
@ -0,0 +1,117 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec3 attr_Normal;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
//#if defined(USE_VERTEX_ANIMATION)
|
||||
attribute vec4 attr_Position2;
|
||||
attribute vec3 attr_Normal2;
|
||||
//#endif
|
||||
|
||||
uniform vec4 u_FogDistance;
|
||||
uniform vec4 u_FogDepth;
|
||||
uniform float u_FogEyeT;
|
||||
|
||||
//#if defined(USE_DEFORM_VERTEXES)
|
||||
uniform int u_DeformGen;
|
||||
uniform float u_DeformParams[5];
|
||||
//#endif
|
||||
|
||||
uniform float u_Time;
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
|
||||
//#if defined(USE_VERTEX_ANIMATION)
|
||||
uniform float u_VertexLerp;
|
||||
//#endif
|
||||
|
||||
varying float var_Scale;
|
||||
|
||||
#if defined(USE_DEFORM_VERTEXES)
|
||||
vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
|
||||
{
|
||||
if (u_DeformGen == 0)
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
float base = u_DeformParams[0];
|
||||
float amplitude = u_DeformParams[1];
|
||||
float phase = u_DeformParams[2];
|
||||
float frequency = u_DeformParams[3];
|
||||
float spread = u_DeformParams[4];
|
||||
|
||||
if (u_DeformGen == DGEN_BULGE)
|
||||
{
|
||||
phase *= M_PI * 0.25 * st.x;
|
||||
}
|
||||
else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)
|
||||
{
|
||||
phase += dot(pos.xyz, vec3(spread));
|
||||
}
|
||||
|
||||
float value = phase + (u_Time * frequency);
|
||||
float func;
|
||||
|
||||
if (u_DeformGen == DGEN_WAVE_SIN)
|
||||
{
|
||||
func = sin(value * 2.0 * M_PI);
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_SQUARE)
|
||||
{
|
||||
func = sign(sin(value * 2.0 * M_PI));
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_TRIANGLE)
|
||||
{
|
||||
func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0;
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_SAWTOOTH)
|
||||
{
|
||||
func = fract(value);
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)
|
||||
{
|
||||
func = (1.0 - fract(value));
|
||||
}
|
||||
else if (u_DeformGen == DGEN_BULGE)
|
||||
{
|
||||
func = sin(value);
|
||||
}
|
||||
|
||||
return pos + normal * (base + func * amplitude);
|
||||
}
|
||||
#endif
|
||||
|
||||
float CalcFog(vec4 position)
|
||||
{
|
||||
float s = dot(position, u_FogDistance) * 8.0;
|
||||
float t = dot(position, u_FogDepth);
|
||||
|
||||
if (t < 1.0)
|
||||
{
|
||||
t = step(step(0.0, -u_FogEyeT), t);
|
||||
}
|
||||
else
|
||||
{
|
||||
t /= t - min(u_FogEyeT, 0.0);
|
||||
}
|
||||
|
||||
return s * t;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(USE_VERTEX_ANIMATION)
|
||||
vec4 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
||||
vec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp));
|
||||
#else
|
||||
vec4 position = attr_Position;
|
||||
vec3 normal = attr_Normal;
|
||||
#endif
|
||||
|
||||
#if defined(USE_DEFORM_VERTEXES)
|
||||
position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st);
|
||||
#endif
|
||||
|
||||
gl_Position = u_ModelViewProjectionMatrix * position;
|
||||
|
||||
var_Scale = CalcFog(position);
|
||||
}
|
43
code/renderergl2/glsl/generic_fp.glsl
Normal file
43
code/renderergl2/glsl/generic_fp.glsl
Normal file
|
@ -0,0 +1,43 @@
|
|||
uniform sampler2D u_DiffuseMap;
|
||||
|
||||
#if defined(USE_LIGHTMAP)
|
||||
uniform sampler2D u_LightMap;
|
||||
|
||||
uniform int u_Texture1Env;
|
||||
#endif
|
||||
|
||||
varying vec2 var_DiffuseTex;
|
||||
|
||||
#if defined(USE_LIGHTMAP)
|
||||
varying vec2 var_LightTex;
|
||||
#endif
|
||||
|
||||
varying vec4 var_Color;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture2D(u_DiffuseMap, var_DiffuseTex);
|
||||
#if defined(USE_LIGHTMAP)
|
||||
vec4 color2 = texture2D(u_LightMap, var_LightTex);
|
||||
#if defined(RGBE_LIGHTMAP)
|
||||
color2.rgb *= exp2(color2.a * 255.0 - 128.0);
|
||||
color2.a = 1.0;
|
||||
#endif
|
||||
|
||||
if (u_Texture1Env == TEXENV_MODULATE)
|
||||
{
|
||||
color *= color2;
|
||||
}
|
||||
else if (u_Texture1Env == TEXENV_ADD)
|
||||
{
|
||||
color += color2;
|
||||
}
|
||||
else if (u_Texture1Env == TEXENV_REPLACE)
|
||||
{
|
||||
color = color2;
|
||||
}
|
||||
#endif
|
||||
|
||||
gl_FragColor = color * var_Color;
|
||||
}
|
251
code/renderergl2/glsl/generic_vp.glsl
Normal file
251
code/renderergl2/glsl/generic_vp.glsl
Normal file
|
@ -0,0 +1,251 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec3 attr_Normal;
|
||||
|
||||
#if defined(USE_VERTEX_ANIMATION)
|
||||
attribute vec4 attr_Position2;
|
||||
attribute vec3 attr_Normal2;
|
||||
#endif
|
||||
|
||||
attribute vec4 attr_Color;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
#if defined(USE_LIGHTMAP) || defined(USE_TCGEN)
|
||||
attribute vec4 attr_TexCoord1;
|
||||
#endif
|
||||
|
||||
uniform vec4 u_DiffuseTexMatrix;
|
||||
uniform vec4 u_DiffuseTexOffTurb;
|
||||
|
||||
#if defined(USE_TCGEN) || defined(USE_RGBAGEN)
|
||||
uniform vec3 u_ViewOrigin;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN)
|
||||
uniform int u_TCGen0;
|
||||
uniform vec3 u_TCGen0Vector0;
|
||||
uniform vec3 u_TCGen0Vector1;
|
||||
#endif
|
||||
|
||||
#if defined(USE_FOG)
|
||||
uniform vec4 u_FogDistance;
|
||||
uniform vec4 u_FogDepth;
|
||||
uniform float u_FogEyeT;
|
||||
uniform vec4 u_FogColorMask;
|
||||
#endif
|
||||
|
||||
#if defined(USE_DEFORM_VERTEXES)
|
||||
uniform int u_DeformGen;
|
||||
uniform float u_DeformParams[5];
|
||||
uniform float u_Time;
|
||||
#endif
|
||||
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
uniform vec4 u_BaseColor;
|
||||
uniform vec4 u_VertColor;
|
||||
|
||||
#if defined(USE_RGBAGEN)
|
||||
uniform int u_ColorGen;
|
||||
uniform int u_AlphaGen;
|
||||
uniform vec3 u_AmbientLight;
|
||||
uniform vec3 u_DirectedLight;
|
||||
uniform vec4 u_LightOrigin;
|
||||
uniform float u_PortalRange;
|
||||
#endif
|
||||
|
||||
#if defined(USE_VERTEX_ANIMATION)
|
||||
uniform float u_VertexLerp;
|
||||
#endif
|
||||
|
||||
varying vec2 var_DiffuseTex;
|
||||
#if defined(USE_LIGHTMAP)
|
||||
varying vec2 var_LightTex;
|
||||
#endif
|
||||
varying vec4 var_Color;
|
||||
|
||||
#if defined(USE_DEFORM_VERTEXES)
|
||||
vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
|
||||
{
|
||||
float base = u_DeformParams[0];
|
||||
float amplitude = u_DeformParams[1];
|
||||
float phase = u_DeformParams[2];
|
||||
float frequency = u_DeformParams[3];
|
||||
float spread = u_DeformParams[4];
|
||||
|
||||
if (u_DeformGen == DGEN_BULGE)
|
||||
{
|
||||
phase *= M_PI * 0.25 * st.x;
|
||||
}
|
||||
else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)
|
||||
{
|
||||
phase += dot(pos.xyz, vec3(spread));
|
||||
}
|
||||
|
||||
float value = phase + (u_Time * frequency);
|
||||
float func;
|
||||
|
||||
if (u_DeformGen == DGEN_WAVE_SIN)
|
||||
{
|
||||
func = sin(value * 2.0 * M_PI);
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_SQUARE)
|
||||
{
|
||||
func = sign(sin(value * 2.0 * M_PI));
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_TRIANGLE)
|
||||
{
|
||||
func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0;
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_SAWTOOTH)
|
||||
{
|
||||
func = fract(value);
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)
|
||||
{
|
||||
func = (1.0 - fract(value));
|
||||
}
|
||||
else if (u_DeformGen == DGEN_BULGE)
|
||||
{
|
||||
func = sin(value);
|
||||
}
|
||||
|
||||
return pos + normal * (base + func * amplitude);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN)
|
||||
vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1)
|
||||
{
|
||||
vec2 tex = attr_TexCoord0.st;
|
||||
|
||||
if (TCGen == TCGEN_LIGHTMAP)
|
||||
{
|
||||
tex = attr_TexCoord1.st;
|
||||
}
|
||||
else if (TCGen == TCGEN_ENVIRONMENT_MAPPED)
|
||||
{
|
||||
vec3 viewer = normalize(u_ViewOrigin - position);
|
||||
tex = -reflect(viewer, normal).yz * vec2(0.5, -0.5) + 0.5;
|
||||
}
|
||||
else if (TCGen == TCGEN_VECTOR)
|
||||
{
|
||||
tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1));
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCMOD)
|
||||
vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb)
|
||||
{
|
||||
float amplitude = offTurb.z;
|
||||
float phase = offTurb.w;
|
||||
vec2 st2 = vec2(dot(st, texMatrix.xz), dot(st, texMatrix.yw)) + offTurb.xy;
|
||||
|
||||
vec3 offsetPos = position / 1024.0;
|
||||
offsetPos.x += offsetPos.z;
|
||||
|
||||
vec2 texOffset = sin((offsetPos.xy + vec2(phase)) * 2.0 * M_PI);
|
||||
|
||||
return st2 + texOffset * amplitude;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_RGBAGEN)
|
||||
vec4 CalcColor(vec3 position, vec3 normal)
|
||||
{
|
||||
vec4 color = u_VertColor * attr_Color + u_BaseColor;
|
||||
|
||||
if (u_ColorGen == CGEN_LIGHTING_DIFFUSE)
|
||||
{
|
||||
float incoming = clamp(dot(normal, u_LightOrigin.xyz), 0.0, 1.0);
|
||||
|
||||
color.rgb = clamp(u_DirectedLight * incoming + u_AmbientLight, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec3 toView = u_ViewOrigin - position;
|
||||
vec3 viewer = normalize(u_ViewOrigin - position);
|
||||
|
||||
if (u_AlphaGen == AGEN_LIGHTING_SPECULAR)
|
||||
{
|
||||
vec3 lightDir = normalize(vec3(-960.0, -1980.0, 96.0) - position.xyz);
|
||||
vec3 halfangle = normalize(lightDir + viewer);
|
||||
|
||||
color.a = pow(max(dot(normal, halfangle), 0.0), 8.0);
|
||||
}
|
||||
else if (u_AlphaGen == AGEN_PORTAL)
|
||||
{
|
||||
float alpha = length(toView) / u_PortalRange;
|
||||
|
||||
color.a = clamp(alpha, 0.0, 1.0);
|
||||
}
|
||||
else if (u_AlphaGen == AGEN_FRESNEL)
|
||||
{
|
||||
color.a = 0.10 + 0.90 * pow(1.0 - dot(normal, viewer), 5);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_FOG)
|
||||
float CalcFog(vec4 position)
|
||||
{
|
||||
float s = dot(position, u_FogDistance) * 8.0;
|
||||
float t = dot(position, u_FogDepth);
|
||||
|
||||
if (t < 1.0)
|
||||
{
|
||||
t = step(step(0.0, -u_FogEyeT), t);
|
||||
}
|
||||
else
|
||||
{
|
||||
t /= t - min(u_FogEyeT, 0.0);
|
||||
}
|
||||
|
||||
return s * t;
|
||||
}
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(USE_VERTEX_ANIMATION)
|
||||
vec4 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
||||
vec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp));
|
||||
#else
|
||||
vec4 position = attr_Position;
|
||||
vec3 normal = attr_Normal;
|
||||
#endif
|
||||
|
||||
#if defined(USE_DEFORM_VERTEXES)
|
||||
position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st);
|
||||
#endif
|
||||
|
||||
gl_Position = u_ModelViewProjectionMatrix * position;
|
||||
|
||||
#if defined(USE_TCGEN)
|
||||
vec2 tex = GenTexCoords(u_TCGen0, position.xyz, normal, u_TCGen0Vector0, u_TCGen0Vector1);
|
||||
#else
|
||||
vec2 tex = attr_TexCoord0.st;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCMOD)
|
||||
var_DiffuseTex = ModTexCoords(tex, position.xyz, u_DiffuseTexMatrix, u_DiffuseTexOffTurb);
|
||||
#else
|
||||
var_DiffuseTex = tex;
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHTMAP)
|
||||
var_LightTex = attr_TexCoord1.st;
|
||||
#endif
|
||||
|
||||
#if defined(USE_RGBAGEN)
|
||||
var_Color = CalcColor(position.xyz, normal);
|
||||
#else
|
||||
var_Color = u_VertColor * attr_Color + u_BaseColor;
|
||||
#endif
|
||||
|
||||
#if defined(USE_FOG)
|
||||
var_Color *= vec4(1.0) - u_FogColorMask * sqrt(clamp(CalcFog(position), 0.0, 1.0));
|
||||
#endif
|
||||
}
|
429
code/renderergl2/glsl/lightall_fp.glsl
Normal file
429
code/renderergl2/glsl/lightall_fp.glsl
Normal file
|
@ -0,0 +1,429 @@
|
|||
uniform sampler2D u_DiffuseMap;
|
||||
|
||||
#if defined(USE_LIGHTMAP)
|
||||
uniform sampler2D u_LightMap;
|
||||
#endif
|
||||
|
||||
#if defined(USE_NORMALMAP)
|
||||
uniform sampler2D u_NormalMap;
|
||||
#endif
|
||||
|
||||
#if defined(USE_DELUXEMAP)
|
||||
uniform sampler2D u_DeluxeMap;
|
||||
#endif
|
||||
|
||||
#if defined(USE_SPECULARMAP)
|
||||
uniform sampler2D u_SpecularMap;
|
||||
#endif
|
||||
|
||||
#if defined(USE_SHADOWMAP)
|
||||
uniform sampler2D u_ShadowMap;
|
||||
#endif
|
||||
|
||||
uniform vec3 u_ViewOrigin;
|
||||
|
||||
#if defined(USE_TCGEN)
|
||||
uniform int u_TCGen0;
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT_VECTOR)
|
||||
uniform vec4 u_LightOrigin;
|
||||
uniform vec3 u_DirectedLight;
|
||||
uniform vec3 u_AmbientLight;
|
||||
uniform float u_LightRadius;
|
||||
#endif
|
||||
|
||||
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
|
||||
uniform vec3 u_PrimaryLightColor;
|
||||
uniform vec3 u_PrimaryLightAmbient;
|
||||
uniform float u_PrimaryLightRadius;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(USE_LIGHT)
|
||||
uniform vec2 u_MaterialInfo;
|
||||
#endif
|
||||
|
||||
varying vec2 var_DiffuseTex;
|
||||
#if defined(USE_LIGHTMAP)
|
||||
varying vec2 var_LightTex;
|
||||
#endif
|
||||
varying vec4 var_Color;
|
||||
|
||||
#if defined(USE_NORMALMAP) && !defined(USE_VERT_TANGENT_SPACE)
|
||||
varying vec3 var_Position;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
|
||||
varying vec3 var_SampleToView;
|
||||
#endif
|
||||
|
||||
#if !defined(USE_FAST_LIGHT)
|
||||
varying vec3 var_Normal;
|
||||
#endif
|
||||
|
||||
#if defined(USE_VERT_TANGENT_SPACE)
|
||||
varying vec3 var_Tangent;
|
||||
varying vec3 var_Bitangent;
|
||||
#endif
|
||||
|
||||
varying vec3 var_VertLight;
|
||||
|
||||
#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP)
|
||||
varying vec3 var_LightDirection;
|
||||
#endif
|
||||
|
||||
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
|
||||
varying vec3 var_PrimaryLightDirection;
|
||||
#endif
|
||||
|
||||
|
||||
#define EPSILON 0.00000001
|
||||
|
||||
#if defined(USE_PARALLAXMAP)
|
||||
float SampleHeight(sampler2D normalMap, vec2 t)
|
||||
{
|
||||
#if defined(SWIZZLE_NORMALMAP)
|
||||
return texture2D(normalMap, t).r;
|
||||
#else
|
||||
return texture2D(normalMap, t).a;
|
||||
#endif
|
||||
}
|
||||
|
||||
float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)
|
||||
{
|
||||
const int linearSearchSteps = 16;
|
||||
const int binarySearchSteps = 6;
|
||||
|
||||
float depthStep = 1.0 / float(linearSearchSteps);
|
||||
|
||||
// current size of search window
|
||||
float size = depthStep;
|
||||
|
||||
// current depth position
|
||||
float depth = 0.0;
|
||||
|
||||
// best match found (starts with last position 1.0)
|
||||
float bestDepth = 1.0;
|
||||
|
||||
// search front to back for first point inside object
|
||||
for(int i = 0; i < linearSearchSteps - 1; ++i)
|
||||
{
|
||||
depth += size;
|
||||
|
||||
float t = 1.0 - SampleHeight(normalMap, dp + ds * depth);
|
||||
|
||||
if(bestDepth > 0.996) // if no depth found yet
|
||||
if(depth >= t)
|
||||
bestDepth = depth; // store best depth
|
||||
}
|
||||
|
||||
depth = bestDepth;
|
||||
|
||||
// recurse around first point (depth) for closest match
|
||||
for(int i = 0; i < binarySearchSteps; ++i)
|
||||
{
|
||||
size *= 0.5;
|
||||
|
||||
float t = 1.0 - SampleHeight(normalMap, dp + ds * depth);
|
||||
|
||||
if(depth >= t)
|
||||
{
|
||||
bestDepth = depth;
|
||||
depth -= 2.0 * size;
|
||||
}
|
||||
|
||||
depth += size;
|
||||
}
|
||||
|
||||
return bestDepth;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 CalcDiffuse(vec3 diffuseAlbedo, vec3 N, vec3 L, vec3 E, float NE, float NL, float shininess)
|
||||
{
|
||||
#if defined(USE_OREN_NAYAR) || defined(USE_TRIACE_OREN_NAYAR)
|
||||
float gamma = dot(E, L) - NE * NL;
|
||||
float B = 2.22222 + 0.1 * shininess;
|
||||
|
||||
#if defined(USE_OREN_NAYAR)
|
||||
float A = 1.0 - 1.0 / (2.0 + 0.33 * shininess);
|
||||
gamma = clamp(gamma, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
#if defined(USE_TRIACE_OREN_NAYAR)
|
||||
float A = 1.0 - 1.0 / (2.0 + 0.65 * shininess);
|
||||
|
||||
if (gamma >= 0.0)
|
||||
#endif
|
||||
{
|
||||
B *= max(max(NL, NE), EPSILON);
|
||||
}
|
||||
|
||||
return diffuseAlbedo * (A + gamma / B);
|
||||
#else
|
||||
return diffuseAlbedo;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(USE_SPECULARMAP)
|
||||
vec3 CalcSpecular(vec3 specularReflectance, float NH, float NL, float NE, float EH, float shininess)
|
||||
{
|
||||
#if defined(USE_BLINN) || defined(USE_TRIACE) || defined(USE_TORRANCE_SPARROW)
|
||||
float blinn = pow(NH, shininess);
|
||||
#endif
|
||||
|
||||
#if defined(USE_BLINN)
|
||||
return specularReflectance * blinn;
|
||||
#endif
|
||||
|
||||
#if defined(USE_COOK_TORRANCE) || defined (USE_TRIACE) || defined (USE_TORRANCE_SPARROW)
|
||||
vec3 fresnel = specularReflectance + (vec3(1.0) - specularReflectance) * pow(1.0 - EH, 5);
|
||||
#endif
|
||||
|
||||
#if defined(USE_COOK_TORRANCE) || defined(USE_TORRANCE_SPARROW)
|
||||
float geo = 2.0 * NH * min(NE, NL);
|
||||
geo /= max(EH, geo);
|
||||
#endif
|
||||
|
||||
#if defined(USE_COOK_TORRANCE)
|
||||
float m_sq = 2.0 / max(shininess, EPSILON);
|
||||
float NH_sq = NH * NH;
|
||||
float m_NH_sq = m_sq * NH_sq;
|
||||
float beckmann = exp((NH_sq - 1.0) / max(m_NH_sq, EPSILON)) / max(4.0 * m_NH_sq * NH_sq, EPSILON);
|
||||
|
||||
return fresnel * geo * beckmann / max(NE, EPSILON);
|
||||
#endif
|
||||
|
||||
#if defined(USE_TRIACE)
|
||||
float scale = 0.1248582 * shininess + 0.2691817;
|
||||
|
||||
return fresnel * scale * blinn / max(max(NL, NE), EPSILON);
|
||||
#endif
|
||||
|
||||
#if defined(USE_TORRANCE_SPARROW)
|
||||
float scale = 0.125 * shininess + 1.0;
|
||||
|
||||
return fresnel * geo * scale * blinn / max(NE, EPSILON);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
#if !defined(USE_FAST_LIGHT) && (defined(USE_LIGHT) || defined(USE_NORMALMAP))
|
||||
vec3 surfN = normalize(var_Normal);
|
||||
#endif
|
||||
|
||||
#if defined(USE_DELUXEMAP)
|
||||
vec3 L = 2.0 * texture2D(u_DeluxeMap, var_LightTex).xyz - vec3(1.0);
|
||||
//L += var_LightDirection * 0.0001;
|
||||
#elif defined(USE_LIGHT)
|
||||
vec3 L = var_LightDirection;
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHTMAP)
|
||||
vec4 lightSample = texture2D(u_LightMap, var_LightTex).rgba;
|
||||
#if defined(RGBE_LIGHTMAP)
|
||||
lightSample.rgb *= exp2(lightSample.a * 255.0 - 128.0);
|
||||
#endif
|
||||
vec3 lightColor = lightSample.rgb;
|
||||
#elif defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT)
|
||||
#if defined(USE_INVSQRLIGHT)
|
||||
float intensity = 1.0 / dot(L, L);
|
||||
#else
|
||||
float intensity = clamp((1.0 - dot(L, L) / (u_LightRadius * u_LightRadius)) * 1.07, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
vec3 lightColor = u_DirectedLight * intensity;
|
||||
vec3 ambientColor = u_AmbientLight;
|
||||
#elif defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT)
|
||||
vec3 lightColor = var_VertLight;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
|
||||
vec3 E = normalize(var_SampleToView);
|
||||
#endif
|
||||
vec2 texCoords = var_DiffuseTex;
|
||||
|
||||
float ambientDiff = 1.0;
|
||||
|
||||
#if defined(USE_NORMALMAP)
|
||||
#if defined(USE_VERT_TANGENT_SPACE)
|
||||
mat3 tangentToWorld = mat3(var_Tangent, var_Bitangent, var_Normal);
|
||||
#else
|
||||
vec3 q0 = dFdx(var_Position);
|
||||
vec3 q1 = dFdy(var_Position);
|
||||
vec2 st0 = dFdx(texCoords);
|
||||
vec2 st1 = dFdy(texCoords);
|
||||
float dir = sign(st1.t * st0.s - st0.t * st1.s);
|
||||
|
||||
vec3 tangent = normalize(q0 * st1.t - q1 * st0.t) * dir;
|
||||
vec3 bitangent = -normalize(q0 * st1.s - q1 * st0.s) * dir;
|
||||
|
||||
mat3 tangentToWorld = mat3(tangent, bitangent, var_Normal);
|
||||
#endif
|
||||
|
||||
#if defined(USE_PARALLAXMAP)
|
||||
vec3 offsetDir = normalize(E * tangentToWorld);
|
||||
offsetDir.xy *= -0.05 / offsetDir.z;
|
||||
|
||||
texCoords += offsetDir.xy * RayIntersectDisplaceMap(texCoords, offsetDir.xy, u_NormalMap);
|
||||
#endif
|
||||
vec3 texN;
|
||||
#if defined(SWIZZLE_NORMALMAP)
|
||||
texN.xy = 2.0 * texture2D(u_NormalMap, texCoords).ag - 1.0;
|
||||
#else
|
||||
texN.xy = 2.0 * texture2D(u_NormalMap, texCoords).rg - 1.0;
|
||||
#endif
|
||||
texN.z = sqrt(clamp(1.0 - dot(texN.xy, texN.xy), 0.0, 1.0));
|
||||
vec3 N = tangentToWorld * texN;
|
||||
#if defined(r_normalAmbient)
|
||||
ambientDiff = 0.781341 * texN.z + 0.218659;
|
||||
#endif
|
||||
#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
|
||||
vec3 N = surfN;
|
||||
#endif
|
||||
|
||||
#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || (defined(USE_TCGEN) && defined(USE_NORMALMAP))
|
||||
N = normalize(N);
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN) && defined(USE_NORMALMAP)
|
||||
if (u_TCGen0 == TCGEN_ENVIRONMENT_MAPPED)
|
||||
{
|
||||
texCoords = -reflect(E, N).yz * vec2(0.5, -0.5) + 0.5;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec4 diffuseAlbedo = texture2D(u_DiffuseMap, texCoords);
|
||||
#if defined(USE_LIGHT) && defined(USE_GAMMA2_TEXTURES)
|
||||
diffuseAlbedo.rgb *= diffuseAlbedo.rgb;
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT) && defined(USE_FAST_LIGHT)
|
||||
gl_FragColor = diffuse.rgb;
|
||||
#if defined(USE_LIGHTMAP)
|
||||
gl_FragColor *= lightColor;
|
||||
#endif
|
||||
#elif defined(USE_LIGHT)
|
||||
L = normalize(L);
|
||||
|
||||
float surfNL = clamp(dot(surfN, L), 0.0, 1.0);
|
||||
|
||||
#if defined(USE_SHADOWMAP)
|
||||
vec2 shadowTex = gl_FragCoord.xy * r_FBufScale;
|
||||
float shadowValue = texture2D(u_ShadowMap, shadowTex).r;
|
||||
|
||||
// surfaces not facing the light are always shadowed
|
||||
shadowValue *= step(0.0, dot(surfN, var_PrimaryLightDirection));
|
||||
|
||||
#if defined(SHADOWMAP_MODULATE)
|
||||
//vec3 shadowColor = min(u_PrimaryLightAmbient, lightColor);
|
||||
vec3 shadowColor = u_PrimaryLightAmbient * lightColor;
|
||||
|
||||
#if 0
|
||||
// Only shadow when the world light is parallel to the primary light
|
||||
shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDirection), 0.0, 1.0);
|
||||
#endif
|
||||
lightColor = mix(shadowColor, lightColor, shadowValue);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX)
|
||||
#if defined(USE_STANDARD_DELUXEMAP)
|
||||
// Standard deluxe mapping treats the light sample as fully directed
|
||||
// and doesn't compensate for light angle attenuation.
|
||||
vec3 ambientColor = vec3(0.0);
|
||||
#else
|
||||
// Separate the light sample into directed and ambient parts.
|
||||
//
|
||||
// ambientMax - if the cosine of the angle between the surface
|
||||
// normal and the light is below this value, the light
|
||||
// is fully ambient.
|
||||
// directedMax - if the cosine of the angle between the surface
|
||||
// normal and the light is above this value, the light
|
||||
// is fully directed.
|
||||
const float ambientMax = 0.25;
|
||||
const float directedMax = 0.5;
|
||||
|
||||
float directedScale = clamp((surfNL - ambientMax) / (directedMax - ambientMax), 0.0, 1.0);
|
||||
|
||||
// Scale the directed portion to compensate for the baked-in
|
||||
// light angle attenuation.
|
||||
directedScale /= max(surfNL, ambientMax);
|
||||
|
||||
#if defined(r_normalAmbient)
|
||||
directedScale *= 1.0 - r_normalAmbient;
|
||||
#endif
|
||||
|
||||
// Recover any unused light as ambient
|
||||
vec3 ambientColor = lightColor;
|
||||
lightColor *= directedScale;
|
||||
ambientColor -= lightColor * surfNL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
float NL = clamp(dot(N, L), 0.0, 1.0);
|
||||
float NE = clamp(dot(N, E), 0.0, 1.0);
|
||||
|
||||
float maxReflectance = u_MaterialInfo.x;
|
||||
float shininess = u_MaterialInfo.y;
|
||||
|
||||
#if defined(USE_SPECULARMAP)
|
||||
vec4 specularReflectance = texture2D(u_SpecularMap, texCoords);
|
||||
specularReflectance.rgb *= maxReflectance;
|
||||
shininess *= specularReflectance.a;
|
||||
// adjust diffuse by specular reflectance, to maintain energy conservation
|
||||
diffuseAlbedo.rgb *= vec3(1.0) - specularReflectance.rgb;
|
||||
#endif
|
||||
|
||||
gl_FragColor.rgb = lightColor * NL * CalcDiffuse(diffuseAlbedo.rgb, N, L, E, NE, NL, shininess);
|
||||
gl_FragColor.rgb += ambientDiff * ambientColor * diffuseAlbedo.rgb;
|
||||
#if defined(USE_PRIMARY_LIGHT)
|
||||
vec3 L2 = var_PrimaryLightDirection;
|
||||
float NL2 = clamp(dot(N, L2), 0.0, 1.0);
|
||||
|
||||
#if defined(USE_SHADOWMAP)
|
||||
gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * NL2 * CalcDiffuse(diffuseAlbedo.rgb, N, L2, E, NE, NL2, shininess);
|
||||
#else
|
||||
gl_FragColor.rgb += u_PrimaryLightColor * NL2 * CalcDiffuse(diffuseAlbedo.rgb, N, L2, E, NE, NL2, shininess);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_SPECULARMAP)
|
||||
vec3 H = normalize(L + E);
|
||||
|
||||
float EH = clamp(dot(E, H), 0.0, 1.0);
|
||||
float NH = clamp(dot(N, H), 0.0, 1.0);
|
||||
|
||||
gl_FragColor.rgb += lightColor * NL * CalcSpecular(specularReflectance.rgb, NH, NL, NE, EH, shininess);
|
||||
|
||||
#if defined(r_normalAmbient)
|
||||
vec3 ambientHalf = normalize(surfN + E);
|
||||
float ambientSpec = max(dot(ambientHalf, N) + 0.5, 0.0);
|
||||
ambientSpec *= ambientSpec * 0.44;
|
||||
gl_FragColor.rgb += specularReflectance.rgb * ambientSpec * ambientColor;
|
||||
#endif
|
||||
|
||||
#if defined(USE_PRIMARY_LIGHT)
|
||||
vec3 H2 = normalize(L2 + E);
|
||||
float EH2 = clamp(dot(E, H2), 0.0, 1.0);
|
||||
float NH2 = clamp(dot(N, H2), 0.0, 1.0);
|
||||
|
||||
|
||||
#if defined(USE_SHADOWMAP)
|
||||
gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * NL2 * CalcSpecular(specularReflectance.rgb, NH2, NL2, NE, EH2, shininess);
|
||||
#else
|
||||
gl_FragColor.rgb += u_PrimaryLightColor * NL2 * CalcSpecular(specularReflectance.rgb, NH2, NL2, NE, EH2, shininess);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
gl_FragColor.rgb = diffuseAlbedo.rgb;
|
||||
#endif
|
||||
|
||||
gl_FragColor.a = diffuseAlbedo.a;
|
||||
|
||||
gl_FragColor *= var_Color;
|
||||
}
|
245
code/renderergl2/glsl/lightall_vp.glsl
Normal file
245
code/renderergl2/glsl/lightall_vp.glsl
Normal file
|
@ -0,0 +1,245 @@
|
|||
attribute vec4 attr_TexCoord0;
|
||||
#if defined(USE_LIGHTMAP) || defined(USE_TCGEN)
|
||||
attribute vec4 attr_TexCoord1;
|
||||
#endif
|
||||
attribute vec4 attr_Color;
|
||||
|
||||
attribute vec4 attr_Position;
|
||||
attribute vec3 attr_Normal;
|
||||
|
||||
#if defined(USE_VERT_TANGENT_SPACE)
|
||||
attribute vec3 attr_Tangent;
|
||||
attribute vec3 attr_Bitangent;
|
||||
#endif
|
||||
|
||||
#if defined(USE_VERTEX_ANIMATION)
|
||||
attribute vec4 attr_Position2;
|
||||
attribute vec3 attr_Normal2;
|
||||
#if defined(USE_VERT_TANGENT_SPACE)
|
||||
attribute vec3 attr_Tangent2;
|
||||
attribute vec3 attr_Bitangent2;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR)
|
||||
attribute vec3 attr_LightDirection;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
|
||||
uniform vec3 u_ViewOrigin;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN)
|
||||
uniform int u_TCGen0;
|
||||
uniform vec3 u_TCGen0Vector0;
|
||||
uniform vec3 u_TCGen0Vector1;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCMOD)
|
||||
uniform vec4 u_DiffuseTexMatrix;
|
||||
uniform vec4 u_DiffuseTexOffTurb;
|
||||
#endif
|
||||
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
uniform vec4 u_BaseColor;
|
||||
uniform vec4 u_VertColor;
|
||||
|
||||
#if defined(USE_MODELMATRIX)
|
||||
uniform mat4 u_ModelMatrix;
|
||||
#endif
|
||||
|
||||
#if defined(USE_VERTEX_ANIMATION)
|
||||
uniform float u_VertexLerp;
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT_VECTOR)
|
||||
uniform vec4 u_LightOrigin;
|
||||
#if defined(USE_FAST_LIGHT)
|
||||
uniform vec3 u_DirectedLight;
|
||||
uniform vec3 u_AmbientLight;
|
||||
uniform float u_LightRadius;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
|
||||
uniform vec4 u_PrimaryLightOrigin;
|
||||
#endif
|
||||
|
||||
varying vec2 var_DiffuseTex;
|
||||
|
||||
#if defined(USE_LIGHTMAP)
|
||||
varying vec2 var_LightTex;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
|
||||
varying vec3 var_SampleToView;
|
||||
#endif
|
||||
|
||||
varying vec4 var_Color;
|
||||
|
||||
#if defined(USE_NORMALMAP) && !defined(USE_VERT_TANGENT_SPACE)
|
||||
varying vec3 var_Position;
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(USE_FAST_LIGHT)
|
||||
varying vec3 var_Normal;
|
||||
#if defined(USE_VERT_TANGENT_SPACE)
|
||||
varying vec3 var_Tangent;
|
||||
varying vec3 var_Bitangent;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT)
|
||||
varying vec3 var_VertLight;
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT)
|
||||
varying vec3 var_LightDirection;
|
||||
#endif
|
||||
|
||||
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
|
||||
varying vec3 var_PrimaryLightDirection;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN)
|
||||
vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1)
|
||||
{
|
||||
vec2 tex = attr_TexCoord0.st;
|
||||
|
||||
if (TCGen == TCGEN_LIGHTMAP)
|
||||
{
|
||||
tex = attr_TexCoord1.st;
|
||||
}
|
||||
else if (TCGen == TCGEN_ENVIRONMENT_MAPPED)
|
||||
{
|
||||
vec3 viewer = normalize(u_ViewOrigin - position);
|
||||
tex = -reflect(viewer, normal).yz * vec2(0.5, -0.5) + 0.5;
|
||||
}
|
||||
else if (TCGen == TCGEN_VECTOR)
|
||||
{
|
||||
tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1));
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCMOD)
|
||||
vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb)
|
||||
{
|
||||
float amplitude = offTurb.z;
|
||||
float phase = offTurb.w;
|
||||
vec2 st2 = vec2(dot(st, texMatrix.xz), dot(st, texMatrix.yw)) + offTurb.xy;
|
||||
|
||||
vec3 offsetPos = vec3(0); //position / 1024.0;
|
||||
offsetPos.x += offsetPos.z;
|
||||
|
||||
vec2 texOffset = sin((offsetPos.xy + vec2(phase)) * 2.0 * M_PI);
|
||||
|
||||
return st2 + texOffset * amplitude;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(USE_VERTEX_ANIMATION)
|
||||
vec4 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
||||
vec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp));
|
||||
#if defined(USE_VERT_TANGENT_SPACE)
|
||||
vec3 tangent = normalize(mix(attr_Tangent, attr_Tangent2, u_VertexLerp));
|
||||
vec3 bitangent = normalize(mix(attr_Bitangent, attr_Bitangent2, u_VertexLerp));
|
||||
#endif
|
||||
#else
|
||||
vec4 position = attr_Position;
|
||||
vec3 normal = attr_Normal;
|
||||
#if defined(USE_VERT_TANGENT_SPACE)
|
||||
vec3 tangent = attr_Tangent;
|
||||
vec3 bitangent = attr_Bitangent;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
gl_Position = u_ModelViewProjectionMatrix * position;
|
||||
|
||||
#if (defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX)) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT)
|
||||
vec3 L = attr_LightDirection;
|
||||
#endif
|
||||
|
||||
#if defined(USE_MODELMATRIX)
|
||||
position = u_ModelMatrix * position;
|
||||
normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz;
|
||||
#if defined(USE_VERT_TANGENT_SPACE)
|
||||
tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz;
|
||||
bitangent = (u_ModelMatrix * vec4(bitangent, 0.0)).xyz;
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHTMAP) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT)
|
||||
L = (u_ModelMatrix * vec4(L, 0.0)).xyz;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_NORMALMAP) && !defined(USE_VERT_TANGENT_SPACE)
|
||||
var_Position = position.xyz;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
|
||||
var_SampleToView = u_ViewOrigin - position.xyz;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCGEN)
|
||||
vec2 texCoords = GenTexCoords(u_TCGen0, position.xyz, normal, u_TCGen0Vector0, u_TCGen0Vector1);
|
||||
#else
|
||||
vec2 texCoords = attr_TexCoord0.st;
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCMOD)
|
||||
var_DiffuseTex = ModTexCoords(texCoords, position.xyz, u_DiffuseTexMatrix, u_DiffuseTexOffTurb);
|
||||
#else
|
||||
var_DiffuseTex = texCoords;
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHTMAP)
|
||||
var_LightTex = attr_TexCoord1.st;
|
||||
#endif
|
||||
|
||||
#if !defined(USE_FAST_LIGHT)
|
||||
var_Normal = normal;
|
||||
#if defined(USE_VERT_TANGENT_SPACE)
|
||||
var_Tangent = tangent;
|
||||
var_Bitangent = bitangent;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT) && !defined(USE_DELUXEMAP)
|
||||
#if defined(USE_LIGHT_VECTOR)
|
||||
vec3 L = u_LightOrigin.xyz - (position.xyz * u_LightOrigin.w);
|
||||
#endif
|
||||
#if !defined(USE_FAST_LIGHT)
|
||||
var_LightDirection = L;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT)
|
||||
var_VertLight = u_VertColor.rgb * attr_Color.rgb;
|
||||
var_Color.rgb = vec3(1.0);
|
||||
var_Color.a = u_VertColor.a * attr_Color.a + u_BaseColor.a;
|
||||
#else
|
||||
var_Color = u_VertColor * attr_Color + u_BaseColor;
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT_VECTOR) && defined(USE_FAST_LIGHT)
|
||||
#if defined(USE_INVSQRLIGHT)
|
||||
float intensity = 1.0 / dot(L, L);
|
||||
#else
|
||||
float intensity = clamp((1.0 - dot(L, L) / (u_LightRadius * u_LightRadius)) * 1.07, 0.0, 1.0);
|
||||
#endif
|
||||
float NL = clamp(dot(normal, normalize(L)), 0.0, 1.0);
|
||||
|
||||
var_Color.rgb *= u_DirectedLight * intensity * NL + u_AmbientLight;
|
||||
#endif
|
||||
|
||||
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
|
||||
var_PrimaryLightDirection = u_PrimaryLightOrigin.xyz - (position.xyz * u_PrimaryLightOrigin.w);
|
||||
#endif
|
||||
}
|
98
code/renderergl2/glsl/pshadow_fp.glsl
Normal file
98
code/renderergl2/glsl/pshadow_fp.glsl
Normal file
|
@ -0,0 +1,98 @@
|
|||
uniform sampler2D u_ShadowMap;
|
||||
|
||||
uniform vec3 u_LightForward;
|
||||
uniform vec3 u_LightUp;
|
||||
uniform vec3 u_LightRight;
|
||||
uniform vec4 u_LightOrigin;
|
||||
uniform float u_LightRadius;
|
||||
varying vec3 var_Position;
|
||||
varying vec3 var_Normal;
|
||||
|
||||
float sampleDistMap(sampler2D texMap, vec2 uv, float scale)
|
||||
{
|
||||
vec3 distv = texture2D(texMap, uv).xyz;
|
||||
return dot(distv, vec3(1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)) * scale;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 lightToPos = var_Position - u_LightOrigin.xyz;
|
||||
vec2 st = vec2(-dot(u_LightRight, lightToPos), dot(u_LightUp, lightToPos));
|
||||
|
||||
float fade = length(st);
|
||||
|
||||
#if defined(USE_DISCARD)
|
||||
if (fade >= 1.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
fade = clamp(8.0 - fade * 8.0, 0.0, 1.0);
|
||||
|
||||
st = st * 0.5 + vec2(0.5);
|
||||
|
||||
#if defined(USE_SOLID_PSHADOWS)
|
||||
float intensity = max(sign(u_LightRadius - length(lightToPos)), 0.0);
|
||||
#else
|
||||
float intensity = clamp((1.0 - dot(lightToPos, lightToPos) / (u_LightRadius * u_LightRadius)) * 2.0, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
float lightDist = length(lightToPos);
|
||||
float dist;
|
||||
|
||||
#if defined(USE_DISCARD)
|
||||
if (dot(u_LightForward, lightToPos) <= 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
if (dot(var_Normal, lightToPos) > 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
#else
|
||||
intensity *= max(sign(dot(u_LightForward, lightToPos)), 0.0);
|
||||
intensity *= max(sign(-dot(var_Normal, lightToPos)), 0.0);
|
||||
#endif
|
||||
|
||||
intensity *= fade;
|
||||
#if defined(USE_PCF)
|
||||
float part;
|
||||
|
||||
dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, -1.0/512.0), u_LightRadius);
|
||||
part = max(sign(lightDist - dist), 0.0);
|
||||
|
||||
dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, -1.0/512.0), u_LightRadius);
|
||||
part += max(sign(lightDist - dist), 0.0);
|
||||
|
||||
dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, 1.0/512.0), u_LightRadius);
|
||||
part += max(sign(lightDist - dist), 0.0);
|
||||
|
||||
dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, 1.0/512.0), u_LightRadius);
|
||||
part += max(sign(lightDist - dist), 0.0);
|
||||
|
||||
#if defined(USE_DISCARD)
|
||||
if (part <= 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
intensity *= part * 0.25;
|
||||
#else
|
||||
dist = sampleDistMap(u_ShadowMap, st, u_LightRadius);
|
||||
|
||||
#if defined(USE_DISCARD)
|
||||
if (lightDist - dist <= 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
intensity *= max(sign(lightDist - dist), 0.0);
|
||||
#endif
|
||||
|
||||
gl_FragColor.rgb = vec3(0);
|
||||
gl_FragColor.a = clamp(intensity, 0.0, 0.75);
|
||||
}
|
17
code/renderergl2/glsl/pshadow_vp.glsl
Normal file
17
code/renderergl2/glsl/pshadow_vp.glsl
Normal file
|
@ -0,0 +1,17 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec3 attr_Normal;
|
||||
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
varying vec3 var_Position;
|
||||
varying vec3 var_Normal;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = attr_Position;
|
||||
|
||||
gl_Position = u_ModelViewProjectionMatrix * position;
|
||||
|
||||
var_Position = position.xyz;
|
||||
var_Normal = attr_Normal;
|
||||
}
|
41
code/renderergl2/glsl/shadowfill_fp.glsl
Normal file
41
code/renderergl2/glsl/shadowfill_fp.glsl
Normal file
|
@ -0,0 +1,41 @@
|
|||
uniform vec4 u_LightOrigin;
|
||||
uniform float u_LightRadius;
|
||||
|
||||
varying vec3 var_Position;
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(USE_DEPTH)
|
||||
float depth = length(u_LightOrigin.xyz - var_Position) / u_LightRadius;
|
||||
#if 0
|
||||
// 32 bit precision
|
||||
const vec4 bitSh = vec4( 256 * 256 * 256, 256 * 256, 256, 1);
|
||||
const vec4 bitMsk = vec4( 0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
|
||||
|
||||
vec4 comp;
|
||||
comp = depth * bitSh;
|
||||
comp.xyz = fract(comp.xyz);
|
||||
comp -= comp.xxyz * bitMsk;
|
||||
gl_FragColor = comp;
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// 24 bit precision
|
||||
const vec3 bitSh = vec3( 256 * 256, 256, 1);
|
||||
const vec3 bitMsk = vec3( 0, 1.0 / 256.0, 1.0 / 256.0);
|
||||
|
||||
vec3 comp;
|
||||
comp = depth * bitSh;
|
||||
comp.xy = fract(comp.xy);
|
||||
comp -= comp.xxy * bitMsk;
|
||||
gl_FragColor = vec4(comp, 1.0);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// 8 bit precision
|
||||
gl_FragColor = vec4(depth, depth, depth, 1);
|
||||
#endif
|
||||
#else
|
||||
gl_FragColor = vec4(0, 0, 0, 1);
|
||||
#endif
|
||||
}
|
89
code/renderergl2/glsl/shadowfill_vp.glsl
Normal file
89
code/renderergl2/glsl/shadowfill_vp.glsl
Normal file
|
@ -0,0 +1,89 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec3 attr_Normal;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
//#if defined(USE_VERTEX_ANIMATION)
|
||||
attribute vec4 attr_Position2;
|
||||
attribute vec3 attr_Normal2;
|
||||
//#endif
|
||||
|
||||
//#if defined(USE_DEFORM_VERTEXES)
|
||||
uniform int u_DeformGen;
|
||||
uniform float u_DeformParams[5];
|
||||
//#endif
|
||||
|
||||
uniform float u_Time;
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
|
||||
uniform mat4 u_ModelMatrix;
|
||||
|
||||
//#if defined(USE_VERTEX_ANIMATION)
|
||||
uniform float u_VertexLerp;
|
||||
//#endif
|
||||
|
||||
varying vec3 var_Position;
|
||||
|
||||
vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
|
||||
{
|
||||
if (u_DeformGen == 0)
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
float base = u_DeformParams[0];
|
||||
float amplitude = u_DeformParams[1];
|
||||
float phase = u_DeformParams[2];
|
||||
float frequency = u_DeformParams[3];
|
||||
float spread = u_DeformParams[4];
|
||||
|
||||
if (u_DeformGen == DGEN_BULGE)
|
||||
{
|
||||
phase *= M_PI * 0.25 * st.x;
|
||||
}
|
||||
else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)
|
||||
{
|
||||
phase += dot(pos.xyz, vec3(spread));
|
||||
}
|
||||
|
||||
float value = phase + (u_Time * frequency);
|
||||
float func;
|
||||
|
||||
if (u_DeformGen == DGEN_WAVE_SIN)
|
||||
{
|
||||
func = sin(value * 2.0 * M_PI);
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_SQUARE)
|
||||
{
|
||||
func = sign(sin(value * 2.0 * M_PI));
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_TRIANGLE)
|
||||
{
|
||||
func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0;
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_SAWTOOTH)
|
||||
{
|
||||
func = fract(value);
|
||||
}
|
||||
else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)
|
||||
{
|
||||
func = (1.0 - fract(value));
|
||||
}
|
||||
else if (u_DeformGen == DGEN_BULGE)
|
||||
{
|
||||
func = sin(value);
|
||||
}
|
||||
|
||||
return pos + normal * (base + func * amplitude);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
||||
vec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp));
|
||||
|
||||
position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st);
|
||||
|
||||
gl_Position = u_ModelViewProjectionMatrix * position;
|
||||
|
||||
var_Position = (u_ModelMatrix * position).xyz;
|
||||
}
|
127
code/renderergl2/glsl/shadowmask_fp.glsl
Normal file
127
code/renderergl2/glsl/shadowmask_fp.glsl
Normal file
|
@ -0,0 +1,127 @@
|
|||
uniform sampler2D u_ScreenDepthMap;
|
||||
|
||||
uniform sampler2D u_ShadowMap;
|
||||
#if defined(USE_SHADOW_CASCADE)
|
||||
uniform sampler2D u_ShadowMap2;
|
||||
uniform sampler2D u_ShadowMap3;
|
||||
#endif
|
||||
|
||||
uniform mat4 u_ShadowMvp;
|
||||
#if defined(USE_SHADOW_CASCADE)
|
||||
uniform mat4 u_ShadowMvp2;
|
||||
uniform mat4 u_ShadowMvp3;
|
||||
#endif
|
||||
|
||||
uniform vec3 u_ViewOrigin;
|
||||
uniform vec4 u_ViewInfo; // zfar / znear, zfar
|
||||
|
||||
varying vec2 var_DepthTex;
|
||||
varying vec3 var_ViewDir;
|
||||
|
||||
// Input: It uses texture coords as the random number seed.
|
||||
// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive.
|
||||
// Author: Michael Pohoreski
|
||||
// Copyright: Copyleft 2012 :-)
|
||||
// Source: http://stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader
|
||||
|
||||
float random( const vec2 p )
|
||||
{
|
||||
// We need irrationals for pseudo randomness.
|
||||
// Most (all?) known transcendental numbers will (generally) work.
|
||||
const vec2 r = vec2(
|
||||
23.1406926327792690, // e^pi (Gelfond's constant)
|
||||
2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant)
|
||||
//return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) );
|
||||
return mod( 123456789., 1e-7 + 256. * dot(p,r) );
|
||||
}
|
||||
|
||||
float PCF(const sampler2D shadowmap, const vec2 st, const float dist)
|
||||
{
|
||||
float mult;
|
||||
float scale = 2.0 / r_shadowMapSize;
|
||||
|
||||
#if defined(USE_SHADOW_FILTER)
|
||||
float r = random(var_DepthTex.xy);
|
||||
float sinr = sin(r) * scale;
|
||||
float cosr = cos(r) * scale;
|
||||
mat2 rmat = mat2(cosr, sinr, -sinr, cosr);
|
||||
|
||||
mult = step(dist, texture2D(shadowmap, st + rmat * vec2(-0.7055767, 0.196515)).r);
|
||||
mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.3524343, -0.7791386)).r);
|
||||
mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.2391056, 0.9189604)).r);
|
||||
#if defined(USE_SHADOW_FILTER2)
|
||||
mult += step(dist, texture2D(shadowmap, st + rmat * vec2(-0.07580382, -0.09224417)).r);
|
||||
mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.5784913, -0.002528916)).r);
|
||||
mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.192888, 0.4064181)).r);
|
||||
mult += step(dist, texture2D(shadowmap, st + rmat * vec2(-0.6335801, -0.5247476)).r);
|
||||
mult += step(dist, texture2D(shadowmap, st + rmat * vec2(-0.5579782, 0.7491854)).r);
|
||||
mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.7320465, 0.6317794)).r);
|
||||
|
||||
mult *= 0.11111;
|
||||
#else
|
||||
mult *= 0.33333;
|
||||
#endif
|
||||
#else
|
||||
mult = step(dist, texture2D(shadowmap, st).r);
|
||||
#endif
|
||||
|
||||
return mult;
|
||||
}
|
||||
|
||||
float getLinearDepth(sampler2D depthMap, vec2 tex, float zFarDivZNear)
|
||||
{
|
||||
float sampleZDivW = texture2D(depthMap, tex).r;
|
||||
return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float result;
|
||||
|
||||
float depth = getLinearDepth(u_ScreenDepthMap, var_DepthTex, u_ViewInfo.x);
|
||||
float sampleZ = u_ViewInfo.y * depth;
|
||||
|
||||
vec4 biasPos = vec4(u_ViewOrigin + var_ViewDir * depth * 0.99, 1.0);
|
||||
|
||||
vec4 shadowpos = u_ShadowMvp * biasPos;
|
||||
|
||||
#if defined(USE_SHADOW_CASCADE)
|
||||
const float fadeTo = 1.0;
|
||||
result = fadeTo;
|
||||
#else
|
||||
result = 0.0;
|
||||
#endif
|
||||
|
||||
if (all(lessThanEqual(abs(shadowpos.xyz), vec3(abs(shadowpos.w)))))
|
||||
{
|
||||
shadowpos.xyz = shadowpos.xyz / shadowpos.w * 0.5 + 0.5;
|
||||
result = PCF(u_ShadowMap, shadowpos.xy, shadowpos.z);
|
||||
}
|
||||
#if defined(USE_SHADOW_CASCADE)
|
||||
else
|
||||
{
|
||||
shadowpos = u_ShadowMvp2 * biasPos;
|
||||
|
||||
if (all(lessThanEqual(abs(shadowpos.xyz), vec3(abs(shadowpos.w)))))
|
||||
{
|
||||
shadowpos.xyz = shadowpos.xyz / shadowpos.w * 0.5 + 0.5;
|
||||
result = PCF(u_ShadowMap2, shadowpos.xy, shadowpos.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
shadowpos = u_ShadowMvp3 * biasPos;
|
||||
|
||||
if (all(lessThanEqual(abs(shadowpos.xyz), vec3(abs(shadowpos.w)))))
|
||||
{
|
||||
shadowpos.xyz = shadowpos.xyz / shadowpos.w * 0.5 + 0.5;
|
||||
result = PCF(u_ShadowMap3, shadowpos.xy, shadowpos.z);
|
||||
|
||||
float fade = clamp(sampleZ / r_shadowCascadeZFar * 10.0 - 9.0, 0.0, 1.0);
|
||||
result = mix(result, fadeTo, fade);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
gl_FragColor = vec4(vec3(result), 1.0);
|
||||
}
|
18
code/renderergl2/glsl/shadowmask_vp.glsl
Normal file
18
code/renderergl2/glsl/shadowmask_vp.glsl
Normal file
|
@ -0,0 +1,18 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
uniform vec3 u_ViewForward;
|
||||
uniform vec3 u_ViewLeft;
|
||||
uniform vec3 u_ViewUp;
|
||||
uniform vec4 u_ViewInfo; // zfar / znear
|
||||
|
||||
varying vec2 var_DepthTex;
|
||||
varying vec3 var_ViewDir;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = attr_Position;
|
||||
vec2 screenCoords = gl_Position.xy / gl_Position.w;
|
||||
var_DepthTex = attr_TexCoord0.xy;
|
||||
var_ViewDir = u_ViewForward + u_ViewLeft * -screenCoords.x + u_ViewUp * screenCoords.y;
|
||||
}
|
86
code/renderergl2/glsl/ssao_fp.glsl
Normal file
86
code/renderergl2/glsl/ssao_fp.glsl
Normal file
|
@ -0,0 +1,86 @@
|
|||
uniform sampler2D u_ScreenDepthMap;
|
||||
|
||||
uniform vec4 u_ViewInfo; // zfar / znear, zfar
|
||||
|
||||
varying vec2 var_ScreenTex;
|
||||
|
||||
vec2 poissonDisc[9] = vec2[9](
|
||||
vec2(-0.7055767, 0.196515), vec2(0.3524343, -0.7791386),
|
||||
vec2(0.2391056, 0.9189604), vec2(-0.07580382, -0.09224417),
|
||||
vec2(0.5784913, -0.002528916), vec2(0.192888, 0.4064181),
|
||||
vec2(-0.6335801, -0.5247476), vec2(-0.5579782, 0.7491854),
|
||||
vec2(0.7320465, 0.6317794)
|
||||
);
|
||||
|
||||
// Input: It uses texture coords as the random number seed.
|
||||
// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive.
|
||||
// Author: Michael Pohoreski
|
||||
// Copyright: Copyleft 2012 :-)
|
||||
// Source: http://stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader
|
||||
|
||||
float random( const vec2 p )
|
||||
{
|
||||
// We need irrationals for pseudo randomness.
|
||||
// Most (all?) known transcendental numbers will (generally) work.
|
||||
const vec2 r = vec2(
|
||||
23.1406926327792690, // e^pi (Gelfond's constant)
|
||||
2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant)
|
||||
//return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) );
|
||||
return mod( 123456789., 1e-7 + 256. * dot(p,r) );
|
||||
}
|
||||
|
||||
mat2 randomRotation( const vec2 p )
|
||||
{
|
||||
float r = random(p);
|
||||
float sinr = sin(r);
|
||||
float cosr = cos(r);
|
||||
return mat2(cosr, sinr, -sinr, cosr);
|
||||
}
|
||||
|
||||
float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
|
||||
{
|
||||
float sampleZDivW = texture2D(depthMap, tex).r;
|
||||
return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
|
||||
}
|
||||
|
||||
float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar)
|
||||
{
|
||||
float result = 0;
|
||||
|
||||
float sampleZ = zFar * getLinearDepth(depthMap, tex, zFarDivZNear);
|
||||
|
||||
vec2 expectedSlope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y));
|
||||
|
||||
if (length(expectedSlope) > 5000.0)
|
||||
return 1.0;
|
||||
|
||||
vec2 offsetScale = vec2(3.0 / sampleZ);
|
||||
|
||||
mat2 rmat = randomRotation(tex);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
vec2 offset = rmat * poissonDisc[i] * offsetScale;
|
||||
float sampleZ2 = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear);
|
||||
|
||||
if (abs(sampleZ - sampleZ2) > 20.0)
|
||||
result += 1.0;
|
||||
else
|
||||
{
|
||||
float expectedZ = sampleZ + dot(expectedSlope, offset);
|
||||
result += step(expectedZ - 1.0, sampleZ2);
|
||||
}
|
||||
}
|
||||
|
||||
result *= 0.33333;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y);
|
||||
|
||||
gl_FragColor = vec4(vec3(result), 1.0);
|
||||
}
|
12
code/renderergl2/glsl/ssao_vp.glsl
Normal file
12
code/renderergl2/glsl/ssao_vp.glsl
Normal file
|
@ -0,0 +1,12 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
varying vec2 var_ScreenTex;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = attr_Position;
|
||||
var_ScreenTex = attr_TexCoord0.xy;
|
||||
//vec2 screenCoords = gl_Position.xy / gl_Position.w;
|
||||
//var_ScreenTex = screenCoords * 0.5 + 0.5;
|
||||
}
|
12
code/renderergl2/glsl/texturecolor_fp.glsl
Normal file
12
code/renderergl2/glsl/texturecolor_fp.glsl
Normal file
|
@ -0,0 +1,12 @@
|
|||
#version 120
|
||||
|
||||
uniform sampler2D u_DiffuseMap;
|
||||
uniform vec4 u_Color;
|
||||
|
||||
varying vec2 var_Tex1;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(u_DiffuseMap, var_Tex1) * u_Color;
|
||||
}
|
15
code/renderergl2/glsl/texturecolor_vp.glsl
Normal file
15
code/renderergl2/glsl/texturecolor_vp.glsl
Normal file
|
@ -0,0 +1,15 @@
|
|||
#version 120
|
||||
|
||||
attribute vec4 attr_Position;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
|
||||
varying vec2 var_Tex1;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_ModelViewProjectionMatrix * attr_Position;
|
||||
var_Tex1 = attr_TexCoord0.st;
|
||||
}
|
48
code/renderergl2/glsl/tonemap_fp.glsl
Normal file
48
code/renderergl2/glsl/tonemap_fp.glsl
Normal file
|
@ -0,0 +1,48 @@
|
|||
uniform sampler2D u_TextureMap;
|
||||
uniform sampler2D u_LevelsMap;
|
||||
|
||||
uniform vec4 u_Color;
|
||||
|
||||
uniform vec2 u_AutoExposureMinMax;
|
||||
uniform vec3 u_ToneMinAvgMaxLinear;
|
||||
|
||||
varying vec2 var_TexCoords;
|
||||
|
||||
const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721); //vec3(0.299, 0.587, 0.114);
|
||||
|
||||
vec3 FilmicTonemap(vec3 x)
|
||||
{
|
||||
const float SS = 0.22; // Shoulder Strength
|
||||
const float LS = 0.30; // Linear Strength
|
||||
const float LA = 0.10; // Linear Angle
|
||||
const float TS = 0.20; // Toe Strength
|
||||
const float TAN = 0.01; // Toe Angle Numerator
|
||||
const float TAD = 0.30; // Toe Angle Denominator
|
||||
|
||||
vec3 SSxx = SS * x * x;
|
||||
vec3 LSx = LS * x;
|
||||
vec3 LALSx = LSx * LA;
|
||||
|
||||
return ((SSxx + LALSx + TS * TAN) / (SSxx + LSx + TS * TAD)) - TAN / TAD;
|
||||
|
||||
//return ((x*(SS*x+LA*LS)+TS*TAN)/(x*(SS*x+LS)+TS*TAD)) - TAN/TAD;
|
||||
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color;
|
||||
vec3 minAvgMax = texture2D(u_LevelsMap, var_TexCoords).rgb;
|
||||
vec3 logMinAvgMaxLum = clamp(minAvgMax * 20.0 - 10.0, -u_AutoExposureMinMax.y, -u_AutoExposureMinMax.x);
|
||||
|
||||
float avgLum = exp2(logMinAvgMaxLum.y);
|
||||
//float maxLum = exp2(logMinAvgMaxLum.z);
|
||||
|
||||
color.rgb *= u_ToneMinAvgMaxLinear.y / avgLum;
|
||||
color.rgb = max(vec3(0.0), color.rgb - vec3(u_ToneMinAvgMaxLinear.x));
|
||||
|
||||
vec3 fWhite = 1.0 / FilmicTonemap(vec3(u_ToneMinAvgMaxLinear.z - u_ToneMinAvgMaxLinear.x));
|
||||
color.rgb = FilmicTonemap(color.rgb) * fWhite;
|
||||
|
||||
gl_FragColor = clamp(color, 0.0, 1.0);
|
||||
}
|
13
code/renderergl2/glsl/tonemap_vp.glsl
Normal file
13
code/renderergl2/glsl/tonemap_vp.glsl
Normal file
|
@ -0,0 +1,13 @@
|
|||
attribute vec4 attr_Position;
|
||||
attribute vec4 attr_TexCoord0;
|
||||
|
||||
uniform mat4 u_ModelViewProjectionMatrix;
|
||||
|
||||
varying vec2 var_TexCoords;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_ModelViewProjectionMatrix * attr_Position;
|
||||
var_TexCoords = attr_TexCoord0.st;
|
||||
}
|
656
code/renderergl2/tr_animation.c
Normal file
656
code/renderergl2/tr_animation.c
Normal file
|
@ -0,0 +1,656 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
/*
|
||||
|
||||
All bones should be an identity orientation to display the mesh exactly
|
||||
as it is specified.
|
||||
|
||||
For all other frames, the bones represent the transformation from the
|
||||
orientation of the bone in the base frame to the orientation in this
|
||||
frame.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
==============
|
||||
R_AddAnimSurfaces
|
||||
==============
|
||||
*/
|
||||
void R_AddAnimSurfaces( trRefEntity_t *ent ) {
|
||||
md4Header_t *header;
|
||||
md4Surface_t *surface;
|
||||
md4LOD_t *lod;
|
||||
shader_t *shader;
|
||||
int i;
|
||||
|
||||
header = (md4Header_t *) tr.currentModel->modelData;
|
||||
lod = (md4LOD_t *)( (byte *)header + header->ofsLODs );
|
||||
|
||||
surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces );
|
||||
for ( i = 0 ; i < lod->numSurfaces ; i++ ) {
|
||||
shader = R_GetShaderByHandle( surface->shaderIndex );
|
||||
R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse, qfalse );
|
||||
surface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
RB_SurfaceAnim
|
||||
==============
|
||||
*/
|
||||
void RB_SurfaceAnim( md4Surface_t *surface ) {
|
||||
int i, j, k;
|
||||
float frontlerp, backlerp;
|
||||
int *triangles;
|
||||
int indexes;
|
||||
int baseIndex, baseVertex;
|
||||
int numVerts;
|
||||
md4Vertex_t *v;
|
||||
md4Bone_t bones[MD4_MAX_BONES];
|
||||
md4Bone_t *bonePtr, *bone;
|
||||
md4Header_t *header;
|
||||
md4Frame_t *frame;
|
||||
md4Frame_t *oldFrame;
|
||||
int frameSize;
|
||||
|
||||
|
||||
if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) {
|
||||
backlerp = 0;
|
||||
frontlerp = 1;
|
||||
} else {
|
||||
backlerp = backEnd.currentEntity->e.backlerp;
|
||||
frontlerp = 1.0f - backlerp;
|
||||
}
|
||||
header = (md4Header_t *)((byte *)surface + surface->ofsHeader);
|
||||
|
||||
frameSize = (size_t)( &((md4Frame_t *)0)->bones[ header->numBones ] );
|
||||
|
||||
frame = (md4Frame_t *)((byte *)header + header->ofsFrames +
|
||||
backEnd.currentEntity->e.frame * frameSize );
|
||||
oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames +
|
||||
backEnd.currentEntity->e.oldframe * frameSize );
|
||||
|
||||
RB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 );
|
||||
|
||||
triangles = (int *) ((byte *)surface + surface->ofsTriangles);
|
||||
indexes = surface->numTriangles * 3;
|
||||
baseIndex = tess.numIndexes;
|
||||
baseVertex = tess.numVertexes;
|
||||
for (j = 0 ; j < indexes ; j++) {
|
||||
tess.indexes[baseIndex + j] = baseIndex + triangles[j];
|
||||
}
|
||||
tess.numIndexes += indexes;
|
||||
|
||||
//
|
||||
// lerp all the needed bones
|
||||
//
|
||||
if ( !backlerp ) {
|
||||
// no lerping needed
|
||||
bonePtr = frame->bones;
|
||||
} else {
|
||||
bonePtr = bones;
|
||||
for ( i = 0 ; i < header->numBones*12 ; i++ ) {
|
||||
((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i]
|
||||
+ backlerp * ((float *)oldFrame->bones)[i];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// deform the vertexes by the lerped bones
|
||||
//
|
||||
numVerts = surface->numVerts;
|
||||
// FIXME
|
||||
// This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
|
||||
// in for reference.
|
||||
//v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts + 12);
|
||||
v = (md4Vertex_t *) ((byte *)surface + surface->ofsVerts);
|
||||
for ( j = 0; j < numVerts; j++ ) {
|
||||
vec3_t tempVert, tempNormal;
|
||||
md4Weight_t *w;
|
||||
|
||||
VectorClear( tempVert );
|
||||
VectorClear( tempNormal );
|
||||
w = v->weights;
|
||||
for ( k = 0 ; k < v->numWeights ; k++, w++ ) {
|
||||
bone = bonePtr + w->boneIndex;
|
||||
|
||||
tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
|
||||
tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
|
||||
tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
|
||||
|
||||
tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
|
||||
tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
|
||||
tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
|
||||
}
|
||||
|
||||
tess.xyz[baseVertex + j][0] = tempVert[0];
|
||||
tess.xyz[baseVertex + j][1] = tempVert[1];
|
||||
tess.xyz[baseVertex + j][2] = tempVert[2];
|
||||
|
||||
tess.normal[baseVertex + j][0] = tempNormal[0];
|
||||
tess.normal[baseVertex + j][1] = tempNormal[1];
|
||||
tess.normal[baseVertex + j][2] = tempNormal[2];
|
||||
|
||||
tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
|
||||
tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
|
||||
|
||||
// FIXME
|
||||
// This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
|
||||
// in for reference.
|
||||
//v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
|
||||
v = (md4Vertex_t *)&v->weights[v->numWeights];
|
||||
}
|
||||
|
||||
tess.numVertexes += surface->numVerts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// copied and adapted from tr_mesh.c
|
||||
|
||||
/*
|
||||
=============
|
||||
R_MDRCullModel
|
||||
=============
|
||||
*/
|
||||
|
||||
static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) {
|
||||
vec3_t bounds[2];
|
||||
mdrFrame_t *oldFrame, *newFrame;
|
||||
int i, frameSize;
|
||||
|
||||
frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
|
||||
|
||||
// compute frame pointers
|
||||
newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
|
||||
oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe);
|
||||
|
||||
// cull bounding sphere ONLY if this is not an upscaled entity
|
||||
if ( !ent->e.nonNormalizedAxes )
|
||||
{
|
||||
if ( ent->e.frame == ent->e.oldframe )
|
||||
{
|
||||
switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
|
||||
{
|
||||
// Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend
|
||||
// we do. After all, the purpose of md4s are not that different, are they?
|
||||
|
||||
case CULL_OUT:
|
||||
tr.pc.c_sphere_cull_md3_out++;
|
||||
return CULL_OUT;
|
||||
|
||||
case CULL_IN:
|
||||
tr.pc.c_sphere_cull_md3_in++;
|
||||
return CULL_IN;
|
||||
|
||||
case CULL_CLIP:
|
||||
tr.pc.c_sphere_cull_md3_clip++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int sphereCull, sphereCullB;
|
||||
|
||||
sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
|
||||
if ( newFrame == oldFrame ) {
|
||||
sphereCullB = sphereCull;
|
||||
} else {
|
||||
sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
|
||||
}
|
||||
|
||||
if ( sphereCull == sphereCullB )
|
||||
{
|
||||
if ( sphereCull == CULL_OUT )
|
||||
{
|
||||
tr.pc.c_sphere_cull_md3_out++;
|
||||
return CULL_OUT;
|
||||
}
|
||||
else if ( sphereCull == CULL_IN )
|
||||
{
|
||||
tr.pc.c_sphere_cull_md3_in++;
|
||||
return CULL_IN;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.pc.c_sphere_cull_md3_clip++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate a bounding box in the current coordinate system
|
||||
for (i = 0 ; i < 3 ; i++) {
|
||||
bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
|
||||
bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
|
||||
}
|
||||
|
||||
switch ( R_CullLocalBox( bounds ) )
|
||||
{
|
||||
case CULL_IN:
|
||||
tr.pc.c_box_cull_md3_in++;
|
||||
return CULL_IN;
|
||||
case CULL_CLIP:
|
||||
tr.pc.c_box_cull_md3_clip++;
|
||||
return CULL_CLIP;
|
||||
case CULL_OUT:
|
||||
default:
|
||||
tr.pc.c_box_cull_md3_out++;
|
||||
return CULL_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_MDRComputeFogNum
|
||||
|
||||
=================
|
||||
*/
|
||||
|
||||
int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) {
|
||||
int i, j;
|
||||
fog_t *fog;
|
||||
mdrFrame_t *mdrFrame;
|
||||
vec3_t localOrigin;
|
||||
int frameSize;
|
||||
|
||||
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
|
||||
|
||||
// FIXME: non-normalized axis issues
|
||||
mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
|
||||
VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin );
|
||||
for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
|
||||
fog = &tr.world->fogs[i];
|
||||
for ( j = 0 ; j < 3 ; j++ ) {
|
||||
if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) {
|
||||
break;
|
||||
}
|
||||
if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( j == 3 ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
R_MDRAddAnimSurfaces
|
||||
==============
|
||||
*/
|
||||
|
||||
// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c
|
||||
|
||||
void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
|
||||
mdrHeader_t *header;
|
||||
mdrSurface_t *surface;
|
||||
mdrLOD_t *lod;
|
||||
shader_t *shader;
|
||||
skin_t *skin;
|
||||
int i, j;
|
||||
int lodnum = 0;
|
||||
int fogNum = 0;
|
||||
int cull;
|
||||
qboolean personalModel;
|
||||
|
||||
header = (mdrHeader_t *) tr.currentModel->modelData;
|
||||
|
||||
personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
|
||||
|
||||
if ( ent->e.renderfx & RF_WRAP_FRAMES )
|
||||
{
|
||||
ent->e.frame %= header->numFrames;
|
||||
ent->e.oldframe %= header->numFrames;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate the frames so there is no chance of a crash.
|
||||
// This will write directly into the entity structure, so
|
||||
// when the surfaces are rendered, they don't need to be
|
||||
// range checked again.
|
||||
//
|
||||
if ((ent->e.frame >= header->numFrames)
|
||||
|| (ent->e.frame < 0)
|
||||
|| (ent->e.oldframe >= header->numFrames)
|
||||
|| (ent->e.oldframe < 0) )
|
||||
{
|
||||
ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n",
|
||||
ent->e.oldframe, ent->e.frame, tr.currentModel->name );
|
||||
ent->e.frame = 0;
|
||||
ent->e.oldframe = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// cull the entire model if merged bounding box of both frames
|
||||
// is outside the view frustum.
|
||||
//
|
||||
cull = R_MDRCullModel (header, ent);
|
||||
if ( cull == CULL_OUT ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// figure out the current LOD of the model we're rendering, and set the lod pointer respectively.
|
||||
lodnum = R_ComputeLOD(ent);
|
||||
// check whether this model has as that many LODs at all. If not, try the closest thing we got.
|
||||
if(header->numLODs <= 0)
|
||||
return;
|
||||
if(header->numLODs <= lodnum)
|
||||
lodnum = header->numLODs - 1;
|
||||
|
||||
lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs);
|
||||
for(i = 0; i < lodnum; i++)
|
||||
{
|
||||
lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd);
|
||||
}
|
||||
|
||||
// set up lighting
|
||||
if ( !personalModel || r_shadows->integer > 1 )
|
||||
{
|
||||
R_SetupEntityLighting( &tr.refdef, ent );
|
||||
}
|
||||
|
||||
// fogNum?
|
||||
fogNum = R_MDRComputeFogNum( header, ent );
|
||||
|
||||
surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces );
|
||||
|
||||
for ( i = 0 ; i < lod->numSurfaces ; i++ )
|
||||
{
|
||||
|
||||
if(ent->e.customShader)
|
||||
shader = R_GetShaderByHandle(ent->e.customShader);
|
||||
else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
|
||||
{
|
||||
skin = R_GetSkinByHandle(ent->e.customSkin);
|
||||
shader = tr.defaultShader;
|
||||
|
||||
for(j = 0; j < skin->numSurfaces; j++)
|
||||
{
|
||||
if (!strcmp(skin->surfaces[j]->name, surface->name))
|
||||
{
|
||||
shader = skin->surfaces[j]->shader;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(surface->shaderIndex > 0)
|
||||
shader = R_GetShaderByHandle( surface->shaderIndex );
|
||||
else
|
||||
shader = tr.defaultShader;
|
||||
|
||||
// we will add shadows even if the main object isn't visible in the view
|
||||
|
||||
// stencil shadows can't do personal models unless I polyhedron clip
|
||||
if ( !personalModel
|
||||
&& r_shadows->integer == 2
|
||||
&& fogNum == 0
|
||||
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
|
||||
&& shader->sort == SS_OPAQUE )
|
||||
{
|
||||
R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse );
|
||||
}
|
||||
|
||||
// projection shadows work fine with personal models
|
||||
if ( r_shadows->integer == 3
|
||||
&& fogNum == 0
|
||||
&& (ent->e.renderfx & RF_SHADOW_PLANE )
|
||||
&& shader->sort == SS_OPAQUE )
|
||||
{
|
||||
R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse );
|
||||
}
|
||||
|
||||
if (!personalModel)
|
||||
R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse );
|
||||
|
||||
surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
RB_MDRSurfaceAnim
|
||||
==============
|
||||
*/
|
||||
void RB_MDRSurfaceAnim( md4Surface_t *surface )
|
||||
{
|
||||
int i, j, k;
|
||||
float frontlerp, backlerp;
|
||||
int *triangles;
|
||||
int indexes;
|
||||
int baseIndex, baseVertex;
|
||||
int numVerts;
|
||||
mdrVertex_t *v;
|
||||
mdrHeader_t *header;
|
||||
mdrFrame_t *frame;
|
||||
mdrFrame_t *oldFrame;
|
||||
mdrBone_t bones[MD4_MAX_BONES], *bonePtr, *bone;
|
||||
|
||||
int frameSize;
|
||||
|
||||
// don't lerp if lerping off, or this is the only frame, or the last frame...
|
||||
//
|
||||
if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame)
|
||||
{
|
||||
backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used
|
||||
frontlerp = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
backlerp = backEnd.currentEntity->e.backlerp;
|
||||
frontlerp = 1.0f - backlerp;
|
||||
}
|
||||
|
||||
header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader);
|
||||
|
||||
frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
|
||||
|
||||
frame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
|
||||
backEnd.currentEntity->e.frame * frameSize );
|
||||
oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
|
||||
backEnd.currentEntity->e.oldframe * frameSize );
|
||||
|
||||
RB_CheckOverflow( surface->numVerts, surface->numTriangles );
|
||||
|
||||
triangles = (int *) ((byte *)surface + surface->ofsTriangles);
|
||||
indexes = surface->numTriangles * 3;
|
||||
baseIndex = tess.numIndexes;
|
||||
baseVertex = tess.numVertexes;
|
||||
|
||||
// Set up all triangles.
|
||||
for (j = 0 ; j < indexes ; j++)
|
||||
{
|
||||
tess.indexes[baseIndex + j] = baseVertex + triangles[j];
|
||||
}
|
||||
tess.numIndexes += indexes;
|
||||
|
||||
//
|
||||
// lerp all the needed bones
|
||||
//
|
||||
if ( !backlerp )
|
||||
{
|
||||
// no lerping needed
|
||||
bonePtr = frame->bones;
|
||||
}
|
||||
else
|
||||
{
|
||||
bonePtr = bones;
|
||||
|
||||
for ( i = 0 ; i < header->numBones*12 ; i++ )
|
||||
{
|
||||
((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// deform the vertexes by the lerped bones
|
||||
//
|
||||
numVerts = surface->numVerts;
|
||||
v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts);
|
||||
for ( j = 0; j < numVerts; j++ )
|
||||
{
|
||||
vec3_t tempVert, tempNormal;
|
||||
mdrWeight_t *w;
|
||||
|
||||
VectorClear( tempVert );
|
||||
VectorClear( tempNormal );
|
||||
w = v->weights;
|
||||
for ( k = 0 ; k < v->numWeights ; k++, w++ )
|
||||
{
|
||||
bone = bonePtr + w->boneIndex;
|
||||
|
||||
tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
|
||||
tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
|
||||
tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
|
||||
|
||||
tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
|
||||
tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
|
||||
tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
|
||||
}
|
||||
|
||||
tess.xyz[baseVertex + j][0] = tempVert[0];
|
||||
tess.xyz[baseVertex + j][1] = tempVert[1];
|
||||
tess.xyz[baseVertex + j][2] = tempVert[2];
|
||||
|
||||
tess.normal[baseVertex + j][0] = tempNormal[0];
|
||||
tess.normal[baseVertex + j][1] = tempNormal[1];
|
||||
tess.normal[baseVertex + j][2] = tempNormal[2];
|
||||
|
||||
tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
|
||||
tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
|
||||
|
||||
v = (mdrVertex_t *)&v->weights[v->numWeights];
|
||||
}
|
||||
|
||||
tess.numVertexes += surface->numVerts;
|
||||
}
|
||||
|
||||
|
||||
#define MC_MASK_X ((1<<(MC_BITS_X))-1)
|
||||
#define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
|
||||
#define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
|
||||
#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
|
||||
|
||||
#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
|
||||
|
||||
#define MC_POS_X (0)
|
||||
#define MC_SHIFT_X (0)
|
||||
|
||||
#define MC_POS_Y ((((MC_BITS_X))/8))
|
||||
#define MC_SHIFT_Y ((((MC_BITS_X)%8)))
|
||||
|
||||
#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
|
||||
#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
|
||||
|
||||
#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
|
||||
#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
|
||||
|
||||
#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
|
||||
#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
|
||||
|
||||
#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
|
||||
#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
|
||||
|
||||
#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
|
||||
#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
|
||||
|
||||
#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
|
||||
#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
|
||||
|
||||
#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
|
||||
#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
|
||||
|
||||
#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
|
||||
#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
|
||||
|
||||
#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
|
||||
#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
|
||||
|
||||
#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
|
||||
#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
|
||||
|
||||
void MC_UnCompress(float mat[3][4],const unsigned char * comp)
|
||||
{
|
||||
int val;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[0];
|
||||
val-=1<<(MC_BITS_X-1);
|
||||
mat[0][3]=((float)(val))*MC_SCALE_X;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[1];
|
||||
val-=1<<(MC_BITS_Y-1);
|
||||
mat[1][3]=((float)(val))*MC_SCALE_Y;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[2];
|
||||
val-=1<<(MC_BITS_Z-1);
|
||||
mat[2][3]=((float)(val))*MC_SCALE_Z;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[3];
|
||||
val-=1<<(MC_BITS_VECT-1);
|
||||
mat[0][0]=((float)(val))*MC_SCALE_VECT;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[4];
|
||||
val-=1<<(MC_BITS_VECT-1);
|
||||
mat[0][1]=((float)(val))*MC_SCALE_VECT;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[5];
|
||||
val-=1<<(MC_BITS_VECT-1);
|
||||
mat[0][2]=((float)(val))*MC_SCALE_VECT;
|
||||
|
||||
|
||||
val=(int)((unsigned short *)(comp))[6];
|
||||
val-=1<<(MC_BITS_VECT-1);
|
||||
mat[1][0]=((float)(val))*MC_SCALE_VECT;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[7];
|
||||
val-=1<<(MC_BITS_VECT-1);
|
||||
mat[1][1]=((float)(val))*MC_SCALE_VECT;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[8];
|
||||
val-=1<<(MC_BITS_VECT-1);
|
||||
mat[1][2]=((float)(val))*MC_SCALE_VECT;
|
||||
|
||||
|
||||
val=(int)((unsigned short *)(comp))[9];
|
||||
val-=1<<(MC_BITS_VECT-1);
|
||||
mat[2][0]=((float)(val))*MC_SCALE_VECT;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[10];
|
||||
val-=1<<(MC_BITS_VECT-1);
|
||||
mat[2][1]=((float)(val))*MC_SCALE_VECT;
|
||||
|
||||
val=(int)((unsigned short *)(comp))[11];
|
||||
val-=1<<(MC_BITS_VECT-1);
|
||||
mat[2][2]=((float)(val))*MC_SCALE_VECT;
|
||||
}
|
1786
code/renderergl2/tr_backend.c
Normal file
1786
code/renderergl2/tr_backend.c
Normal file
File diff suppressed because it is too large
Load diff
3554
code/renderergl2/tr_bsp.c
Normal file
3554
code/renderergl2/tr_bsp.c
Normal file
File diff suppressed because it is too large
Load diff
583
code/renderergl2/tr_cmds.c
Normal file
583
code/renderergl2/tr_cmds.c
Normal file
|
@ -0,0 +1,583 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "tr_local.h"
|
||||
|
||||
volatile renderCommandList_t *renderCommandList;
|
||||
|
||||
/*
|
||||
=====================
|
||||
R_PerformanceCounters
|
||||
=====================
|
||||
*/
|
||||
void R_PerformanceCounters( void ) {
|
||||
if ( !r_speeds->integer ) {
|
||||
// clear the counters even if we aren't printing
|
||||
Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
|
||||
Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if (r_speeds->integer == 1) {
|
||||
ri.Printf (PRINT_ALL, "%i/%i/%i shaders/batches/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n",
|
||||
backEnd.pc.c_shaders, backEnd.pc.c_surfBatches, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes,
|
||||
backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3,
|
||||
R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) );
|
||||
} else if (r_speeds->integer == 2) {
|
||||
ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
|
||||
tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out,
|
||||
tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );
|
||||
ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
|
||||
tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out,
|
||||
tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );
|
||||
} else if (r_speeds->integer == 3) {
|
||||
ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster );
|
||||
} else if (r_speeds->integer == 4) {
|
||||
if ( backEnd.pc.c_dlightVertexes ) {
|
||||
ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n",
|
||||
tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,
|
||||
backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );
|
||||
}
|
||||
}
|
||||
else if (r_speeds->integer == 5 )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar );
|
||||
}
|
||||
else if (r_speeds->integer == 6 )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n",
|
||||
backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders );
|
||||
}
|
||||
else if (r_speeds->integer == 7 )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "VBO draws: static %i dynamic %i\nMultidraws: %i merged %i\n",
|
||||
backEnd.pc.c_staticVboDraws, backEnd.pc.c_dynamicVboDraws, backEnd.pc.c_multidraws, backEnd.pc.c_multidrawsMerged );
|
||||
ri.Printf( PRINT_ALL, "GLSL binds: %i draws: gen %i light %i fog %i dlight %i\n",
|
||||
backEnd.pc.c_glslShaderBinds, backEnd.pc.c_genericDraws, backEnd.pc.c_lightallDraws, backEnd.pc.c_fogDraws, backEnd.pc.c_dlightDraws);
|
||||
}
|
||||
|
||||
Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
|
||||
Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
R_IssueRenderCommands
|
||||
====================
|
||||
*/
|
||||
void R_IssueRenderCommands( qboolean runPerformanceCounters ) {
|
||||
renderCommandList_t *cmdList;
|
||||
|
||||
cmdList = &backEndData->commands;
|
||||
assert(cmdList);
|
||||
// add an end-of-list command
|
||||
*(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST;
|
||||
|
||||
// clear it out, in case this is a sync and not a buffer flip
|
||||
cmdList->used = 0;
|
||||
|
||||
if ( runPerformanceCounters ) {
|
||||
R_PerformanceCounters();
|
||||
}
|
||||
|
||||
// actually start the commands going
|
||||
if ( !r_skipBackEnd->integer ) {
|
||||
// let it start on the new batch
|
||||
RB_ExecuteRenderCommands( cmdList->cmds );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
R_IssuePendingRenderCommands
|
||||
|
||||
Issue any pending commands and wait for them to complete.
|
||||
====================
|
||||
*/
|
||||
void R_IssuePendingRenderCommands( void ) {
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
}
|
||||
R_IssueRenderCommands( qfalse );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_GetCommandBuffer
|
||||
|
||||
make sure there is enough command space
|
||||
============
|
||||
*/
|
||||
void *R_GetCommandBuffer( int bytes ) {
|
||||
renderCommandList_t *cmdList;
|
||||
|
||||
cmdList = &backEndData->commands;
|
||||
bytes = PAD(bytes, sizeof(void *));
|
||||
|
||||
// always leave room for the end of list command
|
||||
if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) {
|
||||
if ( bytes > MAX_RENDER_COMMANDS - 4 ) {
|
||||
ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
|
||||
}
|
||||
// if we run out of room, just start dropping commands
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmdList->used += bytes;
|
||||
|
||||
return cmdList->cmds + cmdList->used - bytes;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_AddDrawSurfCmd
|
||||
|
||||
=============
|
||||
*/
|
||||
void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
||||
drawSurfsCommand_t *cmd;
|
||||
|
||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
||||
if ( !cmd ) {
|
||||
return;
|
||||
}
|
||||
cmd->commandId = RC_DRAW_SURFS;
|
||||
|
||||
cmd->drawSurfs = drawSurfs;
|
||||
cmd->numDrawSurfs = numDrawSurfs;
|
||||
|
||||
cmd->refdef = tr.refdef;
|
||||
cmd->viewParms = tr.viewParms;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_AddCapShadowmapCmd
|
||||
|
||||
=============
|
||||
*/
|
||||
void R_AddCapShadowmapCmd( int map, int cubeSide ) {
|
||||
capShadowmapCommand_t *cmd;
|
||||
|
||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
||||
if ( !cmd ) {
|
||||
return;
|
||||
}
|
||||
cmd->commandId = RC_CAPSHADOWMAP;
|
||||
|
||||
cmd->map = map;
|
||||
cmd->cubeSide = cubeSide;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PostProcessingCmd
|
||||
|
||||
=============
|
||||
*/
|
||||
void R_AddPostProcessCmd( ) {
|
||||
postProcessCommand_t *cmd;
|
||||
|
||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
||||
if ( !cmd ) {
|
||||
return;
|
||||
}
|
||||
cmd->commandId = RC_POSTPROCESS;
|
||||
|
||||
cmd->refdef = tr.refdef;
|
||||
cmd->viewParms = tr.viewParms;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RE_SetColor
|
||||
|
||||
Passing NULL will set the color to white
|
||||
=============
|
||||
*/
|
||||
void RE_SetColor( const float *rgba ) {
|
||||
setColorCommand_t *cmd;
|
||||
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
}
|
||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
||||
if ( !cmd ) {
|
||||
return;
|
||||
}
|
||||
cmd->commandId = RC_SET_COLOR;
|
||||
if ( !rgba ) {
|
||||
static float colorWhite[4] = { 1, 1, 1, 1 };
|
||||
|
||||
rgba = colorWhite;
|
||||
}
|
||||
|
||||
cmd->color[0] = rgba[0];
|
||||
cmd->color[1] = rgba[1];
|
||||
cmd->color[2] = rgba[2];
|
||||
cmd->color[3] = rgba[3];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
RE_StretchPic
|
||||
=============
|
||||
*/
|
||||
void RE_StretchPic ( float x, float y, float w, float h,
|
||||
float s1, float t1, float s2, float t2, qhandle_t hShader ) {
|
||||
stretchPicCommand_t *cmd;
|
||||
|
||||
if (!tr.registered) {
|
||||
return;
|
||||
}
|
||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
||||
if ( !cmd ) {
|
||||
return;
|
||||
}
|
||||
cmd->commandId = RC_STRETCH_PIC;
|
||||
cmd->shader = R_GetShaderByHandle( hShader );
|
||||
cmd->x = x;
|
||||
cmd->y = y;
|
||||
cmd->w = w;
|
||||
cmd->h = h;
|
||||
cmd->s1 = s1;
|
||||
cmd->t1 = t1;
|
||||
cmd->s2 = s2;
|
||||
cmd->t2 = t2;
|
||||
}
|
||||
|
||||
#define MODE_RED_CYAN 1
|
||||
#define MODE_RED_BLUE 2
|
||||
#define MODE_RED_GREEN 3
|
||||
#define MODE_GREEN_MAGENTA 4
|
||||
#define MODE_MAX MODE_GREEN_MAGENTA
|
||||
|
||||
void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode)
|
||||
{
|
||||
rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE;
|
||||
|
||||
if(colormode > MODE_MAX)
|
||||
{
|
||||
if(stereoFrame == STEREO_LEFT)
|
||||
stereoFrame = STEREO_RIGHT;
|
||||
else if(stereoFrame == STEREO_RIGHT)
|
||||
stereoFrame = STEREO_LEFT;
|
||||
|
||||
colormode -= MODE_MAX;
|
||||
}
|
||||
|
||||
if(colormode == MODE_GREEN_MAGENTA)
|
||||
{
|
||||
if(stereoFrame == STEREO_LEFT)
|
||||
rgba[0] = rgba[2] = GL_FALSE;
|
||||
else if(stereoFrame == STEREO_RIGHT)
|
||||
rgba[1] = GL_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(stereoFrame == STEREO_LEFT)
|
||||
rgba[1] = rgba[2] = GL_FALSE;
|
||||
else if(stereoFrame == STEREO_RIGHT)
|
||||
{
|
||||
rgba[0] = GL_FALSE;
|
||||
|
||||
if(colormode == MODE_RED_BLUE)
|
||||
rgba[1] = GL_FALSE;
|
||||
else if(colormode == MODE_RED_GREEN)
|
||||
rgba[2] = GL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
RE_BeginFrame
|
||||
|
||||
If running in stereo, RE_BeginFrame will be called twice
|
||||
for each RE_EndFrame
|
||||
====================
|
||||
*/
|
||||
void RE_BeginFrame( stereoFrame_t stereoFrame ) {
|
||||
drawBufferCommand_t *cmd = NULL;
|
||||
colorMaskCommand_t *colcmd = NULL;
|
||||
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
}
|
||||
glState.finishCalled = qfalse;
|
||||
|
||||
tr.frameCount++;
|
||||
tr.frameSceneNum = 0;
|
||||
|
||||
//
|
||||
// do overdraw measurement
|
||||
//
|
||||
if ( r_measureOverdraw->integer )
|
||||
{
|
||||
if ( glConfig.stencilBits < 4 )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
|
||||
ri.Cvar_Set( "r_measureOverdraw", "0" );
|
||||
r_measureOverdraw->modified = qfalse;
|
||||
}
|
||||
else if ( r_shadows->integer == 2 )
|
||||
{
|
||||
ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
|
||||
ri.Cvar_Set( "r_measureOverdraw", "0" );
|
||||
r_measureOverdraw->modified = qfalse;
|
||||
}
|
||||
else
|
||||
{
|
||||
R_IssuePendingRenderCommands();
|
||||
qglEnable( GL_STENCIL_TEST );
|
||||
qglStencilMask( ~0U );
|
||||
qglClearStencil( 0U );
|
||||
qglStencilFunc( GL_ALWAYS, 0U, ~0U );
|
||||
qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
|
||||
}
|
||||
r_measureOverdraw->modified = qfalse;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is only reached if it was on and is now off
|
||||
if ( r_measureOverdraw->modified ) {
|
||||
R_IssuePendingRenderCommands();
|
||||
qglDisable( GL_STENCIL_TEST );
|
||||
}
|
||||
r_measureOverdraw->modified = qfalse;
|
||||
}
|
||||
|
||||
//
|
||||
// texturemode stuff
|
||||
//
|
||||
if ( r_textureMode->modified ) {
|
||||
R_IssuePendingRenderCommands();
|
||||
GL_TextureMode( r_textureMode->string );
|
||||
r_textureMode->modified = qfalse;
|
||||
}
|
||||
|
||||
//
|
||||
// gamma stuff
|
||||
//
|
||||
if ( r_gamma->modified ) {
|
||||
r_gamma->modified = qfalse;
|
||||
|
||||
R_IssuePendingRenderCommands();
|
||||
R_SetColorMappings();
|
||||
}
|
||||
|
||||
// check for errors
|
||||
if ( !r_ignoreGLErrors->integer )
|
||||
{
|
||||
int err;
|
||||
|
||||
R_IssuePendingRenderCommands();
|
||||
if ((err = qglGetError()) != GL_NO_ERROR)
|
||||
ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err);
|
||||
}
|
||||
|
||||
if (glConfig.stereoEnabled) {
|
||||
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
|
||||
return;
|
||||
|
||||
cmd->commandId = RC_DRAW_BUFFER;
|
||||
|
||||
if ( stereoFrame == STEREO_LEFT ) {
|
||||
cmd->buffer = (int)GL_BACK_LEFT;
|
||||
} else if ( stereoFrame == STEREO_RIGHT ) {
|
||||
cmd->buffer = (int)GL_BACK_RIGHT;
|
||||
} else {
|
||||
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(r_anaglyphMode->integer)
|
||||
{
|
||||
if(r_anaglyphMode->modified)
|
||||
{
|
||||
// clear both, front and backbuffer.
|
||||
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
backEnd.colorMask[0] = GL_FALSE;
|
||||
backEnd.colorMask[1] = GL_FALSE;
|
||||
backEnd.colorMask[2] = GL_FALSE;
|
||||
backEnd.colorMask[3] = GL_FALSE;
|
||||
qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
if (glRefConfig.framebufferObject)
|
||||
{
|
||||
// clear all framebuffers
|
||||
if (tr.msaaResolveFbo)
|
||||
{
|
||||
FBO_Bind(tr.msaaResolveFbo);
|
||||
qglClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
if (tr.renderFbo)
|
||||
{
|
||||
FBO_Bind(tr.renderFbo);
|
||||
qglClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
if (tr.screenScratchFbo)
|
||||
{
|
||||
FBO_Bind(tr.screenScratchFbo);
|
||||
qglClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
FBO_Bind(NULL);
|
||||
}
|
||||
|
||||
qglDrawBuffer(GL_FRONT);
|
||||
qglClear(GL_COLOR_BUFFER_BIT);
|
||||
qglDrawBuffer(GL_BACK);
|
||||
qglClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
r_anaglyphMode->modified = qfalse;
|
||||
}
|
||||
|
||||
if(stereoFrame == STEREO_LEFT)
|
||||
{
|
||||
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
|
||||
return;
|
||||
|
||||
if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
|
||||
return;
|
||||
}
|
||||
else if(stereoFrame == STEREO_RIGHT)
|
||||
{
|
||||
clearDepthCommand_t *cldcmd;
|
||||
|
||||
if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) )
|
||||
return;
|
||||
|
||||
cldcmd->commandId = RC_CLEARDEPTH;
|
||||
|
||||
if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
|
||||
return;
|
||||
}
|
||||
else
|
||||
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
|
||||
|
||||
R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
|
||||
colcmd->commandId = RC_COLORMASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(stereoFrame != STEREO_CENTER)
|
||||
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
|
||||
|
||||
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
|
||||
return;
|
||||
}
|
||||
|
||||
if(cmd)
|
||||
{
|
||||
cmd->commandId = RC_DRAW_BUFFER;
|
||||
|
||||
if(r_anaglyphMode->modified)
|
||||
{
|
||||
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
backEnd.colorMask[0] = 0;
|
||||
backEnd.colorMask[1] = 0;
|
||||
backEnd.colorMask[2] = 0;
|
||||
backEnd.colorMask[3] = 0;
|
||||
r_anaglyphMode->modified = qfalse;
|
||||
}
|
||||
|
||||
if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
|
||||
cmd->buffer = (int)GL_FRONT;
|
||||
else
|
||||
cmd->buffer = (int)GL_BACK;
|
||||
}
|
||||
}
|
||||
|
||||
tr.refdef.stereoFrame = stereoFrame;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
RE_EndFrame
|
||||
|
||||
Returns the number of msec spent in the back end
|
||||
=============
|
||||
*/
|
||||
void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
|
||||
swapBuffersCommand_t *cmd;
|
||||
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
}
|
||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
||||
if ( !cmd ) {
|
||||
return;
|
||||
}
|
||||
cmd->commandId = RC_SWAP_BUFFERS;
|
||||
|
||||
R_IssueRenderCommands( qtrue );
|
||||
|
||||
R_InitNextFrame();
|
||||
|
||||
if ( frontEndMsec ) {
|
||||
*frontEndMsec = tr.frontEndMsec;
|
||||
}
|
||||
tr.frontEndMsec = 0;
|
||||
if ( backEndMsec ) {
|
||||
*backEndMsec = backEnd.pc.msec;
|
||||
}
|
||||
backEnd.pc.msec = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RE_TakeVideoFrame
|
||||
=============
|
||||
*/
|
||||
void RE_TakeVideoFrame( int width, int height,
|
||||
byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg )
|
||||
{
|
||||
videoFrameCommand_t *cmd;
|
||||
|
||||
if( !tr.registered ) {
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
|
||||
if( !cmd ) {
|
||||
return;
|
||||
}
|
||||
|
||||
cmd->commandId = RC_VIDEOFRAME;
|
||||
|
||||
cmd->width = width;
|
||||
cmd->height = height;
|
||||
cmd->captureBuffer = captureBuffer;
|
||||
cmd->encodeBuffer = encodeBuffer;
|
||||
cmd->motionJpeg = motionJpeg;
|
||||
}
|
806
code/renderergl2/tr_curve.c
Normal file
806
code/renderergl2/tr_curve.c
Normal file
|
@ -0,0 +1,806 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
/*
|
||||
|
||||
This file does all of the processing necessary to turn a raw grid of points
|
||||
read from the map file into a srfGridMesh_t ready for rendering.
|
||||
|
||||
The level of detail solution is direction independent, based only on subdivided
|
||||
distance from the true curve.
|
||||
|
||||
Only a single entry point:
|
||||
|
||||
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
|
||||
srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
LerpDrawVert
|
||||
============
|
||||
*/
|
||||
static void LerpDrawVert( srfVert_t *a, srfVert_t *b, srfVert_t *out ) {
|
||||
out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]);
|
||||
out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]);
|
||||
out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]);
|
||||
|
||||
out->st[0] = 0.5f * (a->st[0] + b->st[0]);
|
||||
out->st[1] = 0.5f * (a->st[1] + b->st[1]);
|
||||
|
||||
out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]);
|
||||
out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]);
|
||||
|
||||
out->vertexColors[0] = 0.5f * (a->vertexColors[0] + b->vertexColors[0]);
|
||||
out->vertexColors[1] = 0.5f * (a->vertexColors[1] + b->vertexColors[1]);
|
||||
out->vertexColors[2] = 0.5f * (a->vertexColors[2] + b->vertexColors[2]);
|
||||
out->vertexColors[3] = 0.5f * (a->vertexColors[3] + b->vertexColors[3]);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Transpose
|
||||
============
|
||||
*/
|
||||
static void Transpose( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
|
||||
int i, j;
|
||||
srfVert_t temp;
|
||||
|
||||
if ( width > height ) {
|
||||
for ( i = 0 ; i < height ; i++ ) {
|
||||
for ( j = i + 1 ; j < width ; j++ ) {
|
||||
if ( j < height ) {
|
||||
// swap the value
|
||||
temp = ctrl[j][i];
|
||||
ctrl[j][i] = ctrl[i][j];
|
||||
ctrl[i][j] = temp;
|
||||
} else {
|
||||
// just copy
|
||||
ctrl[j][i] = ctrl[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ( i = 0 ; i < width ; i++ ) {
|
||||
for ( j = i + 1 ; j < height ; j++ ) {
|
||||
if ( j < width ) {
|
||||
// swap the value
|
||||
temp = ctrl[i][j];
|
||||
ctrl[i][j] = ctrl[j][i];
|
||||
ctrl[j][i] = temp;
|
||||
} else {
|
||||
// just copy
|
||||
ctrl[i][j] = ctrl[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
MakeMeshNormals
|
||||
|
||||
Handles all the complicated wrapping and degenerate cases
|
||||
=================
|
||||
*/
|
||||
static void MakeMeshNormals( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
|
||||
int i, j, k, dist;
|
||||
vec3_t normal;
|
||||
vec3_t sum;
|
||||
int count = 0;
|
||||
vec3_t base;
|
||||
vec3_t delta;
|
||||
int x, y;
|
||||
srfVert_t *dv;
|
||||
vec3_t around[8], temp;
|
||||
qboolean good[8];
|
||||
qboolean wrapWidth, wrapHeight;
|
||||
float len;
|
||||
static int neighbors[8][2] = {
|
||||
{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
|
||||
};
|
||||
|
||||
wrapWidth = qfalse;
|
||||
for ( i = 0 ; i < height ; i++ ) {
|
||||
VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
|
||||
len = VectorLengthSquared( delta );
|
||||
if ( len > 1.0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( i == height ) {
|
||||
wrapWidth = qtrue;
|
||||
}
|
||||
|
||||
wrapHeight = qfalse;
|
||||
for ( i = 0 ; i < width ; i++ ) {
|
||||
VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
|
||||
len = VectorLengthSquared( delta );
|
||||
if ( len > 1.0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( i == width) {
|
||||
wrapHeight = qtrue;
|
||||
}
|
||||
|
||||
|
||||
for ( i = 0 ; i < width ; i++ ) {
|
||||
for ( j = 0 ; j < height ; j++ ) {
|
||||
count = 0;
|
||||
dv = &ctrl[j][i];
|
||||
VectorCopy( dv->xyz, base );
|
||||
for ( k = 0 ; k < 8 ; k++ ) {
|
||||
VectorClear( around[k] );
|
||||
good[k] = qfalse;
|
||||
|
||||
for ( dist = 1 ; dist <= 3 ; dist++ ) {
|
||||
x = i + neighbors[k][0] * dist;
|
||||
y = j + neighbors[k][1] * dist;
|
||||
if ( wrapWidth ) {
|
||||
if ( x < 0 ) {
|
||||
x = width - 1 + x;
|
||||
} else if ( x >= width ) {
|
||||
x = 1 + x - width;
|
||||
}
|
||||
}
|
||||
if ( wrapHeight ) {
|
||||
if ( y < 0 ) {
|
||||
y = height - 1 + y;
|
||||
} else if ( y >= height ) {
|
||||
y = 1 + y - height;
|
||||
}
|
||||
}
|
||||
|
||||
if ( x < 0 || x >= width || y < 0 || y >= height ) {
|
||||
break; // edge of patch
|
||||
}
|
||||
VectorSubtract( ctrl[y][x].xyz, base, temp );
|
||||
if ( VectorNormalize2( temp, temp ) == 0 ) {
|
||||
continue; // degenerate edge, get more dist
|
||||
} else {
|
||||
good[k] = qtrue;
|
||||
VectorCopy( temp, around[k] );
|
||||
break; // good edge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VectorClear( sum );
|
||||
for ( k = 0 ; k < 8 ; k++ ) {
|
||||
if ( !good[k] || !good[(k+1)&7] ) {
|
||||
continue; // didn't get two points
|
||||
}
|
||||
CrossProduct( around[(k+1)&7], around[k], normal );
|
||||
if ( VectorNormalize2( normal, normal ) == 0 ) {
|
||||
continue;
|
||||
}
|
||||
VectorAdd( normal, sum, sum );
|
||||
count++;
|
||||
}
|
||||
//if ( count == 0 ) {
|
||||
// printf("bad normal\n");
|
||||
//}
|
||||
VectorNormalize2( sum, dv->normal );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numTriangles,
|
||||
srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2])
|
||||
{
|
||||
int i, j;
|
||||
srfVert_t *dv[3];
|
||||
static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE];
|
||||
srfTriangle_t *tri;
|
||||
|
||||
// FIXME: use more elegant way
|
||||
for(i = 0; i < width; i++)
|
||||
{
|
||||
for(j = 0; j < height; j++)
|
||||
{
|
||||
dv[0] = &ctrl2[j * width + i];
|
||||
*dv[0] = ctrl[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0, tri = triangles; i < numTriangles; i++, tri++)
|
||||
{
|
||||
dv[0] = &ctrl2[tri->indexes[0]];
|
||||
dv[1] = &ctrl2[tri->indexes[1]];
|
||||
dv[2] = &ctrl2[tri->indexes[2]];
|
||||
|
||||
R_CalcTangentVectors(dv);
|
||||
}
|
||||
|
||||
#if 0
|
||||
for(i = 0; i < (width * height); i++)
|
||||
{
|
||||
dv0 = &ctrl2[i];
|
||||
|
||||
VectorNormalize(dv0->normal);
|
||||
#if 0
|
||||
VectorNormalize(dv0->tangent);
|
||||
VectorNormalize(dv0->bitangent);
|
||||
#else
|
||||
d = DotProduct(dv0->tangent, dv0->normal);
|
||||
VectorMA(dv0->tangent, -d, dv0->normal, dv0->tangent);
|
||||
VectorNormalize(dv0->tangent);
|
||||
|
||||
d = DotProduct(dv0->bitangent, dv0->normal);
|
||||
VectorMA(dv0->bitangent, -d, dv0->normal, dv0->bitangent);
|
||||
VectorNormalize(dv0->bitangent);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
// do another extra smoothing for normals to avoid flat shading
|
||||
for(i = 0; i < (width * height); i++)
|
||||
{
|
||||
for(j = 0; j < (width * height); j++)
|
||||
{
|
||||
if(R_CompareVert(&ctrl2[i], &ctrl2[j], qfalse))
|
||||
{
|
||||
VectorAdd(ctrl2[i].normal, ctrl2[j].normal, ctrl2[i].normal);
|
||||
}
|
||||
}
|
||||
|
||||
VectorNormalize(ctrl2[i].normal);
|
||||
}
|
||||
#endif
|
||||
|
||||
for(i = 0; i < width; i++)
|
||||
{
|
||||
for(j = 0; j < height; j++)
|
||||
{
|
||||
dv[0] = &ctrl2[j * width + i];
|
||||
dv[1] = &ctrl[j][i];
|
||||
|
||||
VectorCopy(dv[0]->tangent, dv[1]->tangent);
|
||||
VectorCopy(dv[0]->bitangent, dv[1]->bitangent);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int MakeMeshTriangles(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
|
||||
srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2])
|
||||
{
|
||||
int i, j;
|
||||
int numTriangles;
|
||||
int w, h;
|
||||
srfVert_t *dv;
|
||||
static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE];
|
||||
|
||||
h = height - 1;
|
||||
w = width - 1;
|
||||
numTriangles = 0;
|
||||
for(i = 0; i < h; i++)
|
||||
{
|
||||
for(j = 0; j < w; j++)
|
||||
{
|
||||
int v1, v2, v3, v4;
|
||||
|
||||
// vertex order to be reckognized as tristrips
|
||||
v1 = i * width + j + 1;
|
||||
v2 = v1 - 1;
|
||||
v3 = v2 + width;
|
||||
v4 = v3 + 1;
|
||||
|
||||
triangles[numTriangles].indexes[0] = v2;
|
||||
triangles[numTriangles].indexes[1] = v3;
|
||||
triangles[numTriangles].indexes[2] = v1;
|
||||
numTriangles++;
|
||||
|
||||
triangles[numTriangles].indexes[0] = v1;
|
||||
triangles[numTriangles].indexes[1] = v3;
|
||||
triangles[numTriangles].indexes[2] = v4;
|
||||
numTriangles++;
|
||||
}
|
||||
}
|
||||
|
||||
R_CalcSurfaceTriangleNeighbors(numTriangles, triangles);
|
||||
|
||||
// FIXME: use more elegant way
|
||||
for(i = 0; i < width; i++)
|
||||
{
|
||||
for(j = 0; j < height; j++)
|
||||
{
|
||||
dv = &ctrl2[j * width + i];
|
||||
*dv = ctrl[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
R_CalcSurfaceTrianglePlanes(numTriangles, triangles, ctrl2);
|
||||
|
||||
return numTriangles;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
InvertCtrl
|
||||
============
|
||||
*/
|
||||
static void InvertCtrl( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
|
||||
int i, j;
|
||||
srfVert_t temp;
|
||||
|
||||
for ( i = 0 ; i < height ; i++ ) {
|
||||
for ( j = 0 ; j < width/2 ; j++ ) {
|
||||
temp = ctrl[i][j];
|
||||
ctrl[i][j] = ctrl[i][width-1-j];
|
||||
ctrl[i][width-1-j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
InvertErrorTable
|
||||
=================
|
||||
*/
|
||||
static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {
|
||||
int i;
|
||||
float copy[2][MAX_GRID_SIZE];
|
||||
|
||||
Com_Memcpy( copy, errorTable, sizeof( copy ) );
|
||||
|
||||
for ( i = 0 ; i < width ; i++ ) {
|
||||
errorTable[1][i] = copy[0][i]; //[width-1-i];
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < height ; i++ ) {
|
||||
errorTable[0][i] = copy[1][height-1-i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
PutPointsOnCurve
|
||||
==================
|
||||
*/
|
||||
static void PutPointsOnCurve( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
|
||||
int width, int height ) {
|
||||
int i, j;
|
||||
srfVert_t prev, next;
|
||||
|
||||
for ( i = 0 ; i < width ; i++ ) {
|
||||
for ( j = 1 ; j < height ; j += 2 ) {
|
||||
LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev );
|
||||
LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next );
|
||||
LerpDrawVert( &prev, &next, &ctrl[j][i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for ( j = 0 ; j < height ; j++ ) {
|
||||
for ( i = 1 ; i < width ; i += 2 ) {
|
||||
LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev );
|
||||
LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next );
|
||||
LerpDrawVert( &prev, &next, &ctrl[j][i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_CreateSurfaceGridMesh
|
||||
=================
|
||||
*/
|
||||
srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,
|
||||
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE],
|
||||
int numTriangles, srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2]) {
|
||||
int i, j, size;
|
||||
srfVert_t *vert;
|
||||
vec3_t tmpVec;
|
||||
srfGridMesh_t *grid;
|
||||
|
||||
// copy the results out to a grid
|
||||
size = (width * height - 1) * sizeof( srfVert_t ) + sizeof( *grid );
|
||||
|
||||
#ifdef PATCH_STITCHING
|
||||
grid = /*ri.Hunk_Alloc*/ ri.Malloc( size );
|
||||
Com_Memset(grid, 0, size);
|
||||
|
||||
grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 );
|
||||
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
|
||||
|
||||
grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 );
|
||||
Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
|
||||
|
||||
grid->numTriangles = numTriangles;
|
||||
grid->triangles = ri.Malloc(grid->numTriangles * sizeof(srfTriangle_t));
|
||||
Com_Memcpy(grid->triangles, triangles, numTriangles * sizeof(srfTriangle_t));
|
||||
|
||||
grid->numVerts = (width * height);
|
||||
grid->verts = ri.Malloc(grid->numVerts * sizeof(srfVert_t));
|
||||
#else
|
||||
grid = ri.Hunk_Alloc( size );
|
||||
Com_Memset(grid, 0, size);
|
||||
|
||||
grid->widthLodError = ri.Hunk_Alloc( width * 4 );
|
||||
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
|
||||
|
||||
grid->heightLodError = ri.Hunk_Alloc( height * 4 );
|
||||
Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
|
||||
|
||||
grid->numTriangles = numTriangles;
|
||||
grid->triangles = ri.Hunk_Alloc(grid->numTriangles * sizeof(srfTriangle_t), h_low);
|
||||
Com_Memcpy(grid->triangles, triangles, numTriangles * sizeof(srfTriangle_t));
|
||||
|
||||
grid->numVerts = (width * height);
|
||||
grid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low);
|
||||
#endif
|
||||
|
||||
grid->width = width;
|
||||
grid->height = height;
|
||||
grid->surfaceType = SF_GRID;
|
||||
ClearBounds( grid->meshBounds[0], grid->meshBounds[1] );
|
||||
for ( i = 0 ; i < width ; i++ ) {
|
||||
for ( j = 0 ; j < height ; j++ ) {
|
||||
vert = &grid->verts[j*width+i];
|
||||
*vert = ctrl[j][i];
|
||||
AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );
|
||||
}
|
||||
}
|
||||
|
||||
// compute local origin and bounds
|
||||
VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );
|
||||
VectorScale( grid->localOrigin, 0.5f, grid->localOrigin );
|
||||
VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );
|
||||
grid->meshRadius = VectorLength( tmpVec );
|
||||
|
||||
VectorCopy( grid->localOrigin, grid->lodOrigin );
|
||||
grid->lodRadius = grid->meshRadius;
|
||||
//
|
||||
return grid;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_FreeSurfaceGridMesh
|
||||
=================
|
||||
*/
|
||||
void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) {
|
||||
ri.Free(grid->widthLodError);
|
||||
ri.Free(grid->heightLodError);
|
||||
ri.Free(grid->triangles);
|
||||
ri.Free(grid->verts);
|
||||
ri.Free(grid);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_SubdividePatchToGrid
|
||||
=================
|
||||
*/
|
||||
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
|
||||
srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
|
||||
int i, j, k, l;
|
||||
srfVert_t_cleared( prev );
|
||||
srfVert_t_cleared( next );
|
||||
srfVert_t_cleared( mid );
|
||||
float len, maxLen;
|
||||
int dir;
|
||||
int t;
|
||||
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
|
||||
float errorTable[2][MAX_GRID_SIZE];
|
||||
int numTriangles;
|
||||
static srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2];
|
||||
int consecutiveComplete;
|
||||
|
||||
for ( i = 0 ; i < width ; i++ ) {
|
||||
for ( j = 0 ; j < height ; j++ ) {
|
||||
ctrl[j][i] = points[j*width+i];
|
||||
}
|
||||
}
|
||||
|
||||
for ( dir = 0 ; dir < 2 ; dir++ ) {
|
||||
|
||||
for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
|
||||
errorTable[dir][j] = 0;
|
||||
}
|
||||
|
||||
consecutiveComplete = 0;
|
||||
|
||||
// horizontal subdivisions
|
||||
for ( j = 0 ; ; j = (j + 2) % (width - 1) ) {
|
||||
// check subdivided midpoints against control points
|
||||
|
||||
// FIXME: also check midpoints of adjacent patches against the control points
|
||||
// this would basically stitch all patches in the same LOD group together.
|
||||
|
||||
maxLen = 0;
|
||||
for ( i = 0 ; i < height ; i++ ) {
|
||||
vec3_t midxyz;
|
||||
vec3_t midxyz2;
|
||||
vec3_t dir;
|
||||
vec3_t projected;
|
||||
float d;
|
||||
|
||||
// calculate the point on the curve
|
||||
for ( l = 0 ; l < 3 ; l++ ) {
|
||||
midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2
|
||||
+ ctrl[i][j+2].xyz[l] ) * 0.25f;
|
||||
}
|
||||
|
||||
// see how far off the line it is
|
||||
// using dist-from-line will not account for internal
|
||||
// texture warping, but it gives a lot less polygons than
|
||||
// dist-from-midpoint
|
||||
VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
|
||||
VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );
|
||||
VectorNormalize( dir );
|
||||
|
||||
d = DotProduct( midxyz, dir );
|
||||
VectorScale( dir, d, projected );
|
||||
VectorSubtract( midxyz, projected, midxyz2);
|
||||
len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later
|
||||
if ( len > maxLen ) {
|
||||
maxLen = len;
|
||||
}
|
||||
}
|
||||
|
||||
maxLen = sqrt(maxLen);
|
||||
|
||||
// if all the points are on the lines, remove the entire columns
|
||||
if ( maxLen < 0.1f ) {
|
||||
errorTable[dir][j+1] = 999;
|
||||
// if we go over the whole grid twice without adding any columns, stop
|
||||
if (++consecutiveComplete >= width)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
// see if we want to insert subdivided columns
|
||||
if ( width + 2 > MAX_GRID_SIZE ) {
|
||||
errorTable[dir][j+1] = 1.0f/maxLen;
|
||||
break; // can't subdivide any more
|
||||
}
|
||||
|
||||
if ( maxLen <= r_subdivisions->value ) {
|
||||
errorTable[dir][j+1] = 1.0f/maxLen;
|
||||
// if we go over the whole grid twice without adding any columns, stop
|
||||
if (++consecutiveComplete >= width)
|
||||
break;
|
||||
continue; // didn't need subdivision
|
||||
}
|
||||
|
||||
errorTable[dir][j+2] = 1.0f/maxLen;
|
||||
|
||||
consecutiveComplete = 0;
|
||||
|
||||
// insert two columns and replace the peak
|
||||
width += 2;
|
||||
for ( i = 0 ; i < height ; i++ ) {
|
||||
LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );
|
||||
LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );
|
||||
LerpDrawVert( &prev, &next, &mid );
|
||||
|
||||
for ( k = width - 1 ; k > j + 3 ; k-- ) {
|
||||
ctrl[i][k] = ctrl[i][k-2];
|
||||
}
|
||||
ctrl[i][j + 1] = prev;
|
||||
ctrl[i][j + 2] = mid;
|
||||
ctrl[i][j + 3] = next;
|
||||
}
|
||||
|
||||
// skip the new one, we'll get it on the next pass
|
||||
j += 2;
|
||||
}
|
||||
|
||||
Transpose( width, height, ctrl );
|
||||
t = width;
|
||||
width = height;
|
||||
height = t;
|
||||
}
|
||||
|
||||
|
||||
// put all the aproximating points on the curve
|
||||
PutPointsOnCurve( ctrl, width, height );
|
||||
|
||||
// cull out any rows or columns that are colinear
|
||||
for ( i = 1 ; i < width-1 ; i++ ) {
|
||||
if ( errorTable[0][i] != 999 ) {
|
||||
continue;
|
||||
}
|
||||
for ( j = i+1 ; j < width ; j++ ) {
|
||||
for ( k = 0 ; k < height ; k++ ) {
|
||||
ctrl[k][j-1] = ctrl[k][j];
|
||||
}
|
||||
errorTable[0][j-1] = errorTable[0][j];
|
||||
}
|
||||
width--;
|
||||
}
|
||||
|
||||
for ( i = 1 ; i < height-1 ; i++ ) {
|
||||
if ( errorTable[1][i] != 999 ) {
|
||||
continue;
|
||||
}
|
||||
for ( j = i+1 ; j < height ; j++ ) {
|
||||
for ( k = 0 ; k < width ; k++ ) {
|
||||
ctrl[j-1][k] = ctrl[j][k];
|
||||
}
|
||||
errorTable[1][j-1] = errorTable[1][j];
|
||||
}
|
||||
height--;
|
||||
}
|
||||
|
||||
#if 1
|
||||
// flip for longest tristrips as an optimization
|
||||
// the results should be visually identical with or
|
||||
// without this step
|
||||
if ( height > width ) {
|
||||
Transpose( width, height, ctrl );
|
||||
InvertErrorTable( errorTable, width, height );
|
||||
t = width;
|
||||
width = height;
|
||||
height = t;
|
||||
InvertCtrl( width, height, ctrl );
|
||||
}
|
||||
#endif
|
||||
|
||||
// calculate triangles
|
||||
numTriangles = MakeMeshTriangles(width, height, ctrl, triangles);
|
||||
|
||||
// calculate normals
|
||||
MakeMeshNormals( width, height, ctrl );
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
MakeMeshTangentVectors(width, height, ctrl, numTriangles, triangles);
|
||||
#endif
|
||||
|
||||
return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numTriangles, triangles);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_GridInsertColumn
|
||||
===============
|
||||
*/
|
||||
srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) {
|
||||
int i, j;
|
||||
int width, height, oldwidth;
|
||||
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
|
||||
float errorTable[2][MAX_GRID_SIZE];
|
||||
float lodRadius;
|
||||
vec3_t lodOrigin;
|
||||
int numTriangles;
|
||||
static srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2];
|
||||
|
||||
oldwidth = 0;
|
||||
width = grid->width + 1;
|
||||
if (width > MAX_GRID_SIZE)
|
||||
return NULL;
|
||||
height = grid->height;
|
||||
for (i = 0; i < width; i++) {
|
||||
if (i == column) {
|
||||
//insert new column
|
||||
for (j = 0; j < grid->height; j++) {
|
||||
LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] );
|
||||
if (j == row)
|
||||
VectorCopy(point, ctrl[j][i].xyz);
|
||||
}
|
||||
errorTable[0][i] = loderror;
|
||||
continue;
|
||||
}
|
||||
errorTable[0][i] = grid->widthLodError[oldwidth];
|
||||
for (j = 0; j < grid->height; j++) {
|
||||
ctrl[j][i] = grid->verts[j * grid->width + oldwidth];
|
||||
}
|
||||
oldwidth++;
|
||||
}
|
||||
for (j = 0; j < grid->height; j++) {
|
||||
errorTable[1][j] = grid->heightLodError[j];
|
||||
}
|
||||
// put all the aproximating points on the curve
|
||||
//PutPointsOnCurve( ctrl, width, height );
|
||||
|
||||
// calculate triangles
|
||||
numTriangles = MakeMeshTriangles(width, height, ctrl, triangles);
|
||||
|
||||
// calculate normals
|
||||
MakeMeshNormals( width, height, ctrl );
|
||||
|
||||
VectorCopy(grid->lodOrigin, lodOrigin);
|
||||
lodRadius = grid->lodRadius;
|
||||
// free the old grid
|
||||
R_FreeSurfaceGridMesh(grid);
|
||||
// create a new grid
|
||||
grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numTriangles, triangles);
|
||||
grid->lodRadius = lodRadius;
|
||||
VectorCopy(lodOrigin, grid->lodOrigin);
|
||||
return grid;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_GridInsertRow
|
||||
===============
|
||||
*/
|
||||
srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) {
|
||||
int i, j;
|
||||
int width, height, oldheight;
|
||||
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
|
||||
float errorTable[2][MAX_GRID_SIZE];
|
||||
float lodRadius;
|
||||
vec3_t lodOrigin;
|
||||
int numTriangles;
|
||||
static srfTriangle_t triangles[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2];
|
||||
|
||||
oldheight = 0;
|
||||
width = grid->width;
|
||||
height = grid->height + 1;
|
||||
if (height > MAX_GRID_SIZE)
|
||||
return NULL;
|
||||
for (i = 0; i < height; i++) {
|
||||
if (i == row) {
|
||||
//insert new row
|
||||
for (j = 0; j < grid->width; j++) {
|
||||
LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );
|
||||
if (j == column)
|
||||
VectorCopy(point, ctrl[i][j].xyz);
|
||||
}
|
||||
errorTable[1][i] = loderror;
|
||||
continue;
|
||||
}
|
||||
errorTable[1][i] = grid->heightLodError[oldheight];
|
||||
for (j = 0; j < grid->width; j++) {
|
||||
ctrl[i][j] = grid->verts[oldheight * grid->width + j];
|
||||
}
|
||||
oldheight++;
|
||||
}
|
||||
for (j = 0; j < grid->width; j++) {
|
||||
errorTable[0][j] = grid->widthLodError[j];
|
||||
}
|
||||
// put all the aproximating points on the curve
|
||||
//PutPointsOnCurve( ctrl, width, height );
|
||||
|
||||
// calculate triangles
|
||||
numTriangles = MakeMeshTriangles(width, height, ctrl, triangles);
|
||||
|
||||
// calculate normals
|
||||
MakeMeshNormals( width, height, ctrl );
|
||||
|
||||
VectorCopy(grid->lodOrigin, lodOrigin);
|
||||
lodRadius = grid->lodRadius;
|
||||
// free the old grid
|
||||
R_FreeSurfaceGridMesh(grid);
|
||||
// create a new grid
|
||||
grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numTriangles, triangles);
|
||||
grid->lodRadius = lodRadius;
|
||||
VectorCopy(lodOrigin, grid->lodOrigin);
|
||||
return grid;
|
||||
}
|
667
code/renderergl2/tr_extensions.c
Normal file
667
code/renderergl2/tr_extensions.c
Normal file
|
@ -0,0 +1,667 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2011 James Canete (use.less01@gmail.com)
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_extensions.c - extensions needed by the renderer not in sdl_glimp.c
|
||||
|
||||
#ifdef USE_LOCAL_HEADERS
|
||||
# include "SDL.h"
|
||||
#else
|
||||
# include <SDL.h>
|
||||
#endif
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
// GL_EXT_draw_range_elements
|
||||
void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
|
||||
|
||||
// GL_EXT_multi_draw_arrays
|
||||
void (APIENTRY * qglMultiDrawArraysEXT) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
|
||||
void (APIENTRY * qglMultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount);
|
||||
|
||||
// GL_ARB_vertex_shader
|
||||
void (APIENTRY * qglBindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB * name);
|
||||
void (APIENTRY * qglGetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length,
|
||||
GLint * size, GLenum * type, GLcharARB * name);
|
||||
GLint(APIENTRY * qglGetAttribLocationARB) (GLhandleARB programObj, const GLcharARB * name);
|
||||
|
||||
// GL_ARB_vertex_program
|
||||
void (APIENTRY * qglVertexAttrib4fARB) (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
|
||||
void (APIENTRY * qglVertexAttrib4fvARB) (GLuint, const GLfloat *);
|
||||
void (APIENTRY * qglVertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized,
|
||||
GLsizei stride, const GLvoid * pointer);
|
||||
void (APIENTRY * qglEnableVertexAttribArrayARB) (GLuint index);
|
||||
void (APIENTRY * qglDisableVertexAttribArrayARB) (GLuint index);
|
||||
|
||||
// GL_ARB_vertex_buffer_object
|
||||
void (APIENTRY * qglBindBufferARB) (GLenum target, GLuint buffer);
|
||||
void (APIENTRY * qglDeleteBuffersARB) (GLsizei n, const GLuint * buffers);
|
||||
void (APIENTRY * qglGenBuffersARB) (GLsizei n, GLuint * buffers);
|
||||
|
||||
GLboolean(APIENTRY * qglIsBufferARB) (GLuint buffer);
|
||||
void (APIENTRY * qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage);
|
||||
void (APIENTRY * qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data);
|
||||
void (APIENTRY * qglGetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid * data);
|
||||
|
||||
void (APIENTRY * qglGetBufferParameterivARB) (GLenum target, GLenum pname, GLint * params);
|
||||
void (APIENTRY * qglGetBufferPointervARB) (GLenum target, GLenum pname, GLvoid * *params);
|
||||
|
||||
// GL_ARB_shader_objects
|
||||
void (APIENTRY * qglDeleteObjectARB) (GLhandleARB obj);
|
||||
|
||||
GLhandleARB(APIENTRY * qglGetHandleARB) (GLenum pname);
|
||||
void (APIENTRY * qglDetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj);
|
||||
|
||||
GLhandleARB(APIENTRY * qglCreateShaderObjectARB) (GLenum shaderType);
|
||||
void (APIENTRY * qglShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB * *string,
|
||||
const GLint * length);
|
||||
void (APIENTRY * qglCompileShaderARB) (GLhandleARB shaderObj);
|
||||
|
||||
GLhandleARB(APIENTRY * qglCreateProgramObjectARB) (void);
|
||||
void (APIENTRY * qglAttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj);
|
||||
void (APIENTRY * qglLinkProgramARB) (GLhandleARB programObj);
|
||||
void (APIENTRY * qglUseProgramObjectARB) (GLhandleARB programObj);
|
||||
void (APIENTRY * qglValidateProgramARB) (GLhandleARB programObj);
|
||||
void (APIENTRY * qglUniform1fARB) (GLint location, GLfloat v0);
|
||||
void (APIENTRY * qglUniform2fARB) (GLint location, GLfloat v0, GLfloat v1);
|
||||
void (APIENTRY * qglUniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
void (APIENTRY * qglUniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
||||
void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0);
|
||||
void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1);
|
||||
void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2);
|
||||
void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
||||
void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
||||
void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
||||
void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
||||
void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value);
|
||||
void (APIENTRY * qglUniform2ivARB) (GLint location, GLsizei count, const GLint * value);
|
||||
void (APIENTRY * qglUniform3ivARB) (GLint location, GLsizei count, const GLint * value);
|
||||
void (APIENTRY * qglUniform4ivARB) (GLint location, GLsizei count, const GLint * value);
|
||||
void (APIENTRY * qglUniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
||||
void (APIENTRY * qglUniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
||||
void (APIENTRY * qglUniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
|
||||
void (APIENTRY * qglGetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat * params);
|
||||
void (APIENTRY * qglGetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint * params);
|
||||
void (APIENTRY * qglGetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog);
|
||||
void (APIENTRY * qglGetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei * count,
|
||||
GLhandleARB * obj);
|
||||
GLint(APIENTRY * qglGetUniformLocationARB) (GLhandleARB programObj, const GLcharARB * name);
|
||||
void (APIENTRY * qglGetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxIndex, GLsizei * length,
|
||||
GLint * size, GLenum * type, GLcharARB * name);
|
||||
void (APIENTRY * qglGetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat * params);
|
||||
void (APIENTRY * qglGetUniformivARB) (GLhandleARB programObj, GLint location, GLint * params);
|
||||
void (APIENTRY * qglGetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source);
|
||||
|
||||
// GL_ARB_texture_compression
|
||||
void (APIENTRY * qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
|
||||
GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
|
||||
void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
|
||||
GLint border, GLsizei imageSize, const GLvoid *data);
|
||||
void (APIENTRY * qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border,
|
||||
GLsizei imageSize, const GLvoid *data);
|
||||
void (APIENTRY * qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
|
||||
void (APIENTRY * qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
|
||||
GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
|
||||
void (APIENTRY * qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format,
|
||||
GLsizei imageSize, const GLvoid *data);
|
||||
void (APIENTRY * qglGetCompressedTexImageARB)(GLenum target, GLint lod,
|
||||
GLvoid *img);
|
||||
|
||||
// GL_EXT_framebuffer_object
|
||||
GLboolean (APIENTRY * qglIsRenderbufferEXT)(GLuint renderbuffer);
|
||||
void (APIENTRY * qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer);
|
||||
void (APIENTRY * qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers);
|
||||
void (APIENTRY * qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers);
|
||||
|
||||
void (APIENTRY * qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
|
||||
void (APIENTRY * qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params);
|
||||
|
||||
GLboolean (APIENTRY * qglIsFramebufferEXT)(GLuint framebuffer);
|
||||
void (APIENTRY * qglBindFramebufferEXT)(GLenum target, GLuint framebuffer);
|
||||
void (APIENTRY * qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers);
|
||||
void (APIENTRY * qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers);
|
||||
|
||||
GLenum (APIENTRY * qglCheckFramebufferStatusEXT)(GLenum target);
|
||||
|
||||
void (APIENTRY * qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
||||
GLint level);
|
||||
void (APIENTRY * qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
||||
GLint level);
|
||||
void (APIENTRY * qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
|
||||
GLint level, GLint zoffset);
|
||||
|
||||
void (APIENTRY * qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget,
|
||||
GLuint renderbuffer);
|
||||
|
||||
void (APIENTRY * qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
|
||||
|
||||
void (APIENTRY * qglGenerateMipmapEXT)(GLenum target);
|
||||
|
||||
// GL_ARB_occlusion_query
|
||||
void (APIENTRY * qglGenQueriesARB)(GLsizei n, GLuint *ids);
|
||||
void (APIENTRY * qglDeleteQueriesARB)(GLsizei n, const GLuint *ids);
|
||||
GLboolean (APIENTRY * qglIsQueryARB)(GLuint id);
|
||||
void (APIENTRY * qglBeginQueryARB)(GLenum target, GLuint id);
|
||||
void (APIENTRY * qglEndQueryARB)(GLenum target);
|
||||
void (APIENTRY * qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
|
||||
void (APIENTRY * qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params);
|
||||
void (APIENTRY * qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params);
|
||||
|
||||
// GL_EXT_framebuffer_blit
|
||||
void (APIENTRY * qglBlitFramebufferEXT)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||
GLbitfield mask, GLenum filter);
|
||||
|
||||
// GL_EXT_framebuffer_multisample
|
||||
void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples,
|
||||
GLenum internalformat, GLsizei width, GLsizei height);
|
||||
|
||||
// GL_ARB_draw_buffers
|
||||
void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs);
|
||||
|
||||
static qboolean GLimp_HaveExtension(const char *ext)
|
||||
{
|
||||
const char *ptr = Q_stristr( glConfig.extensions_string, ext );
|
||||
if (ptr == NULL)
|
||||
return qfalse;
|
||||
ptr += strlen(ext);
|
||||
return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string.
|
||||
}
|
||||
|
||||
void GLimp_InitExtraExtensions()
|
||||
{
|
||||
char *extension;
|
||||
const char* result[3] = { "...ignoring %s\n", "...using %s\n", "...%s not found\n" };
|
||||
|
||||
// GL_EXT_draw_range_elements
|
||||
extension = "GL_EXT_draw_range_elements";
|
||||
glRefConfig.drawRangeElements = qfalse;
|
||||
qglMultiDrawArraysEXT = NULL;
|
||||
qglMultiDrawElementsEXT = NULL;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
qglDrawRangeElementsEXT = (void *) SDL_GL_GetProcAddress("glDrawRangeElementsEXT");
|
||||
|
||||
if ( r_ext_draw_range_elements->integer)
|
||||
glRefConfig.drawRangeElements = qtrue;
|
||||
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.drawRangeElements], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_EXT_multi_draw_arrays
|
||||
extension = "GL_EXT_multi_draw_arrays";
|
||||
glRefConfig.multiDrawArrays = qfalse;
|
||||
qglMultiDrawArraysEXT = NULL;
|
||||
qglMultiDrawElementsEXT = NULL;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
qglMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawArraysEXT");
|
||||
qglMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawElementsEXT");
|
||||
|
||||
if ( r_ext_multi_draw_arrays->integer )
|
||||
glRefConfig.multiDrawArrays = qtrue;
|
||||
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.multiDrawArrays], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_vertex_program
|
||||
//glRefConfig.vertexProgram = qfalse;
|
||||
extension = "GL_ARB_vertex_program";
|
||||
qglVertexAttrib4fARB = NULL;
|
||||
qglVertexAttrib4fvARB = NULL;
|
||||
qglVertexAttribPointerARB = NULL;
|
||||
qglEnableVertexAttribArrayARB = NULL;
|
||||
qglDisableVertexAttribArrayARB = NULL;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
qglVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fARB");
|
||||
qglVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fvARB");
|
||||
qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) SDL_GL_GetProcAddress("glVertexAttribPointerARB");
|
||||
qglEnableVertexAttribArrayARB =
|
||||
(PFNGLENABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glEnableVertexAttribArrayARB");
|
||||
qglDisableVertexAttribArrayARB =
|
||||
(PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glDisableVertexAttribArrayARB");
|
||||
|
||||
ri.Printf(PRINT_ALL, result[1], extension);
|
||||
//glRefConfig.vertexProgram = qtrue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Error(ERR_FATAL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_vertex_buffer_object
|
||||
//glRefConfig.vertexBufferObject = qfalse;
|
||||
extension = "GL_ARB_vertex_buffer_object";
|
||||
qglBindBufferARB = NULL;
|
||||
qglDeleteBuffersARB = NULL;
|
||||
qglGenBuffersARB = NULL;
|
||||
qglIsBufferARB = NULL;
|
||||
qglBufferDataARB = NULL;
|
||||
qglBufferSubDataARB = NULL;
|
||||
qglGetBufferSubDataARB = NULL;
|
||||
qglGetBufferParameterivARB = NULL;
|
||||
qglGetBufferPointervARB = NULL;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
qglBindBufferARB = (PFNGLBINDBUFFERARBPROC) SDL_GL_GetProcAddress("glBindBufferARB");
|
||||
qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB");
|
||||
qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC) SDL_GL_GetProcAddress("glGenBuffersARB");
|
||||
qglIsBufferARB = (PFNGLISBUFFERARBPROC) SDL_GL_GetProcAddress("glIsBufferARB");
|
||||
qglBufferDataARB = (PFNGLBUFFERDATAARBPROC) SDL_GL_GetProcAddress("glBufferDataARB");
|
||||
qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glBufferSubDataARB");
|
||||
qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glGetBufferSubDataARB");
|
||||
qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetBufferParameterivARB");
|
||||
qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) SDL_GL_GetProcAddress("glGetBufferPointervARB");
|
||||
ri.Printf(PRINT_ALL, result[1], extension);
|
||||
//glRefConfig.vertexBufferObject = qtrue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Error(ERR_FATAL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_shader_objects
|
||||
extension = "GL_ARB_shader_objects";
|
||||
//glRefConfig.shaderObjects = qfalse;
|
||||
qglDeleteObjectARB = NULL;
|
||||
qglGetHandleARB = NULL;
|
||||
qglDetachObjectARB = NULL;
|
||||
qglCreateShaderObjectARB = NULL;
|
||||
qglShaderSourceARB = NULL;
|
||||
qglCompileShaderARB = NULL;
|
||||
qglCreateProgramObjectARB = NULL;
|
||||
qglAttachObjectARB = NULL;
|
||||
qglLinkProgramARB = NULL;
|
||||
qglUseProgramObjectARB = NULL;
|
||||
qglValidateProgramARB = NULL;
|
||||
qglUniform1fARB = NULL;
|
||||
qglUniform2fARB = NULL;
|
||||
qglUniform3fARB = NULL;
|
||||
qglUniform4fARB = NULL;
|
||||
qglUniform1iARB = NULL;
|
||||
qglUniform2iARB = NULL;
|
||||
qglUniform3iARB = NULL;
|
||||
qglUniform4iARB = NULL;
|
||||
qglUniform1fvARB = NULL;
|
||||
qglUniform2fvARB = NULL;
|
||||
qglUniform3fvARB = NULL;
|
||||
qglUniform4fvARB = NULL;
|
||||
qglUniform2ivARB = NULL;
|
||||
qglUniform3ivARB = NULL;
|
||||
qglUniform4ivARB = NULL;
|
||||
qglUniformMatrix2fvARB = NULL;
|
||||
qglUniformMatrix3fvARB = NULL;
|
||||
qglUniformMatrix4fvARB = NULL;
|
||||
qglGetObjectParameterfvARB = NULL;
|
||||
qglGetObjectParameterivARB = NULL;
|
||||
qglGetInfoLogARB = NULL;
|
||||
qglGetAttachedObjectsARB = NULL;
|
||||
qglGetUniformLocationARB = NULL;
|
||||
qglGetActiveUniformARB = NULL;
|
||||
qglGetUniformfvARB = NULL;
|
||||
qglGetUniformivARB = NULL;
|
||||
qglGetShaderSourceARB = NULL;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
qglDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
|
||||
qglGetHandleARB = (PFNGLGETHANDLEARBPROC) SDL_GL_GetProcAddress("glGetHandleARB");
|
||||
qglDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) SDL_GL_GetProcAddress("glDetachObjectARB");
|
||||
qglCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
|
||||
qglShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
|
||||
qglCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
|
||||
qglCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
|
||||
qglAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
|
||||
qglLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
|
||||
qglUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
|
||||
qglValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) SDL_GL_GetProcAddress("glValidateProgramARB");
|
||||
qglUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
|
||||
qglUniform2fARB = (PFNGLUNIFORM2FARBPROC) SDL_GL_GetProcAddress("glUniform2fARB");
|
||||
qglUniform3fARB = (PFNGLUNIFORM3FARBPROC) SDL_GL_GetProcAddress("glUniform3fARB");
|
||||
qglUniform4fARB = (PFNGLUNIFORM4FARBPROC) SDL_GL_GetProcAddress("glUniform4fARB");
|
||||
qglUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
|
||||
qglUniform2iARB = (PFNGLUNIFORM2IARBPROC) SDL_GL_GetProcAddress("glUniform2iARB");
|
||||
qglUniform3iARB = (PFNGLUNIFORM3IARBPROC) SDL_GL_GetProcAddress("glUniform3iARB");
|
||||
qglUniform4iARB = (PFNGLUNIFORM4IARBPROC) SDL_GL_GetProcAddress("glUniform4iARB");
|
||||
qglUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) SDL_GL_GetProcAddress("glUniform1fvARB");
|
||||
qglUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) SDL_GL_GetProcAddress("glUniform2fvARB");
|
||||
qglUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) SDL_GL_GetProcAddress("glUniform3fvARB");
|
||||
qglUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) SDL_GL_GetProcAddress("glUniform4fvARB");
|
||||
qglUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) SDL_GL_GetProcAddress("glUniform2ivARB");
|
||||
qglUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) SDL_GL_GetProcAddress("glUniform3ivARB");
|
||||
qglUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) SDL_GL_GetProcAddress("glUniform4ivARB");
|
||||
qglUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix2fvARB");
|
||||
qglUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix3fvARB");
|
||||
qglUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix4fvARB");
|
||||
qglGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterfvARB");
|
||||
qglGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
|
||||
qglGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
|
||||
qglGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) SDL_GL_GetProcAddress("glGetAttachedObjectsARB");
|
||||
qglGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
|
||||
qglGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) SDL_GL_GetProcAddress("glGetActiveUniformARB");
|
||||
qglGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) SDL_GL_GetProcAddress("glGetUniformfvARB");
|
||||
qglGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) SDL_GL_GetProcAddress("glGetUniformivARB");
|
||||
qglGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glGetShaderSourceARB");
|
||||
ri.Printf(PRINT_ALL, result[1], extension);
|
||||
//glRefConfig.shaderObjects = qtrue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Error(ERR_FATAL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_vertex_shader
|
||||
//glRefConfig.vertexShader = qfalse;
|
||||
extension = "GL_ARB_vertex_shader";
|
||||
qglBindAttribLocationARB = NULL;
|
||||
qglGetActiveAttribARB = NULL;
|
||||
qglGetAttribLocationARB = NULL;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
//int reservedComponents;
|
||||
|
||||
//qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.maxVertexUniforms);
|
||||
//qglGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats);
|
||||
//qglGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.maxVertexAttribs);
|
||||
|
||||
//reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices
|
||||
|
||||
#if 0
|
||||
if(glConfig.driverType == GLDRV_MESA)
|
||||
{
|
||||
// HACK
|
||||
// restrict to number of vertex uniforms to 512 because of:
|
||||
// xreal.x86_64: nv50_program.c:4181: nv50_program_validate_data: Assertion `p->param_nr <= 512' failed
|
||||
|
||||
glConfig.maxVertexUniforms = Q_bound(0, glConfig.maxVertexUniforms, 512);
|
||||
}
|
||||
#endif
|
||||
|
||||
//glConfig.maxVertexSkinningBones = (int) Q_bound(0.0, (Q_max(glConfig.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES);
|
||||
//glConfig.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ((glConfig.maxVertexSkinningBones >= 12) ? qtrue : qfalse);
|
||||
|
||||
qglBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glBindAttribLocationARB");
|
||||
qglGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) SDL_GL_GetProcAddress("glGetActiveAttribARB");
|
||||
qglGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetAttribLocationARB");
|
||||
ri.Printf(PRINT_ALL, result[1], extension);
|
||||
//glRefConfig.vertexShader = qtrue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Error(ERR_FATAL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_shading_language_100
|
||||
extension = "GL_ARB_shading_language_100";
|
||||
glRefConfig.textureFloat = qfalse;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
char version[256];
|
||||
|
||||
Q_strncpyz( version, (char *) qglGetString (GL_SHADING_LANGUAGE_VERSION_ARB), sizeof( version ) );
|
||||
|
||||
sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion);
|
||||
|
||||
ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Error(ERR_FATAL, result[2], extension);
|
||||
}
|
||||
|
||||
glRefConfig.memInfo = MI_NONE;
|
||||
|
||||
if( GLimp_HaveExtension( "GL_NVX_gpu_memory_info" ) )
|
||||
{
|
||||
glRefConfig.memInfo = MI_NVX;
|
||||
}
|
||||
else if( GLimp_HaveExtension( "GL_ATI_meminfo" ) )
|
||||
{
|
||||
glRefConfig.memInfo = MI_ATI;
|
||||
}
|
||||
|
||||
extension = "GL_ARB_texture_non_power_of_two";
|
||||
glRefConfig.textureNonPowerOfTwo = qfalse;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
if(1) //(r_ext_texture_non_power_of_two->integer)
|
||||
{
|
||||
glRefConfig.textureNonPowerOfTwo = qtrue;
|
||||
}
|
||||
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.textureNonPowerOfTwo], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_texture_float
|
||||
extension = "GL_ARB_texture_float";
|
||||
glRefConfig.textureFloat = qfalse;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
if( r_ext_texture_float->integer )
|
||||
{
|
||||
glRefConfig.textureFloat = qtrue;
|
||||
}
|
||||
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.textureFloat], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_half_float_pixel
|
||||
extension = "GL_ARB_half_float_pixel";
|
||||
glRefConfig.halfFloatPixel = qfalse;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
if( r_arb_half_float_pixel->integer )
|
||||
glRefConfig.halfFloatPixel = qtrue;
|
||||
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.halfFloatPixel], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_EXT_framebuffer_object
|
||||
extension = "GL_EXT_framebuffer_object";
|
||||
glRefConfig.framebufferObject = qfalse;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glRefConfig.maxRenderbufferSize);
|
||||
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glRefConfig.maxColorAttachments);
|
||||
|
||||
qglIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsRenderbufferEXT");
|
||||
qglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindRenderbufferEXT");
|
||||
qglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteRenderbuffersEXT");
|
||||
qglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenRenderbuffersEXT");
|
||||
qglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) SDL_GL_GetProcAddress("glRenderbufferStorageEXT");
|
||||
qglGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetRenderbufferParameterivEXT");
|
||||
qglIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsFramebufferEXT");
|
||||
qglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindFramebufferEXT");
|
||||
qglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
|
||||
qglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenFramebuffersEXT");
|
||||
qglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
|
||||
qglFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture1DEXT");
|
||||
qglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
|
||||
qglFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture3DEXT");
|
||||
qglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glFramebufferRenderbufferEXT");
|
||||
qglGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameterivEXT");
|
||||
qglGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) SDL_GL_GetProcAddress("glGenerateMipmapEXT");
|
||||
|
||||
if(r_ext_framebuffer_object->value)
|
||||
glRefConfig.framebufferObject = qtrue;
|
||||
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.framebufferObject], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_EXT_packed_depth_stencil
|
||||
extension = "GL_EXT_packed_depth_stencil";
|
||||
glRefConfig.packedDepthStencil = qfalse;
|
||||
if( GLimp_HaveExtension(extension))
|
||||
{
|
||||
glRefConfig.packedDepthStencil = qtrue;
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.packedDepthStencil], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_occlusion_query
|
||||
extension = "GL_ARB_occlusion_query";
|
||||
glRefConfig.occlusionQuery = qfalse;
|
||||
if (GLimp_HaveExtension(extension))
|
||||
{
|
||||
qglGenQueriesARB = (PFNGLGENQUERIESARBPROC) SDL_GL_GetProcAddress("glGenQueriesARB");
|
||||
qglDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) SDL_GL_GetProcAddress("glDeleteQueriesARB");
|
||||
qglIsQueryARB = (PFNGLISQUERYARBPROC) SDL_GL_GetProcAddress("glIsQueryARB");
|
||||
qglBeginQueryARB = (PFNGLBEGINQUERYARBPROC) SDL_GL_GetProcAddress("glBeginQueryARB");
|
||||
qglEndQueryARB = (PFNGLENDQUERYARBPROC) SDL_GL_GetProcAddress("glEndQueryARB");
|
||||
qglGetQueryivARB = (PFNGLGETQUERYIVARBPROC) SDL_GL_GetProcAddress("glGetQueryivARB");
|
||||
qglGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectivARB");
|
||||
qglGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectuivARB");
|
||||
glRefConfig.occlusionQuery = qtrue;
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.occlusionQuery], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_EXT_framebuffer_blit
|
||||
extension = "GL_EXT_framebuffer_blit";
|
||||
glRefConfig.framebufferBlit = qfalse;
|
||||
if (GLimp_HaveExtension(extension))
|
||||
{
|
||||
qglBlitFramebufferEXT = (void *)SDL_GL_GetProcAddress("glBlitFramebufferEXT");
|
||||
glRefConfig.framebufferBlit = qtrue;
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.framebufferBlit], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_EXT_framebuffer_multisample
|
||||
extension = "GL_EXT_framebuffer_multisample";
|
||||
glRefConfig.framebufferMultisample = qfalse;
|
||||
if (GLimp_HaveExtension(extension))
|
||||
{
|
||||
qglRenderbufferStorageMultisampleEXT = (void *)SDL_GL_GetProcAddress("glRenderbufferStorageMultisampleEXT");
|
||||
glRefConfig.framebufferMultisample = qtrue;
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.framebufferMultisample], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_EXT_texture_sRGB
|
||||
extension = "GL_EXT_texture_sRGB";
|
||||
glRefConfig.texture_srgb = qfalse;
|
||||
if (GLimp_HaveExtension(extension))
|
||||
{
|
||||
if (r_srgb->integer)
|
||||
glRefConfig.texture_srgb = qtrue;
|
||||
|
||||
ri.Printf(PRINT_ALL, result[glRefConfig.texture_srgb], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
glRefConfig.textureCompression = TCR_NONE;
|
||||
|
||||
// GL_EXT_texture_compression_latc
|
||||
extension = "GL_EXT_texture_compression_latc";
|
||||
if (GLimp_HaveExtension(extension))
|
||||
{
|
||||
if (r_ext_compressed_textures->integer)
|
||||
glRefConfig.textureCompression |= TCR_LATC;
|
||||
|
||||
ri.Printf(PRINT_ALL, result[r_ext_compressed_textures->integer ? 1 : 0], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_texture_compression_bptc
|
||||
extension = "GL_ARB_texture_compression_bptc";
|
||||
if (GLimp_HaveExtension(extension))
|
||||
{
|
||||
if (r_ext_compressed_textures->integer >= 2)
|
||||
glRefConfig.textureCompression |= TCR_BPTC;
|
||||
|
||||
ri.Printf(PRINT_ALL, result[(r_ext_compressed_textures->integer >= 2) ? 1 : 0], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_draw_buffers
|
||||
extension = "GL_ARB_draw_buffers";
|
||||
qglDrawBuffersARB = NULL;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
qglDrawBuffersARB = (void *) SDL_GL_GetProcAddress("glDrawBuffersARB");
|
||||
|
||||
ri.Printf(PRINT_ALL, result[1], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
|
||||
// GL_ARB_depth_clamp
|
||||
extension = "GL_ARB_depth_clamp";
|
||||
glRefConfig.depthClamp = qfalse;
|
||||
if( GLimp_HaveExtension( extension ) )
|
||||
{
|
||||
glRefConfig.depthClamp = qtrue;
|
||||
ri.Printf(PRINT_ALL, result[1], extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, result[2], extension);
|
||||
}
|
||||
}
|
240
code/renderergl2/tr_extramath.c
Normal file
240
code/renderergl2/tr_extramath.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2010 James Canete (use.less01@gmail.com)
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_extramath.c - extra math needed by the renderer not in qmath.c
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
// Some matrix helper functions
|
||||
// FIXME: do these already exist in ioq3 and I don't know about them?
|
||||
|
||||
void Matrix16Zero( matrix_t out )
|
||||
{
|
||||
out[ 0] = 0.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f;
|
||||
out[ 1] = 0.0f; out[ 5] = 0.0f; out[ 9] = 0.0f; out[13] = 0.0f;
|
||||
out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 0.0f; out[14] = 0.0f;
|
||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 0.0f;
|
||||
}
|
||||
|
||||
void Matrix16Identity( matrix_t out )
|
||||
{
|
||||
out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f;
|
||||
out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = 0.0f;
|
||||
out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = 0.0f;
|
||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix16Copy( const matrix_t in, matrix_t out )
|
||||
{
|
||||
out[ 0] = in[ 0]; out[ 4] = in[ 4]; out[ 8] = in[ 8]; out[12] = in[12];
|
||||
out[ 1] = in[ 1]; out[ 5] = in[ 5]; out[ 9] = in[ 9]; out[13] = in[13];
|
||||
out[ 2] = in[ 2]; out[ 6] = in[ 6]; out[10] = in[10]; out[14] = in[14];
|
||||
out[ 3] = in[ 3]; out[ 7] = in[ 7]; out[11] = in[11]; out[15] = in[15];
|
||||
}
|
||||
|
||||
void Matrix16Multiply( const matrix_t in1, const matrix_t in2, matrix_t out )
|
||||
{
|
||||
out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3];
|
||||
out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3];
|
||||
out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3];
|
||||
out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3];
|
||||
|
||||
out[ 4] = in1[ 0] * in2[ 4] + in1[ 4] * in2[ 5] + in1[ 8] * in2[ 6] + in1[12] * in2[ 7];
|
||||
out[ 5] = in1[ 1] * in2[ 4] + in1[ 5] * in2[ 5] + in1[ 9] * in2[ 6] + in1[13] * in2[ 7];
|
||||
out[ 6] = in1[ 2] * in2[ 4] + in1[ 6] * in2[ 5] + in1[10] * in2[ 6] + in1[14] * in2[ 7];
|
||||
out[ 7] = in1[ 3] * in2[ 4] + in1[ 7] * in2[ 5] + in1[11] * in2[ 6] + in1[15] * in2[ 7];
|
||||
|
||||
out[ 8] = in1[ 0] * in2[ 8] + in1[ 4] * in2[ 9] + in1[ 8] * in2[10] + in1[12] * in2[11];
|
||||
out[ 9] = in1[ 1] * in2[ 8] + in1[ 5] * in2[ 9] + in1[ 9] * in2[10] + in1[13] * in2[11];
|
||||
out[10] = in1[ 2] * in2[ 8] + in1[ 6] * in2[ 9] + in1[10] * in2[10] + in1[14] * in2[11];
|
||||
out[11] = in1[ 3] * in2[ 8] + in1[ 7] * in2[ 9] + in1[11] * in2[10] + in1[15] * in2[11];
|
||||
|
||||
out[12] = in1[ 0] * in2[12] + in1[ 4] * in2[13] + in1[ 8] * in2[14] + in1[12] * in2[15];
|
||||
out[13] = in1[ 1] * in2[12] + in1[ 5] * in2[13] + in1[ 9] * in2[14] + in1[13] * in2[15];
|
||||
out[14] = in1[ 2] * in2[12] + in1[ 6] * in2[13] + in1[10] * in2[14] + in1[14] * in2[15];
|
||||
out[15] = in1[ 3] * in2[12] + in1[ 7] * in2[13] + in1[11] * in2[14] + in1[15] * in2[15];
|
||||
}
|
||||
|
||||
void Matrix16Transform( const matrix_t in1, const vec4_t in2, vec4_t out )
|
||||
{
|
||||
out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3];
|
||||
out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3];
|
||||
out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3];
|
||||
out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3];
|
||||
}
|
||||
|
||||
qboolean Matrix16Compare( const matrix_t a, const matrix_t b )
|
||||
{
|
||||
return !(a[ 0] != b[ 0] || a[ 4] != b[ 4] || a[ 8] != b[ 8] || a[12] != b[12] ||
|
||||
a[ 1] != b[ 1] || a[ 5] != b[ 5] || a[ 9] != b[ 9] || a[13] != b[13] ||
|
||||
a[ 2] != b[ 2] || a[ 6] != b[ 6] || a[10] != b[10] || a[14] != b[14] ||
|
||||
a[ 3] != b[ 3] || a[ 7] != b[ 7] || a[11] != b[11] || a[15] != b[15]);
|
||||
}
|
||||
|
||||
void Matrix16Dump( const matrix_t in )
|
||||
{
|
||||
ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 0], in[ 4], in[ 8], in[12]);
|
||||
ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 1], in[ 5], in[ 9], in[13]);
|
||||
ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 2], in[ 6], in[10], in[14]);
|
||||
ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 3], in[ 7], in[11], in[15]);
|
||||
}
|
||||
|
||||
void Matrix16Translation( vec3_t vec, matrix_t out )
|
||||
{
|
||||
out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = vec[0];
|
||||
out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = vec[1];
|
||||
out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = vec[2];
|
||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix16Ortho( float left, float right, float bottom, float top, float znear, float zfar, matrix_t out )
|
||||
{
|
||||
out[ 0] = 2.0f / (right - left); out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = -(right + left) / (right - left);
|
||||
out[ 1] = 0.0f; out[ 5] = 2.0f / (top - bottom); out[ 9] = 0.0f; out[13] = -(top + bottom) / (top - bottom);
|
||||
out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 2.0f / (zfar - znear); out[14] = -(zfar + znear) / (zfar - znear);
|
||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix16View(vec3_t axes[3], vec3_t origin, matrix_t out)
|
||||
{
|
||||
out[0] = axes[0][0];
|
||||
out[1] = axes[1][0];
|
||||
out[2] = axes[2][0];
|
||||
out[3] = 0;
|
||||
|
||||
out[4] = axes[0][1];
|
||||
out[5] = axes[1][1];
|
||||
out[6] = axes[2][1];
|
||||
out[7] = 0;
|
||||
|
||||
out[8] = axes[0][2];
|
||||
out[9] = axes[1][2];
|
||||
out[10] = axes[2][2];
|
||||
out[11] = 0;
|
||||
|
||||
out[12] = -DotProduct(origin, axes[0]);
|
||||
out[13] = -DotProduct(origin, axes[1]);
|
||||
out[14] = -DotProduct(origin, axes[2]);
|
||||
out[15] = 1;
|
||||
}
|
||||
|
||||
void Matrix16SimpleInverse( const matrix_t in, matrix_t out)
|
||||
{
|
||||
vec3_t v;
|
||||
float invSqrLen;
|
||||
|
||||
VectorCopy(in + 0, v);
|
||||
invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
|
||||
out[ 0] = v[0]; out[ 4] = v[1]; out[ 8] = v[2]; out[12] = -DotProduct(v, &in[12]);
|
||||
|
||||
VectorCopy(in + 4, v);
|
||||
invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
|
||||
out[ 1] = v[0]; out[ 5] = v[1]; out[ 9] = v[2]; out[13] = -DotProduct(v, &in[12]);
|
||||
|
||||
VectorCopy(in + 8, v);
|
||||
invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
|
||||
out[ 2] = v[0]; out[ 6] = v[1]; out[10] = v[2]; out[14] = -DotProduct(v, &in[12]);
|
||||
|
||||
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
|
||||
}
|
||||
|
||||
void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c)
|
||||
{
|
||||
c[0] = a[0] * (1.0f - lerp) + b[0] * lerp;
|
||||
c[1] = a[1] * (1.0f - lerp) + b[1] * lerp;
|
||||
c[2] = a[2] * (1.0f - lerp) + b[2] * lerp;
|
||||
}
|
||||
|
||||
qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2)
|
||||
{
|
||||
float radiusSum = radius1 + radius2;
|
||||
vec3_t diff;
|
||||
|
||||
VectorSubtract(origin1, origin2, diff);
|
||||
|
||||
if (DotProduct(diff, diff) <= radiusSum * radiusSum)
|
||||
{
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3)
|
||||
{
|
||||
vec3_t diff;
|
||||
|
||||
VectorScale(origin1, 0.5f, origin3);
|
||||
VectorMA(origin3, 0.5f, origin2, origin3);
|
||||
|
||||
VectorSubtract(origin1, origin2, diff);
|
||||
*radius3 = VectorLength(diff) * 0.5f + MAX(radius1, radius2);
|
||||
}
|
||||
|
||||
int NextPowerOfTwo(int in)
|
||||
{
|
||||
int out;
|
||||
|
||||
for (out = 1; out < in; out <<= 1)
|
||||
;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
unsigned short FloatToHalf(float in)
|
||||
{
|
||||
unsigned short out;
|
||||
|
||||
union
|
||||
{
|
||||
float f;
|
||||
unsigned int i;
|
||||
} f32;
|
||||
|
||||
int sign, inExponent, inFraction;
|
||||
int outExponent, outFraction;
|
||||
|
||||
f32.f = in;
|
||||
|
||||
sign = (f32.i & 0x80000000) >> 31;
|
||||
inExponent = (f32.i & 0x7F800000) >> 23;
|
||||
inFraction = f32.i & 0x007FFFFF;
|
||||
|
||||
outExponent = CLAMP(inExponent - 127, -15, 16) + 15;
|
||||
|
||||
outFraction = 0;
|
||||
if (outExponent == 0x1F)
|
||||
{
|
||||
if (inExponent == 0xFF && inFraction != 0)
|
||||
outFraction = 0x3FF;
|
||||
}
|
||||
else if (outExponent == 0x00)
|
||||
{
|
||||
if (inExponent == 0x00 && inFraction != 0)
|
||||
outFraction = 0x3FF;
|
||||
}
|
||||
else
|
||||
outFraction = inFraction >> 13;
|
||||
|
||||
out = (sign << 15) | (outExponent << 10) | outFraction;
|
||||
|
||||
return out;
|
||||
}
|
105
code/renderergl2/tr_extramath.h
Normal file
105
code/renderergl2/tr_extramath.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2010 James Canete (use.less01@gmail.com)
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_extramath.h
|
||||
|
||||
#ifndef __TR_EXTRAMATH_H__
|
||||
#define __TR_EXTRAMATH_H__
|
||||
|
||||
typedef vec_t matrix_t[16];
|
||||
typedef int vec2i_t[2];
|
||||
typedef int vec3i_t[3];
|
||||
typedef int vec4i_t[4];
|
||||
|
||||
void Matrix16Zero( matrix_t out );
|
||||
void Matrix16Identity( matrix_t out );
|
||||
void Matrix16Copy( const matrix_t in, matrix_t out );
|
||||
void Matrix16Multiply( const matrix_t in1, const matrix_t in2, matrix_t out );
|
||||
void Matrix16Transform( const matrix_t in1, const vec4_t in2, vec4_t out );
|
||||
qboolean Matrix16Compare(const matrix_t a, const matrix_t b);
|
||||
void Matrix16Dump( const matrix_t in );
|
||||
void Matrix16Translation( vec3_t vec, matrix_t out );
|
||||
void Matrix16Ortho( float left, float right, float bottom, float top, float znear, float zfar, matrix_t out );
|
||||
void Matrix16View(vec3_t axes[3], vec3_t origin, matrix_t out);
|
||||
void Matrix16SimpleInverse( const matrix_t in, matrix_t out);
|
||||
|
||||
#define VectorCopy2(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1])
|
||||
#define VectorSet2(v,x,y) ((v)[0]=(x),(v)[1]=(y));
|
||||
|
||||
#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
|
||||
#define VectorSet4(v,x,y,z,w) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z),(v)[3]=(w))
|
||||
#define DotProduct4(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3])
|
||||
#define VectorScale4(a,b,c) ((c)[0]=(a)[0]*(b),(c)[1]=(a)[1]*(b),(c)[2]=(a)[2]*(b),(c)[3]=(a)[3]*(b))
|
||||
|
||||
#define VectorCopy5(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3],(b)[4]=(a)[4])
|
||||
|
||||
#define OffsetByteToFloat(a) ((float)(a) * 1.0f/127.5f - 1.0f)
|
||||
#define FloatToOffsetByte(a) (byte)(((a) + 1.0f) * 127.5f)
|
||||
#define ByteToFloat(a) ((float)(a) * 1.0f/255.0f)
|
||||
#define FloatToByte(a) (byte)((a) * 255.0f)
|
||||
|
||||
#define RGBtosRGB(a) (((a) < 0.0031308f) ? (12.92f * (a)) : (1.055f * pow((a), 0.41666f) - 0.055f))
|
||||
#define sRGBtoRGB(a) (((a) <= 0.04045f) ? ((a) / 12.92f) : (pow((((a) + 0.055f) / 1.055f), 2.4)) )
|
||||
|
||||
static ID_INLINE int VectorCompare4(const vec4_t v1, const vec4_t v2)
|
||||
{
|
||||
if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ID_INLINE int VectorCompare5(const vec5_t v1, const vec5_t v2)
|
||||
{
|
||||
if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3] || v1[4] != v2[4])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c);
|
||||
|
||||
|
||||
qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2);
|
||||
void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3);
|
||||
|
||||
#ifndef SGN
|
||||
#define SGN(x) (((x) >= 0) ? !!(x) : -1)
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef CLAMP
|
||||
#define CLAMP(a,b,c) MIN(MAX((a),(b)),(c))
|
||||
#endif
|
||||
|
||||
int NextPowerOfTwo(int in);
|
||||
unsigned short FloatToHalf(float in);
|
||||
|
||||
#endif
|
43
code/renderergl2/tr_extratypes.h
Normal file
43
code/renderergl2/tr_extratypes.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2009-2011 Andrei Drexler, Richard Allen, James Canete
|
||||
|
||||
This file is part of Reaction source code.
|
||||
|
||||
Reaction 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.
|
||||
|
||||
Reaction 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 Reaction source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __TR_EXTRATYPES_H__
|
||||
#define __TR_EXTRATYPES_H__
|
||||
|
||||
// tr_extratypes.h, for mods that want to extend tr_types.h without losing compatibility with original VMs
|
||||
|
||||
// extra renderfx flags start at 0x0400
|
||||
#define RF_SUNFLARE 0x0400
|
||||
|
||||
// extra refdef flags start at 0x0008
|
||||
#define RDF_NOFOG 0x0008 // don't apply fog
|
||||
#define RDF_EXTRA 0x0010 // Makro - refdefex_t to follow after refdef_t
|
||||
#define RDF_SUNLIGHT 0x0020 // SmileTheory - render sunlight and shadows
|
||||
|
||||
typedef struct {
|
||||
float blurFactor;
|
||||
float sunDir[3];
|
||||
float sunCol[3];
|
||||
float sunAmbCol[3];
|
||||
} refdefex_t;
|
||||
|
||||
#endif
|
861
code/renderergl2/tr_fbo.c
Normal file
861
code/renderergl2/tr_fbo.c
Normal file
|
@ -0,0 +1,861 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2006 Kirk Barnes
|
||||
Copyright (C) 2006-2008 Robert Beckebans <trebor_7@users.sourceforge.net>
|
||||
|
||||
This file is part of XreaL source code.
|
||||
|
||||
XreaL 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.
|
||||
|
||||
XreaL 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 XreaL source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_fbo.c
|
||||
#include "tr_local.h"
|
||||
|
||||
/*
|
||||
=============
|
||||
R_CheckFBO
|
||||
=============
|
||||
*/
|
||||
qboolean R_CheckFBO(const FBO_t * fbo)
|
||||
{
|
||||
int code;
|
||||
int id;
|
||||
|
||||
qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &id);
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
|
||||
|
||||
code = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
|
||||
if(code == GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
{
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
// an error occured
|
||||
switch (code)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Unsupported framebuffer format\n", fbo->name);
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete attachment\n", fbo->name);
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
|
||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing attachment\n", fbo->name);
|
||||
break;
|
||||
|
||||
//case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
|
||||
// ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, duplicate attachment\n", fbo->name);
|
||||
// break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
|
||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same dimensions\n",
|
||||
fbo->name);
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
|
||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same format\n",
|
||||
fbo->name);
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
|
||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing draw buffer\n", fbo->name);
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
|
||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing read buffer\n", fbo->name);
|
||||
break;
|
||||
|
||||
default:
|
||||
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code);
|
||||
//ri.Error(ERR_FATAL, "R_CheckFBO: (%s) unknown error 0x%X", fbo->name, code);
|
||||
//assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
FBO_Create
|
||||
============
|
||||
*/
|
||||
FBO_t *FBO_Create(const char *name, int width, int height)
|
||||
{
|
||||
FBO_t *fbo;
|
||||
|
||||
if(strlen(name) >= MAX_QPATH)
|
||||
{
|
||||
ri.Error(ERR_DROP, "FBO_Create: \"%s\" is too long\n", name);
|
||||
}
|
||||
|
||||
if(width <= 0 || width > glRefConfig.maxRenderbufferSize)
|
||||
{
|
||||
ri.Error(ERR_DROP, "FBO_Create: bad width %i", width);
|
||||
}
|
||||
|
||||
if(height <= 0 || height > glRefConfig.maxRenderbufferSize)
|
||||
{
|
||||
ri.Error(ERR_DROP, "FBO_Create: bad height %i", height);
|
||||
}
|
||||
|
||||
if(tr.numFBOs == MAX_FBOS)
|
||||
{
|
||||
ri.Error(ERR_DROP, "FBO_Create: MAX_FBOS hit");
|
||||
}
|
||||
|
||||
fbo = tr.fbos[tr.numFBOs] = ri.Hunk_Alloc(sizeof(*fbo), h_low);
|
||||
Q_strncpyz(fbo->name, name, sizeof(fbo->name));
|
||||
fbo->index = tr.numFBOs++;
|
||||
fbo->width = width;
|
||||
fbo->height = height;
|
||||
|
||||
qglGenFramebuffersEXT(1, &fbo->frameBuffer);
|
||||
|
||||
return fbo;
|
||||
}
|
||||
|
||||
void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
|
||||
{
|
||||
uint32_t *pRenderBuffer;
|
||||
GLenum attachment;
|
||||
qboolean absent;
|
||||
|
||||
switch(format)
|
||||
{
|
||||
case GL_RGB:
|
||||
case GL_RGBA:
|
||||
case GL_RGB8:
|
||||
case GL_RGBA8:
|
||||
case GL_RGB16F_ARB:
|
||||
case GL_RGBA16F_ARB:
|
||||
case GL_RGB32F_ARB:
|
||||
case GL_RGBA32F_ARB:
|
||||
fbo->colorFormat = format;
|
||||
pRenderBuffer = &fbo->colorBuffers[index];
|
||||
attachment = GL_COLOR_ATTACHMENT0_EXT + index;
|
||||
break;
|
||||
|
||||
case GL_DEPTH_COMPONENT:
|
||||
case GL_DEPTH_COMPONENT16_ARB:
|
||||
case GL_DEPTH_COMPONENT24_ARB:
|
||||
case GL_DEPTH_COMPONENT32_ARB:
|
||||
fbo->depthFormat = format;
|
||||
pRenderBuffer = &fbo->depthBuffer;
|
||||
attachment = GL_DEPTH_ATTACHMENT_EXT;
|
||||
break;
|
||||
|
||||
case GL_STENCIL_INDEX:
|
||||
case GL_STENCIL_INDEX1_EXT:
|
||||
case GL_STENCIL_INDEX4_EXT:
|
||||
case GL_STENCIL_INDEX8_EXT:
|
||||
case GL_STENCIL_INDEX16_EXT:
|
||||
fbo->stencilFormat = format;
|
||||
pRenderBuffer = &fbo->stencilBuffer;
|
||||
attachment = GL_STENCIL_ATTACHMENT_EXT;
|
||||
break;
|
||||
|
||||
case GL_DEPTH_STENCIL_EXT:
|
||||
case GL_DEPTH24_STENCIL8_EXT:
|
||||
fbo->packedDepthStencilFormat = format;
|
||||
pRenderBuffer = &fbo->packedDepthStencilBuffer;
|
||||
attachment = 0; // special for stencil and depth
|
||||
break;
|
||||
|
||||
default:
|
||||
ri.Printf(PRINT_WARNING, "FBO_CreateBuffer: invalid format %d\n", format);
|
||||
return;
|
||||
}
|
||||
|
||||
absent = *pRenderBuffer == 0;
|
||||
if (absent)
|
||||
qglGenRenderbuffersEXT(1, pRenderBuffer);
|
||||
|
||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *pRenderBuffer);
|
||||
if (multisample && glRefConfig.framebufferMultisample)
|
||||
{
|
||||
qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, multisample, format, fbo->width, fbo->height);
|
||||
}
|
||||
else
|
||||
{
|
||||
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fbo->width, fbo->height);
|
||||
}
|
||||
|
||||
if(absent)
|
||||
{
|
||||
if (attachment == 0)
|
||||
{
|
||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
|
||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
|
||||
}
|
||||
else
|
||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AttachFBOTexture1D
|
||||
=================
|
||||
*/
|
||||
void R_AttachFBOTexture1D(int texId, int index)
|
||||
{
|
||||
if(index < 0 || index >= glRefConfig.maxColorAttachments)
|
||||
{
|
||||
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture1D: invalid attachment index %i\n", index);
|
||||
return;
|
||||
}
|
||||
|
||||
qglFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_1D, texId, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AttachFBOTexture2D
|
||||
=================
|
||||
*/
|
||||
void R_AttachFBOTexture2D(int target, int texId, int index)
|
||||
{
|
||||
if(target != GL_TEXTURE_2D && (target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB))
|
||||
{
|
||||
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid target %i\n", target);
|
||||
return;
|
||||
}
|
||||
|
||||
if(index < 0 || index >= glRefConfig.maxColorAttachments)
|
||||
{
|
||||
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid attachment index %i\n", index);
|
||||
return;
|
||||
}
|
||||
|
||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, texId, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AttachFBOTexture3D
|
||||
=================
|
||||
*/
|
||||
void R_AttachFBOTexture3D(int texId, int index, int zOffset)
|
||||
{
|
||||
if(index < 0 || index >= glRefConfig.maxColorAttachments)
|
||||
{
|
||||
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture3D: invalid attachment index %i\n", index);
|
||||
return;
|
||||
}
|
||||
|
||||
qglFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_3D_EXT, texId, 0, zOffset);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AttachFBOTextureDepth
|
||||
=================
|
||||
*/
|
||||
void R_AttachFBOTextureDepth(int texId)
|
||||
{
|
||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AttachFBOTexturePackedDepthStencil
|
||||
=================
|
||||
*/
|
||||
void R_AttachFBOTexturePackedDepthStencil(int texId)
|
||||
{
|
||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
|
||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
|
||||
}
|
||||
|
||||
void FBO_AttachTextureImage(image_t *img, int index)
|
||||
{
|
||||
if (!glState.currentFBO)
|
||||
{
|
||||
ri.Printf(PRINT_WARNING, "FBO: attempted to attach a texture image with no FBO bound!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
R_AttachFBOTexture2D(GL_TEXTURE_2D, img->texnum, index);
|
||||
glState.currentFBO->colorImage[index] = img;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
FBO_Bind
|
||||
============
|
||||
*/
|
||||
void FBO_Bind(FBO_t * fbo)
|
||||
{
|
||||
if (glState.currentFBO == fbo)
|
||||
return;
|
||||
|
||||
if (r_logFile->integer)
|
||||
{
|
||||
// don't just call LogComment, or we will get a call to va() every frame!
|
||||
if (fbo)
|
||||
GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo->name));
|
||||
else
|
||||
GLimp_LogComment("--- FBO_Bind ( NULL ) ---\n");
|
||||
}
|
||||
|
||||
if (!fbo)
|
||||
{
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
//qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
glState.currentFBO = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
|
||||
|
||||
/*
|
||||
if(fbo->colorBuffers[0])
|
||||
{
|
||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->colorBuffers[0]);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
if(fbo->depthBuffer)
|
||||
{
|
||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->depthBuffer);
|
||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthBuffer);
|
||||
}
|
||||
*/
|
||||
|
||||
glState.currentFBO = fbo;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
FBO_Init
|
||||
============
|
||||
*/
|
||||
void FBO_Init(void)
|
||||
{
|
||||
int i;
|
||||
// int width, height, hdrFormat, multisample;
|
||||
int hdrFormat, multisample;
|
||||
|
||||
ri.Printf(PRINT_ALL, "------- FBO_Init -------\n");
|
||||
|
||||
if(!glRefConfig.framebufferObject)
|
||||
return;
|
||||
|
||||
tr.numFBOs = 0;
|
||||
|
||||
GL_CheckErrors();
|
||||
|
||||
R_IssuePendingRenderCommands();
|
||||
|
||||
/* if(glRefConfig.textureNonPowerOfTwo)
|
||||
{
|
||||
width = glConfig.vidWidth;
|
||||
height = glConfig.vidHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = NextPowerOfTwo(glConfig.vidWidth);
|
||||
height = NextPowerOfTwo(glConfig.vidHeight);
|
||||
} */
|
||||
|
||||
hdrFormat = GL_RGBA8;
|
||||
if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat)
|
||||
{
|
||||
hdrFormat = GL_RGB16F_ARB;
|
||||
}
|
||||
|
||||
qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample);
|
||||
|
||||
if (r_ext_framebuffer_multisample->integer < multisample)
|
||||
{
|
||||
multisample = r_ext_framebuffer_multisample->integer;
|
||||
}
|
||||
|
||||
if (multisample < 2 || !glRefConfig.framebufferBlit)
|
||||
multisample = 0;
|
||||
|
||||
if (multisample != r_ext_framebuffer_multisample->integer)
|
||||
{
|
||||
ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample);
|
||||
}
|
||||
|
||||
// only create a render FBO if we need to resolve MSAA or do HDR
|
||||
// otherwise just render straight to the screen (tr.renderFbo = NULL)
|
||||
if (multisample && glRefConfig.framebufferMultisample)
|
||||
{
|
||||
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
|
||||
FBO_Bind(tr.renderFbo);
|
||||
|
||||
FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample);
|
||||
FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample);
|
||||
|
||||
R_CheckFBO(tr.renderFbo);
|
||||
|
||||
|
||||
tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height);
|
||||
FBO_Bind(tr.msaaResolveFbo);
|
||||
|
||||
//FBO_CreateBuffer(tr.msaaResolveFbo, hdrFormat, 0, 0);
|
||||
FBO_AttachTextureImage(tr.renderImage, 0);
|
||||
|
||||
//FBO_CreateBuffer(tr.msaaResolveFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
||||
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
|
||||
|
||||
R_CheckFBO(tr.msaaResolveFbo);
|
||||
}
|
||||
else if (r_hdr->integer)
|
||||
{
|
||||
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
|
||||
FBO_Bind(tr.renderFbo);
|
||||
|
||||
//FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, 0);
|
||||
FBO_AttachTextureImage(tr.renderImage, 0);
|
||||
|
||||
//FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
||||
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
|
||||
|
||||
R_CheckFBO(tr.renderFbo);
|
||||
}
|
||||
|
||||
// clear render buffer
|
||||
// this fixes the corrupt screen bug with r_hdr 1 on older hardware
|
||||
if (tr.renderFbo)
|
||||
{
|
||||
FBO_Bind(tr.renderFbo);
|
||||
qglClearColor( 1, 0, 0.5, 1 );
|
||||
qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
FBO_Bind(NULL);
|
||||
}
|
||||
|
||||
if (r_drawSunRays->integer)
|
||||
{
|
||||
tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
|
||||
FBO_Bind(tr.sunRaysFbo);
|
||||
|
||||
FBO_AttachTextureImage(tr.sunRaysImage, 0);
|
||||
|
||||
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
|
||||
|
||||
R_CheckFBO(tr.sunRaysFbo);
|
||||
}
|
||||
|
||||
// FIXME: Don't use separate color/depth buffers for a shadow buffer
|
||||
for( i = 0; i < MAX_DRAWN_PSHADOWS; i++)
|
||||
{
|
||||
tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height);
|
||||
FBO_Bind(tr.pshadowFbos[i]);
|
||||
|
||||
//FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0);
|
||||
FBO_AttachTextureImage(tr.pshadowMaps[i], 0);
|
||||
|
||||
FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
||||
//R_AttachFBOTextureDepth(tr.textureDepthImage->texnum);
|
||||
|
||||
R_CheckFBO(tr.pshadowFbos[i]);
|
||||
}
|
||||
|
||||
for ( i = 0; i < 3; i++)
|
||||
{
|
||||
tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
|
||||
FBO_Bind(tr.sunShadowFbo[i]);
|
||||
|
||||
//FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0);
|
||||
//FBO_AttachTextureImage(tr.sunShadowImage, 0);
|
||||
qglDrawBuffer(GL_NONE);
|
||||
qglReadBuffer(GL_NONE);
|
||||
|
||||
//FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
||||
R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum);
|
||||
|
||||
R_CheckFBO(tr.sunShadowFbo[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
|
||||
FBO_Bind(tr.textureScratchFbo[i]);
|
||||
|
||||
//FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0);
|
||||
FBO_AttachTextureImage(tr.textureScratchImage[i], 0);
|
||||
|
||||
R_CheckFBO(tr.textureScratchFbo[i]);
|
||||
}
|
||||
|
||||
{
|
||||
tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
|
||||
FBO_Bind(tr.calcLevelsFbo);
|
||||
|
||||
//FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0);
|
||||
FBO_AttachTextureImage(tr.calcLevelsImage, 0);
|
||||
|
||||
R_CheckFBO(tr.calcLevelsFbo);
|
||||
}
|
||||
|
||||
{
|
||||
tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
|
||||
FBO_Bind(tr.targetLevelsFbo);
|
||||
|
||||
//FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0);
|
||||
FBO_AttachTextureImage(tr.targetLevelsImage, 0);
|
||||
|
||||
R_CheckFBO(tr.targetLevelsFbo);
|
||||
}
|
||||
|
||||
if (r_softOverbright->integer)
|
||||
{
|
||||
//tr.screenScratchFbo = FBO_Create("_screenscratch", width, height);
|
||||
tr.screenScratchFbo = FBO_Create("_screenscratch", tr.screenScratchImage->width, tr.screenScratchImage->height);
|
||||
FBO_Bind(tr.screenScratchFbo);
|
||||
|
||||
//FBO_CreateBuffer(tr.screenScratchFbo, format, 0, 0);
|
||||
FBO_AttachTextureImage(tr.screenScratchImage, 0);
|
||||
|
||||
// FIXME: hack: share zbuffer between render fbo and pre-screen fbo
|
||||
//FBO_CreateBuffer(tr.screenScratchFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
|
||||
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
|
||||
|
||||
R_CheckFBO(tr.screenScratchFbo);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
|
||||
FBO_Bind(tr.quarterFbo[i]);
|
||||
|
||||
//FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0);
|
||||
FBO_AttachTextureImage(tr.quarterImage[i], 0);
|
||||
|
||||
R_CheckFBO(tr.quarterFbo[i]);
|
||||
}
|
||||
|
||||
{
|
||||
tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
|
||||
FBO_Bind(tr.screenShadowFbo);
|
||||
|
||||
FBO_AttachTextureImage(tr.screenShadowImage, 0);
|
||||
|
||||
R_CheckFBO(tr.screenShadowFbo);
|
||||
}
|
||||
|
||||
if (r_ssao->integer)
|
||||
{
|
||||
tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height);
|
||||
FBO_Bind(tr.hdrDepthFbo);
|
||||
|
||||
FBO_AttachTextureImage(tr.hdrDepthImage, 0);
|
||||
|
||||
R_CheckFBO(tr.hdrDepthFbo);
|
||||
|
||||
tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
|
||||
FBO_Bind(tr.screenSsaoFbo);
|
||||
|
||||
FBO_AttachTextureImage(tr.screenSsaoImage, 0);
|
||||
|
||||
R_CheckFBO(tr.screenSsaoFbo);
|
||||
}
|
||||
|
||||
GL_CheckErrors();
|
||||
|
||||
FBO_Bind(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
FBO_Shutdown
|
||||
============
|
||||
*/
|
||||
void FBO_Shutdown(void)
|
||||
{
|
||||
int i, j;
|
||||
FBO_t *fbo;
|
||||
|
||||
ri.Printf(PRINT_ALL, "------- FBO_Shutdown -------\n");
|
||||
|
||||
if(!glRefConfig.framebufferObject)
|
||||
return;
|
||||
|
||||
FBO_Bind(NULL);
|
||||
|
||||
for(i = 0; i < tr.numFBOs; i++)
|
||||
{
|
||||
fbo = tr.fbos[i];
|
||||
|
||||
for(j = 0; j < glRefConfig.maxColorAttachments; j++)
|
||||
{
|
||||
if(fbo->colorBuffers[j])
|
||||
qglDeleteRenderbuffersEXT(1, &fbo->colorBuffers[j]);
|
||||
}
|
||||
|
||||
if(fbo->depthBuffer)
|
||||
qglDeleteRenderbuffersEXT(1, &fbo->depthBuffer);
|
||||
|
||||
if(fbo->stencilBuffer)
|
||||
qglDeleteRenderbuffersEXT(1, &fbo->stencilBuffer);
|
||||
|
||||
if(fbo->frameBuffer)
|
||||
qglDeleteFramebuffersEXT(1, &fbo->frameBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_FBOList_f
|
||||
============
|
||||
*/
|
||||
void R_FBOList_f(void)
|
||||
{
|
||||
int i;
|
||||
FBO_t *fbo;
|
||||
|
||||
if(!glRefConfig.framebufferObject)
|
||||
{
|
||||
ri.Printf(PRINT_ALL, "GL_EXT_framebuffer_object is not available.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ri.Printf(PRINT_ALL, " size name\n");
|
||||
ri.Printf(PRINT_ALL, "----------------------------------------------------------\n");
|
||||
|
||||
for(i = 0; i < tr.numFBOs; i++)
|
||||
{
|
||||
fbo = tr.fbos[i];
|
||||
|
||||
ri.Printf(PRINT_ALL, " %4i: %4i %4i %s\n", i, fbo->width, fbo->height, fbo->name);
|
||||
}
|
||||
|
||||
ri.Printf(PRINT_ALL, " %i FBOs\n", tr.numFBOs);
|
||||
}
|
||||
|
||||
// FIXME
|
||||
extern void RB_SetGL2D (void);
|
||||
|
||||
void FBO_BlitFromTexture(struct image_s *src, vec4i_t inSrcBox, vec2_t inSrcTexScale, FBO_t *dst, vec4i_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend)
|
||||
{
|
||||
vec4i_t dstBox, srcBox;
|
||||
vec2_t srcTexScale;
|
||||
vec4_t color;
|
||||
vec4_t quadVerts[4];
|
||||
vec2_t texCoords[4];
|
||||
vec2_t invTexRes;
|
||||
FBO_t *oldFbo = glState.currentFBO;
|
||||
matrix_t projection;
|
||||
int width, height;
|
||||
|
||||
if (!src)
|
||||
return;
|
||||
|
||||
if (inSrcBox)
|
||||
{
|
||||
VectorSet4(srcBox, inSrcBox[0], inSrcBox[1], inSrcBox[0] + inSrcBox[2], inSrcBox[1] + inSrcBox[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet4(srcBox, 0, 0, src->width, src->height);
|
||||
}
|
||||
|
||||
// framebuffers are 0 bottom, Y up.
|
||||
if (inDstBox)
|
||||
{
|
||||
if (dst)
|
||||
{
|
||||
dstBox[0] = inDstBox[0];
|
||||
dstBox[1] = dst->height - inDstBox[1] - inDstBox[3];
|
||||
dstBox[2] = inDstBox[0] + inDstBox[2];
|
||||
dstBox[3] = dst->height - inDstBox[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
dstBox[0] = inDstBox[0];
|
||||
dstBox[1] = glConfig.vidHeight - inDstBox[1] - inDstBox[3];
|
||||
dstBox[2] = inDstBox[0] + inDstBox[2];
|
||||
dstBox[3] = glConfig.vidHeight - inDstBox[1];
|
||||
}
|
||||
}
|
||||
else if (dst)
|
||||
{
|
||||
VectorSet4(dstBox, 0, dst->height, dst->width, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet4(dstBox, 0, glConfig.vidHeight, glConfig.vidWidth, 0);
|
||||
}
|
||||
|
||||
if (inSrcTexScale)
|
||||
{
|
||||
VectorCopy2(inSrcTexScale, srcTexScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
srcTexScale[0] = srcTexScale[1] = 1.0f;
|
||||
}
|
||||
|
||||
if (inColor)
|
||||
{
|
||||
VectorCopy4(inColor, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy4(colorWhite, color);
|
||||
}
|
||||
|
||||
if (!shaderProgram)
|
||||
{
|
||||
shaderProgram = &tr.textureColorShader;
|
||||
}
|
||||
|
||||
FBO_Bind(dst);
|
||||
|
||||
if (glState.currentFBO)
|
||||
{
|
||||
width = glState.currentFBO->width;
|
||||
height = glState.currentFBO->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = glConfig.vidWidth;
|
||||
height = glConfig.vidHeight;
|
||||
}
|
||||
|
||||
qglViewport( 0, 0, width, height );
|
||||
qglScissor( 0, 0, width, height );
|
||||
|
||||
Matrix16Ortho(0, width, height, 0, 0, 1, projection);
|
||||
|
||||
qglDisable( GL_CULL_FACE );
|
||||
|
||||
GL_BindToTMU(src, TB_COLORMAP);
|
||||
|
||||
VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0, 1);
|
||||
VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0, 1);
|
||||
VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0, 1);
|
||||
VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0, 1);
|
||||
|
||||
texCoords[0][0] = srcBox[0] / (float)src->width; texCoords[0][1] = 1.0f - srcBox[1] / (float)src->height;
|
||||
texCoords[1][0] = srcBox[2] / (float)src->width; texCoords[1][1] = 1.0f - srcBox[1] / (float)src->height;
|
||||
texCoords[2][0] = srcBox[2] / (float)src->width; texCoords[2][1] = 1.0f - srcBox[3] / (float)src->height;
|
||||
texCoords[3][0] = srcBox[0] / (float)src->width; texCoords[3][1] = 1.0f - srcBox[3] / (float)src->height;
|
||||
|
||||
invTexRes[0] = 1.0f / src->width * srcTexScale[0];
|
||||
invTexRes[1] = 1.0f / src->height * srcTexScale[1];
|
||||
|
||||
GL_State( blend );
|
||||
|
||||
GLSL_BindProgram(shaderProgram);
|
||||
|
||||
GLSL_SetUniformMatrix16(shaderProgram, UNIFORM_MODELVIEWPROJECTIONMATRIX, projection);
|
||||
GLSL_SetUniformVec4(shaderProgram, UNIFORM_COLOR, color);
|
||||
GLSL_SetUniformVec2(shaderProgram, UNIFORM_INVTEXRES, invTexRes);
|
||||
GLSL_SetUniformVec2(shaderProgram, UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax);
|
||||
GLSL_SetUniformVec3(shaderProgram, UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear);
|
||||
|
||||
RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
|
||||
|
||||
FBO_Bind(oldFbo);
|
||||
}
|
||||
|
||||
void FBO_Blit(FBO_t *src, vec4i_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, vec4i_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend)
|
||||
{
|
||||
vec4i_t srcBox;
|
||||
|
||||
if (!src)
|
||||
return;
|
||||
|
||||
// framebuffers are 0 bottom, Y up.
|
||||
if (inSrcBox)
|
||||
{
|
||||
srcBox[0] = inSrcBox[0];
|
||||
srcBox[1] = src->height - inSrcBox[1] - inSrcBox[3];
|
||||
srcBox[2] = inSrcBox[2];
|
||||
srcBox[3] = inSrcBox[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet4(srcBox, 0, src->height, src->width, -src->height);
|
||||
}
|
||||
|
||||
FBO_BlitFromTexture(src->colorImage[0], srcBox, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE);
|
||||
}
|
||||
|
||||
void FBO_FastBlit(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, int buffers, int filter)
|
||||
{
|
||||
vec4i_t srcBoxFinal, dstBoxFinal;
|
||||
GLuint srcFb, dstFb;
|
||||
|
||||
if (!glRefConfig.framebufferBlit)
|
||||
{
|
||||
FBO_Blit(src, srcBox, NULL, dst, dstBox, NULL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// get to a neutral state first
|
||||
//FBO_Bind(NULL);
|
||||
|
||||
srcFb = src ? src->frameBuffer : 0;
|
||||
dstFb = dst ? dst->frameBuffer : 0;
|
||||
|
||||
if (!srcBox)
|
||||
{
|
||||
if (src)
|
||||
{
|
||||
VectorSet4(srcBoxFinal, 0, 0, src->width, src->height);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet4(srcBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet4(srcBoxFinal, srcBox[0], srcBox[1], srcBox[0] + srcBox[2], srcBox[1] + srcBox[3]);
|
||||
}
|
||||
|
||||
if (!dstBox)
|
||||
{
|
||||
if (dst)
|
||||
{
|
||||
VectorSet4(dstBoxFinal, 0, 0, dst->width, dst->height);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet4(dstBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]);
|
||||
}
|
||||
|
||||
qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, srcFb);
|
||||
qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dstFb);
|
||||
qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3],
|
||||
dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3],
|
||||
buffers, filter);
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glState.currentFBO = NULL;
|
||||
}
|
64
code/renderergl2/tr_fbo.h
Normal file
64
code/renderergl2/tr_fbo.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2010 James Canete (use.less01@gmail.com)
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_fbo.h
|
||||
|
||||
#ifndef __TR_FBO_H__
|
||||
#define __TR_FBO_H__
|
||||
|
||||
struct image_s;
|
||||
struct shaderProgram_s;
|
||||
|
||||
typedef struct FBO_s
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
|
||||
int index;
|
||||
|
||||
uint32_t frameBuffer;
|
||||
|
||||
uint32_t colorBuffers[16];
|
||||
int colorFormat;
|
||||
struct image_s *colorImage[16];
|
||||
|
||||
uint32_t depthBuffer;
|
||||
int depthFormat;
|
||||
|
||||
uint32_t stencilBuffer;
|
||||
int stencilFormat;
|
||||
|
||||
uint32_t packedDepthStencilBuffer;
|
||||
int packedDepthStencilFormat;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
} FBO_t;
|
||||
|
||||
void FBO_Bind(FBO_t *fbo);
|
||||
void FBO_Init(void);
|
||||
void FBO_Shutdown(void);
|
||||
|
||||
void FBO_BlitFromTexture(struct image_s *src, vec4i_t srcBox, vec2_t srcTexScale, FBO_t *dst, vec4i_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend);
|
||||
void FBO_Blit(FBO_t *src, vec4i_t srcBox, vec2_t srcTexScale, FBO_t *dst, vec4i_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend);
|
||||
void FBO_FastBlit(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, int buffers, int filter);
|
||||
|
||||
|
||||
#endif
|
532
code/renderergl2/tr_flares.c
Normal file
532
code/renderergl2/tr_flares.c
Normal file
|
@ -0,0 +1,532 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_flares.c
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
LIGHT FLARES
|
||||
|
||||
A light flare is an effect that takes place inside the eye when bright light
|
||||
sources are visible. The size of the flare reletive to the screen is nearly
|
||||
constant, irrespective of distance, but the intensity should be proportional to the
|
||||
projected area of the light source.
|
||||
|
||||
A surface that has been flagged as having a light flare will calculate the depth
|
||||
buffer value that its midpoint should have when the surface is added.
|
||||
|
||||
After all opaque surfaces have been rendered, the depth buffer is read back for
|
||||
each flare in view. If the point has not been obscured by a closer surface, the
|
||||
flare should be drawn.
|
||||
|
||||
Surfaces that have a repeated texture should never be flagged as flaring, because
|
||||
there will only be a single flare added at the midpoint of the polygon.
|
||||
|
||||
To prevent abrupt popping, the intensity of the flare is interpolated up and
|
||||
down as it changes visibility. This involves scene to scene state, unlike almost
|
||||
all other aspects of the renderer, and is complicated by the fact that a single
|
||||
frame may have multiple scenes.
|
||||
|
||||
RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially
|
||||
up to five or more times in a frame with 3D status bar icons).
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
|
||||
// flare states maintain visibility over multiple frames for fading
|
||||
// layers: view, mirror, menu
|
||||
typedef struct flare_s {
|
||||
struct flare_s *next; // for active chain
|
||||
|
||||
int addedFrame;
|
||||
|
||||
qboolean inPortal; // true if in a portal view of the scene
|
||||
int frameSceneNum;
|
||||
void *surface;
|
||||
int fogNum;
|
||||
|
||||
int fadeTime;
|
||||
|
||||
qboolean visible; // state of last test
|
||||
float drawIntensity; // may be non 0 even if !visible due to fading
|
||||
|
||||
int windowX, windowY;
|
||||
float eyeZ;
|
||||
|
||||
vec3_t origin;
|
||||
vec3_t color;
|
||||
} flare_t;
|
||||
|
||||
#define MAX_FLARES 128
|
||||
|
||||
flare_t r_flareStructs[MAX_FLARES];
|
||||
flare_t *r_activeFlares, *r_inactiveFlares;
|
||||
|
||||
int flareCoeff;
|
||||
|
||||
/*
|
||||
==================
|
||||
R_ClearFlares
|
||||
==================
|
||||
*/
|
||||
void R_ClearFlares( void ) {
|
||||
int i;
|
||||
|
||||
Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) );
|
||||
r_activeFlares = NULL;
|
||||
r_inactiveFlares = NULL;
|
||||
|
||||
for ( i = 0 ; i < MAX_FLARES ; i++ ) {
|
||||
r_flareStructs[i].next = r_inactiveFlares;
|
||||
r_inactiveFlares = &r_flareStructs[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
RB_AddFlare
|
||||
|
||||
This is called at surface tesselation time
|
||||
==================
|
||||
*/
|
||||
void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) {
|
||||
int i;
|
||||
flare_t *f;
|
||||
vec3_t local;
|
||||
float d = 1;
|
||||
vec4_t eye, clip, normalized, window;
|
||||
|
||||
backEnd.pc.c_flareAdds++;
|
||||
|
||||
if(normal && (normal[0] || normal[1] || normal[2]))
|
||||
{
|
||||
VectorSubtract( backEnd.viewParms.or.origin, point, local );
|
||||
VectorNormalizeFast(local);
|
||||
d = DotProduct(local, normal);
|
||||
|
||||
// If the viewer is behind the flare don't add it.
|
||||
if(d < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// if the point is off the screen, don't bother adding it
|
||||
// calculate screen coordinates and depth
|
||||
R_TransformModelToClip( point, backEnd.or.modelMatrix,
|
||||
backEnd.viewParms.projectionMatrix, eye, clip );
|
||||
|
||||
// check to see if the point is completely off screen
|
||||
for ( i = 0 ; i < 3 ; i++ ) {
|
||||
if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );
|
||||
|
||||
if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
|
||||
|| window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
|
||||
return; // shouldn't happen, since we check the clip[] above, except for FP rounding
|
||||
}
|
||||
|
||||
// see if a flare with a matching surface, scene, and view exists
|
||||
for ( f = r_activeFlares ; f ; f = f->next ) {
|
||||
if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
|
||||
&& f->inPortal == backEnd.viewParms.isPortal ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate a new one
|
||||
if (!f ) {
|
||||
if ( !r_inactiveFlares ) {
|
||||
// the list is completely full
|
||||
return;
|
||||
}
|
||||
f = r_inactiveFlares;
|
||||
r_inactiveFlares = r_inactiveFlares->next;
|
||||
f->next = r_activeFlares;
|
||||
r_activeFlares = f;
|
||||
|
||||
f->surface = surface;
|
||||
f->frameSceneNum = backEnd.viewParms.frameSceneNum;
|
||||
f->inPortal = backEnd.viewParms.isPortal;
|
||||
f->addedFrame = -1;
|
||||
}
|
||||
|
||||
if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
|
||||
f->visible = qfalse;
|
||||
f->fadeTime = backEnd.refdef.time - 2000;
|
||||
}
|
||||
|
||||
f->addedFrame = backEnd.viewParms.frameCount;
|
||||
f->fogNum = fogNum;
|
||||
|
||||
VectorCopy(point, f->origin);
|
||||
VectorCopy( color, f->color );
|
||||
|
||||
// fade the intensity of the flare down as the
|
||||
// light surface turns away from the viewer
|
||||
VectorScale( f->color, d, f->color );
|
||||
|
||||
// save info needed to test
|
||||
f->windowX = backEnd.viewParms.viewportX + window[0];
|
||||
f->windowY = backEnd.viewParms.viewportY + window[1];
|
||||
|
||||
f->eyeZ = eye[2];
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
RB_AddDlightFlares
|
||||
==================
|
||||
*/
|
||||
void RB_AddDlightFlares( void ) {
|
||||
dlight_t *l;
|
||||
int i, j, k;
|
||||
fog_t *fog = NULL;
|
||||
|
||||
if ( !r_flares->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
l = backEnd.refdef.dlights;
|
||||
|
||||
if(tr.world)
|
||||
fog = tr.world->fogs;
|
||||
|
||||
for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) {
|
||||
|
||||
if(fog)
|
||||
{
|
||||
// find which fog volume the light is in
|
||||
for ( j = 1 ; j < tr.world->numfogs ; j++ ) {
|
||||
fog = &tr.world->fogs[j];
|
||||
for ( k = 0 ; k < 3 ; k++ ) {
|
||||
if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( k == 3 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( j == tr.world->numfogs ) {
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
j = 0;
|
||||
|
||||
RB_AddFlare( (void *)l, j, l->origin, l->color, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FLARE BACK END
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==================
|
||||
RB_TestFlare
|
||||
==================
|
||||
*/
|
||||
void RB_TestFlare( flare_t *f ) {
|
||||
float depth;
|
||||
qboolean visible;
|
||||
float fade;
|
||||
float screenZ;
|
||||
|
||||
backEnd.pc.c_flareTests++;
|
||||
|
||||
// doing a readpixels is as good as doing a glFinish(), so
|
||||
// don't bother with another sync
|
||||
glState.finishCalled = qfalse;
|
||||
|
||||
// read back the z buffer contents
|
||||
qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );
|
||||
|
||||
screenZ = backEnd.viewParms.projectionMatrix[14] /
|
||||
( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] );
|
||||
|
||||
visible = ( -f->eyeZ - -screenZ ) < 24;
|
||||
|
||||
if ( visible ) {
|
||||
if ( !f->visible ) {
|
||||
f->visible = qtrue;
|
||||
f->fadeTime = backEnd.refdef.time - 1;
|
||||
}
|
||||
fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value;
|
||||
} else {
|
||||
if ( f->visible ) {
|
||||
f->visible = qfalse;
|
||||
f->fadeTime = backEnd.refdef.time - 1;
|
||||
}
|
||||
fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value;
|
||||
}
|
||||
|
||||
if ( fade < 0 ) {
|
||||
fade = 0;
|
||||
}
|
||||
if ( fade > 1 ) {
|
||||
fade = 1;
|
||||
}
|
||||
|
||||
f->drawIntensity = fade;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
RB_RenderFlare
|
||||
==================
|
||||
*/
|
||||
void RB_RenderFlare( flare_t *f ) {
|
||||
float size;
|
||||
vec3_t color;
|
||||
int iColor[3];
|
||||
float distance, intensity, factor;
|
||||
byte fogFactors[3] = {255, 255, 255};
|
||||
|
||||
backEnd.pc.c_flareRenders++;
|
||||
|
||||
// We don't want too big values anyways when dividing by distance.
|
||||
if(f->eyeZ > -1.0f)
|
||||
distance = 1.0f;
|
||||
else
|
||||
distance = -f->eyeZ;
|
||||
|
||||
// calculate the flare size..
|
||||
size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance );
|
||||
|
||||
/*
|
||||
* This is an alternative to intensity scaling. It changes the size of the flare on screen instead
|
||||
* with growing distance. See in the description at the top why this is not the way to go.
|
||||
// size will change ~ 1/r.
|
||||
size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f));
|
||||
*/
|
||||
|
||||
/*
|
||||
* As flare sizes stay nearly constant with increasing distance we must decrease the intensity
|
||||
* to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be
|
||||
* got by considering the ratio of
|
||||
* (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare)
|
||||
* An important requirement is:
|
||||
* intensity <= 1 for all distances.
|
||||
*
|
||||
* The formula used here to compute the intensity is as follows:
|
||||
* intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2
|
||||
* As you can see, the intensity will have a max. of 1 when the distance is 0.
|
||||
* The coefficient flareCoeff will determine the falloff speed with increasing distance.
|
||||
*/
|
||||
|
||||
factor = distance + size * sqrt(flareCoeff);
|
||||
|
||||
intensity = flareCoeff * size * size / (factor * factor);
|
||||
|
||||
VectorScale(f->color, f->drawIntensity * intensity, color);
|
||||
|
||||
// Calculations for fogging
|
||||
if(tr.world && f->fogNum < tr.world->numfogs)
|
||||
{
|
||||
tess.numVertexes = 1;
|
||||
VectorCopy(f->origin, tess.xyz[0]);
|
||||
tess.fogNum = f->fogNum;
|
||||
|
||||
RB_CalcModulateColorsByFog(fogFactors);
|
||||
|
||||
// We don't need to render the flare if colors are 0 anyways.
|
||||
if(!(fogFactors[0] || fogFactors[1] || fogFactors[2]))
|
||||
return;
|
||||
}
|
||||
|
||||
iColor[0] = color[0] * fogFactors[0];
|
||||
iColor[1] = color[1] * fogFactors[1];
|
||||
iColor[2] = color[2] * fogFactors[2];
|
||||
|
||||
RB_BeginSurface( tr.flareShader, f->fogNum );
|
||||
|
||||
// FIXME: use quadstamp?
|
||||
tess.xyz[tess.numVertexes][0] = f->windowX - size;
|
||||
tess.xyz[tess.numVertexes][1] = f->windowY - size;
|
||||
tess.texCoords[tess.numVertexes][0][0] = 0;
|
||||
tess.texCoords[tess.numVertexes][0][1] = 0;
|
||||
tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][3] = 1.0f;
|
||||
tess.numVertexes++;
|
||||
|
||||
tess.xyz[tess.numVertexes][0] = f->windowX - size;
|
||||
tess.xyz[tess.numVertexes][1] = f->windowY + size;
|
||||
tess.texCoords[tess.numVertexes][0][0] = 0;
|
||||
tess.texCoords[tess.numVertexes][0][1] = 1;
|
||||
tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][3] = 1.0f;
|
||||
tess.numVertexes++;
|
||||
|
||||
tess.xyz[tess.numVertexes][0] = f->windowX + size;
|
||||
tess.xyz[tess.numVertexes][1] = f->windowY + size;
|
||||
tess.texCoords[tess.numVertexes][0][0] = 1;
|
||||
tess.texCoords[tess.numVertexes][0][1] = 1;
|
||||
tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][3] = 1.0f;
|
||||
tess.numVertexes++;
|
||||
|
||||
tess.xyz[tess.numVertexes][0] = f->windowX + size;
|
||||
tess.xyz[tess.numVertexes][1] = f->windowY - size;
|
||||
tess.texCoords[tess.numVertexes][0][0] = 1;
|
||||
tess.texCoords[tess.numVertexes][0][1] = 0;
|
||||
tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f;
|
||||
tess.vertexColors[tess.numVertexes][3] = 1.0f;
|
||||
tess.numVertexes++;
|
||||
|
||||
tess.indexes[tess.numIndexes++] = 0;
|
||||
tess.indexes[tess.numIndexes++] = 1;
|
||||
tess.indexes[tess.numIndexes++] = 2;
|
||||
tess.indexes[tess.numIndexes++] = 0;
|
||||
tess.indexes[tess.numIndexes++] = 2;
|
||||
tess.indexes[tess.numIndexes++] = 3;
|
||||
|
||||
RB_EndSurface();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
RB_RenderFlares
|
||||
|
||||
Because flares are simulating an occular effect, they should be drawn after
|
||||
everything (all views) in the entire frame has been drawn.
|
||||
|
||||
Because of the way portals use the depth buffer to mark off areas, the
|
||||
needed information would be lost after each view, so we are forced to draw
|
||||
flares after each view.
|
||||
|
||||
The resulting artifact is that flares in mirrors or portals don't dim properly
|
||||
when occluded by something in the main view, and portal flares that should
|
||||
extend past the portal edge will be overwritten.
|
||||
==================
|
||||
*/
|
||||
void RB_RenderFlares (void) {
|
||||
flare_t *f;
|
||||
flare_t **prev;
|
||||
qboolean draw;
|
||||
matrix_t oldmodelview, oldprojection, matrix;
|
||||
|
||||
if ( !r_flares->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(r_flareCoeff->modified)
|
||||
{
|
||||
if(r_flareCoeff->value == 0.0f)
|
||||
flareCoeff = atof(FLARE_STDCOEFF);
|
||||
else
|
||||
flareCoeff = r_flareCoeff->value;
|
||||
|
||||
r_flareCoeff->modified = qfalse;
|
||||
}
|
||||
|
||||
// Reset currentEntity to world so that any previously referenced entities
|
||||
// don't have influence on the rendering of these flares (i.e. RF_ renderer flags).
|
||||
backEnd.currentEntity = &tr.worldEntity;
|
||||
backEnd.or = backEnd.viewParms.world;
|
||||
|
||||
// RB_AddDlightFlares();
|
||||
|
||||
// perform z buffer readback on each flare in this view
|
||||
draw = qfalse;
|
||||
prev = &r_activeFlares;
|
||||
while ( ( f = *prev ) != NULL ) {
|
||||
// throw out any flares that weren't added last frame
|
||||
if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) {
|
||||
*prev = f->next;
|
||||
f->next = r_inactiveFlares;
|
||||
r_inactiveFlares = f;
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't draw any here that aren't from this scene / portal
|
||||
f->drawIntensity = 0;
|
||||
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
|
||||
&& f->inPortal == backEnd.viewParms.isPortal ) {
|
||||
RB_TestFlare( f );
|
||||
if ( f->drawIntensity ) {
|
||||
draw = qtrue;
|
||||
} else {
|
||||
// this flare has completely faded out, so remove it from the chain
|
||||
*prev = f->next;
|
||||
f->next = r_inactiveFlares;
|
||||
r_inactiveFlares = f;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
prev = &f->next;
|
||||
}
|
||||
|
||||
if ( !draw ) {
|
||||
return; // none visible
|
||||
}
|
||||
|
||||
if ( backEnd.viewParms.isPortal ) {
|
||||
qglDisable (GL_CLIP_PLANE0);
|
||||
}
|
||||
|
||||
Matrix16Copy(glState.projection, oldprojection);
|
||||
Matrix16Copy(glState.modelview, oldmodelview);
|
||||
Matrix16Identity(matrix);
|
||||
GL_SetModelviewMatrix(matrix);
|
||||
Matrix16Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
|
||||
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
|
||||
-99999, 99999, matrix );
|
||||
GL_SetProjectionMatrix(matrix);
|
||||
|
||||
for ( f = r_activeFlares ; f ; f = f->next ) {
|
||||
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
|
||||
&& f->inPortal == backEnd.viewParms.isPortal
|
||||
&& f->drawIntensity ) {
|
||||
RB_RenderFlare( f );
|
||||
}
|
||||
}
|
||||
|
||||
GL_SetProjectionMatrix(oldprojection);
|
||||
GL_SetModelviewMatrix(oldmodelview);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
1831
code/renderergl2/tr_glsl.c
Normal file
1831
code/renderergl2/tr_glsl.c
Normal file
File diff suppressed because it is too large
Load diff
3358
code/renderergl2/tr_image.c
Normal file
3358
code/renderergl2/tr_image.c
Normal file
File diff suppressed because it is too large
Load diff
1574
code/renderergl2/tr_init.c
Normal file
1574
code/renderergl2/tr_init.c
Normal file
File diff suppressed because it is too large
Load diff
451
code/renderergl2/tr_light.c
Normal file
451
code/renderergl2/tr_light.c
Normal file
|
@ -0,0 +1,451 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_light.c
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
#define DLIGHT_AT_RADIUS 16
|
||||
// at the edge of a dlight's influence, this amount of light will be added
|
||||
|
||||
#define DLIGHT_MINIMUM_RADIUS 16
|
||||
// never calculate a range less than this to prevent huge light numbers
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_TransformDlights
|
||||
|
||||
Transforms the origins of an array of dlights.
|
||||
Used by both the front end (for DlightBmodel) and
|
||||
the back end (before doing the lighting calculation)
|
||||
===============
|
||||
*/
|
||||
void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) {
|
||||
int i;
|
||||
vec3_t temp;
|
||||
|
||||
for ( i = 0 ; i < count ; i++, dl++ ) {
|
||||
VectorSubtract( dl->origin, or->origin, temp );
|
||||
dl->transformed[0] = DotProduct( temp, or->axis[0] );
|
||||
dl->transformed[1] = DotProduct( temp, or->axis[1] );
|
||||
dl->transformed[2] = DotProduct( temp, or->axis[2] );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_DlightBmodel
|
||||
|
||||
Determine which dynamic lights may effect this bmodel
|
||||
=============
|
||||
*/
|
||||
void R_DlightBmodel( bmodel_t *bmodel ) {
|
||||
int i, j;
|
||||
dlight_t *dl;
|
||||
int mask;
|
||||
msurface_t *surf;
|
||||
|
||||
// transform all the lights
|
||||
R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or );
|
||||
|
||||
mask = 0;
|
||||
for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {
|
||||
dl = &tr.refdef.dlights[i];
|
||||
|
||||
// see if the point is close enough to the bounds to matter
|
||||
for ( j = 0 ; j < 3 ; j++ ) {
|
||||
if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
|
||||
break;
|
||||
}
|
||||
if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( j < 3 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// we need to check this light
|
||||
mask |= 1 << i;
|
||||
}
|
||||
|
||||
tr.currentEntity->needDlights = (mask != 0);
|
||||
|
||||
// set the dlight bits in all the surfaces
|
||||
for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
|
||||
surf = tr.world->surfaces + bmodel->firstSurface + i;
|
||||
|
||||
if ( *surf->data == SF_FACE ) {
|
||||
((srfSurfaceFace_t *)surf->data)->dlightBits = mask;
|
||||
} else if ( *surf->data == SF_GRID ) {
|
||||
((srfGridMesh_t *)surf->data)->dlightBits = mask;
|
||||
} else if ( *surf->data == SF_TRIANGLES ) {
|
||||
((srfTriangles_t *)surf->data)->dlightBits = mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
LIGHT SAMPLING
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
extern cvar_t *r_ambientScale;
|
||||
extern cvar_t *r_directedScale;
|
||||
extern cvar_t *r_debugLight;
|
||||
|
||||
/*
|
||||
=================
|
||||
R_SetupEntityLightingGrid
|
||||
|
||||
=================
|
||||
*/
|
||||
static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) {
|
||||
vec3_t lightOrigin;
|
||||
int pos[3];
|
||||
int i, j;
|
||||
byte *gridData;
|
||||
float frac[3];
|
||||
int gridStep[3];
|
||||
vec3_t direction;
|
||||
float totalFactor;
|
||||
|
||||
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
|
||||
// seperate lightOrigins are needed so an object that is
|
||||
// sinking into the ground can still be lit, and so
|
||||
// multi-part models can be lit identically
|
||||
VectorCopy( ent->e.lightingOrigin, lightOrigin );
|
||||
} else {
|
||||
VectorCopy( ent->e.origin, lightOrigin );
|
||||
}
|
||||
|
||||
VectorSubtract( lightOrigin, world->lightGridOrigin, lightOrigin );
|
||||
for ( i = 0 ; i < 3 ; i++ ) {
|
||||
float v;
|
||||
|
||||
v = lightOrigin[i]*world->lightGridInverseSize[i];
|
||||
pos[i] = floor( v );
|
||||
frac[i] = v - pos[i];
|
||||
if ( pos[i] < 0 ) {
|
||||
pos[i] = 0;
|
||||
} else if ( pos[i] >= world->lightGridBounds[i] - 1 ) {
|
||||
pos[i] = world->lightGridBounds[i] - 1;
|
||||
}
|
||||
}
|
||||
|
||||
VectorClear( ent->ambientLight );
|
||||
VectorClear( ent->directedLight );
|
||||
VectorClear( direction );
|
||||
|
||||
assert( world->lightGridData ); // NULL with -nolight maps
|
||||
|
||||
// trilerp the light value
|
||||
gridStep[0] = 8;
|
||||
gridStep[1] = 8 * world->lightGridBounds[0];
|
||||
gridStep[2] = 8 * world->lightGridBounds[0] * world->lightGridBounds[1];
|
||||
gridData = world->lightGridData + pos[0] * gridStep[0]
|
||||
+ pos[1] * gridStep[1] + pos[2] * gridStep[2];
|
||||
|
||||
totalFactor = 0;
|
||||
for ( i = 0 ; i < 8 ; i++ ) {
|
||||
float factor;
|
||||
byte *data;
|
||||
int lat, lng;
|
||||
vec3_t normal;
|
||||
qboolean ignore;
|
||||
#if idppc
|
||||
float d0, d1, d2, d3, d4, d5;
|
||||
#endif
|
||||
factor = 1.0;
|
||||
data = gridData;
|
||||
ignore = qfalse;
|
||||
for ( j = 0 ; j < 3 ; j++ ) {
|
||||
if ( i & (1<<j) ) {
|
||||
if ((pos[j] + 1) >= world->lightGridBounds[j] - 1)
|
||||
{
|
||||
ignore = qtrue; // ignore values outside lightgrid
|
||||
}
|
||||
factor *= frac[j];
|
||||
data += gridStep[j];
|
||||
} else {
|
||||
factor *= (1.0f - frac[j]);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ignore )
|
||||
continue;
|
||||
|
||||
if (world->hdrLightGrid)
|
||||
{
|
||||
float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6;
|
||||
if (!(hdrData[0]+hdrData[1]+hdrData[2]+hdrData[3]+hdrData[4]+hdrData[5]) ) {
|
||||
continue; // ignore samples in walls
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]) ) {
|
||||
continue; // ignore samples in walls
|
||||
}
|
||||
}
|
||||
totalFactor += factor;
|
||||
#if idppc
|
||||
d0 = data[0]; d1 = data[1]; d2 = data[2];
|
||||
d3 = data[3]; d4 = data[4]; d5 = data[5];
|
||||
|
||||
ent->ambientLight[0] += factor * d0;
|
||||
ent->ambientLight[1] += factor * d1;
|
||||
ent->ambientLight[2] += factor * d2;
|
||||
|
||||
ent->directedLight[0] += factor * d3;
|
||||
ent->directedLight[1] += factor * d4;
|
||||
ent->directedLight[2] += factor * d5;
|
||||
#else
|
||||
if (world->hdrLightGrid)
|
||||
{
|
||||
// FIXME: this is hideous
|
||||
float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6;
|
||||
|
||||
ent->ambientLight[0] += factor * hdrData[0];
|
||||
ent->ambientLight[1] += factor * hdrData[1];
|
||||
ent->ambientLight[2] += factor * hdrData[2];
|
||||
|
||||
ent->directedLight[0] += factor * hdrData[3];
|
||||
ent->directedLight[1] += factor * hdrData[4];
|
||||
ent->directedLight[2] += factor * hdrData[5];
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->ambientLight[0] += factor * data[0];
|
||||
ent->ambientLight[1] += factor * data[1];
|
||||
ent->ambientLight[2] += factor * data[2];
|
||||
|
||||
ent->directedLight[0] += factor * data[3];
|
||||
ent->directedLight[1] += factor * data[4];
|
||||
ent->directedLight[2] += factor * data[5];
|
||||
}
|
||||
#endif
|
||||
lat = data[7];
|
||||
lng = data[6];
|
||||
lat *= (FUNCTABLE_SIZE/256);
|
||||
lng *= (FUNCTABLE_SIZE/256);
|
||||
|
||||
// decode X as cos( lat ) * sin( long )
|
||||
// decode Y as sin( lat ) * sin( long )
|
||||
// decode Z as cos( long )
|
||||
|
||||
normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
|
||||
normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
|
||||
normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
|
||||
|
||||
VectorMA( direction, factor, normal, direction );
|
||||
}
|
||||
|
||||
if ( totalFactor > 0 && totalFactor < 0.99 ) {
|
||||
totalFactor = 1.0f / totalFactor;
|
||||
VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
|
||||
VectorScale( ent->directedLight, totalFactor, ent->directedLight );
|
||||
}
|
||||
|
||||
VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
|
||||
VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
|
||||
|
||||
VectorNormalize2( direction, ent->lightDir );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
LogLight
|
||||
===============
|
||||
*/
|
||||
static void LogLight( trRefEntity_t *ent ) {
|
||||
int max1, max2;
|
||||
|
||||
if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
max1 = ent->ambientLight[0];
|
||||
if ( ent->ambientLight[1] > max1 ) {
|
||||
max1 = ent->ambientLight[1];
|
||||
} else if ( ent->ambientLight[2] > max1 ) {
|
||||
max1 = ent->ambientLight[2];
|
||||
}
|
||||
|
||||
max2 = ent->directedLight[0];
|
||||
if ( ent->directedLight[1] > max2 ) {
|
||||
max2 = ent->directedLight[1];
|
||||
} else if ( ent->directedLight[2] > max2 ) {
|
||||
max2 = ent->directedLight[2];
|
||||
}
|
||||
|
||||
ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_SetupEntityLighting
|
||||
|
||||
Calculates all the lighting values that will be used
|
||||
by the Calc_* functions
|
||||
=================
|
||||
*/
|
||||
void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
|
||||
int i;
|
||||
dlight_t *dl;
|
||||
float power;
|
||||
vec3_t dir;
|
||||
float d;
|
||||
vec3_t lightDir;
|
||||
vec3_t lightOrigin;
|
||||
|
||||
// lighting calculations
|
||||
if ( ent->lightingCalculated ) {
|
||||
return;
|
||||
}
|
||||
ent->lightingCalculated = qtrue;
|
||||
|
||||
//
|
||||
// trace a sample point down to find ambient light
|
||||
//
|
||||
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
|
||||
// seperate lightOrigins are needed so an object that is
|
||||
// sinking into the ground can still be lit, and so
|
||||
// multi-part models can be lit identically
|
||||
VectorCopy( ent->e.lightingOrigin, lightOrigin );
|
||||
} else {
|
||||
VectorCopy( ent->e.origin, lightOrigin );
|
||||
}
|
||||
|
||||
// if NOWORLDMODEL, only use dynamic lights (menu system, etc)
|
||||
if ( !(refdef->rdflags & RDF_NOWORLDMODEL )
|
||||
&& tr.world->lightGridData ) {
|
||||
R_SetupEntityLightingGrid( ent, tr.world );
|
||||
} else {
|
||||
ent->ambientLight[0] = ent->ambientLight[1] =
|
||||
ent->ambientLight[2] = tr.identityLight * 150;
|
||||
ent->directedLight[0] = ent->directedLight[1] =
|
||||
ent->directedLight[2] = tr.identityLight * 150;
|
||||
VectorCopy( tr.sunDirection, ent->lightDir );
|
||||
}
|
||||
|
||||
// bonus items and view weapons have a fixed minimum add
|
||||
if ( !r_hdr->integer /* ent->e.renderfx & RF_MINLIGHT */ ) {
|
||||
// give everything a minimum light add
|
||||
ent->ambientLight[0] += tr.identityLight * 32;
|
||||
ent->ambientLight[1] += tr.identityLight * 32;
|
||||
ent->ambientLight[2] += tr.identityLight * 32;
|
||||
}
|
||||
|
||||
//
|
||||
// modify the light by dynamic lights
|
||||
//
|
||||
d = VectorLength( ent->directedLight );
|
||||
VectorScale( ent->lightDir, d, lightDir );
|
||||
|
||||
for ( i = 0 ; i < refdef->num_dlights ; i++ ) {
|
||||
dl = &refdef->dlights[i];
|
||||
VectorSubtract( dl->origin, lightOrigin, dir );
|
||||
d = VectorNormalize( dir );
|
||||
|
||||
power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
|
||||
if ( d < DLIGHT_MINIMUM_RADIUS ) {
|
||||
d = DLIGHT_MINIMUM_RADIUS;
|
||||
}
|
||||
d = power / ( d * d );
|
||||
|
||||
VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
|
||||
VectorMA( lightDir, d, dir, lightDir );
|
||||
}
|
||||
|
||||
// clamp ambient
|
||||
if ( !r_hdr->integer )
|
||||
{
|
||||
for ( i = 0 ; i < 3 ; i++ ) {
|
||||
if ( ent->ambientLight[i] > tr.identityLightByte ) {
|
||||
ent->ambientLight[i] = tr.identityLightByte;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( r_debugLight->integer ) {
|
||||
LogLight( ent );
|
||||
}
|
||||
|
||||
// save out the byte packet version
|
||||
((byte *)&ent->ambientLightInt)[0] = ri.ftol(ent->ambientLight[0]);
|
||||
((byte *)&ent->ambientLightInt)[1] = ri.ftol(ent->ambientLight[1]);
|
||||
((byte *)&ent->ambientLightInt)[2] = ri.ftol(ent->ambientLight[2]);
|
||||
((byte *)&ent->ambientLightInt)[3] = 0xff;
|
||||
|
||||
// transform the direction to local space
|
||||
// no need to do this if using lightentity glsl shader
|
||||
VectorNormalize( lightDir );
|
||||
VectorCopy(lightDir, ent->lightDir);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_LightForPoint
|
||||
=================
|
||||
*/
|
||||
int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
|
||||
{
|
||||
trRefEntity_t ent;
|
||||
|
||||
if ( tr.world->lightGridData == NULL )
|
||||
return qfalse;
|
||||
|
||||
Com_Memset(&ent, 0, sizeof(ent));
|
||||
VectorCopy( point, ent.e.origin );
|
||||
R_SetupEntityLightingGrid( &ent, tr.world );
|
||||
VectorCopy(ent.ambientLight, ambientLight);
|
||||
VectorCopy(ent.directedLight, directedLight);
|
||||
VectorCopy(ent.lightDir, lightDir);
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
||||
int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world )
|
||||
{
|
||||
trRefEntity_t ent;
|
||||
|
||||
if ( world->lightGridData == NULL )
|
||||
return qfalse;
|
||||
|
||||
Com_Memset(&ent, 0, sizeof(ent));
|
||||
VectorCopy( point, ent.e.origin );
|
||||
R_SetupEntityLightingGrid( &ent, world );
|
||||
|
||||
if (DotProduct(ent.lightDir, normal) > 0.2f)
|
||||
VectorCopy(ent.lightDir, lightDir);
|
||||
else
|
||||
VectorCopy(normal, lightDir);
|
||||
|
||||
return qtrue;
|
||||
}
|
2680
code/renderergl2/tr_local.h
Normal file
2680
code/renderergl2/tr_local.h
Normal file
File diff suppressed because it is too large
Load diff
2876
code/renderergl2/tr_main.c
Normal file
2876
code/renderergl2/tr_main.c
Normal file
File diff suppressed because it is too large
Load diff
466
code/renderergl2/tr_marks.c
Normal file
466
code/renderergl2/tr_marks.c
Normal file
|
@ -0,0 +1,466 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_marks.c -- polygon projection on the world polygons
|
||||
|
||||
#include "tr_local.h"
|
||||
//#include "assert.h"
|
||||
|
||||
#define MAX_VERTS_ON_POLY 64
|
||||
|
||||
#define MARKER_OFFSET 0 // 1
|
||||
|
||||
/*
|
||||
=============
|
||||
R_ChopPolyBehindPlane
|
||||
|
||||
Out must have space for two more vertexes than in
|
||||
=============
|
||||
*/
|
||||
#define SIDE_FRONT 0
|
||||
#define SIDE_BACK 1
|
||||
#define SIDE_ON 2
|
||||
static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
|
||||
int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
|
||||
vec3_t normal, vec_t dist, vec_t epsilon) {
|
||||
float dists[MAX_VERTS_ON_POLY+4] = { 0 };
|
||||
int sides[MAX_VERTS_ON_POLY+4] = { 0 };
|
||||
int counts[3];
|
||||
float dot;
|
||||
int i, j;
|
||||
float *p1, *p2, *clip;
|
||||
float d;
|
||||
|
||||
// don't clip if it might overflow
|
||||
if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
|
||||
*numOutPoints = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine sides for each point
|
||||
for ( i = 0 ; i < numInPoints ; i++ ) {
|
||||
dot = DotProduct( inPoints[i], normal );
|
||||
dot -= dist;
|
||||
dists[i] = dot;
|
||||
if ( dot > epsilon ) {
|
||||
sides[i] = SIDE_FRONT;
|
||||
} else if ( dot < -epsilon ) {
|
||||
sides[i] = SIDE_BACK;
|
||||
} else {
|
||||
sides[i] = SIDE_ON;
|
||||
}
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
|
||||
*numOutPoints = 0;
|
||||
|
||||
if ( !counts[0] ) {
|
||||
return;
|
||||
}
|
||||
if ( !counts[1] ) {
|
||||
*numOutPoints = numInPoints;
|
||||
Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );
|
||||
return;
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < numInPoints ; i++ ) {
|
||||
p1 = inPoints[i];
|
||||
clip = outPoints[ *numOutPoints ];
|
||||
|
||||
if ( sides[i] == SIDE_ON ) {
|
||||
VectorCopy( p1, clip );
|
||||
(*numOutPoints)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( sides[i] == SIDE_FRONT ) {
|
||||
VectorCopy( p1, clip );
|
||||
(*numOutPoints)++;
|
||||
clip = outPoints[ *numOutPoints ];
|
||||
}
|
||||
|
||||
if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// generate a split point
|
||||
p2 = inPoints[ (i+1) % numInPoints ];
|
||||
|
||||
d = dists[i] - dists[i+1];
|
||||
if ( d == 0 ) {
|
||||
dot = 0;
|
||||
} else {
|
||||
dot = dists[i] / d;
|
||||
}
|
||||
|
||||
// clip xyz
|
||||
|
||||
for (j=0 ; j<3 ; j++) {
|
||||
clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
|
||||
}
|
||||
|
||||
(*numOutPoints)++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_BoxSurfaces_r
|
||||
|
||||
=================
|
||||
*/
|
||||
void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {
|
||||
|
||||
int s, c;
|
||||
msurface_t *surf;
|
||||
int *mark;
|
||||
|
||||
// do the tail recursion in a loop
|
||||
while ( node->contents == -1 ) {
|
||||
s = BoxOnPlaneSide( mins, maxs, node->plane );
|
||||
if (s == 1) {
|
||||
node = node->children[0];
|
||||
} else if (s == 2) {
|
||||
node = node->children[1];
|
||||
} else {
|
||||
R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);
|
||||
node = node->children[1];
|
||||
}
|
||||
}
|
||||
|
||||
// add the individual surfaces
|
||||
mark = tr.world->marksurfaces + node->firstmarksurface;
|
||||
c = node->nummarksurfaces;
|
||||
while (c--) {
|
||||
int *surfViewCount;
|
||||
//
|
||||
if (*listlength >= listsize) break;
|
||||
//
|
||||
surfViewCount = &tr.world->surfacesViewCount[*mark];
|
||||
surf = tr.world->surfaces + *mark;
|
||||
// check if the surface has NOIMPACT or NOMARKS set
|
||||
if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
|
||||
|| ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
|
||||
*surfViewCount = tr.viewCount;
|
||||
}
|
||||
// extra check for surfaces to avoid list overflows
|
||||
else if (*(surf->data) == SF_FACE) {
|
||||
// the face plane should go through the box
|
||||
s = BoxOnPlaneSide( mins, maxs, &surf->cullinfo.plane );
|
||||
if (s == 1 || s == 2) {
|
||||
*surfViewCount = tr.viewCount;
|
||||
} else if (DotProduct(surf->cullinfo.plane.normal, dir) > -0.5) {
|
||||
// don't add faces that make sharp angles with the projection direction
|
||||
*surfViewCount = tr.viewCount;
|
||||
}
|
||||
}
|
||||
else if (*(surf->data) != SF_GRID &&
|
||||
*(surf->data) != SF_TRIANGLES)
|
||||
*surfViewCount = tr.viewCount;
|
||||
// check the viewCount because the surface may have
|
||||
// already been added if it spans multiple leafs
|
||||
if (*surfViewCount != tr.viewCount) {
|
||||
*surfViewCount = tr.viewCount;
|
||||
list[*listlength] = surf->data;
|
||||
(*listlength)++;
|
||||
}
|
||||
mark++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AddMarkFragments
|
||||
|
||||
=================
|
||||
*/
|
||||
void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
|
||||
int numPlanes, vec3_t *normals, float *dists,
|
||||
int maxPoints, vec3_t pointBuffer,
|
||||
int maxFragments, markFragment_t *fragmentBuffer,
|
||||
int *returnedPoints, int *returnedFragments,
|
||||
vec3_t mins, vec3_t maxs) {
|
||||
int pingPong, i;
|
||||
markFragment_t *mf;
|
||||
|
||||
// chop the surface by all the bounding planes of the to be projected polygon
|
||||
pingPong = 0;
|
||||
|
||||
for ( i = 0 ; i < numPlanes ; i++ ) {
|
||||
|
||||
R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
|
||||
&numClipPoints, clipPoints[!pingPong],
|
||||
normals[i], dists[i], 0.5 );
|
||||
pingPong ^= 1;
|
||||
if ( numClipPoints == 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// completely clipped away?
|
||||
if ( numClipPoints == 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add this fragment to the returned list
|
||||
if ( numClipPoints + (*returnedPoints) > maxPoints ) {
|
||||
return; // not enough space for this polygon
|
||||
}
|
||||
/*
|
||||
// all the clip points should be within the bounding box
|
||||
for ( i = 0 ; i < numClipPoints ; i++ ) {
|
||||
int j;
|
||||
for ( j = 0 ; j < 3 ; j++ ) {
|
||||
if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
|
||||
if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
|
||||
}
|
||||
if (j < 3) break;
|
||||
}
|
||||
if (i < numClipPoints) return;
|
||||
*/
|
||||
|
||||
mf = fragmentBuffer + (*returnedFragments);
|
||||
mf->firstPoint = (*returnedPoints);
|
||||
mf->numPoints = numClipPoints;
|
||||
Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
|
||||
|
||||
(*returnedPoints) += numClipPoints;
|
||||
(*returnedFragments)++;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_MarkFragments
|
||||
|
||||
=================
|
||||
*/
|
||||
int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
|
||||
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
|
||||
int numsurfaces, numPlanes;
|
||||
int i, j, k, m, n;
|
||||
surfaceType_t *surfaces[64];
|
||||
vec3_t mins, maxs;
|
||||
int returnedFragments;
|
||||
int returnedPoints;
|
||||
vec3_t normals[MAX_VERTS_ON_POLY+2];
|
||||
float dists[MAX_VERTS_ON_POLY+2];
|
||||
vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
|
||||
int numClipPoints;
|
||||
float *v;
|
||||
srfGridMesh_t *cv;
|
||||
srfTriangle_t *tri;
|
||||
srfVert_t *dv;
|
||||
vec3_t normal;
|
||||
vec3_t projectionDir;
|
||||
vec3_t v1, v2;
|
||||
|
||||
if (numPoints <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//increment view count for double check prevention
|
||||
tr.viewCount++;
|
||||
|
||||
//
|
||||
VectorNormalize2( projection, projectionDir );
|
||||
// find all the brushes that are to be considered
|
||||
ClearBounds( mins, maxs );
|
||||
for ( i = 0 ; i < numPoints ; i++ ) {
|
||||
vec3_t temp;
|
||||
|
||||
AddPointToBounds( points[i], mins, maxs );
|
||||
VectorAdd( points[i], projection, temp );
|
||||
AddPointToBounds( temp, mins, maxs );
|
||||
// make sure we get all the leafs (also the one(s) in front of the hit surface)
|
||||
VectorMA( points[i], -20, projectionDir, temp );
|
||||
AddPointToBounds( temp, mins, maxs );
|
||||
}
|
||||
|
||||
if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
|
||||
// create the bounding planes for the to be projected polygon
|
||||
for ( i = 0 ; i < numPoints ; i++ ) {
|
||||
VectorSubtract(points[(i+1)%numPoints], points[i], v1);
|
||||
VectorAdd(points[i], projection, v2);
|
||||
VectorSubtract(points[i], v2, v2);
|
||||
CrossProduct(v1, v2, normals[i]);
|
||||
VectorNormalizeFast(normals[i]);
|
||||
dists[i] = DotProduct(normals[i], points[i]);
|
||||
}
|
||||
// add near and far clipping planes for projection
|
||||
VectorCopy(projectionDir, normals[numPoints]);
|
||||
dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
|
||||
VectorCopy(projectionDir, normals[numPoints+1]);
|
||||
VectorInverse(normals[numPoints+1]);
|
||||
dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
|
||||
numPlanes = numPoints + 2;
|
||||
|
||||
numsurfaces = 0;
|
||||
R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
|
||||
//assert(numsurfaces <= 64);
|
||||
//assert(numsurfaces != 64);
|
||||
|
||||
returnedPoints = 0;
|
||||
returnedFragments = 0;
|
||||
|
||||
for ( i = 0 ; i < numsurfaces ; i++ ) {
|
||||
|
||||
if (*surfaces[i] == SF_GRID) {
|
||||
|
||||
cv = (srfGridMesh_t *) surfaces[i];
|
||||
for ( m = 0 ; m < cv->height - 1 ; m++ ) {
|
||||
for ( n = 0 ; n < cv->width - 1 ; n++ ) {
|
||||
// We triangulate the grid and chop all triangles within
|
||||
// the bounding planes of the to be projected polygon.
|
||||
// LOD is not taken into account, not such a big deal though.
|
||||
//
|
||||
// It's probably much nicer to chop the grid itself and deal
|
||||
// with this grid as a normal SF_GRID surface so LOD will
|
||||
// be applied. However the LOD of that chopped grid must
|
||||
// be synced with the LOD of the original curve.
|
||||
// One way to do this; the chopped grid shares vertices with
|
||||
// the original curve. When LOD is applied to the original
|
||||
// curve the unused vertices are flagged. Now the chopped curve
|
||||
// should skip the flagged vertices. This still leaves the
|
||||
// problems with the vertices at the chopped grid edges.
|
||||
//
|
||||
// To avoid issues when LOD applied to "hollow curves" (like
|
||||
// the ones around many jump pads) we now just add a 2 unit
|
||||
// offset to the triangle vertices.
|
||||
// The offset is added in the vertex normal vector direction
|
||||
// so all triangles will still fit together.
|
||||
// The 2 unit offset should avoid pretty much all LOD problems.
|
||||
|
||||
numClipPoints = 3;
|
||||
|
||||
dv = cv->verts + m * cv->width + n;
|
||||
|
||||
VectorCopy(dv[0].xyz, clipPoints[0][0]);
|
||||
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
|
||||
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
|
||||
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
|
||||
VectorCopy(dv[1].xyz, clipPoints[0][2]);
|
||||
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
|
||||
// check the normal of this triangle
|
||||
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
|
||||
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
|
||||
CrossProduct(v1, v2, normal);
|
||||
VectorNormalizeFast(normal);
|
||||
if (DotProduct(normal, projectionDir) < -0.1) {
|
||||
// add the fragments of this triangle
|
||||
R_AddMarkFragments(numClipPoints, clipPoints,
|
||||
numPlanes, normals, dists,
|
||||
maxPoints, pointBuffer,
|
||||
maxFragments, fragmentBuffer,
|
||||
&returnedPoints, &returnedFragments, mins, maxs);
|
||||
|
||||
if ( returnedFragments == maxFragments ) {
|
||||
return returnedFragments; // not enough space for more fragments
|
||||
}
|
||||
}
|
||||
|
||||
VectorCopy(dv[1].xyz, clipPoints[0][0]);
|
||||
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
|
||||
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
|
||||
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
|
||||
VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
|
||||
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
|
||||
// check the normal of this triangle
|
||||
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
|
||||
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
|
||||
CrossProduct(v1, v2, normal);
|
||||
VectorNormalizeFast(normal);
|
||||
if (DotProduct(normal, projectionDir) < -0.05) {
|
||||
// add the fragments of this triangle
|
||||
R_AddMarkFragments(numClipPoints, clipPoints,
|
||||
numPlanes, normals, dists,
|
||||
maxPoints, pointBuffer,
|
||||
maxFragments, fragmentBuffer,
|
||||
&returnedPoints, &returnedFragments, mins, maxs);
|
||||
|
||||
if ( returnedFragments == maxFragments ) {
|
||||
return returnedFragments; // not enough space for more fragments
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*surfaces[i] == SF_FACE) {
|
||||
|
||||
srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i];
|
||||
|
||||
// check the normal of this face
|
||||
if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++)
|
||||
{
|
||||
for(j = 0; j < 3; j++)
|
||||
{
|
||||
v = surf->verts[tri->indexes[j]].xyz;
|
||||
VectorMA(v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j]);
|
||||
}
|
||||
|
||||
// add the fragments of this face
|
||||
R_AddMarkFragments( 3 , clipPoints,
|
||||
numPlanes, normals, dists,
|
||||
maxPoints, pointBuffer,
|
||||
maxFragments, fragmentBuffer,
|
||||
&returnedPoints, &returnedFragments, mins, maxs);
|
||||
if ( returnedFragments == maxFragments ) {
|
||||
return returnedFragments; // not enough space for more fragments
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
|
||||
|
||||
srfTriangles_t *surf = (srfTriangles_t *) surfaces[i];
|
||||
|
||||
for(k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++)
|
||||
{
|
||||
for(j = 0; j < 3; j++)
|
||||
{
|
||||
v = surf->verts[tri->indexes[j]].xyz;
|
||||
VectorMA(v, MARKER_OFFSET, surf->verts[tri->indexes[j]].normal, clipPoints[0][j]);
|
||||
}
|
||||
|
||||
// add the fragments of this face
|
||||
R_AddMarkFragments(3, clipPoints,
|
||||
numPlanes, normals, dists,
|
||||
maxPoints, pointBuffer,
|
||||
maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
|
||||
if(returnedFragments == maxFragments)
|
||||
{
|
||||
return returnedFragments; // not enough space for more fragments
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnedFragments;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
401
code/renderergl2/tr_mesh.c
Normal file
401
code/renderergl2/tr_mesh.c
Normal file
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_mesh.c: triangle model functions
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
static float ProjectRadius( float r, vec3_t location )
|
||||
{
|
||||
float pr;
|
||||
float dist;
|
||||
float c;
|
||||
vec3_t p;
|
||||
float projected[4];
|
||||
|
||||
c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin );
|
||||
dist = DotProduct( tr.viewParms.or.axis[0], location ) - c;
|
||||
|
||||
if ( dist <= 0 )
|
||||
return 0;
|
||||
|
||||
p[0] = 0;
|
||||
p[1] = fabs( r );
|
||||
p[2] = -dist;
|
||||
|
||||
projected[0] = p[0] * tr.viewParms.projectionMatrix[0] +
|
||||
p[1] * tr.viewParms.projectionMatrix[4] +
|
||||
p[2] * tr.viewParms.projectionMatrix[8] +
|
||||
tr.viewParms.projectionMatrix[12];
|
||||
|
||||
projected[1] = p[0] * tr.viewParms.projectionMatrix[1] +
|
||||
p[1] * tr.viewParms.projectionMatrix[5] +
|
||||
p[2] * tr.viewParms.projectionMatrix[9] +
|
||||
tr.viewParms.projectionMatrix[13];
|
||||
|
||||
projected[2] = p[0] * tr.viewParms.projectionMatrix[2] +
|
||||
p[1] * tr.viewParms.projectionMatrix[6] +
|
||||
p[2] * tr.viewParms.projectionMatrix[10] +
|
||||
tr.viewParms.projectionMatrix[14];
|
||||
|
||||
projected[3] = p[0] * tr.viewParms.projectionMatrix[3] +
|
||||
p[1] * tr.viewParms.projectionMatrix[7] +
|
||||
p[2] * tr.viewParms.projectionMatrix[11] +
|
||||
tr.viewParms.projectionMatrix[15];
|
||||
|
||||
|
||||
pr = projected[1] / projected[3];
|
||||
|
||||
if ( pr > 1.0f )
|
||||
pr = 1.0f;
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_CullModel
|
||||
=============
|
||||
*/
|
||||
static int R_CullModel( mdvModel_t *model, trRefEntity_t *ent ) {
|
||||
vec3_t bounds[2];
|
||||
mdvFrame_t *oldFrame, *newFrame;
|
||||
int i;
|
||||
|
||||
// compute frame pointers
|
||||
newFrame = model->frames + ent->e.frame;
|
||||
oldFrame = model->frames + ent->e.oldframe;
|
||||
|
||||
// cull bounding sphere ONLY if this is not an upscaled entity
|
||||
if ( !ent->e.nonNormalizedAxes )
|
||||
{
|
||||
if ( ent->e.frame == ent->e.oldframe )
|
||||
{
|
||||
switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
|
||||
{
|
||||
case CULL_OUT:
|
||||
tr.pc.c_sphere_cull_md3_out++;
|
||||
return CULL_OUT;
|
||||
|
||||
case CULL_IN:
|
||||
tr.pc.c_sphere_cull_md3_in++;
|
||||
return CULL_IN;
|
||||
|
||||
case CULL_CLIP:
|
||||
tr.pc.c_sphere_cull_md3_clip++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int sphereCull, sphereCullB;
|
||||
|
||||
sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
|
||||
if ( newFrame == oldFrame ) {
|
||||
sphereCullB = sphereCull;
|
||||
} else {
|
||||
sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
|
||||
}
|
||||
|
||||
if ( sphereCull == sphereCullB )
|
||||
{
|
||||
if ( sphereCull == CULL_OUT )
|
||||
{
|
||||
tr.pc.c_sphere_cull_md3_out++;
|
||||
return CULL_OUT;
|
||||
}
|
||||
else if ( sphereCull == CULL_IN )
|
||||
{
|
||||
tr.pc.c_sphere_cull_md3_in++;
|
||||
return CULL_IN;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.pc.c_sphere_cull_md3_clip++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate a bounding box in the current coordinate system
|
||||
for (i = 0 ; i < 3 ; i++) {
|
||||
bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
|
||||
bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
|
||||
}
|
||||
|
||||
switch ( R_CullLocalBox( bounds ) )
|
||||
{
|
||||
case CULL_IN:
|
||||
tr.pc.c_box_cull_md3_in++;
|
||||
return CULL_IN;
|
||||
case CULL_CLIP:
|
||||
tr.pc.c_box_cull_md3_clip++;
|
||||
return CULL_CLIP;
|
||||
case CULL_OUT:
|
||||
default:
|
||||
tr.pc.c_box_cull_md3_out++;
|
||||
return CULL_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
R_ComputeLOD
|
||||
|
||||
=================
|
||||
*/
|
||||
int R_ComputeLOD( trRefEntity_t *ent ) {
|
||||
float radius;
|
||||
float flod, lodscale;
|
||||
float projectedRadius;
|
||||
mdvFrame_t *frame;
|
||||
mdrHeader_t *mdr;
|
||||
mdrFrame_t *mdrframe;
|
||||
int lod;
|
||||
|
||||
if ( tr.currentModel->numLods < 2 )
|
||||
{
|
||||
// model has only 1 LOD level, skip computations and bias
|
||||
lod = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// multiple LODs exist, so compute projected bounding sphere
|
||||
// and use that as a criteria for selecting LOD
|
||||
|
||||
if(tr.currentModel->type == MOD_MDR)
|
||||
{
|
||||
int frameSize;
|
||||
mdr = (mdrHeader_t *) tr.currentModel->modelData;
|
||||
frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]);
|
||||
|
||||
mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame);
|
||||
|
||||
radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
//frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
|
||||
frame = tr.currentModel->mdv[0]->frames;
|
||||
|
||||
frame += ent->e.frame;
|
||||
|
||||
radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
|
||||
}
|
||||
|
||||
if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 )
|
||||
{
|
||||
lodscale = r_lodscale->value;
|
||||
if (lodscale > 20) lodscale = 20;
|
||||
flod = 1.0f - projectedRadius * lodscale;
|
||||
}
|
||||
else
|
||||
{
|
||||
// object intersects near view plane, e.g. view weapon
|
||||
flod = 0;
|
||||
}
|
||||
|
||||
flod *= tr.currentModel->numLods;
|
||||
lod = ri.ftol(flod);
|
||||
|
||||
if ( lod < 0 )
|
||||
{
|
||||
lod = 0;
|
||||
}
|
||||
else if ( lod >= tr.currentModel->numLods )
|
||||
{
|
||||
lod = tr.currentModel->numLods - 1;
|
||||
}
|
||||
}
|
||||
|
||||
lod += r_lodbias->integer;
|
||||
|
||||
if ( lod >= tr.currentModel->numLods )
|
||||
lod = tr.currentModel->numLods - 1;
|
||||
if ( lod < 0 )
|
||||
lod = 0;
|
||||
|
||||
return lod;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_ComputeFogNum
|
||||
|
||||
=================
|
||||
*/
|
||||
int R_ComputeFogNum( mdvModel_t *model, trRefEntity_t *ent ) {
|
||||
int i, j;
|
||||
fog_t *fog;
|
||||
mdvFrame_t *mdvFrame;
|
||||
vec3_t localOrigin;
|
||||
|
||||
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// FIXME: non-normalized axis issues
|
||||
mdvFrame = model->frames + ent->e.frame;
|
||||
VectorAdd( ent->e.origin, mdvFrame->localOrigin, localOrigin );
|
||||
for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
|
||||
fog = &tr.world->fogs[i];
|
||||
for ( j = 0 ; j < 3 ; j++ ) {
|
||||
if ( localOrigin[j] - mdvFrame->radius >= fog->bounds[1][j] ) {
|
||||
break;
|
||||
}
|
||||
if ( localOrigin[j] + mdvFrame->radius <= fog->bounds[0][j] ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( j == 3 ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AddMD3Surfaces
|
||||
|
||||
=================
|
||||
*/
|
||||
void R_AddMD3Surfaces( trRefEntity_t *ent ) {
|
||||
int i;
|
||||
mdvModel_t *model = NULL;
|
||||
mdvSurface_t *surface = NULL;
|
||||
shader_t *shader = NULL;
|
||||
int cull;
|
||||
int lod;
|
||||
int fogNum;
|
||||
qboolean personalModel;
|
||||
|
||||
// don't add third_person objects if not in a portal
|
||||
personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal
|
||||
|| (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)));
|
||||
|
||||
if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
|
||||
ent->e.frame %= tr.currentModel->mdv[0]->numFrames;
|
||||
ent->e.oldframe %= tr.currentModel->mdv[0]->numFrames;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate the frames so there is no chance of a crash.
|
||||
// This will write directly into the entity structure, so
|
||||
// when the surfaces are rendered, they don't need to be
|
||||
// range checked again.
|
||||
//
|
||||
if ( (ent->e.frame >= tr.currentModel->mdv[0]->numFrames)
|
||||
|| (ent->e.frame < 0)
|
||||
|| (ent->e.oldframe >= tr.currentModel->mdv[0]->numFrames)
|
||||
|| (ent->e.oldframe < 0) ) {
|
||||
ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n",
|
||||
ent->e.oldframe, ent->e.frame,
|
||||
tr.currentModel->name );
|
||||
ent->e.frame = 0;
|
||||
ent->e.oldframe = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// compute LOD
|
||||
//
|
||||
lod = R_ComputeLOD( ent );
|
||||
|
||||
model = tr.currentModel->mdv[lod];
|
||||
|
||||
//
|
||||
// cull the entire model if merged bounding box of both frames
|
||||
// is outside the view frustum.
|
||||
//
|
||||
cull = R_CullModel ( model, ent );
|
||||
if ( cull == CULL_OUT ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// set up lighting now that we know we aren't culled
|
||||
//
|
||||
if ( !personalModel || r_shadows->integer > 1 ) {
|
||||
R_SetupEntityLighting( &tr.refdef, ent );
|
||||
}
|
||||
|
||||
//
|
||||
// see if we are in a fog volume
|
||||
//
|
||||
fogNum = R_ComputeFogNum( model, ent );
|
||||
|
||||
//
|
||||
// draw all surfaces
|
||||
//
|
||||
surface = model->surfaces;
|
||||
for ( i = 0 ; i < model->numSurfaces ; i++ ) {
|
||||
|
||||
if ( ent->e.customShader ) {
|
||||
shader = R_GetShaderByHandle( ent->e.customShader );
|
||||
} else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) {
|
||||
skin_t *skin;
|
||||
int j;
|
||||
|
||||
skin = R_GetSkinByHandle( ent->e.customSkin );
|
||||
|
||||
// match the surface name to something in the skin file
|
||||
shader = tr.defaultShader;
|
||||
for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
|
||||
// the names have both been lowercased
|
||||
if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) {
|
||||
shader = skin->surfaces[j]->shader;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shader == tr.defaultShader) {
|
||||
ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name);
|
||||
}
|
||||
else if (shader->defaultShader) {
|
||||
ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
|
||||
}
|
||||
//} else if ( surface->numShaders <= 0 ) {
|
||||
//shader = tr.defaultShader;
|
||||
} else {
|
||||
//md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );
|
||||
//md3Shader += ent->e.skinNum % surface->numShaders;
|
||||
//shader = tr.shaders[ md3Shader->shaderIndex ];
|
||||
shader = tr.shaders[ surface->shaderIndexes[ ent->e.skinNum % surface->numShaderIndexes ] ];
|
||||
}
|
||||
|
||||
// don't add third_person objects if not viewing through a portal
|
||||
if(!personalModel)
|
||||
{
|
||||
srfVBOMDVMesh_t *vboSurface = &model->vboSurfaces[i];
|
||||
|
||||
R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse );
|
||||
}
|
||||
|
||||
surface++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
1569
code/renderergl2/tr_model.c
Normal file
1569
code/renderergl2/tr_model.c
Normal file
File diff suppressed because it is too large
Load diff
1110
code/renderergl2/tr_model_iqm.c
Normal file
1110
code/renderergl2/tr_model_iqm.c
Normal file
File diff suppressed because it is too large
Load diff
503
code/renderergl2/tr_postprocess.c
Normal file
503
code/renderergl2/tr_postprocess.c
Normal file
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete
|
||||
|
||||
This file is part of Reaction source code.
|
||||
|
||||
Reaction 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.
|
||||
|
||||
Reaction 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 Reaction source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
void RB_ToneMap(FBO_t *hdrFbo, vec4i_t hdrBox, FBO_t *ldrFbo, vec4i_t ldrBox, int autoExposure)
|
||||
{
|
||||
vec4i_t srcBox, dstBox;
|
||||
vec4_t color;
|
||||
static int lastFrameCount = 0;
|
||||
|
||||
if (autoExposure)
|
||||
{
|
||||
if (lastFrameCount == 0 || tr.frameCount < lastFrameCount || tr.frameCount - lastFrameCount > 5)
|
||||
{
|
||||
// determine average log luminance
|
||||
FBO_t *srcFbo, *dstFbo, *tmp;
|
||||
int size = 256;
|
||||
|
||||
lastFrameCount = tr.frameCount;
|
||||
|
||||
VectorSet4(dstBox, 0, 0, size, size);
|
||||
|
||||
FBO_Blit(hdrFbo, hdrBox, NULL, tr.textureScratchFbo[0], dstBox, &tr.calclevels4xShader[0], NULL, 0);
|
||||
|
||||
srcFbo = tr.textureScratchFbo[0];
|
||||
dstFbo = tr.textureScratchFbo[1];
|
||||
|
||||
// downscale to 1x1 texture
|
||||
while (size > 1)
|
||||
{
|
||||
VectorSet4(srcBox, 0, 0, size, size);
|
||||
//size >>= 2;
|
||||
size >>= 1;
|
||||
VectorSet4(dstBox, 0, 0, size, size);
|
||||
|
||||
if (size == 1)
|
||||
dstFbo = tr.targetLevelsFbo;
|
||||
|
||||
//FBO_Blit(targetFbo, srcBox, NULL, tr.textureScratchFbo[nextScratch], dstBox, &tr.calclevels4xShader[1], NULL, 0);
|
||||
FBO_FastBlit(srcFbo, srcBox, dstFbo, dstBox, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
tmp = srcFbo;
|
||||
srcFbo = dstFbo;
|
||||
dstFbo = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// blend with old log luminance for gradual change
|
||||
VectorSet4(srcBox, 0, 0, 0, 0);
|
||||
|
||||
color[0] =
|
||||
color[1] =
|
||||
color[2] = 1.0f;
|
||||
if (glRefConfig.textureFloat)
|
||||
color[3] = 0.03f;
|
||||
else
|
||||
color[3] = 0.1f;
|
||||
|
||||
FBO_Blit(tr.targetLevelsFbo, srcBox, NULL, tr.calcLevelsFbo, NULL, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
// tonemap
|
||||
color[0] =
|
||||
color[1] =
|
||||
color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value);
|
||||
color[3] = 1.0f;
|
||||
|
||||
if (autoExposure)
|
||||
GL_BindToTMU(tr.calcLevelsImage, TB_LEVELSMAP);
|
||||
else
|
||||
GL_BindToTMU(tr.fixedLevelsImage, TB_LEVELSMAP);
|
||||
|
||||
FBO_Blit(hdrFbo, hdrBox, NULL, ldrFbo, ldrBox, &tr.tonemapShader, color, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RB_BokehBlur
|
||||
|
||||
|
||||
Blurs a part of one framebuffer to another.
|
||||
|
||||
Framebuffers can be identical.
|
||||
=============
|
||||
*/
|
||||
void RB_BokehBlur(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, float blur)
|
||||
{
|
||||
// vec4i_t srcBox, dstBox;
|
||||
vec4_t color;
|
||||
|
||||
blur *= 10.0f;
|
||||
|
||||
if (blur < 0.004f)
|
||||
return;
|
||||
|
||||
if (glRefConfig.framebufferObject)
|
||||
{
|
||||
// bokeh blur
|
||||
if (blur > 0.0f)
|
||||
{
|
||||
vec4i_t quarterBox;
|
||||
|
||||
quarterBox[0] = 0;
|
||||
quarterBox[1] = tr.quarterFbo[0]->height;
|
||||
quarterBox[2] = tr.quarterFbo[0]->width;
|
||||
quarterBox[3] = -tr.quarterFbo[0]->height;
|
||||
|
||||
// create a quarter texture
|
||||
//FBO_Blit(NULL, NULL, NULL, tr.quarterFbo[0], NULL, NULL, NULL, 0);
|
||||
FBO_FastBlit(src, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
}
|
||||
|
||||
#ifndef HQ_BLUR
|
||||
if (blur > 1.0f)
|
||||
{
|
||||
// create a 1/16th texture
|
||||
//FBO_Blit(tr.quarterFbo[0], NULL, NULL, tr.textureScratchFbo[0], NULL, NULL, NULL, 0);
|
||||
FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (blur > 0.0f && blur <= 1.0f)
|
||||
{
|
||||
// Crossfade original with quarter texture
|
||||
VectorSet4(color, 1, 1, 1, blur);
|
||||
|
||||
FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
#ifndef HQ_BLUR
|
||||
// ok blur, but can see some pixelization
|
||||
else if (blur > 1.0f && blur <= 2.0f)
|
||||
{
|
||||
// crossfade quarter texture with 1/16th texture
|
||||
FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, NULL, 0);
|
||||
|
||||
VectorSet4(color, 1, 1, 1, blur - 1.0f);
|
||||
|
||||
FBO_Blit(tr.textureScratchFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
else if (blur > 2.0f)
|
||||
{
|
||||
// blur 1/16th texture then replace
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
vec2_t blurTexScale;
|
||||
float subblur;
|
||||
|
||||
subblur = ((blur - 2.0f) / 2.0f) / 3.0f * (float)(i + 1);
|
||||
|
||||
blurTexScale[0] =
|
||||
blurTexScale[1] = subblur;
|
||||
|
||||
color[0] =
|
||||
color[1] =
|
||||
color[2] = 0.5f;
|
||||
color[3] = 1.0f;
|
||||
|
||||
if (i != 0)
|
||||
FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
|
||||
else
|
||||
FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0);
|
||||
}
|
||||
|
||||
FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0);
|
||||
}
|
||||
#else // higher quality blur, but slower
|
||||
else if (blur > 1.0f)
|
||||
{
|
||||
// blur quarter texture then replace
|
||||
int i;
|
||||
|
||||
src = tr.quarterFbo[0];
|
||||
dst = tr.quarterFbo[1];
|
||||
|
||||
VectorSet4(color, 0.5f, 0.5f, 0.5f, 1);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
vec2_t blurTexScale;
|
||||
float subblur;
|
||||
|
||||
subblur = (blur - 1.0f) / 2.0f * (float)(i + 1);
|
||||
|
||||
blurTexScale[0] =
|
||||
blurTexScale[1] = subblur;
|
||||
|
||||
color[0] =
|
||||
color[1] =
|
||||
color[2] = 1.0f;
|
||||
if (i != 0)
|
||||
color[3] = 1.0f;
|
||||
else
|
||||
color[3] = 0.5f;
|
||||
|
||||
FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha)
|
||||
{
|
||||
vec4i_t srcBox, dstBox;
|
||||
vec4_t color;
|
||||
const float inc = 1.f / passes;
|
||||
const float mul = powf(stretch, inc);
|
||||
float scale;
|
||||
|
||||
{
|
||||
vec2_t texScale;
|
||||
|
||||
texScale[0] =
|
||||
texScale[1] = 1.0f;
|
||||
|
||||
alpha *= inc;
|
||||
VectorSet4(color, alpha, alpha, alpha, 1.0f);
|
||||
|
||||
VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
|
||||
VectorSet4(dstBox, x, y, w, h);
|
||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0);
|
||||
|
||||
--passes;
|
||||
scale = mul;
|
||||
while (passes > 0)
|
||||
{
|
||||
float iscale = 1.f / scale;
|
||||
float s0 = xcenter * (1.f - iscale);
|
||||
float t0 = (1.0f - ycenter) * (1.f - iscale);
|
||||
float s1 = iscale + s0;
|
||||
float t1 = iscale + t0;
|
||||
|
||||
srcBox[0] = s0 * srcFbo->width;
|
||||
srcBox[1] = t0 * srcFbo->height;
|
||||
srcBox[2] = (s1 - s0) * srcFbo->width;
|
||||
srcBox[3] = (t1 - t0) * srcFbo->height;
|
||||
|
||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
|
||||
scale *= mul;
|
||||
--passes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static qboolean RB_UpdateSunFlareVis(void)
|
||||
{
|
||||
GLuint sampleCount = 0;
|
||||
if (!glRefConfig.occlusionQuery)
|
||||
return qtrue;
|
||||
|
||||
tr.sunFlareQueryIndex ^= 1;
|
||||
if (!tr.sunFlareQueryActive[tr.sunFlareQueryIndex])
|
||||
return qtrue;
|
||||
|
||||
/* debug code */
|
||||
if (0)
|
||||
{
|
||||
int iter;
|
||||
for (iter=0 ; ; ++iter)
|
||||
{
|
||||
GLint available = 0;
|
||||
qglGetQueryObjectivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
|
||||
if (available)
|
||||
break;
|
||||
}
|
||||
|
||||
ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter);
|
||||
}
|
||||
|
||||
qglGetQueryObjectuivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_ARB, &sampleCount);
|
||||
return sampleCount > 0;
|
||||
}
|
||||
|
||||
void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox)
|
||||
{
|
||||
vec4_t color;
|
||||
float dot;
|
||||
const float cutoff = 0.25f;
|
||||
qboolean colorize = qtrue;
|
||||
|
||||
// float w, h, w2, h2;
|
||||
matrix_t mvp;
|
||||
vec4_t pos, hpos;
|
||||
|
||||
dot = DotProduct(tr.sunDirection, backEnd.viewParms.or.axis[0]);
|
||||
if (dot < cutoff)
|
||||
return;
|
||||
|
||||
if (!RB_UpdateSunFlareVis())
|
||||
return;
|
||||
|
||||
// From RB_DrawSun()
|
||||
{
|
||||
float dist;
|
||||
matrix_t trans, model, mvp;
|
||||
|
||||
Matrix16Translation( backEnd.viewParms.or.origin, trans );
|
||||
Matrix16Multiply( backEnd.viewParms.world.modelMatrix, trans, model );
|
||||
Matrix16Multiply(backEnd.viewParms.projectionMatrix, model, mvp);
|
||||
|
||||
dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
|
||||
|
||||
VectorScale( tr.sunDirection, dist, pos );
|
||||
}
|
||||
|
||||
// project sun point
|
||||
//Matrix16Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp);
|
||||
Matrix16Transform(mvp, pos, hpos);
|
||||
|
||||
// transform to UV coords
|
||||
hpos[3] = 0.5f / hpos[3];
|
||||
|
||||
pos[0] = 0.5f + hpos[0] * hpos[3];
|
||||
pos[1] = 0.5f + hpos[1] * hpos[3];
|
||||
|
||||
// initialize quarter buffers
|
||||
{
|
||||
float mul = 1.f;
|
||||
vec2_t texScale;
|
||||
vec4i_t rayBox, quarterBox;
|
||||
|
||||
texScale[0] =
|
||||
texScale[1] = 1.0f;
|
||||
|
||||
VectorSet4(color, mul, mul, mul, 1);
|
||||
|
||||
rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcFbo->width;
|
||||
rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcFbo->height;
|
||||
rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcFbo->width;
|
||||
rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcFbo->height;
|
||||
|
||||
quarterBox[0] = 0;
|
||||
quarterBox[1] = tr.quarterFbo[0]->height;
|
||||
quarterBox[2] = tr.quarterFbo[0]->width;
|
||||
quarterBox[3] = -tr.quarterFbo[0]->height;
|
||||
|
||||
// first, downsample the framebuffer
|
||||
if (colorize)
|
||||
{
|
||||
FBO_FastBlit(srcFbo, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
FBO_Blit(tr.sunRaysFbo, rayBox, NULL, tr.quarterFbo[0], quarterBox, NULL, color, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);
|
||||
}
|
||||
else
|
||||
{
|
||||
FBO_FastBlit(tr.sunRaysFbo, rayBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
// radial blur passes, ping-ponging between the two quarter-size buffers
|
||||
{
|
||||
const float stretch_add = 2.f/3.f;
|
||||
float stretch = 1.f + stretch_add;
|
||||
int i;
|
||||
for (i=0; i<2; ++i)
|
||||
{
|
||||
RB_RadialBlur(tr.quarterFbo[i&1], tr.quarterFbo[(~i) & 1], 5, stretch, 0.f, 0.f, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height, pos[0], pos[1], 1.125f);
|
||||
stretch += stretch_add;
|
||||
}
|
||||
}
|
||||
|
||||
// add result back on top of the main buffer
|
||||
{
|
||||
float mul = 1.f;
|
||||
vec2_t texScale;
|
||||
|
||||
texScale[0] =
|
||||
texScale[1] = 1.0f;
|
||||
|
||||
VectorSet4(color, mul, mul, mul, 1);
|
||||
|
||||
FBO_Blit(tr.quarterFbo[0], NULL, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean horizontal)
|
||||
{
|
||||
float dx, dy;
|
||||
float xmul, ymul;
|
||||
float weights[3] = {
|
||||
0.227027027f,
|
||||
0.316216216f,
|
||||
0.070270270f,
|
||||
};
|
||||
float offsets[3] = {
|
||||
0.f,
|
||||
1.3846153846f,
|
||||
3.2307692308f,
|
||||
};
|
||||
|
||||
xmul = horizontal;
|
||||
ymul = 1.f - xmul;
|
||||
|
||||
xmul *= strength;
|
||||
ymul *= strength;
|
||||
|
||||
{
|
||||
vec4i_t srcBox, dstBox;
|
||||
vec4_t color;
|
||||
vec2_t texScale;
|
||||
|
||||
texScale[0] =
|
||||
texScale[1] = 1.0f;
|
||||
|
||||
VectorSet4(color, weights[0], weights[0], weights[0], 1.0f);
|
||||
VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
|
||||
VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->height);
|
||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0 );
|
||||
|
||||
VectorSet4(color, weights[1], weights[1], weights[1], 1.0f);
|
||||
dx = offsets[1] * xmul;
|
||||
dy = offsets[1] * ymul;
|
||||
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
|
||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
|
||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
|
||||
VectorSet4(color, weights[2], weights[2], weights[2], 1.0f);
|
||||
dx = offsets[2] * xmul;
|
||||
dy = offsets[2] * ymul;
|
||||
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
|
||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
|
||||
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
}
|
||||
}
|
||||
|
||||
static void RB_HBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength)
|
||||
{
|
||||
RB_BlurAxis(srcFbo, dstFbo, strength, qtrue);
|
||||
}
|
||||
|
||||
static void RB_VBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength)
|
||||
{
|
||||
RB_BlurAxis(srcFbo, dstFbo, strength, qfalse);
|
||||
}
|
||||
|
||||
void RB_GaussianBlur(float blur)
|
||||
{
|
||||
//float mul = 1.f;
|
||||
float factor = Com_Clamp(0.f, 1.f, blur);
|
||||
|
||||
if (factor <= 0.f)
|
||||
return;
|
||||
|
||||
{
|
||||
vec4i_t srcBox, dstBox;
|
||||
vec4_t color;
|
||||
vec2_t texScale;
|
||||
|
||||
texScale[0] =
|
||||
texScale[1] = 1.0f;
|
||||
|
||||
VectorSet4(color, 1, 1, 1, 1);
|
||||
|
||||
// first, downsample the framebuffer
|
||||
FBO_FastBlit(tr.screenScratchFbo, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
// set the alpha channel
|
||||
VectorSet4(srcBox, 0, 0, tr.whiteImage->width, tr.whiteImage->height);
|
||||
VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
|
||||
qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
||||
FBO_BlitFromTexture(tr.whiteImage, srcBox, texScale, tr.textureScratchFbo[0], dstBox, &tr.textureColorShader, color, GLS_DEPTHTEST_DISABLE);
|
||||
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
|
||||
// blur the tiny buffer horizontally and vertically
|
||||
RB_HBlur(tr.textureScratchFbo[0], tr.textureScratchFbo[1], factor);
|
||||
RB_VBlur(tr.textureScratchFbo[1], tr.textureScratchFbo[0], factor);
|
||||
|
||||
// finally, merge back to framebuffer
|
||||
VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
|
||||
VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
color[3] = factor;
|
||||
FBO_Blit(tr.textureScratchFbo[0], srcBox, texScale, tr.screenScratchFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
}
|
33
code/renderergl2/tr_postprocess.h
Normal file
33
code/renderergl2/tr_postprocess.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete
|
||||
|
||||
This file is part of Reaction source code.
|
||||
|
||||
Reaction 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.
|
||||
|
||||
Reaction 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 Reaction source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef TR_POSTPROCESS_H
|
||||
#define TR_POSTPROCESS_H
|
||||
|
||||
#include "tr_fbo.h"
|
||||
|
||||
void RB_ToneMap(FBO_t *hdrFbo, vec4i_t hdrBox, FBO_t *ldrFbo, vec4i_t ldrBox, int autoExposure);
|
||||
void RB_BokehBlur(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, float blur);
|
||||
void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox);
|
||||
void RB_GaussianBlur(float blur);
|
||||
|
||||
#endif
|
532
code/renderergl2/tr_scene.c
Normal file
532
code/renderergl2/tr_scene.c
Normal file
|
@ -0,0 +1,532 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
int r_firstSceneDrawSurf;
|
||||
|
||||
int r_numdlights;
|
||||
int r_firstSceneDlight;
|
||||
|
||||
int r_numentities;
|
||||
int r_firstSceneEntity;
|
||||
|
||||
int r_numpolys;
|
||||
int r_firstScenePoly;
|
||||
|
||||
int r_numpolyverts;
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
R_InitNextFrame
|
||||
|
||||
====================
|
||||
*/
|
||||
void R_InitNextFrame( void ) {
|
||||
backEndData->commands.used = 0;
|
||||
|
||||
r_firstSceneDrawSurf = 0;
|
||||
|
||||
r_numdlights = 0;
|
||||
r_firstSceneDlight = 0;
|
||||
|
||||
r_numentities = 0;
|
||||
r_firstSceneEntity = 0;
|
||||
|
||||
r_numpolys = 0;
|
||||
r_firstScenePoly = 0;
|
||||
|
||||
r_numpolyverts = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
RE_ClearScene
|
||||
|
||||
====================
|
||||
*/
|
||||
void RE_ClearScene( void ) {
|
||||
r_firstSceneDlight = r_numdlights;
|
||||
r_firstSceneEntity = r_numentities;
|
||||
r_firstScenePoly = r_numpolys;
|
||||
}
|
||||
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
DISCRETE POLYS
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=====================
|
||||
R_AddPolygonSurfaces
|
||||
|
||||
Adds all the scene's polys into this view's drawsurf list
|
||||
=====================
|
||||
*/
|
||||
void R_AddPolygonSurfaces( void ) {
|
||||
int i;
|
||||
shader_t *sh;
|
||||
srfPoly_t *poly;
|
||||
int fogMask;
|
||||
|
||||
tr.currentEntityNum = REFENTITYNUM_WORLD;
|
||||
tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
|
||||
fogMask = -((tr.refdef.rdflags & RDF_NOFOG) == 0);
|
||||
|
||||
for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
|
||||
sh = R_GetShaderByHandle( poly->hShader );
|
||||
R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse, qfalse );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
RE_AddPolyToScene
|
||||
|
||||
=====================
|
||||
*/
|
||||
void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
|
||||
srfPoly_t *poly;
|
||||
int i, j;
|
||||
int fogIndex;
|
||||
fog_t *fog;
|
||||
vec3_t bounds[2];
|
||||
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !hShader ) {
|
||||
// This isn't a useful warning, and an hShader of zero isn't a null shader, it's
|
||||
// the default shader.
|
||||
//ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n");
|
||||
//return;
|
||||
}
|
||||
|
||||
for ( j = 0; j < numPolys; j++ ) {
|
||||
if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {
|
||||
/*
|
||||
NOTE TTimo this was initially a PRINT_WARNING
|
||||
but it happens a lot with high fighting scenes and particles
|
||||
since we don't plan on changing the const and making for room for those effects
|
||||
simply cut this message to developer only
|
||||
*/
|
||||
ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
|
||||
return;
|
||||
}
|
||||
|
||||
poly = &backEndData->polys[r_numpolys];
|
||||
poly->surfaceType = SF_POLY;
|
||||
poly->hShader = hShader;
|
||||
poly->numVerts = numVerts;
|
||||
poly->verts = &backEndData->polyVerts[r_numpolyverts];
|
||||
|
||||
Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );
|
||||
|
||||
if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
|
||||
poly->verts->modulate[0] = 255;
|
||||
poly->verts->modulate[1] = 255;
|
||||
poly->verts->modulate[2] = 255;
|
||||
poly->verts->modulate[3] = 255;
|
||||
}
|
||||
// done.
|
||||
r_numpolys++;
|
||||
r_numpolyverts += numVerts;
|
||||
|
||||
// if no world is loaded
|
||||
if ( tr.world == NULL ) {
|
||||
fogIndex = 0;
|
||||
}
|
||||
// see if it is in a fog volume
|
||||
else if ( tr.world->numfogs == 1 ) {
|
||||
fogIndex = 0;
|
||||
} else {
|
||||
// find which fog volume the poly is in
|
||||
VectorCopy( poly->verts[0].xyz, bounds[0] );
|
||||
VectorCopy( poly->verts[0].xyz, bounds[1] );
|
||||
for ( i = 1 ; i < poly->numVerts ; i++ ) {
|
||||
AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
|
||||
}
|
||||
for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
|
||||
fog = &tr.world->fogs[fogIndex];
|
||||
if ( bounds[1][0] >= fog->bounds[0][0]
|
||||
&& bounds[1][1] >= fog->bounds[0][1]
|
||||
&& bounds[1][2] >= fog->bounds[0][2]
|
||||
&& bounds[0][0] <= fog->bounds[1][0]
|
||||
&& bounds[0][1] <= fog->bounds[1][1]
|
||||
&& bounds[0][2] <= fog->bounds[1][2] ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( fogIndex == tr.world->numfogs ) {
|
||||
fogIndex = 0;
|
||||
}
|
||||
}
|
||||
poly->fogIndex = fogIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=================================================================================
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
RE_AddRefEntityToScene
|
||||
|
||||
=====================
|
||||
*/
|
||||
void RE_AddRefEntityToScene( const refEntity_t *ent ) {
|
||||
vec3_t cross;
|
||||
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
}
|
||||
if ( r_numentities >= MAX_REFENTITIES ) {
|
||||
ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n");
|
||||
return;
|
||||
}
|
||||
if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
|
||||
static qboolean firstTime = qtrue;
|
||||
if (firstTime) {
|
||||
firstTime = qfalse;
|
||||
ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
|
||||
ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
|
||||
}
|
||||
|
||||
backEndData->entities[r_numentities].e = *ent;
|
||||
backEndData->entities[r_numentities].lightingCalculated = qfalse;
|
||||
|
||||
CrossProduct(ent->axis[0], ent->axis[1], cross);
|
||||
backEndData->entities[r_numentities].mirrored = (DotProduct(ent->axis[2], cross) < 0.f);
|
||||
|
||||
r_numentities++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
RE_AddDynamicLightToScene
|
||||
|
||||
=====================
|
||||
*/
|
||||
void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {
|
||||
dlight_t *dl;
|
||||
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
}
|
||||
if ( r_numdlights >= MAX_DLIGHTS ) {
|
||||
return;
|
||||
}
|
||||
if ( intensity <= 0 ) {
|
||||
return;
|
||||
}
|
||||
// these cards don't have the correct blend mode
|
||||
if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
|
||||
return;
|
||||
}
|
||||
dl = &backEndData->dlights[r_numdlights++];
|
||||
VectorCopy (org, dl->origin);
|
||||
dl->radius = intensity;
|
||||
dl->color[0] = r;
|
||||
dl->color[1] = g;
|
||||
dl->color[2] = b;
|
||||
dl->additive = additive;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
RE_AddLightToScene
|
||||
|
||||
=====================
|
||||
*/
|
||||
void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
|
||||
RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
RE_AddAdditiveLightToScene
|
||||
|
||||
=====================
|
||||
*/
|
||||
void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
|
||||
RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue );
|
||||
}
|
||||
|
||||
/*
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
RE_RenderScene
|
||||
|
||||
Draw a 3D view into a part of the window, then return
|
||||
to 2D drawing.
|
||||
|
||||
Rendering a scene may require multiple views to be rendered
|
||||
to handle mirrors,
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
*/
|
||||
void RE_RenderScene( const refdef_t *fd ) {
|
||||
viewParms_t parms;
|
||||
int startTime;
|
||||
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
}
|
||||
GLimp_LogComment( "====== RE_RenderScene =====\n" );
|
||||
|
||||
if ( r_norefresh->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
startTime = ri.Milliseconds();
|
||||
|
||||
if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
|
||||
ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
|
||||
}
|
||||
|
||||
Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
|
||||
|
||||
tr.refdef.x = fd->x;
|
||||
tr.refdef.y = fd->y;
|
||||
tr.refdef.width = fd->width;
|
||||
tr.refdef.height = fd->height;
|
||||
tr.refdef.fov_x = fd->fov_x;
|
||||
tr.refdef.fov_y = fd->fov_y;
|
||||
|
||||
VectorCopy( fd->vieworg, tr.refdef.vieworg );
|
||||
VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
|
||||
VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
|
||||
VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
|
||||
|
||||
tr.refdef.time = fd->time;
|
||||
tr.refdef.rdflags = fd->rdflags;
|
||||
|
||||
// copy the areamask data over and note if it has changed, which
|
||||
// will force a reset of the visible leafs even if the view hasn't moved
|
||||
tr.refdef.areamaskModified = qfalse;
|
||||
if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {
|
||||
int areaDiff;
|
||||
int i;
|
||||
|
||||
// compare the area bits
|
||||
areaDiff = 0;
|
||||
for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {
|
||||
areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
|
||||
((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
|
||||
}
|
||||
|
||||
if ( areaDiff ) {
|
||||
// a door just opened or something
|
||||
tr.refdef.areamaskModified = qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
tr.refdef.sunDir[3] = 0.0f;
|
||||
tr.refdef.sunCol[3] = 1.0f;
|
||||
tr.refdef.sunAmbCol[3] = 1.0f;
|
||||
|
||||
VectorCopy(tr.sunDirection, tr.refdef.sunDir);
|
||||
if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){
|
||||
tr.refdef.colorScale = 1.0f;
|
||||
VectorSet(tr.refdef.sunCol, 0, 0, 0);
|
||||
VectorSet(tr.refdef.sunAmbCol, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.refdef.colorScale = r_forceSun->integer ? r_forceSunMapLightScale->value : tr.mapLightScale;
|
||||
|
||||
if (r_sunlightMode->integer == 1)
|
||||
{
|
||||
tr.refdef.sunCol[0] =
|
||||
tr.refdef.sunCol[1] =
|
||||
tr.refdef.sunCol[2] = 1.0f;
|
||||
|
||||
tr.refdef.sunAmbCol[0] =
|
||||
tr.refdef.sunAmbCol[1] =
|
||||
tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8);
|
||||
if (r_forceSun->integer)
|
||||
{
|
||||
VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol);
|
||||
VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorScale(tr.sunLight, scale, tr.refdef.sunCol);
|
||||
VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (r_forceAutoExposure->integer)
|
||||
{
|
||||
tr.refdef.autoExposureMinMax[0] = r_forceAutoExposureMin->value;
|
||||
tr.refdef.autoExposureMinMax[1] = r_forceAutoExposureMax->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.refdef.autoExposureMinMax[0] = tr.autoExposureMinMax[0];
|
||||
tr.refdef.autoExposureMinMax[1] = tr.autoExposureMinMax[1];
|
||||
}
|
||||
|
||||
if (r_forceToneMap->integer)
|
||||
{
|
||||
tr.refdef.toneMinAvgMaxLinear[0] = pow(2, r_forceToneMapMin->value);
|
||||
tr.refdef.toneMinAvgMaxLinear[1] = pow(2, r_forceToneMapAvg->value);
|
||||
tr.refdef.toneMinAvgMaxLinear[2] = pow(2, r_forceToneMapMax->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.refdef.toneMinAvgMaxLinear[0] = pow(2, tr.toneMinAvgMaxLevel[0]);
|
||||
tr.refdef.toneMinAvgMaxLinear[1] = pow(2, tr.toneMinAvgMaxLevel[1]);
|
||||
tr.refdef.toneMinAvgMaxLinear[2] = pow(2, tr.toneMinAvgMaxLevel[2]);
|
||||
}
|
||||
|
||||
// Makro - copy exta info if present
|
||||
if (fd->rdflags & RDF_EXTRA) {
|
||||
const refdefex_t* extra = (const refdefex_t*) (fd+1);
|
||||
|
||||
tr.refdef.blurFactor = extra->blurFactor;
|
||||
|
||||
if (fd->rdflags & RDF_SUNLIGHT)
|
||||
{
|
||||
VectorCopy(extra->sunDir, tr.refdef.sunDir);
|
||||
VectorCopy(extra->sunCol, tr.refdef.sunCol);
|
||||
VectorCopy(extra->sunAmbCol, tr.refdef.sunAmbCol);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.refdef.blurFactor = 0.0f;
|
||||
}
|
||||
|
||||
// derived info
|
||||
|
||||
tr.refdef.floatTime = tr.refdef.time * 0.001f;
|
||||
|
||||
tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
|
||||
tr.refdef.drawSurfs = backEndData->drawSurfs;
|
||||
|
||||
tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
|
||||
tr.refdef.entities = &backEndData->entities[r_firstSceneEntity];
|
||||
|
||||
tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
|
||||
tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight];
|
||||
|
||||
tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
|
||||
tr.refdef.polys = &backEndData->polys[r_firstScenePoly];
|
||||
|
||||
tr.refdef.num_pshadows = 0;
|
||||
tr.refdef.pshadows = &backEndData->pshadows[0];
|
||||
|
||||
// turn off dynamic lighting globally by clearing all the
|
||||
// dlights if it needs to be disabled or if vertex lighting is enabled
|
||||
if ( r_dynamiclight->integer == 0 ||
|
||||
r_vertexLight->integer == 1 ||
|
||||
glConfig.hardwareType == GLHW_PERMEDIA2 ) {
|
||||
tr.refdef.num_dlights = 0;
|
||||
}
|
||||
|
||||
// a single frame may have multiple scenes draw inside it --
|
||||
// a 3D game view, 3D status bar renderings, 3D menus, etc.
|
||||
// They need to be distinguished by the light flare code, because
|
||||
// the visibility state for a given surface may be different in
|
||||
// each scene / view.
|
||||
tr.frameSceneNum++;
|
||||
tr.sceneCount++;
|
||||
|
||||
// SmileTheory: playing with shadow mapping
|
||||
if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2)
|
||||
{
|
||||
R_RenderDlightCubemaps(fd);
|
||||
}
|
||||
|
||||
/* playing with more shadows */
|
||||
if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && r_shadows->integer == 4)
|
||||
{
|
||||
R_RenderPshadowMaps(fd);
|
||||
}
|
||||
|
||||
// playing with even more shadows
|
||||
if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows))
|
||||
{
|
||||
R_RenderSunShadowMaps(fd, 0);
|
||||
R_RenderSunShadowMaps(fd, 1);
|
||||
R_RenderSunShadowMaps(fd, 2);
|
||||
}
|
||||
|
||||
// setup view parms for the initial view
|
||||
//
|
||||
// set up viewport
|
||||
// The refdef takes 0-at-the-top y coordinates, so
|
||||
// convert to GL's 0-at-the-bottom space
|
||||
//
|
||||
Com_Memset( &parms, 0, sizeof( parms ) );
|
||||
parms.viewportX = tr.refdef.x;
|
||||
parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
|
||||
parms.viewportWidth = tr.refdef.width;
|
||||
parms.viewportHeight = tr.refdef.height;
|
||||
parms.isPortal = qfalse;
|
||||
|
||||
parms.fovX = tr.refdef.fov_x;
|
||||
parms.fovY = tr.refdef.fov_y;
|
||||
|
||||
parms.stereoFrame = tr.refdef.stereoFrame;
|
||||
|
||||
VectorCopy( fd->vieworg, parms.or.origin );
|
||||
VectorCopy( fd->viewaxis[0], parms.or.axis[0] );
|
||||
VectorCopy( fd->viewaxis[1], parms.or.axis[1] );
|
||||
VectorCopy( fd->viewaxis[2], parms.or.axis[2] );
|
||||
|
||||
VectorCopy( fd->vieworg, parms.pvsOrigin );
|
||||
|
||||
if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows))
|
||||
{
|
||||
parms.flags = VPF_USESUNLIGHT;
|
||||
}
|
||||
|
||||
R_RenderView( &parms );
|
||||
|
||||
if(!( fd->rdflags & RDF_NOWORLDMODEL ))
|
||||
R_AddPostProcessCmd();
|
||||
|
||||
// the next scene rendered in this frame will tack on after this one
|
||||
r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
|
||||
r_firstSceneEntity = r_numentities;
|
||||
r_firstSceneDlight = r_numdlights;
|
||||
r_firstScenePoly = r_numpolys;
|
||||
|
||||
tr.frontEndMsec += ri.Milliseconds() - startTime;
|
||||
}
|
1670
code/renderergl2/tr_shade.c
Normal file
1670
code/renderergl2/tr_shade.c
Normal file
File diff suppressed because it is too large
Load diff
1339
code/renderergl2/tr_shade_calc.c
Normal file
1339
code/renderergl2/tr_shade_calc.c
Normal file
File diff suppressed because it is too large
Load diff
3771
code/renderergl2/tr_shader.c
Normal file
3771
code/renderergl2/tr_shader.c
Normal file
File diff suppressed because it is too large
Load diff
343
code/renderergl2/tr_shadows.c
Normal file
343
code/renderergl2/tr_shadows.c
Normal file
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "tr_local.h"
|
||||
|
||||
|
||||
/*
|
||||
|
||||
for a projection shadow:
|
||||
|
||||
point[x] += light vector * ( z - shadow plane )
|
||||
point[y] +=
|
||||
point[z] = shadow plane
|
||||
|
||||
1 0 light[x] / light[z]
|
||||
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int i2;
|
||||
int facing;
|
||||
} edgeDef_t;
|
||||
|
||||
#define MAX_EDGE_DEFS 32
|
||||
|
||||
static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
|
||||
static int numEdgeDefs[SHADER_MAX_VERTEXES];
|
||||
static int facing[SHADER_MAX_INDEXES/3];
|
||||
|
||||
void R_AddEdgeDef( int i1, int i2, int facing ) {
|
||||
int c;
|
||||
|
||||
c = numEdgeDefs[ i1 ];
|
||||
if ( c == MAX_EDGE_DEFS ) {
|
||||
return; // overflow
|
||||
}
|
||||
edgeDefs[ i1 ][ c ].i2 = i2;
|
||||
edgeDefs[ i1 ][ c ].facing = facing;
|
||||
|
||||
numEdgeDefs[ i1 ]++;
|
||||
}
|
||||
|
||||
void R_RenderShadowEdges( void ) {
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
int numTris;
|
||||
|
||||
// dumb way -- render every triangle's edges
|
||||
numTris = tess.numIndexes / 3;
|
||||
|
||||
for ( i = 0 ; i < numTris ; i++ ) {
|
||||
int i1, i2, i3;
|
||||
|
||||
if ( !facing[i] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
i1 = tess.indexes[ i*3 + 0 ];
|
||||
i2 = tess.indexes[ i*3 + 1 ];
|
||||
i3 = tess.indexes[ i*3 + 2 ];
|
||||
|
||||
qglBegin( GL_TRIANGLE_STRIP );
|
||||
qglVertex3fv( tess.xyz[ i1 ] );
|
||||
qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] );
|
||||
qglVertex3fv( tess.xyz[ i2 ] );
|
||||
qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
|
||||
qglVertex3fv( tess.xyz[ i3 ] );
|
||||
qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] );
|
||||
qglVertex3fv( tess.xyz[ i1 ] );
|
||||
qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] );
|
||||
qglEnd();
|
||||
}
|
||||
#else
|
||||
int c, c2;
|
||||
int j, k;
|
||||
int i2;
|
||||
int c_edges, c_rejected;
|
||||
int hit[2];
|
||||
|
||||
// an edge is NOT a silhouette edge if its face doesn't face the light,
|
||||
// or if it has a reverse paired edge that also faces the light.
|
||||
// A well behaved polyhedron would have exactly two faces for each edge,
|
||||
// but lots of models have dangling edges or overfanned edges
|
||||
c_edges = 0;
|
||||
c_rejected = 0;
|
||||
|
||||
for ( i = 0 ; i < tess.numVertexes ; i++ ) {
|
||||
c = numEdgeDefs[ i ];
|
||||
for ( j = 0 ; j < c ; j++ ) {
|
||||
if ( !edgeDefs[ i ][ j ].facing ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hit[0] = 0;
|
||||
hit[1] = 0;
|
||||
|
||||
i2 = edgeDefs[ i ][ j ].i2;
|
||||
c2 = numEdgeDefs[ i2 ];
|
||||
for ( k = 0 ; k < c2 ; k++ ) {
|
||||
if ( edgeDefs[ i2 ][ k ].i2 == i ) {
|
||||
hit[ edgeDefs[ i2 ][ k ].facing ]++;
|
||||
}
|
||||
}
|
||||
|
||||
// if it doesn't share the edge with another front facing
|
||||
// triangle, it is a sil edge
|
||||
if ( hit[ 1 ] == 0 ) {
|
||||
qglBegin( GL_TRIANGLE_STRIP );
|
||||
qglVertex3fv( tess.xyz[ i ] );
|
||||
qglVertex3fv( tess.xyz[ i + tess.numVertexes ] );
|
||||
qglVertex3fv( tess.xyz[ i2 ] );
|
||||
qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
|
||||
qglEnd();
|
||||
c_edges++;
|
||||
} else {
|
||||
c_rejected++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
RB_ShadowTessEnd
|
||||
|
||||
triangleFromEdge[ v1 ][ v2 ]
|
||||
|
||||
|
||||
set triangle from edge( v1, v2, tri )
|
||||
if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
|
||||
}
|
||||
=================
|
||||
*/
|
||||
void RB_ShadowTessEnd( void ) {
|
||||
int i;
|
||||
int numTris;
|
||||
vec3_t lightDir;
|
||||
GLboolean rgba[4];
|
||||
|
||||
// we can only do this if we have enough space in the vertex buffers
|
||||
if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( glConfig.stencilBits < 4 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
VectorCopy( backEnd.currentEntity->lightDir, lightDir );
|
||||
|
||||
// project vertexes away from light direction
|
||||
for ( i = 0 ; i < tess.numVertexes ; i++ ) {
|
||||
VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] );
|
||||
}
|
||||
|
||||
// decide which triangles face the light
|
||||
Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );
|
||||
|
||||
numTris = tess.numIndexes / 3;
|
||||
for ( i = 0 ; i < numTris ; i++ ) {
|
||||
int i1, i2, i3;
|
||||
vec3_t d1, d2, normal;
|
||||
float *v1, *v2, *v3;
|
||||
float d;
|
||||
|
||||
i1 = tess.indexes[ i*3 + 0 ];
|
||||
i2 = tess.indexes[ i*3 + 1 ];
|
||||
i3 = tess.indexes[ i*3 + 2 ];
|
||||
|
||||
v1 = tess.xyz[ i1 ];
|
||||
v2 = tess.xyz[ i2 ];
|
||||
v3 = tess.xyz[ i3 ];
|
||||
|
||||
VectorSubtract( v2, v1, d1 );
|
||||
VectorSubtract( v3, v1, d2 );
|
||||
CrossProduct( d1, d2, normal );
|
||||
|
||||
d = DotProduct( normal, lightDir );
|
||||
if ( d > 0 ) {
|
||||
facing[ i ] = 1;
|
||||
} else {
|
||||
facing[ i ] = 0;
|
||||
}
|
||||
|
||||
// create the edges
|
||||
R_AddEdgeDef( i1, i2, facing[ i ] );
|
||||
R_AddEdgeDef( i2, i3, facing[ i ] );
|
||||
R_AddEdgeDef( i3, i1, facing[ i ] );
|
||||
}
|
||||
|
||||
// draw the silhouette edges
|
||||
|
||||
GL_Bind( tr.whiteImage );
|
||||
qglEnable( GL_CULL_FACE );
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
|
||||
qglColor3f( 0.2f, 0.2f, 0.2f );
|
||||
|
||||
// don't write to the color buffer
|
||||
qglGetBooleanv(GL_COLOR_WRITEMASK, rgba);
|
||||
qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
|
||||
|
||||
qglEnable( GL_STENCIL_TEST );
|
||||
qglStencilFunc( GL_ALWAYS, 1, 255 );
|
||||
|
||||
// mirrors have the culling order reversed
|
||||
if ( backEnd.viewParms.isMirror ) {
|
||||
qglCullFace( GL_FRONT );
|
||||
qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
|
||||
|
||||
R_RenderShadowEdges();
|
||||
|
||||
qglCullFace( GL_BACK );
|
||||
qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
|
||||
|
||||
R_RenderShadowEdges();
|
||||
} else {
|
||||
qglCullFace( GL_BACK );
|
||||
qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
|
||||
|
||||
R_RenderShadowEdges();
|
||||
|
||||
qglCullFace( GL_FRONT );
|
||||
qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
|
||||
|
||||
R_RenderShadowEdges();
|
||||
}
|
||||
|
||||
|
||||
// reenable writing to the color buffer
|
||||
qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
RB_ShadowFinish
|
||||
|
||||
Darken everything that is is a shadow volume.
|
||||
We have to delay this until everything has been shadowed,
|
||||
because otherwise shadows from different body parts would
|
||||
overlap and double darken.
|
||||
=================
|
||||
*/
|
||||
void RB_ShadowFinish( void ) {
|
||||
if ( r_shadows->integer != 2 ) {
|
||||
return;
|
||||
}
|
||||
if ( glConfig.stencilBits < 4 ) {
|
||||
return;
|
||||
}
|
||||
qglEnable( GL_STENCIL_TEST );
|
||||
qglStencilFunc( GL_NOTEQUAL, 0, 255 );
|
||||
|
||||
qglDisable (GL_CLIP_PLANE0);
|
||||
qglDisable (GL_CULL_FACE);
|
||||
|
||||
GL_Bind( tr.whiteImage );
|
||||
|
||||
qglLoadIdentity ();
|
||||
|
||||
qglColor3f( 0.6f, 0.6f, 0.6f );
|
||||
GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
|
||||
|
||||
// qglColor3f( 1, 0, 0 );
|
||||
// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
|
||||
|
||||
qglBegin( GL_QUADS );
|
||||
qglVertex3f( -100, 100, -10 );
|
||||
qglVertex3f( 100, 100, -10 );
|
||||
qglVertex3f( 100, -100, -10 );
|
||||
qglVertex3f( -100, -100, -10 );
|
||||
qglEnd ();
|
||||
|
||||
qglColor4f(1,1,1,1);
|
||||
qglDisable( GL_STENCIL_TEST );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
RB_ProjectionShadowDeform
|
||||
|
||||
=================
|
||||
*/
|
||||
void RB_ProjectionShadowDeform( void ) {
|
||||
float *xyz;
|
||||
int i;
|
||||
float h;
|
||||
vec3_t ground;
|
||||
vec3_t light;
|
||||
float groundDist;
|
||||
float d;
|
||||
vec3_t lightDir;
|
||||
|
||||
xyz = ( float * ) tess.xyz;
|
||||
|
||||
ground[0] = backEnd.or.axis[0][2];
|
||||
ground[1] = backEnd.or.axis[1][2];
|
||||
ground[2] = backEnd.or.axis[2][2];
|
||||
|
||||
groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane;
|
||||
|
||||
VectorCopy( backEnd.currentEntity->lightDir, lightDir );
|
||||
d = DotProduct( lightDir, ground );
|
||||
// don't let the shadows get too long or go negative
|
||||
if ( d < 0.5 ) {
|
||||
VectorMA( lightDir, (0.5 - d), ground, lightDir );
|
||||
d = DotProduct( lightDir, ground );
|
||||
}
|
||||
d = 1.0 / d;
|
||||
|
||||
light[0] = lightDir[0] * d;
|
||||
light[1] = lightDir[1] * d;
|
||||
light[2] = lightDir[2] * d;
|
||||
|
||||
for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
|
||||
h = DotProduct( xyz, ground ) + groundDist;
|
||||
|
||||
xyz[0] -= light[0] * h;
|
||||
xyz[1] -= light[1] * h;
|
||||
xyz[2] -= light[2] * h;
|
||||
}
|
||||
}
|
912
code/renderergl2/tr_sky.c
Normal file
912
code/renderergl2/tr_sky.c
Normal file
|
@ -0,0 +1,912 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_sky.c
|
||||
#include "tr_local.h"
|
||||
|
||||
#define SKY_SUBDIVISIONS 8
|
||||
#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2)
|
||||
|
||||
static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
|
||||
static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
|
||||
|
||||
/*
|
||||
===================================================================================
|
||||
|
||||
POLYGON TO BOX SIDE PROJECTION
|
||||
|
||||
===================================================================================
|
||||
*/
|
||||
|
||||
static vec3_t sky_clip[6] =
|
||||
{
|
||||
{1,1,0},
|
||||
{1,-1,0},
|
||||
{0,-1,1},
|
||||
{0,1,1},
|
||||
{1,0,1},
|
||||
{-1,0,1}
|
||||
};
|
||||
|
||||
static float sky_mins[2][6], sky_maxs[2][6];
|
||||
static float sky_min, sky_max;
|
||||
|
||||
/*
|
||||
================
|
||||
AddSkyPolygon
|
||||
================
|
||||
*/
|
||||
static void AddSkyPolygon (int nump, vec3_t vecs)
|
||||
{
|
||||
int i,j;
|
||||
vec3_t v, av;
|
||||
float s, t, dv;
|
||||
int axis;
|
||||
float *vp;
|
||||
// s = [0]/[2], t = [1]/[2]
|
||||
static int vec_to_st[6][3] =
|
||||
{
|
||||
{-2,3,1},
|
||||
{2,3,-1},
|
||||
|
||||
{1,3,2},
|
||||
{-1,3,-2},
|
||||
|
||||
{-2,-1,3},
|
||||
{-2,1,-3}
|
||||
|
||||
// {-1,2,3},
|
||||
// {1,2,-3}
|
||||
};
|
||||
|
||||
// decide which face it maps to
|
||||
VectorCopy (vec3_origin, v);
|
||||
for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
|
||||
{
|
||||
VectorAdd (vp, v, v);
|
||||
}
|
||||
av[0] = fabs(v[0]);
|
||||
av[1] = fabs(v[1]);
|
||||
av[2] = fabs(v[2]);
|
||||
if (av[0] > av[1] && av[0] > av[2])
|
||||
{
|
||||
if (v[0] < 0)
|
||||
axis = 1;
|
||||
else
|
||||
axis = 0;
|
||||
}
|
||||
else if (av[1] > av[2] && av[1] > av[0])
|
||||
{
|
||||
if (v[1] < 0)
|
||||
axis = 3;
|
||||
else
|
||||
axis = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v[2] < 0)
|
||||
axis = 5;
|
||||
else
|
||||
axis = 4;
|
||||
}
|
||||
|
||||
// project new texture coords
|
||||
for (i=0 ; i<nump ; i++, vecs+=3)
|
||||
{
|
||||
j = vec_to_st[axis][2];
|
||||
if (j > 0)
|
||||
dv = vecs[j - 1];
|
||||
else
|
||||
dv = -vecs[-j - 1];
|
||||
if (dv < 0.001)
|
||||
continue; // don't divide by zero
|
||||
j = vec_to_st[axis][0];
|
||||
if (j < 0)
|
||||
s = -vecs[-j -1] / dv;
|
||||
else
|
||||
s = vecs[j-1] / dv;
|
||||
j = vec_to_st[axis][1];
|
||||
if (j < 0)
|
||||
t = -vecs[-j -1] / dv;
|
||||
else
|
||||
t = vecs[j-1] / dv;
|
||||
|
||||
if (s < sky_mins[0][axis])
|
||||
sky_mins[0][axis] = s;
|
||||
if (t < sky_mins[1][axis])
|
||||
sky_mins[1][axis] = t;
|
||||
if (s > sky_maxs[0][axis])
|
||||
sky_maxs[0][axis] = s;
|
||||
if (t > sky_maxs[1][axis])
|
||||
sky_maxs[1][axis] = t;
|
||||
}
|
||||
}
|
||||
|
||||
#define ON_EPSILON 0.1f // point on plane side epsilon
|
||||
#define MAX_CLIP_VERTS 64
|
||||
/*
|
||||
================
|
||||
ClipSkyPolygon
|
||||
================
|
||||
*/
|
||||
static void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
|
||||
{
|
||||
float *norm;
|
||||
float *v;
|
||||
qboolean front, back;
|
||||
float d, e;
|
||||
float dists[MAX_CLIP_VERTS];
|
||||
int sides[MAX_CLIP_VERTS];
|
||||
vec3_t newv[2][MAX_CLIP_VERTS];
|
||||
int newc[2];
|
||||
int i, j;
|
||||
|
||||
if (nump > MAX_CLIP_VERTS-2)
|
||||
ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
|
||||
if (stage == 6)
|
||||
{ // fully clipped, so draw it
|
||||
AddSkyPolygon (nump, vecs);
|
||||
return;
|
||||
}
|
||||
|
||||
front = back = qfalse;
|
||||
norm = sky_clip[stage];
|
||||
for (i=0, v = vecs ; i<nump ; i++, v+=3)
|
||||
{
|
||||
d = DotProduct (v, norm);
|
||||
if (d > ON_EPSILON)
|
||||
{
|
||||
front = qtrue;
|
||||
sides[i] = SIDE_FRONT;
|
||||
}
|
||||
else if (d < -ON_EPSILON)
|
||||
{
|
||||
back = qtrue;
|
||||
sides[i] = SIDE_BACK;
|
||||
}
|
||||
else
|
||||
sides[i] = SIDE_ON;
|
||||
dists[i] = d;
|
||||
}
|
||||
|
||||
if (!front || !back)
|
||||
{ // not clipped
|
||||
ClipSkyPolygon (nump, vecs, stage+1);
|
||||
return;
|
||||
}
|
||||
|
||||
// clip it
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
VectorCopy (vecs, (vecs+(i*3)) );
|
||||
newc[0] = newc[1] = 0;
|
||||
|
||||
for (i=0, v = vecs ; i<nump ; i++, v+=3)
|
||||
{
|
||||
switch (sides[i])
|
||||
{
|
||||
case SIDE_FRONT:
|
||||
VectorCopy (v, newv[0][newc[0]]);
|
||||
newc[0]++;
|
||||
break;
|
||||
case SIDE_BACK:
|
||||
VectorCopy (v, newv[1][newc[1]]);
|
||||
newc[1]++;
|
||||
break;
|
||||
case SIDE_ON:
|
||||
VectorCopy (v, newv[0][newc[0]]);
|
||||
newc[0]++;
|
||||
VectorCopy (v, newv[1][newc[1]]);
|
||||
newc[1]++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
|
||||
continue;
|
||||
|
||||
d = dists[i] / (dists[i] - dists[i+1]);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
e = v[j] + d*(v[j+3] - v[j]);
|
||||
newv[0][newc[0]][j] = e;
|
||||
newv[1][newc[1]][j] = e;
|
||||
}
|
||||
newc[0]++;
|
||||
newc[1]++;
|
||||
}
|
||||
|
||||
// continue
|
||||
ClipSkyPolygon (newc[0], newv[0][0], stage+1);
|
||||
ClipSkyPolygon (newc[1], newv[1][0], stage+1);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
ClearSkyBox
|
||||
==============
|
||||
*/
|
||||
static void ClearSkyBox (void) {
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<6 ; i++) {
|
||||
sky_mins[0][i] = sky_mins[1][i] = 9999;
|
||||
sky_maxs[0][i] = sky_maxs[1][i] = -9999;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
RB_ClipSkyPolygons
|
||||
================
|
||||
*/
|
||||
void RB_ClipSkyPolygons( shaderCommands_t *input )
|
||||
{
|
||||
vec3_t p[5]; // need one extra point for clipping
|
||||
int i, j;
|
||||
|
||||
ClearSkyBox();
|
||||
|
||||
for ( i = 0; i < input->numIndexes; i += 3 )
|
||||
{
|
||||
for (j = 0 ; j < 3 ; j++)
|
||||
{
|
||||
VectorSubtract( input->xyz[input->indexes[i+j]],
|
||||
backEnd.viewParms.or.origin,
|
||||
p[j] );
|
||||
}
|
||||
ClipSkyPolygon( 3, p[0], 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================================================================================
|
||||
|
||||
CLOUD VERTEX GENERATION
|
||||
|
||||
===================================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** MakeSkyVec
|
||||
**
|
||||
** Parms: s, t range from -1 to 1
|
||||
*/
|
||||
static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )
|
||||
{
|
||||
// 1 = s, 2 = t, 3 = 2048
|
||||
static int st_to_vec[6][3] =
|
||||
{
|
||||
{3,-1,2},
|
||||
{-3,1,2},
|
||||
|
||||
{1,3,2},
|
||||
{-1,-3,2},
|
||||
|
||||
{-2,-1,3}, // 0 degrees yaw, look straight up
|
||||
{2,-1,-3} // look straight down
|
||||
};
|
||||
|
||||
vec3_t b;
|
||||
int j, k;
|
||||
float boxSize;
|
||||
|
||||
boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
|
||||
b[0] = s*boxSize;
|
||||
b[1] = t*boxSize;
|
||||
b[2] = boxSize;
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
k = st_to_vec[axis][j];
|
||||
if (k < 0)
|
||||
{
|
||||
outXYZ[j] = -b[-k - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
outXYZ[j] = b[k - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// avoid bilerp seam
|
||||
s = (s+1)*0.5;
|
||||
t = (t+1)*0.5;
|
||||
if (s < sky_min)
|
||||
{
|
||||
s = sky_min;
|
||||
}
|
||||
else if (s > sky_max)
|
||||
{
|
||||
s = sky_max;
|
||||
}
|
||||
|
||||
if (t < sky_min)
|
||||
{
|
||||
t = sky_min;
|
||||
}
|
||||
else if (t > sky_max)
|
||||
{
|
||||
t = sky_max;
|
||||
}
|
||||
|
||||
t = 1.0 - t;
|
||||
|
||||
|
||||
if ( outSt )
|
||||
{
|
||||
outSt[0] = s;
|
||||
outSt[1] = t;
|
||||
}
|
||||
}
|
||||
|
||||
static int sky_texorder[6] = {0,2,1,3,4,5};
|
||||
static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
|
||||
static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
|
||||
|
||||
static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
|
||||
{
|
||||
int s, t;
|
||||
int firstVertex = tess.numVertexes;
|
||||
//int firstIndex = tess.numIndexes;
|
||||
int minIndex = tess.minIndex;
|
||||
int maxIndex = tess.maxIndex;
|
||||
vec4_t color;
|
||||
|
||||
//tess.numVertexes = 0;
|
||||
//tess.numIndexes = 0;
|
||||
tess.firstIndex = tess.numIndexes;
|
||||
|
||||
GL_Bind( image );
|
||||
GL_Cull( CT_TWO_SIDED );
|
||||
|
||||
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
|
||||
{
|
||||
for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
|
||||
{
|
||||
tess.xyz[tess.numVertexes][0] = s_skyPoints[t][s][0];
|
||||
tess.xyz[tess.numVertexes][1] = s_skyPoints[t][s][1];
|
||||
tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2];
|
||||
tess.xyz[tess.numVertexes][3] = 1.0;
|
||||
|
||||
tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
|
||||
tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
|
||||
|
||||
tess.numVertexes++;
|
||||
|
||||
if(tess.numVertexes >= SHADER_MAX_VERTEXES)
|
||||
{
|
||||
ri.Error(ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySideVBO()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( t = 0; t < maxs[1] - mins[1]; t++ )
|
||||
{
|
||||
for ( s = 0; s < maxs[0] - mins[0]; s++ )
|
||||
{
|
||||
if (tess.numIndexes + 6 >= SHADER_MAX_INDEXES)
|
||||
{
|
||||
ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()");
|
||||
}
|
||||
|
||||
tess.indexes[tess.numIndexes++] = s + t * (maxs[0] - mins[0] + 1) + firstVertex;
|
||||
tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
|
||||
tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex;
|
||||
|
||||
tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex;
|
||||
tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
|
||||
tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
|
||||
}
|
||||
}
|
||||
|
||||
tess.minIndex = firstVertex;
|
||||
tess.maxIndex = tess.numVertexes;
|
||||
|
||||
// FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function
|
||||
RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD);
|
||||
/*
|
||||
{
|
||||
shaderProgram_t *sp = &tr.textureColorShader;
|
||||
|
||||
GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD);
|
||||
GLSL_BindProgram(sp);
|
||||
|
||||
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
||||
|
||||
color[0] =
|
||||
color[1] =
|
||||
color[2] = tr.identityLight;
|
||||
color[3] = 1.0f;
|
||||
GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color);
|
||||
}
|
||||
*/
|
||||
{
|
||||
shaderProgram_t *sp = &tr.lightallShader[0];
|
||||
vec4_t vector;
|
||||
|
||||
GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD);
|
||||
GLSL_BindProgram(sp);
|
||||
|
||||
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
||||
|
||||
color[0] =
|
||||
color[1] =
|
||||
color[2] = tr.identityLight;
|
||||
color[3] = 1.0f;
|
||||
GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color);
|
||||
|
||||
color[0] =
|
||||
color[1] =
|
||||
color[2] =
|
||||
color[3] = 0.0f;
|
||||
GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, color);
|
||||
|
||||
VectorSet4(vector, 1.0, 0.0, 0.0, 1.0);
|
||||
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector);
|
||||
|
||||
VectorSet4(vector, 0.0, 0.0, 0.0, 0.0);
|
||||
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector);
|
||||
}
|
||||
|
||||
R_DrawElementsVBO(tess.numIndexes - tess.firstIndex, tess.firstIndex, tess.minIndex, tess.maxIndex);
|
||||
|
||||
//qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(GL_INDEX_TYPE)));
|
||||
|
||||
//R_BindNullVBO();
|
||||
//R_BindNullIBO();
|
||||
|
||||
tess.numIndexes = tess.firstIndex;
|
||||
tess.numVertexes = firstVertex;
|
||||
tess.firstIndex = 0;
|
||||
tess.minIndex = minIndex;
|
||||
tess.maxIndex = maxIndex;
|
||||
}
|
||||
|
||||
static void DrawSkyBox( shader_t *shader )
|
||||
{
|
||||
int i;
|
||||
|
||||
sky_min = 0;
|
||||
sky_max = 1;
|
||||
|
||||
Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
|
||||
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
int sky_mins_subd[2], sky_maxs_subd[2];
|
||||
int s, t;
|
||||
|
||||
sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
|
||||
( sky_mins[1][i] >= sky_maxs[1][i] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
|
||||
sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
|
||||
sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
|
||||
sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
|
||||
sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
|
||||
else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
|
||||
sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
|
||||
if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )
|
||||
sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
|
||||
else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
|
||||
sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
|
||||
sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
|
||||
else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
|
||||
sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
|
||||
if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS )
|
||||
sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
|
||||
else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
|
||||
sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
//
|
||||
// iterate through the subdivisions
|
||||
//
|
||||
for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
|
||||
{
|
||||
for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
|
||||
{
|
||||
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
|
||||
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
|
||||
i,
|
||||
s_skyTexCoords[t][s],
|
||||
s_skyPoints[t][s] );
|
||||
}
|
||||
}
|
||||
|
||||
DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
|
||||
sky_mins_subd,
|
||||
sky_maxs_subd );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes )
|
||||
{
|
||||
int s, t;
|
||||
int vertexStart = tess.numVertexes;
|
||||
int tHeight, sWidth;
|
||||
|
||||
tHeight = maxs[1] - mins[1] + 1;
|
||||
sWidth = maxs[0] - mins[0] + 1;
|
||||
|
||||
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
|
||||
{
|
||||
for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
|
||||
{
|
||||
VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );
|
||||
tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
|
||||
tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
|
||||
|
||||
tess.numVertexes++;
|
||||
|
||||
if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
|
||||
{
|
||||
ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only add indexes for one pass, otherwise it would draw multiple times for each pass
|
||||
if ( addIndexes ) {
|
||||
for ( t = 0; t < tHeight-1; t++ )
|
||||
{
|
||||
for ( s = 0; s < sWidth-1; s++ )
|
||||
{
|
||||
tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
|
||||
tess.numIndexes++;
|
||||
tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
|
||||
tess.numIndexes++;
|
||||
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
|
||||
tess.numIndexes++;
|
||||
|
||||
tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
|
||||
tess.numIndexes++;
|
||||
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
|
||||
tess.numIndexes++;
|
||||
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
|
||||
tess.numIndexes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FillCloudBox( const shader_t *shader, int stage )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i =0; i < 6; i++ )
|
||||
{
|
||||
int sky_mins_subd[2], sky_maxs_subd[2];
|
||||
int s, t;
|
||||
float MIN_T;
|
||||
|
||||
if ( 1 ) // FIXME? shader->sky.fullClouds )
|
||||
{
|
||||
MIN_T = -HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
// still don't want to draw the bottom, even if fullClouds
|
||||
if ( i == 5 )
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( i )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
MIN_T = -1;
|
||||
break;
|
||||
case 5:
|
||||
// don't draw clouds beneath you
|
||||
continue;
|
||||
case 4: // top
|
||||
default:
|
||||
MIN_T = -HALF_SKY_SUBDIVISIONS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
|
||||
( sky_mins[1][i] >= sky_maxs[1][i] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sky_mins_subd[0] = ri.ftol(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS);
|
||||
sky_mins_subd[1] = ri.ftol(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS);
|
||||
sky_maxs_subd[0] = ri.ftol(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS);
|
||||
sky_maxs_subd[1] = ri.ftol(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS);
|
||||
|
||||
if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
|
||||
sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
|
||||
else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
|
||||
sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
|
||||
if ( sky_mins_subd[1] < MIN_T )
|
||||
sky_mins_subd[1] = MIN_T;
|
||||
else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
|
||||
sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
|
||||
sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
|
||||
else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
|
||||
sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
|
||||
if ( sky_maxs_subd[1] < MIN_T )
|
||||
sky_maxs_subd[1] = MIN_T;
|
||||
else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
|
||||
sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
|
||||
|
||||
//
|
||||
// iterate through the subdivisions
|
||||
//
|
||||
for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
|
||||
{
|
||||
for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
|
||||
{
|
||||
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
|
||||
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
|
||||
i,
|
||||
NULL,
|
||||
s_skyPoints[t][s] );
|
||||
|
||||
s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
|
||||
s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
|
||||
}
|
||||
}
|
||||
|
||||
// only add indexes for first stage
|
||||
FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** R_BuildCloudData
|
||||
*/
|
||||
void R_BuildCloudData( shaderCommands_t *input )
|
||||
{
|
||||
int i;
|
||||
shader_t *shader;
|
||||
|
||||
shader = input->shader;
|
||||
|
||||
assert( shader->isSky );
|
||||
|
||||
sky_min = 1.0 / 256.0f; // FIXME: not correct?
|
||||
sky_max = 255.0 / 256.0f;
|
||||
|
||||
// set up for drawing
|
||||
tess.numIndexes = 0;
|
||||
tess.numVertexes = 0;
|
||||
tess.firstIndex = 0;
|
||||
|
||||
if ( shader->sky.cloudHeight )
|
||||
{
|
||||
for ( i = 0; i < MAX_SHADER_STAGES; i++ )
|
||||
{
|
||||
if ( !tess.xstages[i] ) {
|
||||
break;
|
||||
}
|
||||
FillCloudBox( shader, i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** R_InitSkyTexCoords
|
||||
** Called when a sky shader is parsed
|
||||
*/
|
||||
#define SQR( a ) ((a)*(a))
|
||||
void R_InitSkyTexCoords( float heightCloud )
|
||||
{
|
||||
int i, s, t;
|
||||
float radiusWorld = 4096;
|
||||
float p;
|
||||
float sRad, tRad;
|
||||
vec3_t skyVec;
|
||||
vec3_t v;
|
||||
|
||||
// init zfar so MakeSkyVec works even though
|
||||
// a world hasn't been bounded
|
||||
backEnd.viewParms.zFar = 1024;
|
||||
|
||||
for ( i = 0; i < 6; i++ )
|
||||
{
|
||||
for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
|
||||
{
|
||||
for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
|
||||
{
|
||||
// compute vector from view origin to sky side integral point
|
||||
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
|
||||
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
|
||||
i,
|
||||
NULL,
|
||||
skyVec );
|
||||
|
||||
// compute parametric value 'p' that intersects with cloud layer
|
||||
p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
|
||||
( -2 * skyVec[2] * radiusWorld +
|
||||
2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
|
||||
2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
|
||||
SQR( skyVec[0] ) * SQR( heightCloud ) +
|
||||
2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
|
||||
SQR( skyVec[1] ) * SQR( heightCloud ) +
|
||||
2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
|
||||
SQR( skyVec[2] ) * SQR( heightCloud ) ) );
|
||||
|
||||
s_cloudTexP[i][t][s] = p;
|
||||
|
||||
// compute intersection point based on p
|
||||
VectorScale( skyVec, p, v );
|
||||
v[2] += radiusWorld;
|
||||
|
||||
// compute vector from world origin to intersection point 'v'
|
||||
VectorNormalize( v );
|
||||
|
||||
sRad = Q_acos( v[0] );
|
||||
tRad = Q_acos( v[1] );
|
||||
|
||||
s_cloudTexCoords[i][t][s][0] = sRad;
|
||||
s_cloudTexCoords[i][t][s][1] = tRad;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================================
|
||||
|
||||
/*
|
||||
** RB_DrawSun
|
||||
*/
|
||||
void RB_DrawSun( float scale, shader_t *shader ) {
|
||||
float size;
|
||||
float dist;
|
||||
vec3_t origin, vec1, vec2;
|
||||
|
||||
if ( !backEnd.skyRenderedThisView ) {
|
||||
return;
|
||||
}
|
||||
|
||||
//qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
|
||||
//qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
|
||||
{
|
||||
// FIXME: this could be a lot cleaner
|
||||
matrix_t translation, modelview;
|
||||
|
||||
Matrix16Translation( backEnd.viewParms.or.origin, translation );
|
||||
Matrix16Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview );
|
||||
GL_SetModelviewMatrix( modelview );
|
||||
}
|
||||
|
||||
dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
|
||||
size = dist * scale;
|
||||
|
||||
VectorScale( tr.sunDirection, dist, origin );
|
||||
PerpendicularVector( vec1, tr.sunDirection );
|
||||
CrossProduct( tr.sunDirection, vec1, vec2 );
|
||||
|
||||
VectorScale( vec1, size, vec1 );
|
||||
VectorScale( vec2, size, vec2 );
|
||||
|
||||
// farthest depth range
|
||||
qglDepthRange( 1.0, 1.0 );
|
||||
|
||||
RB_BeginSurface( shader, 0 );
|
||||
|
||||
RB_AddQuadStamp(origin, vec1, vec2, colorWhite);
|
||||
|
||||
RB_EndSurface();
|
||||
|
||||
// back to normal depth range
|
||||
qglDepthRange( 0.0, 1.0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
RB_StageIteratorSky
|
||||
|
||||
All of the visible sky triangles are in tess
|
||||
|
||||
Other things could be stuck in here, like birds in the sky, etc
|
||||
================
|
||||
*/
|
||||
void RB_StageIteratorSky( void ) {
|
||||
if ( r_fastsky->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// go through all the polygons and project them onto
|
||||
// the sky box to see which blocks on each side need
|
||||
// to be drawn
|
||||
RB_ClipSkyPolygons( &tess );
|
||||
|
||||
// r_showsky will let all the sky blocks be drawn in
|
||||
// front of everything to allow developers to see how
|
||||
// much sky is getting sucked in
|
||||
if ( r_showsky->integer ) {
|
||||
qglDepthRange( 0.0, 0.0 );
|
||||
} else {
|
||||
qglDepthRange( 1.0, 1.0 );
|
||||
}
|
||||
|
||||
// draw the outer skybox
|
||||
if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
|
||||
matrix_t oldmodelview;
|
||||
|
||||
GL_State( 0 );
|
||||
//qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
|
||||
|
||||
{
|
||||
// FIXME: this could be a lot cleaner
|
||||
matrix_t trans, product;
|
||||
|
||||
Matrix16Copy( glState.modelview, oldmodelview );
|
||||
Matrix16Translation( backEnd.viewParms.or.origin, trans );
|
||||
Matrix16Multiply( glState.modelview, trans, product );
|
||||
GL_SetModelviewMatrix( product );
|
||||
|
||||
}
|
||||
|
||||
DrawSkyBox( tess.shader );
|
||||
|
||||
GL_SetModelviewMatrix( oldmodelview );
|
||||
}
|
||||
|
||||
// generate the vertexes for all the clouds, which will be drawn
|
||||
// by the generic shader routine
|
||||
R_BuildCloudData( &tess );
|
||||
|
||||
RB_StageIteratorGeneric();
|
||||
|
||||
// draw the inner skybox
|
||||
|
||||
|
||||
// back to normal depth range
|
||||
qglDepthRange( 0.0, 1.0 );
|
||||
|
||||
// note that sky was drawn so we will draw a sun later
|
||||
backEnd.skyRenderedThisView = qtrue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
48
code/renderergl2/tr_subs.c
Normal file
48
code/renderergl2/tr_subs.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2010 James Canete (use.less01@gmail.com)
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_subs.c - common function replacements for modular renderer
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
void QDECL Com_Printf( const char *msg, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
|
||||
va_start(argptr, msg);
|
||||
Q_vsnprintf(text, sizeof(text), msg, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
ri.Printf(PRINT_ALL, "%s", text);
|
||||
}
|
||||
|
||||
void QDECL Com_Error( int level, const char *error, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
|
||||
va_start(argptr, error);
|
||||
Q_vsnprintf(text, sizeof(text), error, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
ri.Error(level, "%s", text);
|
||||
}
|
1657
code/renderergl2/tr_surface.c
Normal file
1657
code/renderergl2/tr_surface.c
Normal file
File diff suppressed because it is too large
Load diff
928
code/renderergl2/tr_vbo.c
Normal file
928
code/renderergl2/tr_vbo.c
Normal file
|
@ -0,0 +1,928 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2007-2009 Robert Beckebans <trebor_7@users.sourceforge.net>
|
||||
|
||||
This file is part of XreaL source code.
|
||||
|
||||
XreaL 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.
|
||||
|
||||
XreaL 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 XreaL source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// tr_vbo.c
|
||||
#include "tr_local.h"
|
||||
|
||||
/*
|
||||
============
|
||||
R_CreateVBO
|
||||
============
|
||||
*/
|
||||
VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage)
|
||||
{
|
||||
VBO_t *vbo;
|
||||
int glUsage;
|
||||
|
||||
switch (usage)
|
||||
{
|
||||
case VBO_USAGE_STATIC:
|
||||
glUsage = GL_STATIC_DRAW_ARB;
|
||||
break;
|
||||
|
||||
case VBO_USAGE_DYNAMIC:
|
||||
glUsage = GL_DYNAMIC_DRAW_ARB;
|
||||
break;
|
||||
|
||||
default:
|
||||
Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(strlen(name) >= MAX_QPATH)
|
||||
{
|
||||
ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long", name);
|
||||
}
|
||||
|
||||
if ( tr.numVBOs == MAX_VBOS ) {
|
||||
ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit");
|
||||
}
|
||||
|
||||
R_IssuePendingRenderCommands();
|
||||
|
||||
vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low);
|
||||
tr.numVBOs++;
|
||||
|
||||
memset(vbo, 0, sizeof(*vbo));
|
||||
|
||||
Q_strncpyz(vbo->name, name, sizeof(vbo->name));
|
||||
|
||||
vbo->vertexesSize = vertexesSize;
|
||||
|
||||
qglGenBuffersARB(1, &vbo->vertexesVBO);
|
||||
|
||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
|
||||
qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage);
|
||||
|
||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
|
||||
glState.currentVBO = NULL;
|
||||
|
||||
GL_CheckErrors();
|
||||
|
||||
return vbo;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_CreateVBO2
|
||||
============
|
||||
*/
|
||||
VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts, unsigned int stateBits, vboUsage_t usage)
|
||||
{
|
||||
VBO_t *vbo;
|
||||
int i;
|
||||
|
||||
byte *data;
|
||||
int dataSize;
|
||||
int dataOfs;
|
||||
|
||||
int glUsage;
|
||||
|
||||
switch (usage)
|
||||
{
|
||||
case VBO_USAGE_STATIC:
|
||||
glUsage = GL_STATIC_DRAW_ARB;
|
||||
break;
|
||||
|
||||
case VBO_USAGE_DYNAMIC:
|
||||
glUsage = GL_DYNAMIC_DRAW_ARB;
|
||||
break;
|
||||
|
||||
default:
|
||||
Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!numVertexes)
|
||||
return NULL;
|
||||
|
||||
if(strlen(name) >= MAX_QPATH)
|
||||
{
|
||||
ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long", name);
|
||||
}
|
||||
|
||||
if ( tr.numVBOs == MAX_VBOS ) {
|
||||
ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit");
|
||||
}
|
||||
|
||||
R_IssuePendingRenderCommands();
|
||||
|
||||
vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low);
|
||||
tr.numVBOs++;
|
||||
|
||||
memset(vbo, 0, sizeof(*vbo));
|
||||
|
||||
Q_strncpyz(vbo->name, name, sizeof(vbo->name));
|
||||
|
||||
if (usage == VBO_USAGE_STATIC)
|
||||
{
|
||||
// since these vertex attributes are never altered, interleave them
|
||||
vbo->ofs_xyz = 0;
|
||||
dataSize = sizeof(verts[0].xyz);
|
||||
|
||||
if(stateBits & ATTR_NORMAL)
|
||||
{
|
||||
vbo->ofs_normal = dataSize;
|
||||
dataSize += sizeof(verts[0].normal);
|
||||
}
|
||||
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
if(stateBits & ATTR_TANGENT)
|
||||
{
|
||||
vbo->ofs_tangent = dataSize;
|
||||
dataSize += sizeof(verts[0].tangent);
|
||||
}
|
||||
|
||||
if(stateBits & ATTR_BITANGENT)
|
||||
{
|
||||
vbo->ofs_bitangent = dataSize;
|
||||
dataSize += sizeof(verts[0].bitangent);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(stateBits & ATTR_TEXCOORD)
|
||||
{
|
||||
vbo->ofs_st = dataSize;
|
||||
dataSize += sizeof(verts[0].st);
|
||||
}
|
||||
|
||||
if(stateBits & ATTR_LIGHTCOORD)
|
||||
{
|
||||
vbo->ofs_lightmap = dataSize;
|
||||
dataSize += sizeof(verts[0].lightmap);
|
||||
}
|
||||
|
||||
if(stateBits & ATTR_COLOR)
|
||||
{
|
||||
vbo->ofs_vertexcolor = dataSize;
|
||||
dataSize += sizeof(verts[0].vertexColors);
|
||||
}
|
||||
|
||||
if(stateBits & ATTR_LIGHTDIRECTION)
|
||||
{
|
||||
vbo->ofs_lightdir = dataSize;
|
||||
dataSize += sizeof(verts[0].lightdir);
|
||||
}
|
||||
|
||||
vbo->stride_xyz = dataSize;
|
||||
vbo->stride_normal = dataSize;
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
vbo->stride_tangent = dataSize;
|
||||
vbo->stride_bitangent = dataSize;
|
||||
#endif
|
||||
vbo->stride_st = dataSize;
|
||||
vbo->stride_lightmap = dataSize;
|
||||
vbo->stride_vertexcolor = dataSize;
|
||||
vbo->stride_lightdir = dataSize;
|
||||
|
||||
// create VBO
|
||||
dataSize *= numVertexes;
|
||||
data = ri.Hunk_AllocateTempMemory(dataSize);
|
||||
dataOfs = 0;
|
||||
|
||||
//ri.Printf(PRINT_ALL, "CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor,
|
||||
//vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor);
|
||||
|
||||
for (i = 0; i < numVertexes; i++)
|
||||
{
|
||||
// xyz
|
||||
memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz));
|
||||
dataOfs += sizeof(verts[i].xyz);
|
||||
|
||||
// normal
|
||||
if(stateBits & ATTR_NORMAL)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal));
|
||||
dataOfs += sizeof(verts[i].normal);
|
||||
}
|
||||
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
// tangent
|
||||
if(stateBits & ATTR_TANGENT)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent));
|
||||
dataOfs += sizeof(verts[i].tangent);
|
||||
}
|
||||
|
||||
// bitangent
|
||||
if(stateBits & ATTR_BITANGENT)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent));
|
||||
dataOfs += sizeof(verts[i].bitangent);
|
||||
}
|
||||
#endif
|
||||
|
||||
// vertex texcoords
|
||||
if(stateBits & ATTR_TEXCOORD)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
|
||||
dataOfs += sizeof(verts[i].st);
|
||||
}
|
||||
|
||||
// feed vertex lightmap texcoords
|
||||
if(stateBits & ATTR_LIGHTCOORD)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
|
||||
dataOfs += sizeof(verts[i].lightmap);
|
||||
}
|
||||
|
||||
// feed vertex colors
|
||||
if(stateBits & ATTR_COLOR)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors));
|
||||
dataOfs += sizeof(verts[i].vertexColors);
|
||||
}
|
||||
|
||||
// feed vertex light directions
|
||||
if(stateBits & ATTR_LIGHTDIRECTION)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
|
||||
dataOfs += sizeof(verts[i].lightdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// since these vertex attributes may be changed, put them in flat arrays
|
||||
dataSize = sizeof(verts[0].xyz);
|
||||
|
||||
if(stateBits & ATTR_NORMAL)
|
||||
{
|
||||
dataSize += sizeof(verts[0].normal);
|
||||
}
|
||||
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
if(stateBits & ATTR_TANGENT)
|
||||
{
|
||||
dataSize += sizeof(verts[0].tangent);
|
||||
}
|
||||
|
||||
if(stateBits & ATTR_BITANGENT)
|
||||
{
|
||||
dataSize += sizeof(verts[0].bitangent);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(stateBits & ATTR_TEXCOORD)
|
||||
{
|
||||
dataSize += sizeof(verts[0].st);
|
||||
}
|
||||
|
||||
if(stateBits & ATTR_LIGHTCOORD)
|
||||
{
|
||||
dataSize += sizeof(verts[0].lightmap);
|
||||
}
|
||||
|
||||
if(stateBits & ATTR_COLOR)
|
||||
{
|
||||
dataSize += sizeof(verts[0].vertexColors);
|
||||
}
|
||||
|
||||
if(stateBits & ATTR_LIGHTDIRECTION)
|
||||
{
|
||||
dataSize += sizeof(verts[0].lightdir);
|
||||
}
|
||||
|
||||
// create VBO
|
||||
dataSize *= numVertexes;
|
||||
data = ri.Hunk_AllocateTempMemory(dataSize);
|
||||
dataOfs = 0;
|
||||
|
||||
vbo->ofs_xyz = 0;
|
||||
vbo->ofs_normal = 0;
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
vbo->ofs_tangent = 0;
|
||||
vbo->ofs_bitangent = 0;
|
||||
#endif
|
||||
vbo->ofs_st = 0;
|
||||
vbo->ofs_lightmap = 0;
|
||||
vbo->ofs_vertexcolor = 0;
|
||||
vbo->ofs_lightdir = 0;
|
||||
|
||||
vbo->stride_xyz = sizeof(verts[0].xyz);
|
||||
vbo->stride_normal = sizeof(verts[0].normal);
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
vbo->stride_tangent = sizeof(verts[0].tangent);
|
||||
vbo->stride_bitangent = sizeof(verts[0].bitangent);
|
||||
#endif
|
||||
vbo->stride_vertexcolor = sizeof(verts[0].vertexColors);
|
||||
vbo->stride_st = sizeof(verts[0].st);
|
||||
vbo->stride_lightmap = sizeof(verts[0].lightmap);
|
||||
vbo->stride_lightdir = sizeof(verts[0].lightdir);
|
||||
|
||||
//ri.Printf(PRINT_ALL, "2CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor,
|
||||
//vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor);
|
||||
|
||||
// xyz
|
||||
for (i = 0; i < numVertexes; i++)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz));
|
||||
dataOfs += sizeof(verts[i].xyz);
|
||||
}
|
||||
|
||||
// normal
|
||||
if(stateBits & ATTR_NORMAL)
|
||||
{
|
||||
vbo->ofs_normal = dataOfs;
|
||||
for (i = 0; i < numVertexes; i++)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal));
|
||||
dataOfs += sizeof(verts[i].normal);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
// tangent
|
||||
if(stateBits & ATTR_TANGENT)
|
||||
{
|
||||
vbo->ofs_tangent = dataOfs;
|
||||
for (i = 0; i < numVertexes; i++)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent));
|
||||
dataOfs += sizeof(verts[i].tangent);
|
||||
}
|
||||
}
|
||||
|
||||
// bitangent
|
||||
if(stateBits & ATTR_BITANGENT)
|
||||
{
|
||||
vbo->ofs_bitangent = dataOfs;
|
||||
for (i = 0; i < numVertexes; i++)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent));
|
||||
dataOfs += sizeof(verts[i].bitangent);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// vertex texcoords
|
||||
if(stateBits & ATTR_TEXCOORD)
|
||||
{
|
||||
vbo->ofs_st = dataOfs;
|
||||
for (i = 0; i < numVertexes; i++)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
|
||||
dataOfs += sizeof(verts[i].st);
|
||||
}
|
||||
}
|
||||
|
||||
// feed vertex lightmap texcoords
|
||||
if(stateBits & ATTR_LIGHTCOORD)
|
||||
{
|
||||
vbo->ofs_lightmap = dataOfs;
|
||||
for (i = 0; i < numVertexes; i++)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
|
||||
dataOfs += sizeof(verts[i].lightmap);
|
||||
}
|
||||
}
|
||||
|
||||
// feed vertex colors
|
||||
if(stateBits & ATTR_COLOR)
|
||||
{
|
||||
vbo->ofs_vertexcolor = dataOfs;
|
||||
for (i = 0; i < numVertexes; i++)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors));
|
||||
dataOfs += sizeof(verts[i].vertexColors);
|
||||
}
|
||||
}
|
||||
|
||||
// feed vertex lightdirs
|
||||
if(stateBits & ATTR_LIGHTDIRECTION)
|
||||
{
|
||||
vbo->ofs_lightdir = dataOfs;
|
||||
for (i = 0; i < numVertexes; i++)
|
||||
{
|
||||
memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
|
||||
dataOfs += sizeof(verts[i].lightdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vbo->vertexesSize = dataSize;
|
||||
|
||||
qglGenBuffersARB(1, &vbo->vertexesVBO);
|
||||
|
||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
|
||||
qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage);
|
||||
|
||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
|
||||
glState.currentVBO = NULL;
|
||||
|
||||
GL_CheckErrors();
|
||||
|
||||
ri.Hunk_FreeTempMemory(data);
|
||||
|
||||
return vbo;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
R_CreateIBO
|
||||
============
|
||||
*/
|
||||
IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage)
|
||||
{
|
||||
IBO_t *ibo;
|
||||
int glUsage;
|
||||
|
||||
switch (usage)
|
||||
{
|
||||
case VBO_USAGE_STATIC:
|
||||
glUsage = GL_STATIC_DRAW_ARB;
|
||||
break;
|
||||
|
||||
case VBO_USAGE_DYNAMIC:
|
||||
glUsage = GL_DYNAMIC_DRAW_ARB;
|
||||
break;
|
||||
|
||||
default:
|
||||
Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(strlen(name) >= MAX_QPATH)
|
||||
{
|
||||
ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long", name);
|
||||
}
|
||||
|
||||
if ( tr.numIBOs == MAX_IBOS ) {
|
||||
ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit");
|
||||
}
|
||||
|
||||
R_IssuePendingRenderCommands();
|
||||
|
||||
ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low);
|
||||
tr.numIBOs++;
|
||||
|
||||
Q_strncpyz(ibo->name, name, sizeof(ibo->name));
|
||||
|
||||
ibo->indexesSize = indexesSize;
|
||||
|
||||
qglGenBuffersARB(1, &ibo->indexesVBO);
|
||||
|
||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO);
|
||||
qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage);
|
||||
|
||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
||||
|
||||
glState.currentIBO = NULL;
|
||||
|
||||
GL_CheckErrors();
|
||||
|
||||
return ibo;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_CreateIBO2
|
||||
============
|
||||
*/
|
||||
IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t * triangles, vboUsage_t usage)
|
||||
{
|
||||
IBO_t *ibo;
|
||||
int i, j;
|
||||
|
||||
byte *indexes;
|
||||
int indexesSize;
|
||||
int indexesOfs;
|
||||
|
||||
srfTriangle_t *tri;
|
||||
glIndex_t index;
|
||||
int glUsage;
|
||||
|
||||
switch (usage)
|
||||
{
|
||||
case VBO_USAGE_STATIC:
|
||||
glUsage = GL_STATIC_DRAW_ARB;
|
||||
break;
|
||||
|
||||
case VBO_USAGE_DYNAMIC:
|
||||
glUsage = GL_DYNAMIC_DRAW_ARB;
|
||||
break;
|
||||
|
||||
default:
|
||||
Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!numTriangles)
|
||||
return NULL;
|
||||
|
||||
if(strlen(name) >= MAX_QPATH)
|
||||
{
|
||||
ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long", name);
|
||||
}
|
||||
|
||||
if ( tr.numIBOs == MAX_IBOS ) {
|
||||
ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit");
|
||||
}
|
||||
|
||||
R_IssuePendingRenderCommands();
|
||||
|
||||
ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low);
|
||||
tr.numIBOs++;
|
||||
|
||||
Q_strncpyz(ibo->name, name, sizeof(ibo->name));
|
||||
|
||||
indexesSize = numTriangles * 3 * sizeof(int);
|
||||
indexes = ri.Hunk_AllocateTempMemory(indexesSize);
|
||||
indexesOfs = 0;
|
||||
|
||||
for(i = 0, tri = triangles; i < numTriangles; i++, tri++)
|
||||
{
|
||||
for(j = 0; j < 3; j++)
|
||||
{
|
||||
index = tri->indexes[j];
|
||||
memcpy(indexes + indexesOfs, &index, sizeof(glIndex_t));
|
||||
indexesOfs += sizeof(glIndex_t);
|
||||
}
|
||||
}
|
||||
|
||||
ibo->indexesSize = indexesSize;
|
||||
|
||||
qglGenBuffersARB(1, &ibo->indexesVBO);
|
||||
|
||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO);
|
||||
qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage);
|
||||
|
||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
||||
|
||||
glState.currentIBO = NULL;
|
||||
|
||||
GL_CheckErrors();
|
||||
|
||||
ri.Hunk_FreeTempMemory(indexes);
|
||||
|
||||
return ibo;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_BindVBO
|
||||
============
|
||||
*/
|
||||
void R_BindVBO(VBO_t * vbo)
|
||||
{
|
||||
if(!vbo)
|
||||
{
|
||||
//R_BindNullVBO();
|
||||
ri.Error(ERR_DROP, "R_BindNullVBO: NULL vbo");
|
||||
return;
|
||||
}
|
||||
|
||||
if(r_logFile->integer)
|
||||
{
|
||||
// don't just call LogComment, or we will get a call to va() every frame!
|
||||
GLimp_LogComment(va("--- R_BindVBO( %s ) ---\n", vbo->name));
|
||||
}
|
||||
|
||||
if(glState.currentVBO != vbo)
|
||||
{
|
||||
glState.currentVBO = vbo;
|
||||
glState.vertexAttribPointersSet = 0;
|
||||
|
||||
glState.vertexAttribsInterpolation = 0;
|
||||
glState.vertexAttribsOldFrame = 0;
|
||||
glState.vertexAttribsNewFrame = 0;
|
||||
|
||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
|
||||
|
||||
backEnd.pc.c_vboVertexBuffers++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_BindNullVBO
|
||||
============
|
||||
*/
|
||||
void R_BindNullVBO(void)
|
||||
{
|
||||
GLimp_LogComment("--- R_BindNullVBO ---\n");
|
||||
|
||||
if(glState.currentVBO)
|
||||
{
|
||||
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
glState.currentVBO = NULL;
|
||||
}
|
||||
|
||||
GL_CheckErrors();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_BindIBO
|
||||
============
|
||||
*/
|
||||
void R_BindIBO(IBO_t * ibo)
|
||||
{
|
||||
if(!ibo)
|
||||
{
|
||||
//R_BindNullIBO();
|
||||
ri.Error(ERR_DROP, "R_BindIBO: NULL ibo");
|
||||
return;
|
||||
}
|
||||
|
||||
if(r_logFile->integer)
|
||||
{
|
||||
// don't just call LogComment, or we will get a call to va() every frame!
|
||||
GLimp_LogComment(va("--- R_BindIBO( %s ) ---\n", ibo->name));
|
||||
}
|
||||
|
||||
if(glState.currentIBO != ibo)
|
||||
{
|
||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO);
|
||||
|
||||
glState.currentIBO = ibo;
|
||||
|
||||
backEnd.pc.c_vboIndexBuffers++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_BindNullIBO
|
||||
============
|
||||
*/
|
||||
void R_BindNullIBO(void)
|
||||
{
|
||||
GLimp_LogComment("--- R_BindNullIBO ---\n");
|
||||
|
||||
if(glState.currentIBO)
|
||||
{
|
||||
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
||||
glState.currentIBO = NULL;
|
||||
glState.vertexAttribPointersSet = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_InitVBOs
|
||||
============
|
||||
*/
|
||||
void R_InitVBOs(void)
|
||||
{
|
||||
int dataSize;
|
||||
int offset;
|
||||
|
||||
ri.Printf(PRINT_ALL, "------- R_InitVBOs -------\n");
|
||||
|
||||
tr.numVBOs = 0;
|
||||
tr.numIBOs = 0;
|
||||
|
||||
dataSize = sizeof(tess.xyz[0]);
|
||||
dataSize += sizeof(tess.normal[0]);
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
dataSize += sizeof(tess.tangent[0]);
|
||||
dataSize += sizeof(tess.bitangent[0]);
|
||||
#endif
|
||||
dataSize += sizeof(tess.vertexColors[0]);
|
||||
dataSize += sizeof(tess.texCoords[0][0]) * 2;
|
||||
dataSize += sizeof(tess.lightdir[0]);
|
||||
dataSize *= SHADER_MAX_VERTEXES;
|
||||
|
||||
tess.vbo = R_CreateVBO("tessVertexArray_VBO", NULL, dataSize, VBO_USAGE_DYNAMIC);
|
||||
|
||||
offset = 0;
|
||||
|
||||
tess.vbo->ofs_xyz = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES;
|
||||
tess.vbo->ofs_normal = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES;
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
tess.vbo->ofs_tangent = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES;
|
||||
tess.vbo->ofs_bitangent = offset; offset += sizeof(tess.bitangent[0]) * SHADER_MAX_VERTEXES;
|
||||
#endif
|
||||
// these next two are actually interleaved
|
||||
tess.vbo->ofs_st = offset;
|
||||
tess.vbo->ofs_lightmap = offset + sizeof(tess.texCoords[0][0]);
|
||||
offset += sizeof(tess.texCoords[0][0]) * 2 * SHADER_MAX_VERTEXES;
|
||||
|
||||
tess.vbo->ofs_vertexcolor = offset; offset += sizeof(tess.vertexColors[0]) * SHADER_MAX_VERTEXES;
|
||||
tess.vbo->ofs_lightdir = offset;
|
||||
|
||||
tess.vbo->stride_xyz = sizeof(tess.xyz[0]);
|
||||
tess.vbo->stride_normal = sizeof(tess.normal[0]);
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
tess.vbo->stride_tangent = sizeof(tess.tangent[0]);
|
||||
tess.vbo->stride_bitangent = sizeof(tess.bitangent[0]);
|
||||
#endif
|
||||
tess.vbo->stride_vertexcolor = sizeof(tess.vertexColors[0]);
|
||||
tess.vbo->stride_st = sizeof(tess.texCoords[0][0]) * 2;
|
||||
tess.vbo->stride_lightmap = sizeof(tess.texCoords[0][0]) * 2;
|
||||
tess.vbo->stride_lightdir = sizeof(tess.lightdir[0]);
|
||||
|
||||
dataSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES;
|
||||
|
||||
tess.ibo = R_CreateIBO("tessVertexArray_IBO", NULL, dataSize, VBO_USAGE_DYNAMIC);
|
||||
|
||||
R_BindNullVBO();
|
||||
R_BindNullIBO();
|
||||
|
||||
GL_CheckErrors();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_ShutdownVBOs
|
||||
============
|
||||
*/
|
||||
void R_ShutdownVBOs(void)
|
||||
{
|
||||
int i;
|
||||
VBO_t *vbo;
|
||||
IBO_t *ibo;
|
||||
|
||||
ri.Printf(PRINT_ALL, "------- R_ShutdownVBOs -------\n");
|
||||
|
||||
R_BindNullVBO();
|
||||
R_BindNullIBO();
|
||||
|
||||
|
||||
for(i = 0; i < tr.numVBOs; i++)
|
||||
{
|
||||
vbo = tr.vbos[i];
|
||||
|
||||
if(vbo->vertexesVBO)
|
||||
{
|
||||
qglDeleteBuffersARB(1, &vbo->vertexesVBO);
|
||||
}
|
||||
|
||||
//ri.Free(vbo);
|
||||
}
|
||||
|
||||
for(i = 0; i < tr.numIBOs; i++)
|
||||
{
|
||||
ibo = tr.ibos[i];
|
||||
|
||||
if(ibo->indexesVBO)
|
||||
{
|
||||
qglDeleteBuffersARB(1, &ibo->indexesVBO);
|
||||
}
|
||||
|
||||
//ri.Free(ibo);
|
||||
}
|
||||
|
||||
tr.numVBOs = 0;
|
||||
tr.numIBOs = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
R_VBOList_f
|
||||
============
|
||||
*/
|
||||
void R_VBOList_f(void)
|
||||
{
|
||||
int i;
|
||||
VBO_t *vbo;
|
||||
IBO_t *ibo;
|
||||
int vertexesSize = 0;
|
||||
int indexesSize = 0;
|
||||
|
||||
ri.Printf(PRINT_ALL, " size name\n");
|
||||
ri.Printf(PRINT_ALL, "----------------------------------------------------------\n");
|
||||
|
||||
for(i = 0; i < tr.numVBOs; i++)
|
||||
{
|
||||
vbo = tr.vbos[i];
|
||||
|
||||
ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vbo->vertexesSize / (1024 * 1024),
|
||||
(vbo->vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vbo->name);
|
||||
|
||||
vertexesSize += vbo->vertexesSize;
|
||||
}
|
||||
|
||||
for(i = 0; i < tr.numIBOs; i++)
|
||||
{
|
||||
ibo = tr.ibos[i];
|
||||
|
||||
ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", ibo->indexesSize / (1024 * 1024),
|
||||
(ibo->indexesSize % (1024 * 1024)) * 100 / (1024 * 1024), ibo->name);
|
||||
|
||||
indexesSize += ibo->indexesSize;
|
||||
}
|
||||
|
||||
ri.Printf(PRINT_ALL, " %i total VBOs\n", tr.numVBOs);
|
||||
ri.Printf(PRINT_ALL, " %d.%02d MB total vertices memory\n", vertexesSize / (1024 * 1024),
|
||||
(vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
|
||||
|
||||
ri.Printf(PRINT_ALL, " %i total IBOs\n", tr.numIBOs);
|
||||
ri.Printf(PRINT_ALL, " %d.%02d MB total triangle indices memory\n", indexesSize / (1024 * 1024),
|
||||
(indexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
RB_UpdateVBOs
|
||||
|
||||
Adapted from Tess_UpdateVBOs from xreal
|
||||
|
||||
Update the default VBO to replace the client side vertex arrays
|
||||
==============
|
||||
*/
|
||||
void RB_UpdateVBOs(unsigned int attribBits)
|
||||
{
|
||||
GLimp_LogComment("--- RB_UpdateVBOs ---\n");
|
||||
|
||||
backEnd.pc.c_dynamicVboDraws++;
|
||||
|
||||
// update the default VBO
|
||||
if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES)
|
||||
{
|
||||
R_BindVBO(tess.vbo);
|
||||
|
||||
if(attribBits & ATTR_BITS)
|
||||
{
|
||||
if(attribBits & ATTR_POSITION)
|
||||
{
|
||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]));
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz);
|
||||
}
|
||||
|
||||
if(attribBits & ATTR_TEXCOORD || attribBits & ATTR_LIGHTCOORD)
|
||||
{
|
||||
// these are interleaved, so we update both if either need it
|
||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2);
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords);
|
||||
}
|
||||
|
||||
if(attribBits & ATTR_NORMAL)
|
||||
{
|
||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]));
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal);
|
||||
}
|
||||
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
if(attribBits & ATTR_TANGENT)
|
||||
{
|
||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]));
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent);
|
||||
}
|
||||
|
||||
if(attribBits & ATTR_BITANGENT)
|
||||
{
|
||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]));
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]), tess.bitangent);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(attribBits & ATTR_COLOR)
|
||||
{
|
||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]));
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors);
|
||||
}
|
||||
|
||||
if(attribBits & ATTR_LIGHTDIRECTION)
|
||||
{
|
||||
//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]));
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz);
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords);
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal);
|
||||
#ifdef USE_VERT_TANGENT_SPACE
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent);
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]), tess.bitangent);
|
||||
#endif
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors);
|
||||
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// update the default IBO
|
||||
if(tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES)
|
||||
{
|
||||
R_BindIBO(tess.ibo);
|
||||
|
||||
qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes);
|
||||
}
|
||||
}
|
850
code/renderergl2/tr_world.c
Normal file
850
code/renderergl2/tr_world.c
Normal file
|
@ -0,0 +1,850 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena 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.
|
||||
|
||||
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "tr_local.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_CullSurface
|
||||
|
||||
Tries to cull surfaces before they are lighted or
|
||||
added to the sorting list.
|
||||
================
|
||||
*/
|
||||
static qboolean R_CullSurface( msurface_t *surf ) {
|
||||
if ( r_nocull->integer || surf->cullinfo.type == CULLINFO_NONE) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if (surf->cullinfo.type & CULLINFO_PLANE)
|
||||
{
|
||||
// Only true for SF_FACE, so treat like its own function
|
||||
float d;
|
||||
cullType_t ct;
|
||||
|
||||
if ( !r_facePlaneCull->integer ) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
ct = surf->shader->cullType;
|
||||
|
||||
if (ct == CT_TWO_SIDED)
|
||||
{
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
// don't cull for depth shadow
|
||||
/*
|
||||
if ( tr.viewParms.flags & VPF_DEPTHSHADOW )
|
||||
{
|
||||
return qfalse;
|
||||
}
|
||||
*/
|
||||
|
||||
// shadowmaps draw back surfaces
|
||||
if ( tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW) )
|
||||
{
|
||||
if (ct == CT_FRONT_SIDED)
|
||||
{
|
||||
ct = CT_BACK_SIDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
ct = CT_FRONT_SIDED;
|
||||
}
|
||||
}
|
||||
|
||||
// do proper cull for orthographic projection
|
||||
if (tr.viewParms.flags & VPF_ORTHOGRAPHIC) {
|
||||
d = DotProduct(tr.viewParms.or.axis[0], surf->cullinfo.plane.normal);
|
||||
if ( ct == CT_FRONT_SIDED ) {
|
||||
if (d > 0)
|
||||
return qtrue;
|
||||
} else {
|
||||
if (d < 0)
|
||||
return qtrue;
|
||||
}
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
d = DotProduct (tr.or.viewOrigin, surf->cullinfo.plane.normal);
|
||||
|
||||
// don't cull exactly on the plane, because there are levels of rounding
|
||||
// through the BSP, ICD, and hardware that may cause pixel gaps if an
|
||||
// epsilon isn't allowed here
|
||||
if ( ct == CT_FRONT_SIDED ) {
|
||||
if ( d < surf->cullinfo.plane.dist - 8 ) {
|
||||
return qtrue;
|
||||
}
|
||||
} else {
|
||||
if ( d > surf->cullinfo.plane.dist + 8 ) {
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if (surf->cullinfo.type & CULLINFO_SPHERE)
|
||||
{
|
||||
int sphereCull;
|
||||
|
||||
if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) {
|
||||
sphereCull = R_CullLocalPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius );
|
||||
} else {
|
||||
sphereCull = R_CullPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius );
|
||||
}
|
||||
|
||||
if ( sphereCull == CULL_OUT )
|
||||
{
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
if (surf->cullinfo.type & CULLINFO_BOX)
|
||||
{
|
||||
int boxCull;
|
||||
|
||||
if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) {
|
||||
boxCull = R_CullLocalBox( surf->cullinfo.bounds );
|
||||
} else {
|
||||
boxCull = R_CullBox( surf->cullinfo.bounds );
|
||||
}
|
||||
|
||||
if ( boxCull == CULL_OUT )
|
||||
{
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
R_DlightSurface
|
||||
|
||||
The given surface is going to be drawn, and it touches a leaf
|
||||
that is touched by one or more dlights, so try to throw out
|
||||
more dlights if possible.
|
||||
====================
|
||||
*/
|
||||
static int R_DlightSurface( msurface_t *surf, int dlightBits ) {
|
||||
float d;
|
||||
int i;
|
||||
dlight_t *dl;
|
||||
|
||||
if ( surf->cullinfo.type & CULLINFO_PLANE )
|
||||
{
|
||||
int i;
|
||||
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
|
||||
if ( ! ( dlightBits & ( 1 << i ) ) ) {
|
||||
continue;
|
||||
}
|
||||
dl = &tr.refdef.dlights[i];
|
||||
d = DotProduct( dl->origin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist;
|
||||
if ( d < -dl->radius || d > dl->radius ) {
|
||||
// dlight doesn't reach the plane
|
||||
dlightBits &= ~( 1 << i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( surf->cullinfo.type & CULLINFO_BOX )
|
||||
{
|
||||
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
|
||||
if ( ! ( dlightBits & ( 1 << i ) ) ) {
|
||||
continue;
|
||||
}
|
||||
dl = &tr.refdef.dlights[i];
|
||||
if ( dl->origin[0] - dl->radius > surf->cullinfo.bounds[1][0]
|
||||
|| dl->origin[0] + dl->radius < surf->cullinfo.bounds[0][0]
|
||||
|| dl->origin[1] - dl->radius > surf->cullinfo.bounds[1][1]
|
||||
|| dl->origin[1] + dl->radius < surf->cullinfo.bounds[0][1]
|
||||
|| dl->origin[2] - dl->radius > surf->cullinfo.bounds[1][2]
|
||||
|| dl->origin[2] + dl->radius < surf->cullinfo.bounds[0][2] ) {
|
||||
// dlight doesn't reach the bounds
|
||||
dlightBits &= ~( 1 << i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( surf->cullinfo.type & CULLINFO_SPHERE )
|
||||
{
|
||||
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
|
||||
if ( ! ( dlightBits & ( 1 << i ) ) ) {
|
||||
continue;
|
||||
}
|
||||
dl = &tr.refdef.dlights[i];
|
||||
if (!SpheresIntersect(dl->origin, dl->radius, surf->cullinfo.localOrigin, surf->cullinfo.radius))
|
||||
{
|
||||
// dlight doesn't reach the bounds
|
||||
dlightBits &= ~( 1 << i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( *surf->data == SF_FACE ) {
|
||||
((srfSurfaceFace_t *)surf->data)->dlightBits = dlightBits;
|
||||
} else if ( *surf->data == SF_GRID ) {
|
||||
((srfGridMesh_t *)surf->data)->dlightBits = dlightBits;
|
||||
} else if ( *surf->data == SF_TRIANGLES ) {
|
||||
((srfTriangles_t *)surf->data)->dlightBits = dlightBits;
|
||||
} else if ( *surf->data == SF_VBO_MESH ) {
|
||||
((srfVBOMesh_t *)surf->data)->dlightBits = dlightBits;
|
||||
} else {
|
||||
dlightBits = 0;
|
||||
}
|
||||
|
||||
if ( dlightBits ) {
|
||||
tr.pc.c_dlightSurfaces++;
|
||||
}
|
||||
|
||||
return dlightBits;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
R_PshadowSurface
|
||||
|
||||
Just like R_DlightSurface, cull any we can
|
||||
====================
|
||||
*/
|
||||
static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) {
|
||||
float d;
|
||||
int i;
|
||||
pshadow_t *ps;
|
||||
|
||||
if ( surf->cullinfo.type & CULLINFO_PLANE )
|
||||
{
|
||||
int i;
|
||||
for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
|
||||
if ( ! ( pshadowBits & ( 1 << i ) ) ) {
|
||||
continue;
|
||||
}
|
||||
ps = &tr.refdef.pshadows[i];
|
||||
d = DotProduct( ps->lightOrigin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist;
|
||||
if ( d < -ps->lightRadius || d > ps->lightRadius ) {
|
||||
// pshadow doesn't reach the plane
|
||||
pshadowBits &= ~( 1 << i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( surf->cullinfo.type & CULLINFO_BOX )
|
||||
{
|
||||
for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
|
||||
if ( ! ( pshadowBits & ( 1 << i ) ) ) {
|
||||
continue;
|
||||
}
|
||||
ps = &tr.refdef.pshadows[i];
|
||||
if ( ps->lightOrigin[0] - ps->lightRadius > surf->cullinfo.bounds[1][0]
|
||||
|| ps->lightOrigin[0] + ps->lightRadius < surf->cullinfo.bounds[0][0]
|
||||
|| ps->lightOrigin[1] - ps->lightRadius > surf->cullinfo.bounds[1][1]
|
||||
|| ps->lightOrigin[1] + ps->lightRadius < surf->cullinfo.bounds[0][1]
|
||||
|| ps->lightOrigin[2] - ps->lightRadius > surf->cullinfo.bounds[1][2]
|
||||
|| ps->lightOrigin[2] + ps->lightRadius < surf->cullinfo.bounds[0][2]
|
||||
|| BoxOnPlaneSide(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1], &ps->cullPlane) == 2 ) {
|
||||
// pshadow doesn't reach the bounds
|
||||
pshadowBits &= ~( 1 << i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( surf->cullinfo.type & CULLINFO_SPHERE )
|
||||
{
|
||||
for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
|
||||
if ( ! ( pshadowBits & ( 1 << i ) ) ) {
|
||||
continue;
|
||||
}
|
||||
ps = &tr.refdef.pshadows[i];
|
||||
if (!SpheresIntersect(ps->viewOrigin, ps->viewRadius, surf->cullinfo.localOrigin, surf->cullinfo.radius)
|
||||
|| DotProduct( surf->cullinfo.localOrigin, ps->cullPlane.normal ) - ps->cullPlane.dist < -surf->cullinfo.radius)
|
||||
{
|
||||
// pshadow doesn't reach the bounds
|
||||
pshadowBits &= ~( 1 << i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( *surf->data == SF_FACE ) {
|
||||
((srfSurfaceFace_t *)surf->data)->pshadowBits = pshadowBits;
|
||||
} else if ( *surf->data == SF_GRID ) {
|
||||
((srfGridMesh_t *)surf->data)->pshadowBits = pshadowBits;
|
||||
} else if ( *surf->data == SF_TRIANGLES ) {
|
||||
((srfTriangles_t *)surf->data)->pshadowBits = pshadowBits;
|
||||
} else if ( *surf->data == SF_VBO_MESH ) {
|
||||
((srfVBOMesh_t *)surf->data)->pshadowBits = pshadowBits;
|
||||
} else {
|
||||
pshadowBits = 0;
|
||||
}
|
||||
|
||||
if ( pshadowBits ) {
|
||||
//tr.pc.c_dlightSurfaces++;
|
||||
}
|
||||
|
||||
return pshadowBits;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
======================
|
||||
R_AddWorldSurface
|
||||
======================
|
||||
*/
|
||||
static void R_AddWorldSurface( msurface_t *surf, int dlightBits, int pshadowBits ) {
|
||||
// FIXME: bmodel fog?
|
||||
|
||||
// try to cull before dlighting or adding
|
||||
if ( R_CullSurface( surf ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for dlighting
|
||||
if ( dlightBits ) {
|
||||
dlightBits = R_DlightSurface( surf, dlightBits );
|
||||
dlightBits = ( dlightBits != 0 );
|
||||
}
|
||||
|
||||
// check for pshadows
|
||||
/*if ( pshadowBits ) */{
|
||||
pshadowBits = R_PshadowSurface( surf, pshadowBits);
|
||||
pshadowBits = ( pshadowBits != 0 );
|
||||
}
|
||||
|
||||
R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits );
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================
|
||||
|
||||
BRUSH MODELS
|
||||
|
||||
=============================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AddBrushModelSurfaces
|
||||
=================
|
||||
*/
|
||||
void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
|
||||
bmodel_t *bmodel;
|
||||
int clip;
|
||||
model_t *pModel;
|
||||
int i;
|
||||
|
||||
pModel = R_GetModelByHandle( ent->e.hModel );
|
||||
|
||||
bmodel = pModel->bmodel;
|
||||
|
||||
clip = R_CullLocalBox( bmodel->bounds );
|
||||
if ( clip == CULL_OUT ) {
|
||||
return;
|
||||
}
|
||||
|
||||
R_SetupEntityLighting( &tr.refdef, ent );
|
||||
R_DlightBmodel( bmodel );
|
||||
|
||||
for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
|
||||
int surf = bmodel->firstSurface + i;
|
||||
|
||||
if (tr.world->surfacesViewCount[surf] != tr.viewCount)
|
||||
{
|
||||
tr.world->surfacesViewCount[surf] = tr.viewCount;
|
||||
R_AddWorldSurface( tr.world->surfaces + surf, tr.currentEntity->needDlights, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================
|
||||
|
||||
WORLD MODEL
|
||||
|
||||
=============================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RecursiveWorldNode
|
||||
================
|
||||
*/
|
||||
static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits, int pshadowBits ) {
|
||||
|
||||
do {
|
||||
int newDlights[2];
|
||||
unsigned int newPShadows[2];
|
||||
|
||||
// if the node wasn't marked as potentially visible, exit
|
||||
// pvs is skipped for depth shadows
|
||||
if (!(tr.viewParms.flags & VPF_DEPTHSHADOW) && node->visCounts[tr.visIndex] != tr.visCounts[tr.visIndex]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the bounding volume is outside the frustum, nothing
|
||||
// inside can be visible OPTIMIZE: don't do this all the way to leafs?
|
||||
|
||||
if ( !r_nocull->integer ) {
|
||||
int r;
|
||||
|
||||
if ( planeBits & 1 ) {
|
||||
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
|
||||
if (r == 2) {
|
||||
return; // culled
|
||||
}
|
||||
if ( r == 1 ) {
|
||||
planeBits &= ~1; // all descendants will also be in front
|
||||
}
|
||||
}
|
||||
|
||||
if ( planeBits & 2 ) {
|
||||
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
|
||||
if (r == 2) {
|
||||
return; // culled
|
||||
}
|
||||
if ( r == 1 ) {
|
||||
planeBits &= ~2; // all descendants will also be in front
|
||||
}
|
||||
}
|
||||
|
||||
if ( planeBits & 4 ) {
|
||||
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
|
||||
if (r == 2) {
|
||||
return; // culled
|
||||
}
|
||||
if ( r == 1 ) {
|
||||
planeBits &= ~4; // all descendants will also be in front
|
||||
}
|
||||
}
|
||||
|
||||
if ( planeBits & 8 ) {
|
||||
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
|
||||
if (r == 2) {
|
||||
return; // culled
|
||||
}
|
||||
if ( r == 1 ) {
|
||||
planeBits &= ~8; // all descendants will also be in front
|
||||
}
|
||||
}
|
||||
|
||||
if ( planeBits & 16 ) {
|
||||
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[4]);
|
||||
if (r == 2) {
|
||||
return; // culled
|
||||
}
|
||||
if ( r == 1 ) {
|
||||
planeBits &= ~16; // all descendants will also be in front
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( node->contents != -1 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// node is just a decision point, so go down both sides
|
||||
// since we don't care about sort orders, just go positive to negative
|
||||
|
||||
// determine which dlights are needed
|
||||
newDlights[0] = 0;
|
||||
newDlights[1] = 0;
|
||||
if ( dlightBits ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
|
||||
dlight_t *dl;
|
||||
float dist;
|
||||
|
||||
if ( dlightBits & ( 1 << i ) ) {
|
||||
dl = &tr.refdef.dlights[i];
|
||||
dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
|
||||
|
||||
if ( dist > -dl->radius ) {
|
||||
newDlights[0] |= ( 1 << i );
|
||||
}
|
||||
if ( dist < dl->radius ) {
|
||||
newDlights[1] |= ( 1 << i );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newPShadows[0] = 0;
|
||||
newPShadows[1] = 0;
|
||||
if ( pshadowBits ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
|
||||
pshadow_t *shadow;
|
||||
float dist;
|
||||
|
||||
if ( pshadowBits & ( 1 << i ) ) {
|
||||
shadow = &tr.refdef.pshadows[i];
|
||||
dist = DotProduct( shadow->lightOrigin, node->plane->normal ) - node->plane->dist;
|
||||
|
||||
if ( dist > -shadow->lightRadius ) {
|
||||
newPShadows[0] |= ( 1 << i );
|
||||
}
|
||||
if ( dist < shadow->lightRadius ) {
|
||||
newPShadows[1] |= ( 1 << i );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recurse down the children, front side first
|
||||
R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0], newPShadows[0] );
|
||||
|
||||
// tail recurse
|
||||
node = node->children[1];
|
||||
dlightBits = newDlights[1];
|
||||
pshadowBits = newPShadows[1];
|
||||
} while ( 1 );
|
||||
|
||||
{
|
||||
// leaf node, so add mark surfaces
|
||||
int c;
|
||||
int surf, *view;
|
||||
|
||||
tr.pc.c_leafs++;
|
||||
|
||||
// add to z buffer bounds
|
||||
if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
|
||||
tr.viewParms.visBounds[0][0] = node->mins[0];
|
||||
}
|
||||
if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
|
||||
tr.viewParms.visBounds[0][1] = node->mins[1];
|
||||
}
|
||||
if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
|
||||
tr.viewParms.visBounds[0][2] = node->mins[2];
|
||||
}
|
||||
|
||||
if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
|
||||
tr.viewParms.visBounds[1][0] = node->maxs[0];
|
||||
}
|
||||
if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
|
||||
tr.viewParms.visBounds[1][1] = node->maxs[1];
|
||||
}
|
||||
if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
|
||||
tr.viewParms.visBounds[1][2] = node->maxs[2];
|
||||
}
|
||||
|
||||
// add merged and unmerged surfaces
|
||||
if (tr.world->viewSurfaces)
|
||||
view = tr.world->viewSurfaces + node->firstmarksurface;
|
||||
else
|
||||
view = tr.world->marksurfaces + node->firstmarksurface;
|
||||
|
||||
c = node->nummarksurfaces;
|
||||
while (c--) {
|
||||
// just mark it as visible, so we don't jump out of the cache derefencing the surface
|
||||
surf = *view;
|
||||
if (surf < 0)
|
||||
{
|
||||
if (tr.world->mergedSurfacesViewCount[-surf - 1] != tr.viewCount)
|
||||
{
|
||||
tr.world->mergedSurfacesViewCount[-surf - 1] = tr.viewCount;
|
||||
tr.world->mergedSurfacesDlightBits[-surf - 1] = dlightBits;
|
||||
tr.world->mergedSurfacesPshadowBits[-surf - 1] = pshadowBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.world->mergedSurfacesDlightBits[-surf - 1] |= dlightBits;
|
||||
tr.world->mergedSurfacesPshadowBits[-surf - 1] |= pshadowBits;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tr.world->surfacesViewCount[surf] != tr.viewCount)
|
||||
{
|
||||
tr.world->surfacesViewCount[surf] = tr.viewCount;
|
||||
tr.world->surfacesDlightBits[surf] = dlightBits;
|
||||
tr.world->surfacesPshadowBits[surf] = pshadowBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.world->surfacesDlightBits[surf] |= dlightBits;
|
||||
tr.world->surfacesPshadowBits[surf] |= pshadowBits;
|
||||
}
|
||||
}
|
||||
view++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_PointInLeaf
|
||||
===============
|
||||
*/
|
||||
static mnode_t *R_PointInLeaf( const vec3_t p ) {
|
||||
mnode_t *node;
|
||||
float d;
|
||||
cplane_t *plane;
|
||||
|
||||
if ( !tr.world ) {
|
||||
ri.Error (ERR_DROP, "R_PointInLeaf: bad model");
|
||||
}
|
||||
|
||||
node = tr.world->nodes;
|
||||
while( 1 ) {
|
||||
if (node->contents != -1) {
|
||||
break;
|
||||
}
|
||||
plane = node->plane;
|
||||
d = DotProduct (p,plane->normal) - plane->dist;
|
||||
if (d > 0) {
|
||||
node = node->children[0];
|
||||
} else {
|
||||
node = node->children[1];
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
R_ClusterPVS
|
||||
==============
|
||||
*/
|
||||
static const byte *R_ClusterPVS (int cluster) {
|
||||
if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {
|
||||
return tr.world->novis;
|
||||
}
|
||||
|
||||
return tr.world->vis + cluster * tr.world->clusterBytes;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_inPVS
|
||||
=================
|
||||
*/
|
||||
qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) {
|
||||
mnode_t *leaf;
|
||||
byte *vis;
|
||||
|
||||
leaf = R_PointInLeaf( p1 );
|
||||
vis = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ??
|
||||
leaf = R_PointInLeaf( p2 );
|
||||
|
||||
if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) {
|
||||
return qfalse;
|
||||
}
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_MarkLeaves
|
||||
|
||||
Mark the leaves and nodes that are in the PVS for the current
|
||||
cluster
|
||||
===============
|
||||
*/
|
||||
static void R_MarkLeaves (void) {
|
||||
const byte *vis;
|
||||
mnode_t *leaf, *parent;
|
||||
int i;
|
||||
int cluster;
|
||||
|
||||
// lockpvs lets designers walk around to determine the
|
||||
// extent of the current pvs
|
||||
if ( r_lockpvs->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// current viewcluster
|
||||
leaf = R_PointInLeaf( tr.viewParms.pvsOrigin );
|
||||
cluster = leaf->cluster;
|
||||
|
||||
// if the cluster is the same and the area visibility matrix
|
||||
// hasn't changed, we don't need to mark everything again
|
||||
|
||||
for(i = 0; i < MAX_VISCOUNTS; i++)
|
||||
{
|
||||
if(tr.visClusters[i] == cluster)
|
||||
{
|
||||
//tr.visIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if r_showcluster was just turned on, remark everything
|
||||
if(i != MAX_VISCOUNTS && !tr.refdef.areamaskModified && !r_showcluster->modified)// && !r_dynamicBspOcclusionCulling->modified)
|
||||
{
|
||||
if(tr.visClusters[i] != tr.visClusters[tr.visIndex] && r_showcluster->integer)
|
||||
{
|
||||
ri.Printf(PRINT_ALL, "found cluster:%i area:%i index:%i\n", cluster, leaf->area, i);
|
||||
}
|
||||
tr.visIndex = i;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the areamask was modified, invalidate all visclusters
|
||||
// this caused doors to open into undrawn areas
|
||||
if (tr.refdef.areamaskModified)
|
||||
{
|
||||
memset(tr.visClusters, -2, sizeof(tr.visClusters));
|
||||
}
|
||||
|
||||
tr.visIndex = (tr.visIndex + 1) % MAX_VISCOUNTS;
|
||||
tr.visCounts[tr.visIndex]++;
|
||||
tr.visClusters[tr.visIndex] = cluster;
|
||||
|
||||
if ( r_showcluster->modified || r_showcluster->integer ) {
|
||||
r_showcluster->modified = qfalse;
|
||||
if ( r_showcluster->integer ) {
|
||||
ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area );
|
||||
}
|
||||
}
|
||||
|
||||
// set all nodes to visible if there is no vis
|
||||
// this caused some levels to simply not render
|
||||
if (r_novis->integer || !tr.world->vis || tr.visClusters[tr.visIndex] == -1) {
|
||||
for (i=0 ; i<tr.world->numnodes ; i++) {
|
||||
if (tr.world->nodes[i].contents != CONTENTS_SOLID) {
|
||||
tr.world->nodes[i].visCounts[tr.visIndex] = tr.visCounts[tr.visIndex];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
vis = R_ClusterPVS(tr.visClusters[tr.visIndex]);
|
||||
|
||||
for (i=0,leaf=tr.world->nodes ; i<tr.world->numnodes ; i++, leaf++) {
|
||||
cluster = leaf->cluster;
|
||||
if ( cluster < 0 || cluster >= tr.world->numClusters ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check general pvs
|
||||
if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for door connection
|
||||
if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) {
|
||||
continue; // not visible
|
||||
}
|
||||
|
||||
parent = leaf;
|
||||
do {
|
||||
if(parent->visCounts[tr.visIndex] == tr.visCounts[tr.visIndex])
|
||||
break;
|
||||
parent->visCounts[tr.visIndex] = tr.visCounts[tr.visIndex];
|
||||
parent = parent->parent;
|
||||
} while (parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_AddWorldSurfaces
|
||||
=============
|
||||
*/
|
||||
void R_AddWorldSurfaces (void) {
|
||||
int planeBits, dlightBits, pshadowBits;
|
||||
|
||||
if ( !r_drawworld->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
tr.currentEntityNum = REFENTITYNUM_WORLD;
|
||||
tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
|
||||
|
||||
// determine which leaves are in the PVS / areamask
|
||||
if (!(tr.viewParms.flags & VPF_DEPTHSHADOW))
|
||||
R_MarkLeaves ();
|
||||
|
||||
// clear out the visible min/max
|
||||
ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
|
||||
|
||||
// perform frustum culling and flag all the potentially visible surfaces
|
||||
if ( tr.refdef.num_dlights > 32 ) {
|
||||
tr.refdef.num_dlights = 32 ;
|
||||
}
|
||||
|
||||
if ( tr.refdef.num_pshadows > 32 ) {
|
||||
tr.refdef.num_pshadows = 32 ;
|
||||
}
|
||||
|
||||
planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15;
|
||||
|
||||
if ( tr.viewParms.flags & VPF_DEPTHSHADOW )
|
||||
{
|
||||
dlightBits = 0;
|
||||
pshadowBits = 0;
|
||||
}
|
||||
else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) )
|
||||
{
|
||||
dlightBits = ( 1 << tr.refdef.num_dlights ) - 1;
|
||||
pshadowBits = ( 1 << tr.refdef.num_pshadows ) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dlightBits = ( 1 << tr.refdef.num_dlights ) - 1;
|
||||
pshadowBits = 0;
|
||||
}
|
||||
|
||||
R_RecursiveWorldNode( tr.world->nodes, planeBits, dlightBits, pshadowBits);
|
||||
|
||||
// now add all the potentially visible surfaces
|
||||
// also mask invisible dlights for next frame
|
||||
{
|
||||
int i;
|
||||
|
||||
tr.refdef.dlightMask = 0;
|
||||
|
||||
for (i = 0; i < tr.world->numWorldSurfaces; i++)
|
||||
{
|
||||
if (tr.world->surfacesViewCount[i] != tr.viewCount)
|
||||
continue;
|
||||
|
||||
R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] );
|
||||
tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i];
|
||||
}
|
||||
for (i = 0; i < tr.world->numMergedSurfaces; i++)
|
||||
{
|
||||
if (tr.world->mergedSurfacesViewCount[i] != tr.viewCount)
|
||||
continue;
|
||||
|
||||
R_AddWorldSurface( tr.world->mergedSurfaces + i, tr.world->mergedSurfacesDlightBits[i], tr.world->mergedSurfacesPshadowBits[i] );
|
||||
tr.refdef.dlightMask |= tr.world->mergedSurfacesDlightBits[i];
|
||||
}
|
||||
|
||||
tr.refdef.dlightMask = ~tr.refdef.dlightMask;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue