mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-25 07:05:40 +00:00
Updated Fragment_NoSpotlight.glsl (fragment shader for legacy engine without spot light)
This commit is contained in:
parent
732bff2769
commit
0ab486645c
|
@ -1,202 +1,196 @@
|
||||||
/**
|
/**
|
||||||
** Supermodel
|
** Supermodel
|
||||||
** A Sega Model 3 Arcade Emulator.
|
** A Sega Model 3 Arcade Emulator.
|
||||||
** Copyright 2011 Bart Trzynadlowski, Nik Henson
|
** Copyright 2011-2016 Bart Trzynadlowski, Nik Henson
|
||||||
**
|
**
|
||||||
** This file is part of Supermodel.
|
** This file is part of Supermodel.
|
||||||
**
|
**
|
||||||
** Supermodel is free software: you can redistribute it and/or modify it under
|
** Supermodel 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
|
** the terms of the GNU General Public License as published by the Free
|
||||||
** Software Foundation, either version 3 of the License, or (at your option)
|
** Software Foundation, either version 3 of the License, or (at your option)
|
||||||
** any later version.
|
** any later version.
|
||||||
**
|
**
|
||||||
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
|
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
|
||||||
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
** more details.
|
** more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU General Public License along
|
** You should have received a copy of the GNU General Public License along
|
||||||
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fragment_NoSpotlight.glsl
|
* Fragment.glsl
|
||||||
*
|
*
|
||||||
* Fragment shader for 3D rendering. Spotlight effect removed. Fixes fragment
|
* Fragment shader for 3D rendering.
|
||||||
* shader link errors on older ATI Radeon GPUs.
|
*/
|
||||||
*
|
|
||||||
* To load external fragment shaders, use the -frag-shader=<file> option when
|
#version 120
|
||||||
* starting Supermodel.
|
|
||||||
*/
|
// Global uniforms
|
||||||
|
uniform sampler2D textureMap; // complete texture map, 2048x2048 texels
|
||||||
#version 120
|
uniform vec4 spotEllipse; // spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height)
|
||||||
|
uniform vec2 spotRange; // spotlight Z range: .x=start (viewspace coordinates), .y=limit
|
||||||
// Global uniforms
|
uniform vec3 spotColor; // spotlight RGB color
|
||||||
uniform sampler2D textureMap; // complete texture map, 2048x2048 texels
|
uniform vec3 lighting[2]; // lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0)
|
||||||
uniform vec4 spotEllipse; // spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height)
|
uniform float mapSize; // texture map size (2048,4096,6144 etc)
|
||||||
uniform vec2 spotRange; // spotlight Z range: .x=start (viewspace coordinates), .y=limit
|
|
||||||
uniform vec3 spotColor; // spotlight RGB color
|
// Inputs from vertex shader
|
||||||
uniform float mapSize; // texture map size (2048,4096,6144 etc)
|
varying vec4 fsSubTexture; // .x=texture X, .y=texture Y, .z=texture width, .w=texture height (all in texels)
|
||||||
|
varying vec4 fsTexParams; // .x=texture enable (if 1, else 0), .y=use transparency (if > 0), .z=U wrap mode (1=mirror, 0=repeat), .w=V wrap mode
|
||||||
// Inputs from vertex shader
|
varying float fsTexFormat; // T1RGB5 contour texture (if > 0)
|
||||||
varying vec4 fsSubTexture; // .x=texture X, .y=texture Y, .z=texture width, .w=texture height (all in texels)
|
varying float fsTexMap; // texture map number
|
||||||
varying vec4 fsTexParams; // .x=texture enable (if 1, else 0), .y=use transparency (if > 0), .z=U wrap mode (1=mirror, 0=repeat), .w=V wrap mode
|
varying float fsTransLevel; // translucence level, 0.0 (transparent) to 1.0 (opaque)
|
||||||
varying float fsTexFormat; // .x=T1RGB5 contour texture (if > 0)
|
varying vec3 fsLightIntensity; // lighting intensity
|
||||||
varying float fsTransLevel; // translucence level, 0.0 (transparent) to 1.0 (opaque)
|
varying float fsSpecularTerm; // specular highlight
|
||||||
varying vec3 fsLightIntensity; // lighting intensity
|
varying float fsFogFactor; // fog factor
|
||||||
varying float fsFogFactor; // fog factor
|
varying float fsViewZ; // Z distance to fragment from viewpoint at origin
|
||||||
varying float fsViewZ; // Z distance to fragment from viewpoint at origin
|
|
||||||
|
/*
|
||||||
/*
|
* WrapTexelCoords():
|
||||||
* WrapTexelCoords():
|
*
|
||||||
*
|
* Computes the normalized OpenGL S,T coordinates within the 2048x2048 texture
|
||||||
* Computes the normalized OpenGL S,T coordinates within the 2048x2048 texture
|
* sheet, taking into account wrapping behavior.
|
||||||
* sheet, taking into account wrapping behavior.
|
*
|
||||||
*
|
* Computing normalized OpenGL texture coordinates (0 to 1) within the
|
||||||
* Computing normalized OpenGL texture coordinates (0 to 1) within the
|
* Real3D texture sheet:
|
||||||
* Real3D texture sheet:
|
*
|
||||||
*
|
* If the texture is not mirrored, we simply have to clamp the
|
||||||
* If the texture is not mirrored, we simply have to clamp the
|
* coordinates to fit within the texture dimensions, add the texture
|
||||||
* coordinates to fit within the texture dimensions, add the texture
|
* X, Y position to select the appropriate one, and normalize by 2048
|
||||||
* X, Y position to select the appropriate one, and normalize by 2048
|
* (the dimensions of the Real3D texture sheet).
|
||||||
* (the dimensions of the Real3D texture sheet).
|
*
|
||||||
*
|
* = [(u,v)%(w,h)+(x,y)]/(2048,2048)
|
||||||
* = [(u,v)%(w,h)+(x,y)]/(2048,2048)
|
*
|
||||||
*
|
* If mirroring is enabled, textures are mirrored every odd multiple of
|
||||||
* If mirroring is enabled, textures are mirrored every odd multiple of
|
* the original texture. To detect whether we are in an odd multiple,
|
||||||
* the original texture. To detect whether we are in an odd multiple,
|
* simply divide the coordinate by the texture dimension and check
|
||||||
* simply divide the coordinate by the texture dimension and check
|
* whether the result is odd. Then, clamp the coordinates as before but
|
||||||
* whether the result is odd. Then, clamp the coordinates as before but
|
* subtract from the last texel to mirror them:
|
||||||
* subtract from the last texel to mirror them:
|
*
|
||||||
*
|
* = [M*((w-1,h-1)-(u,v)%(w,h)) + (1-M)*(u,v)%(w,h) + (x,y)]/(2048,2048)
|
||||||
* = [M*((w-1,h-1)-(u,v)%(w,h)) + (1-M)*(u,v)%(w,h) + (x,y)]/(2048,2048)
|
* where M is 1.0 if the texture must be mirrored.
|
||||||
* where M is 1.0 if the texture must be mirrored.
|
*
|
||||||
*
|
* As an optimization, this function computes TWO texture coordinates
|
||||||
* As an optimization, this function computes TWO texture coordinates
|
* simultaneously. The first is texCoord.xy, the second is in .zw. The other
|
||||||
* simultaneously. The first is texCoord.xy, the second is in .zw. The other
|
* parameters must have .xy = .zw.
|
||||||
* parameters must have .xy = .zw.
|
*/
|
||||||
*/
|
vec4 WrapTexelCoords(vec4 texCoord, vec4 texOffset, vec4 texSize, vec4 mirrorEnable)
|
||||||
vec4 WrapTexelCoords(vec4 texCoord, vec4 texOffset, vec4 texSize, vec4 mirrorEnable)
|
{
|
||||||
{
|
vec4 clampedCoord, mirror, glTexCoord;
|
||||||
vec4 clampedCoord, mirror, glTexCoord;
|
|
||||||
|
clampedCoord = mod(texCoord,texSize); // clamp coordinates to within texture size
|
||||||
clampedCoord = mod(texCoord,texSize); // clamp coordinates to within texture size
|
mirror = mirrorEnable * mod(floor(texCoord/texSize),2.0); // whether this texel needs to be mirrored
|
||||||
mirror = mirrorEnable * mod(floor(texCoord/texSize),2.0); // whether this texel needs to be mirrored
|
|
||||||
|
glTexCoord = ( mirror*(texSize-clampedCoord) +
|
||||||
glTexCoord = ( mirror*(texSize-clampedCoord) +
|
(vec4(1.0,1.0,1.0,1.0)-mirror)*clampedCoord +
|
||||||
(vec4(1.0,1.0,1.0,1.0)-mirror)*clampedCoord +
|
texOffset
|
||||||
texOffset
|
) / mapSize;
|
||||||
) / mapSize;
|
return glTexCoord;
|
||||||
/*
|
}
|
||||||
glTexCoord = ( mirror*(texSize-vec4(1.0,1.0,1.0,1.0)-clampedCoord) +
|
|
||||||
(vec4(1.0,1.0,1.0,1.0)-mirror)*clampedCoord +
|
/*
|
||||||
texOffset
|
* main():
|
||||||
) / mapSize;
|
*
|
||||||
*/
|
* Fragment shader entry point.
|
||||||
return glTexCoord;
|
*/
|
||||||
}
|
|
||||||
|
void main(void)
|
||||||
/*
|
{
|
||||||
* main():
|
vec4 uv_top, uv_bot, c[4];
|
||||||
*
|
vec2 r;
|
||||||
* Fragment shader entry point.
|
vec4 fragColor;
|
||||||
*/
|
vec2 ellipse;
|
||||||
|
vec3 lightIntensity;
|
||||||
void main(void)
|
float insideSpot;
|
||||||
{
|
int x;
|
||||||
vec4 uv_top, uv_bot, c[4];
|
|
||||||
vec2 r;
|
// Get polygon color for untextured polygons (textured polygons will overwrite)
|
||||||
vec4 fragColor;
|
if (fsTexParams.x < 0.5)
|
||||||
vec2 ellipse;
|
fragColor = gl_Color;
|
||||||
vec3 lightIntensity;
|
else
|
||||||
float insideSpot;
|
// Textured polygons: set fragment color to texel value
|
||||||
|
{
|
||||||
// Get polygon color for untextured polygons (textured polygons will overwrite)
|
/*
|
||||||
if (fsTexParams.x < 0.5)
|
* Bilinear Filtering
|
||||||
fragColor = gl_Color;
|
*
|
||||||
else
|
* In order to get this working on ATI, the number of operations is
|
||||||
// Textured polygons: set fragment color to texel value
|
* reduced by putting everything into vec4s. uv_top holds the UV
|
||||||
{
|
* coordinates for the top two texels (.xy=left, .zw=right) and uv_bot
|
||||||
/*
|
* is for the lower two.
|
||||||
* Bilinear Filtering
|
*/
|
||||||
*
|
|
||||||
* In order to get this working on ATI, the number of operations is
|
// Compute fractional blending factor, r, and lower left corner of texel 0
|
||||||
* reduced by putting everything into vec4s. uv_top holds the UV
|
uv_bot.xy = gl_TexCoord[0].st-vec2(0.5,0.5); // move into the lower left blending texel
|
||||||
* coordinates for the top two texels (.xy=left, .zw=right) and uv_bot
|
r = uv_bot.xy-floor(uv_bot.xy); // fractional part
|
||||||
* is for the lower two.
|
uv_bot.xy = floor(uv_bot.xy); // integral part
|
||||||
*/
|
|
||||||
|
// Compute texel coordinates
|
||||||
// Compute fractional blending factor, r, and lower left corner of texel 0
|
uv_bot.xy += vec2(0.5,0.5); // offset to center of pixel (should not be needed but it fixes a lot of glitches, esp. on Nvidia)
|
||||||
uv_bot.xy = gl_TexCoord[0].st-vec2(0.5,0.5); // move into the lower left blending texel
|
uv_bot.zw = uv_bot.xy + vec2(1.0,0.0); // compute coordinates of the other three neighbors
|
||||||
r = uv_bot.xy-floor(uv_bot.xy); // fractional part
|
uv_top = uv_bot + vec4(0.0,1.0,0.0,1.0);
|
||||||
uv_bot.xy = floor(uv_bot.xy); // integral part
|
|
||||||
|
// Compute the properly wrapped texel coordinates
|
||||||
// Compute texel coordinates
|
uv_top = WrapTexelCoords(uv_top,vec4(fsSubTexture.xy,fsSubTexture.xy),vec4(fsSubTexture.zw,fsSubTexture.zw), vec4(fsTexParams.zw,fsTexParams.zw));
|
||||||
uv_bot.xy += vec2(0.5,0.5); // offset to center of pixel (should not be needed but it fixes a lot of glitches, esp. on Nvidia)
|
uv_bot = WrapTexelCoords(uv_bot,vec4(fsSubTexture.xy,fsSubTexture.xy),vec4(fsSubTexture.zw,fsSubTexture.zw), vec4(fsTexParams.zw,fsTexParams.zw));
|
||||||
uv_bot.zw = uv_bot.xy + vec2(1.0,0.0); // compute coordinates of the other three neighbors
|
|
||||||
uv_top = uv_bot + vec4(0.0,1.0,0.0,1.0);
|
// Fetch the texels
|
||||||
|
c[0]=texture2D(textureMap,uv_bot.xy); // bottom-left (base texel)
|
||||||
// Compute the properly wrapped texel coordinates
|
c[1]=texture2D(textureMap,uv_bot.zw); // bottom-right
|
||||||
uv_top = WrapTexelCoords(uv_top,vec4(fsSubTexture.xy,fsSubTexture.xy),vec4(fsSubTexture.zw,fsSubTexture.zw), vec4(fsTexParams.zw,fsTexParams.zw));
|
c[2]=texture2D(textureMap,uv_top.xy); // top-left
|
||||||
uv_bot = WrapTexelCoords(uv_bot,vec4(fsSubTexture.xy,fsSubTexture.xy),vec4(fsSubTexture.zw,fsSubTexture.zw), vec4(fsTexParams.zw,fsTexParams.zw));
|
c[3]=texture2D(textureMap,uv_top.zw); // top-right
|
||||||
|
|
||||||
// Fetch the texels
|
// Interpolate texels and blend result with material color to determine final (unlit) fragment color
|
||||||
c[0]=texture2D(textureMap,uv_bot.xy); // bottom-left (base texel)
|
// fragColor = (c[0]*(1.0-r.s)*(1.0-r.t) + c[1]*r.s*(1.0-r.t) + c[2]*(1.0-r.s)*r.t + c[3]*r.s*r.t);
|
||||||
c[1]=texture2D(textureMap,uv_bot.zw); // bottom-right
|
// Faster method:
|
||||||
c[2]=texture2D(textureMap,uv_top.xy); // top-left
|
c[0] += (c[1]-c[0])*r.s; // 2 alu
|
||||||
c[3]=texture2D(textureMap,uv_top.zw); // top-right
|
c[2] += (c[3]-c[2])*r.s; // 2 alu
|
||||||
|
fragColor = c[0]+(c[2]-c[0])*r.t; //2 alu
|
||||||
// Interpolate texels and blend result with material color to determine final (unlit) fragment color
|
|
||||||
// fragColor = (c[0]*(1.0-r.s)*(1.0-r.t) + c[1]*r.s*(1.0-r.t) + c[2]*(1.0-r.s)*r.t + c[3]*r.s*r.t);
|
/*
|
||||||
// Faster method:
|
* T1RGB5:
|
||||||
c[0] += (c[1]-c[0])*r.s; // 2 alu
|
*
|
||||||
c[2] += (c[3]-c[2])*r.s; // 2 alu
|
* The transparency bit determines whether to discard pixels (if set).
|
||||||
fragColor = c[0]+(c[2]-c[0])*r.t; //2 alu
|
* What is unknown is how this bit behaves when interpolated. OpenGL
|
||||||
|
* processes it as an alpha value, so it might concievably be blended
|
||||||
/*
|
* with neighbors. Here, an arbitrary threshold is chosen.
|
||||||
* T1RGB5:
|
*
|
||||||
*
|
* To-do: blending could probably enabled and this would work even
|
||||||
* The transparency bit determines whether to discard pixels (if set).
|
* better with a hard threshold.
|
||||||
* What is unknown is how this bit behaves when interpolated. OpenGL
|
*
|
||||||
* processes it as an alpha value, so it might concievably be blended
|
* Countour processing also seems to be enabled for RGBA4 textures.
|
||||||
* with neighbors. Here, an arbitrary threshold is chosen.
|
* When the alpha value is 0.0 (or close), pixels are discarded
|
||||||
*
|
* entirely.
|
||||||
* To-do: blending could probably enabled and this would work even
|
*/
|
||||||
* better with a hard threshold.
|
if (fsTexParams.y > 0.5) // contour processing enabled
|
||||||
*
|
{
|
||||||
* Countour processing also seems to be enabled for RGBA4 textures.
|
if (fragColor.a < 0.01) // discard anything with alpha == 0
|
||||||
* When the alpha value is 0.0 (or close), pixels are discarded
|
discard;
|
||||||
* entirely.
|
}
|
||||||
*/
|
|
||||||
if (fsTexParams.y > 0.5) // contour processing enabled
|
// If contour texture and not discarded, force alpha to 1.0 because will later be modified by polygon translucency
|
||||||
{
|
if (fsTexFormat < 0.5) // contour (T1RGB5) texture
|
||||||
if (fragColor.a < 0.01) // discard anything with alpha == 0
|
fragColor.a = 1.0;
|
||||||
discard;
|
}
|
||||||
}
|
|
||||||
|
// Compute spotlight and apply lighting
|
||||||
// If contour texture and not discarded, force alpha to 1.0 because will later be modified by polygon translucency
|
/*
|
||||||
if (fsTexFormat < 0.5) // contour (T1RGB5) texture map
|
ellipse = (gl_FragCoord.xy-spotEllipse.xy)/spotEllipse.zw;
|
||||||
fragColor.a = 1.0;
|
insideSpot = dot(ellipse,ellipse);
|
||||||
}
|
if ((insideSpot <= 1.0) && (fsViewZ>=spotRange.x) && (fsViewZ<spotRange.y))
|
||||||
|
lightIntensity = fsLightIntensity+(1.0-insideSpot)*spotColor;
|
||||||
// Compute spotlight and apply lighting
|
else
|
||||||
/***
|
lightIntensity = fsLightIntensity;
|
||||||
ellipse = (gl_FragCoord.xy-spotEllipse.xy)/spotEllipse.zw;
|
*/
|
||||||
insideSpot = dot(ellipse,ellipse);
|
fragColor.rgb *= fsLightIntensity;
|
||||||
if ((insideSpot <= 1.0) && (fsViewZ>=spotRange.x) && (fsViewZ<spotRange.y))
|
fragColor.rgb += vec3(fsSpecularTerm,fsSpecularTerm,fsSpecularTerm);
|
||||||
lightIntensity = fsLightIntensity+(1.0-insideSpot)*spotColor;
|
|
||||||
else
|
// Translucency (modulates existing alpha channel for RGBA4 texels)
|
||||||
lightIntensity = fsLightIntensity;
|
fragColor.a *= fsTransLevel;
|
||||||
fragColor.rgb *= lightIntensity;
|
|
||||||
***/
|
// Apply fog
|
||||||
fragColor.rgb *= fsLightIntensity;
|
fragColor.rgb = mix(fragColor.rgb, gl_Fog.color.rgb, fsFogFactor);
|
||||||
|
|
||||||
// Translucency (modulates existing alpha channel for RGBA4 texels)
|
// Store final color
|
||||||
fragColor.a *= fsTransLevel;
|
gl_FragColor = fragColor;
|
||||||
|
}
|
||||||
// Apply fog under the control of fog factor setting from polygon header
|
|
||||||
fragColor.rgb = mix(gl_Fog.color.rgb, fragColor.rgb, fsFogFactor );
|
|
||||||
|
|
||||||
// Store final color
|
|
||||||
gl_FragColor = fragColor;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue