1 /* DooM2D: Midnight on the Firing Line
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // this shader will light level geometry
23 // alpha threshold for our occlusion map
24 #define THRESHOLD (0.75)
26 #define SEARCH_RADIUS (4)
27 #define MIN_ALPHA (0.04)
29 uniform sampler2D texLMap; // light texture of lightTexSize
30 uniform sampler2D texBg; // background
31 uniform sampler2D texOccFull; // occluders
32 uniform sampler2D texOccSmall; // occluders, small map
33 uniform vec2 lightTexSize; // x: lightSize; y: size of this texture
34 uniform vec2 mapPixSize;
35 uniform vec4 lightColor;
36 uniform vec2 lightPos;
39 bool lightAtTile (vec2 ltpos, float pixelStep) {
40 if (ltpos.x < 0 || ltpos.y < 0 || ltpos.x >= 1.0 || ltpos.y >= 1.0) return false;
42 for (int dy = 8; dy > 0; --dy) {
43 for (int dx = 8; dx > 0; --dx) {
44 if (texture2D(texLMap, ltpos, 0).a > MIN_ALPHA) return true;
47 ltpos = vec2(lx, ltpos.y+pixelStep);
53 //gl_FragCoord: in background
56 // light is y-mirrored
57 vec2 ourpos = vec2(gl_FragCoord.x, mapPixSize.y-gl_FragCoord.y);
59 ivec2 ocxy = ivec2(int(ourpos.x), int(ourpos.y));
61 if (texelFetch(texOccFull, ocxy, 0).a <= THRESHOLD) {
63 //gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);
67 // check adjacent tiles
71 vec2 ltpos = gl_TexCoord[0].xy; // in light texture (texLMap)
72 float pixelStep = 1.0/lightTexSize.y; // in light texture
73 int move = ocxy.x&0x07;
74 ltpos.x -= pixelStep*move;
75 move = int(gl_FragCoord.y)&0x07;
76 ltpos.y -= pixelStep*move;
77 // check adjacent tiles
79 float savedx = ltpos.x;
80 for (int dy = -1; dy < 2 && !hit; ++dy) {
81 for (int dx = -1; dx < 2 && !hit; ++dx) {
82 if (dx != 0 || dy != 0) hit = lightAtTile(ltpos, pixelStep);
83 ltpos.x += pixelStep*8;
85 ltpos = vec2(savedx, ltpos.y+pixelStep*8);
89 for (int dy = 8; dy > 0; --dy) {
90 if (texture2D(texLMap, ltpos, 0).a > MIN_ALPHA) { hit = true; break; }
94 //gl_FragColor = vec4(gl_TexCoord[0].y, 0, 0, 1);
100 float tlsz = textureSize(texLMap, 0).y;
101 vec2 ltpos = gl_TexCoord[0].xy; // in light texture (texLMap)
102 float pixelStep = 1.0/tlsz; // in light texture
103 //ltpos.y += pixelStep;
104 //hit = (texture2D(texLMap, ltpos/tlsz, 0).a > MIN_ALPHA);
106 texture2D(texLMap, vec2(ltpos.x-pixelStep, ltpos.y-pixelStep), 0).a > MIN_ALPHA ||
107 texture2D(texLMap, vec2(ltpos.x , ltpos.y-pixelStep), 0).a > MIN_ALPHA ||
108 texture2D(texLMap, vec2(ltpos.x+pixelStep, ltpos.y-pixelStep), 0).a > MIN_ALPHA ||
109 texture2D(texLMap, vec2(ltpos.x-pixelStep, ltpos.y ), 0).a > MIN_ALPHA ||
110 texture2D(texLMap, vec2(ltpos.x+pixelStep, ltpos.y ), 0).a > MIN_ALPHA ||
111 texture2D(texLMap, vec2(ltpos.x-pixelStep, ltpos.y+pixelStep), 0).a > MIN_ALPHA ||
112 texture2D(texLMap, vec2(ltpos.x , ltpos.y+pixelStep), 0).a > MIN_ALPHA ||
113 texture2D(texLMap, vec2(ltpos.x+pixelStep, ltpos.y+pixelStep), 0).a > MIN_ALPHA ||
122 //vec2 btxy = gl_FragCoord.xy/mapPixSize;
123 //vec4 bcolor = texture2D(texBg, btxy);
124 vec4 bcolor = texelFetch(texBg, ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y)), 0);
125 // distance from this point to light origin
126 float lit = clamp(1.0-(distance(ourpos, lightPos)/(lightTexSize.x/2.0)), 0.0, 1.0);
127 lit = smoothstep(0.1, 1.0, lit);
128 if (lightColor.a == 0.0) {
129 color = bcolor*vec4(vec3(1.0), lit);
131 color = lightColor*lit;
135 gl_FragColor = color;
136 //gl_FragColor = bcolor;
139 //gl_FragColor = vec4(0.0, 0.0, 1.0, 0.5);
144 // first, we should check if there is no other occluders in +x, +y, and +x+y directions
146 //ivec2 ldxy = ivec2(int(sign(lightPos.x-gl_FragCoord.x)), int(sign(gl_FragCoord.y-lightPos.y)));
147 ivec2 ltposd8 = ivec2(int(lightPos.x), int(lightPos.y))/8;
148 //ivec2 ltposd8 = ocxy/8;
149 ivec2 ldxy = ivec2(sign(ltposd8.x-a8.x), sign(ltposd8.y-a8.y));
151 if (ldxy.x == 0 && ldxy.y == 0) { discard; return; }
152 if (ldxy.x != 0 && ldxy.y != 0) {
154 if (/*texelFetch(texOccSmall, ivec2(a8.x+ldxy.x, a8.y), 0).a > THRESHOLD &&
155 texelFetch(texOccSmall, ivec2(a8.x, a8.y+ldxy.y), 0).a > THRESHOLD &&*/
156 texelFetch(texOccSmall, a8+ldxy, 0).a > THRESHOLD) { discard; return; }
158 // only horizontal or only vertical
159 if (texelFetch(texOccSmall, a8+ldxy, 0).a > THRESHOLD) { discard; return; }
162 // ok, it's not blocked
164 // check for light in +x, +y, and +x+y directions
165 vec2 ltpos = gl_TexCoord[0].xy*textureSize(texLMap, 0).y/*lightTexSize.y*/; // in light texture (texLMap)
166 ivec2 iltpos = ivec2(int(ltpos.x), int(ltpos.y));
170 for (int f = 1; f > 0; --f) {
171 float ar = texelFetch(texLMap, iltpos, 0).a;
172 ar = max(ar, texelFetch(texLMap, ivec2(iltpos.x+ldxy.x, iltpos.y), 0).a);
173 ar = max(ar, texelFetch(texLMap, ivec2(iltpos.x, iltpos.y+ldxy.x), 0).a);
174 ar = max(ar, texelFetch(texLMap, ivec2(iltpos.x+ldxy.x, iltpos.y+ldxy.x), 0).a);
175 if (ar > MIN_ALPHA) {
178 litlt = max(min(ar, 1.0), 0.0);
187 //vec2 btxy = gl_FragCoord.xy/mapPixSize;
188 //vec4 bcolor = texture2D(texBg, btxy);
189 vec4 bcolor = texelFetch(texBg, ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y)), 0);
190 // distance from this point to light origin
191 float lit = clamp(1.0-(distance(ourpos, lightPos)/(lightTexSize.x/2.0)), 0.0, 1.0);
192 lit = smoothstep(0.1, 1.0, lit);
194 if (lightColor.a == 0.0) {
195 color = bcolor*vec4(vec3(1.0), lit);
197 color = lightColor*lit;
201 //gl_FragColor = color;
202 gl_FragColor = bcolor;