diff --git a/data/gfx/snow.xml b/data/gfx/snow.xml index bd3eb7395..e34c24ffb 100644 --- a/data/gfx/snow.xml +++ b/data/gfx/snow.xml @@ -9,7 +9,7 @@ y="-0.01" z="0.0" /> - + - + + diff --git a/data/gui/custom_video_settings.stkgui b/data/gui/custom_video_settings.stkgui index 466036696..d1d8c5eaf 100644 --- a/data/gui/custom_video_settings.stkgui +++ b/data/gui/custom_video_settings.stkgui @@ -1,18 +1,33 @@ -
+
- + + +
+ + +
+ +
- +
@@ -20,7 +35,7 @@
- +
- +
- +
- +
- + -
- - - + + +
- +
+ + + +
+
diff --git a/data/gui/options_video.stkgui b/data/gui/options_video.stkgui index c90eb4851..9f679add6 100644 --- a/data/gui/options_video.stkgui +++ b/data/gui/options_video.stkgui @@ -40,16 +40,6 @@
- - - -
- - - -
- diff --git a/data/shaders/MLAA_COPYING b/data/shaders/MLAA_COPYING new file mode 100644 index 000000000..cb39bd220 --- /dev/null +++ b/data/shaders/MLAA_COPYING @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2010 Jorge Jimenez (jorge@iryoku.com) + * Copyright (C) 2010 Belen Masia (bmasia@unizar.es) + * Copyright (C) 2010 Jose I. Echevarria (joseignacioechevarria@gmail.com) + * Copyright (C) 2010 Fernando Navarro (fernandn@microsoft.com) + * Copyright (C) 2010 Diego Gutierrez (diegog@unizar.es) + * Copyright (C) 2011 Lauri Kasanen (cand@gmx.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the following statement: + * + * "Uses Jimenez's MLAA. Copyright (C) 2010 by Jorge Jimenez, Belen Masia, + * Jose I. Echevarria, Fernando Navarro and Diego Gutierrez." + * + * Only for use in the Mesa project, this point 2 is filled by naming the + * technique Jimenez's MLAA in the Mesa config options. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the copyright holders. + */ diff --git a/data/shaders/bloom.frag b/data/shaders/bloom.frag new file mode 100644 index 000000000..f00f76c1e --- /dev/null +++ b/data/shaders/bloom.frag @@ -0,0 +1,13 @@ +uniform sampler2D tex; +uniform float low; + +void main() +{ + vec3 weights = vec3(0.2126, 0.7152, 0.0722); // ITU-R BT. 709 + vec3 col = texture2D(tex, gl_TexCoord[0].xy).xyz; + float luma = dot(weights, col); + + col *= smoothstep(low, 0.9, luma); + + gl_FragColor = vec4(col, 1.0); +} diff --git a/data/shaders/bloomblend.frag b/data/shaders/bloomblend.frag new file mode 100644 index 000000000..6cb0ec93d --- /dev/null +++ b/data/shaders/bloomblend.frag @@ -0,0 +1,10 @@ +uniform sampler2D tex; + +void main() +{ + vec4 col = texture2D(tex, gl_TexCoord[0].xy); + + col.xyz *= 10.0 * col.a; + + gl_FragColor = vec4(col.xyz, 1.0); +} diff --git a/data/shaders/bloompower.frag b/data/shaders/bloompower.frag new file mode 100644 index 000000000..441090cb6 --- /dev/null +++ b/data/shaders/bloompower.frag @@ -0,0 +1,11 @@ +uniform float power; +uniform sampler2D tex; + +void main() +{ + vec4 col = texture2D(tex, gl_TexCoord[0].xy); + if (col.a < 0.5) + discard; + + gl_FragColor = vec4(col.xyz, power); +} diff --git a/data/shaders/bubble.frag b/data/shaders/bubble.frag index 9fc686210..6e900c98e 100644 --- a/data/shaders/bubble.frag +++ b/data/shaders/bubble.frag @@ -15,13 +15,12 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -uniform sampler2D main_texture; +uniform sampler2D tex; uniform float transparency; varying vec2 uv; void main() { - gl_FragColor = texture2D(main_texture, uv); - gl_FragColor.a *= transparency; + gl_FragColor = texture2D(tex, uv); + gl_FragColor.a *= transparency; } diff --git a/data/shaders/caustics.frag b/data/shaders/caustics.frag new file mode 100644 index 000000000..8ce7a6303 --- /dev/null +++ b/data/shaders/caustics.frag @@ -0,0 +1,17 @@ +uniform sampler2D tex; +uniform sampler2D caustictex; +uniform vec2 dir; +uniform vec2 dir2; + +void main() +{ + vec2 tc = gl_TexCoord[0].xy; + + vec3 col = texture2D(tex, tc).xyz; + float caustic = texture2D(caustictex, tc + dir).x; + float caustic2 = texture2D(caustictex, (tc.yx + dir2 * vec2(-0.6, 0.3)) * vec2(0.6)).x; + + col += caustic * caustic2 * 10.0; + + gl_FragColor = vec4(col, 1.0); +} diff --git a/data/shaders/collapse.frag b/data/shaders/collapse.frag new file mode 100644 index 000000000..7e2e8b64c --- /dev/null +++ b/data/shaders/collapse.frag @@ -0,0 +1,25 @@ +uniform sampler2D tex; +uniform sampler2D oldtex; +uniform vec2 pixel; +uniform vec2 multi; +uniform int size; + +void main() +{ + float res = 0.0; + vec2 tc = gl_TexCoord[0].xy; +// tc.y = 1.0 - tc.y; + tc *= multi; + + for (int i = 0; i < size; i++) + { + float col = texture2D(tex, tc).x; + res = max(col, res); + + tc += pixel; + } + + float old = texture2D(oldtex, gl_TexCoord[0].xy).x; + + gl_FragColor = vec4(mix(old, res, 0.7)); +} diff --git a/data/shaders/colorize.frag b/data/shaders/colorize.frag new file mode 100644 index 000000000..2e44f6a07 --- /dev/null +++ b/data/shaders/colorize.frag @@ -0,0 +1,6 @@ +uniform vec3 col; + +void main() +{ + gl_FragColor = vec4(col, 1.0); +} diff --git a/data/shaders/colorize_ref.frag b/data/shaders/colorize_ref.frag new file mode 100644 index 000000000..c7dac6c99 --- /dev/null +++ b/data/shaders/colorize_ref.frag @@ -0,0 +1,11 @@ +uniform vec3 col; +uniform sampler2D tex; + +void main() +{ + float alpha = texture2D(tex, gl_TexCoord[0].xy).a; + if (alpha < 0.5) + discard; + + gl_FragColor = vec4(col, 1.0); +} diff --git a/data/shaders/displace.frag b/data/shaders/displace.frag new file mode 100644 index 000000000..4ab1a4feb --- /dev/null +++ b/data/shaders/displace.frag @@ -0,0 +1,40 @@ +uniform sampler2D tex; +uniform vec2 screen; +uniform vec2 dir; +uniform vec2 dir2; + +varying float camdist; + +void main() +{ + vec2 tc = gl_TexCoord[0].xy; + + vec4 col = vec4(0.0); + const float maxlen = 0.02; + + float horiz = texture2D(tex, tc + dir).x; + float vert = texture2D(tex, (tc.yx + dir2) * vec2(0.9)).x; + + vec2 offset = vec2(horiz, vert); + offset *= 2.0; + offset -= 1.0; + + // Fade according to distance to cam + float fade = 1.0 - smoothstep(1.0, 40.0, camdist); + + // Fade according to distance from the edges + vec2 edger = gl_TexCoord[1].xy; + const float mindist = 0.1; + fade *= smoothstep(0.0, mindist, edger.x) * smoothstep(0.0, mindist, edger.y) * + (1.0 - smoothstep(1.0 - mindist, 1.0, edger.x)) * + (1.0 - smoothstep(1.0 - mindist, 1.0, edger.y)); + + offset *= 50.0 * fade * maxlen; + + col.r = step(offset.x, 0.0) * -offset.x; + col.g = step(0.0, offset.x) * offset.x; + col.b = step(offset.y, 0.0) * -offset.y; + col.a = step(0.0, offset.y) * offset.y; + + gl_FragColor = col; +} diff --git a/data/shaders/displace.vert b/data/shaders/displace.vert new file mode 100644 index 000000000..f2fe1c59f --- /dev/null +++ b/data/shaders/displace.vert @@ -0,0 +1,9 @@ +varying float camdist; + +void main() { + gl_Position = ftransform(); + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_TexCoord[1] = gl_MultiTexCoord1; + + camdist = length((gl_ModelViewMatrix * gl_Vertex).xyz); +} diff --git a/data/shaders/farplane.vert b/data/shaders/farplane.vert new file mode 100644 index 000000000..a15bb824f --- /dev/null +++ b/data/shaders/farplane.vert @@ -0,0 +1,6 @@ +void main() { + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_TexCoord[1] = gl_MultiTexCoord1; + gl_Position = (gl_ModelViewProjectionMatrix * gl_Vertex).xyww; + gl_FrontColor = gl_Color; +} diff --git a/data/shaders/flip.frag b/data/shaders/flip.frag new file mode 100644 index 000000000..dda3a7076 --- /dev/null +++ b/data/shaders/flip.frag @@ -0,0 +1,9 @@ +uniform sampler2D tex; + +void main() +{ + vec2 texc = gl_TexCoord[0].xy; + texc.y = 1.0 - texc.y; + + gl_FragColor = texture2D(tex, texc); +} diff --git a/data/shaders/fog.frag b/data/shaders/fog.frag new file mode 100644 index 000000000..f2ed93327 --- /dev/null +++ b/data/shaders/fog.frag @@ -0,0 +1,34 @@ +uniform sampler2D tex; + +uniform float fogmax; +uniform float startH; +uniform float endH; +uniform float start; +uniform float end; +uniform vec3 col; +uniform vec3 campos; +uniform mat4 ipvmat; + +float decdepth(vec4 rgba) { + return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0)); +} + +void main() +{ + float z = decdepth(vec4(texture2D(tex, gl_TexCoord[0].xy).xyz, 0.0)); + + vec3 tmp = vec3(gl_TexCoord[0].xy, z); + tmp = tmp * 2.0 - 1.0; + + vec4 xpos = vec4(tmp, 1.0); + xpos = ipvmat * xpos; + xpos.xyz /= xpos.w; + + float dist = distance(campos, xpos.xyz); + float fog = smoothstep(start, end, dist); + fog *= 1.0 - smoothstep(startH, endH, xpos.y); + + fog = min(fog, fogmax); + + gl_FragColor = vec4(col, fog); +} diff --git a/data/shaders/gaussian3h.frag b/data/shaders/gaussian3h.frag new file mode 100644 index 000000000..f1ec80b89 --- /dev/null +++ b/data/shaders/gaussian3h.frag @@ -0,0 +1,19 @@ +uniform sampler2D tex; +uniform vec2 pixel; + +// Gaussian separated blur with radius 3. + +void main() +{ + vec4 sum = vec4(0.0); + float X = gl_TexCoord[0].x; + float Y = gl_TexCoord[0].y; + + sum += texture2D(tex, vec2(X - 3.0 * pixel.x, Y)) * 0.03125; + sum += texture2D(tex, vec2(X - 1.3333 * pixel.x, Y)) * 0.328125; + sum += texture2D(tex, vec2(X, Y)) * 0.273438; + sum += texture2D(tex, vec2(X + 1.3333 * pixel.x, Y)) * 0.328125; + sum += texture2D(tex, vec2(X + 3.0 * pixel.x, Y)) * 0.03125; + + gl_FragColor = sum; +} diff --git a/data/shaders/gaussian3v.frag b/data/shaders/gaussian3v.frag new file mode 100644 index 000000000..fec9ce8b1 --- /dev/null +++ b/data/shaders/gaussian3v.frag @@ -0,0 +1,19 @@ +uniform sampler2D tex; +uniform vec2 pixel; + +// Gaussian separated blur with radius 3. + +void main() +{ + vec4 sum = vec4(0.0); + float X = gl_TexCoord[0].x; + float Y = gl_TexCoord[0].y; + + sum += texture2D(tex, vec2(X, Y - 3.0 * pixel.y)) * 0.03125; + sum += texture2D(tex, vec2(X, Y - 1.3333 * pixel.y)) * 0.328125; + sum += texture2D(tex, vec2(X, Y)) * 0.273438; + sum += texture2D(tex, vec2(X, Y + 1.3333 * pixel.y)) * 0.328125; + sum += texture2D(tex, vec2(X, Y + 3.0 * pixel.y)) * 0.03125; + + gl_FragColor = sum; +} diff --git a/data/shaders/gaussian6h.frag b/data/shaders/gaussian6h.frag new file mode 100644 index 000000000..3aad9b7c0 --- /dev/null +++ b/data/shaders/gaussian6h.frag @@ -0,0 +1,21 @@ +uniform sampler2D tex; +uniform vec2 pixel; + +// Gaussian separated blur with radius 6. + +void main() +{ + vec4 sum = vec4(0.0); + float X = gl_TexCoord[0].x; + float Y = gl_TexCoord[0].y; + + sum += texture2D(tex, vec2(X - 5.13333 * pixel.x, Y)) * 0.00640869; + sum += texture2D(tex, vec2(X - 3.26667 * pixel.x, Y)) * 0.083313; + sum += texture2D(tex, vec2(X - 1.4 * pixel.x, Y)) * 0.305481; + sum += texture2D(tex, vec2(X, Y)) * 0.209473; + sum += texture2D(tex, vec2(X + 1.4 * pixel.x, Y)) * 0.305481; + sum += texture2D(tex, vec2(X + 3.26667 * pixel.x, Y)) * 0.083313; + sum += texture2D(tex, vec2(X + 5.13333 * pixel.x, Y)) * 0.00640869; + + gl_FragColor = sum; +} diff --git a/data/shaders/gaussian6v.frag b/data/shaders/gaussian6v.frag new file mode 100644 index 000000000..5b3e70ee2 --- /dev/null +++ b/data/shaders/gaussian6v.frag @@ -0,0 +1,21 @@ +uniform sampler2D tex; +uniform vec2 pixel; + +// Gaussian separated blur with radius 6. + +void main() +{ + vec4 sum = vec4(0.0); + float X = gl_TexCoord[0].x; + float Y = gl_TexCoord[0].y; + + sum += texture2D(tex, vec2(X, Y - 5.13333 * pixel.y)) * 0.00640869; + sum += texture2D(tex, vec2(X, Y - 3.26667 * pixel.y)) * 0.083313; + sum += texture2D(tex, vec2(X, Y - 1.4 * pixel.y)) * 0.305481; + sum += texture2D(tex, vec2(X, Y)) * 0.209473; + sum += texture2D(tex, vec2(X, Y + 1.4 * pixel.y)) * 0.305481; + sum += texture2D(tex, vec2(X, Y + 3.26667 * pixel.y)) * 0.083313; + sum += texture2D(tex, vec2(X, Y + 5.13333 * pixel.y)) * 0.00640869; + + gl_FragColor = sum; +} diff --git a/data/shaders/glow.frag b/data/shaders/glow.frag new file mode 100644 index 000000000..3932dc42e --- /dev/null +++ b/data/shaders/glow.frag @@ -0,0 +1,16 @@ +uniform sampler2D tex; +uniform vec2 res; + +void main() +{ + vec2 coords = gl_FragCoord.xy / res; + + vec4 col = texture2D(tex, coords); + float alpha = col.a; + + if (alpha < 0.04) discard; + + col *= vec4(vec3(4.0), 1.5); + + gl_FragColor = col; +} diff --git a/data/shaders/godfade.frag b/data/shaders/godfade.frag new file mode 100644 index 000000000..659742738 --- /dev/null +++ b/data/shaders/godfade.frag @@ -0,0 +1,16 @@ +uniform sampler2D tex; +uniform vec3 col; + +void main() +{ + vec4 res = texture2D(tex, gl_TexCoord[0].xy); + + // Keep the sun fully bright, but fade the sky + float mul = distance(res.xyz, col); + mul = step(mul, 0.02); + mul *= 0.97; + + res = res * vec4(mul); + + gl_FragColor = res; +} diff --git a/data/shaders/godray.frag b/data/shaders/godray.frag new file mode 100644 index 000000000..0e06dfb03 --- /dev/null +++ b/data/shaders/godray.frag @@ -0,0 +1,29 @@ +uniform sampler2D tex; +uniform vec2 sunpos; + +#define SAMPLES 12 + +const float decaystep = 0.88; + +void main() +{ + vec2 texc = gl_TexCoord[0].xy; + vec2 tosun = sunpos - texc; + + if (dot(tosun, tosun) > 0.49) discard; + + vec2 dist = tosun * 1.0/(float(SAMPLES) * 1.12); + + vec3 col = texture2D(tex, texc).xyz; + float decay = 1.0; + + for (int i = 0; i < SAMPLES; i++) { + texc += dist; + vec3 here = texture2D(tex, texc).xyz; + here *= decay; + col += here; + decay *= decaystep; + } + + gl_FragColor = vec4(col, 1.0) * 0.8; +} diff --git a/data/shaders/grass.frag b/data/shaders/grass.frag index e70be4351..9bd1e0555 100644 --- a/data/shaders/grass.frag +++ b/data/shaders/grass.frag @@ -1,54 +1,8 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 the SuperTuxKart team -// -// This program 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 3 -// of the License, or (at your option) any later version. -// -// This program 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 this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -uniform vec4 fogColor; -uniform float fogFrom; -uniform float fogTo; -uniform int fog; uniform sampler2D tex; -varying vec4 coord; void main() { - vec4 color = texture2D(tex, gl_TexCoord[0].st); - vec4 solidColor = vec4(color.r, color.g, color.b, 1); + vec4 color = texture2D(tex, gl_TexCoord[0].st); - if (fog == 1) - { - if (coord.z > fogTo) - { - gl_FragColor = fogColor; - gl_FragColor.a = color.a; - } - else if (coord.z > fogFrom) - { - float fogIntensity = (coord.z - fogFrom) / (fogTo - fogFrom); - vec4 color2 = fogIntensity*fogColor + (1.0 - fogIntensity)*solidColor; - color2.a = color.a; - gl_FragColor = color2; - } - else - { - gl_FragColor = color; - } - } - else - { - gl_FragColor = color; - } + gl_FragColor = color; } diff --git a/data/shaders/grass.vert b/data/shaders/grass.vert index 8aeee783c..e2208de2c 100644 --- a/data/shaders/grass.vert +++ b/data/shaders/grass.vert @@ -1,33 +1,11 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 the SuperTuxKart team -// -// This program 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 3 -// of the License, or (at your option) any later version. -// -// This program 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 this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -uniform float angle; -uniform float amplitude; -varying vec4 coord; - +uniform vec3 windDir; void main() { - gl_TexCoord[0] = gl_MultiTexCoord0; - vec4 vertexPosition = ftransform(); //gl_ModelViewMatrix * gl_Vertex; - vertexPosition += vec4(1,0,0,0) * amplitude * gl_Color.r * sin(angle); - gl_Position = vertexPosition; - gl_FrontColor = vec4(1,1,1,1); - gl_BackColor = vec4(1,1,1,1); - coord = vertexPosition; + gl_TexCoord[0] = gl_MultiTexCoord0; + + vec4 vertexPosition = gl_Vertex; + vertexPosition.xyz += windDir * gl_Color.r; + + gl_Position = gl_ModelViewProjectionMatrix * vertexPosition; } diff --git a/data/shaders/lightblend.frag b/data/shaders/lightblend.frag new file mode 100644 index 000000000..64530205e --- /dev/null +++ b/data/shaders/lightblend.frag @@ -0,0 +1,19 @@ +uniform sampler2D tex; +uniform vec3 ambient; +uniform sampler2D spectex; + +void main() +{ + vec2 texc = gl_TexCoord[0].xy; + + vec4 col = texture2D(tex, texc); + vec4 specular = texture2D(spectex, texc); + + col.xyz += ambient; + float spec = col.a - 0.05; + spec *= specular.a; + col.xyz += spec; + col.a = 1.0; + + gl_FragColor = col; +} diff --git a/data/shaders/mipviz.frag b/data/shaders/mipviz.frag new file mode 100644 index 000000000..e6bd31741 --- /dev/null +++ b/data/shaders/mipviz.frag @@ -0,0 +1,52 @@ +#version 120 + +uniform sampler2D tex; +uniform vec2 texsize; +uniform int notex; + +float miplevel(in vec2 texture_coordinate) +{ + // The OpenGL Graphics System: A Specification 4.2 + // - chapter 3.9.11, equation 3.21 + + vec2 dx_vtc = dFdx(texture_coordinate); + vec2 dy_vtc = dFdy(texture_coordinate); + float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)); + + return 0.5 * log2(delta_max_sqr); // == log2(sqrt(delta_max_sqr)); +} + +void main() { + + if (notex != 0) { + gl_FragColor = gl_Color; + return; + } + + // Buggy Intel windows driver workaround + vec4 levels[6] = vec4[]( + vec4(0.0, 0.0, 1.0, 0.8), + vec4(0.0, 0.5, 1.0, 0.4), + vec4(1.0, 1.0, 1.0, 0.0), + vec4(1.0, 0.7, 0.0, 0.2), + vec4(1.0, 0.3, 0.0, 0.6), + vec4(1.0, 0.0, 0.0, 0.8) + ); + + float mip = miplevel(texsize * gl_TexCoord[0].xy) + 2.0; + mip = clamp(mip, 0.0, 5.0); + + int lowmip = int(mip); + int highmip = lowmip + 1; + if (highmip > 5) + highmip = 5; + + float mixer = fract(mip); + + vec4 mixcol = mix(levels[lowmip], levels[highmip], mixer); + vec4 tcol = texture2D(tex, gl_TexCoord[0].xy); + + vec3 col = mix(tcol.xyz, mixcol.xyz, mixcol.a); + + gl_FragColor = vec4(col, tcol.a); +} diff --git a/data/shaders/mlaa_blend2.frag b/data/shaders/mlaa_blend2.frag new file mode 100644 index 000000000..0be80576b --- /dev/null +++ b/data/shaders/mlaa_blend2.frag @@ -0,0 +1,112 @@ +#define MAX_SEARCH_STEPS 8.0 +#define MAX_DISTANCE 33.0 + +#extension GL_ARB_shader_texture_lod: enable + +uniform sampler2D edgesMap; +uniform sampler2D areaMap; + +uniform vec2 PIXEL_SIZE; + +/** + * This one just returns the first level of a mip map chain, which allow us to + * avoid the nasty ddx/ddy warnings, even improving the performance a little + * bit. + */ +vec4 tex2Doffset(sampler2D map, vec2 texcoord, vec2 offset) { + return texture2DLod(map, texcoord + PIXEL_SIZE * offset, 0.0); +} + +float SearchXLeft(vec2 texcoord) { + // We compare with 0.9 to prevent bilinear access precision problems. + float i; + float e = 0.0; + for (i = -1.5; i > -2.0 * MAX_SEARCH_STEPS; i -= 2.0) { + e = tex2Doffset(edgesMap, texcoord, vec2(i, 0.0)).g; + if (e < 0.9) break; + } + return max(i + 1.5 - 2.0 * e, -2.0 * MAX_SEARCH_STEPS); +} + +float SearchXRight(vec2 texcoord) { + float i; + float e = 0.0; + for (i = 1.5; i < 2.0 * MAX_SEARCH_STEPS; i += 2.0) { + e = tex2Doffset(edgesMap, texcoord, vec2(i, 0.0)).g; + if (e < 0.9) break; + } + return min(i - 1.5 + 2.0 * e, 2.0 * MAX_SEARCH_STEPS); +} + +float SearchYDown(vec2 texcoord) { + float i; + float e = 0.0; + for (i = -1.5; i > -2.0 * MAX_SEARCH_STEPS; i -= 2.0) { + e = tex2Doffset(edgesMap, texcoord, vec2(i, 0.0).yx).r; + if (e < 0.9) break; + } + return max(i + 1.5 - 2.0 * e, -2.0 * MAX_SEARCH_STEPS); +} + +float SearchYUp(vec2 texcoord) { + float i; + float e = 0.0; + for (i = 1.5; i < 2.0 * MAX_SEARCH_STEPS; i += 2.0) { + e = tex2Doffset(edgesMap, texcoord, vec2(i, 0.0).yx).r; + if (e < 0.9) break; + } + return min(i - 1.5 + 2.0 * e, 2.0 * MAX_SEARCH_STEPS); +} + + +vec2 round(vec2 invec) { + return vec2(floor(abs(invec) + vec2(0.5)) * sign(invec)); +} + +vec2 Area(vec2 distance, float e1, float e2) { + // * By dividing by areaSize - 1.0 below we are implicitely offsetting to + // always fall inside of a pixel + // * Rounding prevents bilinear access precision problems + float areaSize = MAX_DISTANCE * 5.0; + vec2 pixcoord = MAX_DISTANCE * round(4.0 * vec2(e1, e2)) + distance; + vec2 texcoord = pixcoord / (areaSize - 1.0); + return texture2DLod(areaMap, texcoord, 0.0).ra; +} + +void main() { + vec4 areas = vec4(0.0); + + vec2 e = texture2D(edgesMap, gl_TexCoord[0].xy).rg; + + if (e.g != 0.0) { // Edge at north + + // Search distances to the left and to the right: + vec2 d = vec2(SearchXLeft(gl_TexCoord[0].xy), SearchXRight(gl_TexCoord[0].xy)); + + // Now fetch the crossing edges. Instead of sampling between edgels, we + // sample at 0.25, to be able to discern what value has each edgel: + vec4 coords = vec4(d.x, 0.25, d.y + 1.0, 0.25) * PIXEL_SIZE.xyxy + gl_TexCoord[0].xyxy; + float e1 = texture2DLod(edgesMap, coords.xy, 0.0).r; + float e2 = texture2DLod(edgesMap, coords.zw, 0.0).r; + + // Ok, we know how this pattern looks like, now it is time for getting + // the actual area: + areas.rg = Area(abs(d), e1, e2); + } + + if (e.r != 0.0) { // Edge at west + + // Search distances to the top and to the bottom: + vec2 d = vec2(SearchYUp(gl_TexCoord[0].xy), SearchYDown(gl_TexCoord[0].xy)); + + // Now fetch the crossing edges (yet again): + vec4 coords = vec4(-0.25, d.x, -0.25, d.y - 1.0) * PIXEL_SIZE.xyxy + gl_TexCoord[0].xyxy; + float e1 = texture2DLod(edgesMap, coords.xy, 0.0).g; + float e2 = texture2DLod(edgesMap, coords.zw, 0.0).g; + + // Get the area for this direction: + areas.ba = Area(abs(d), e1, e2); + } + + gl_FragColor = areas; +} diff --git a/data/shaders/mlaa_color1.frag b/data/shaders/mlaa_color1.frag new file mode 100644 index 000000000..44ac9965b --- /dev/null +++ b/data/shaders/mlaa_color1.frag @@ -0,0 +1,25 @@ +varying vec4 offset[2]; + +uniform sampler2D colorMapG; +const float threshold = 0.1f; + +void main() { + vec3 weights = vec3(0.2126,0.7152, 0.0722); // ITU-R BT. 709 + + /** + * Luma calculation requires gamma-corrected colors: + */ + float L = dot(texture2D(colorMapG, gl_TexCoord[0].xy).rgb, weights); + float Lleft = dot(texture2D(colorMapG, offset[0].xy).rgb, weights); + float Ltop = dot(texture2D(colorMapG, offset[0].zw).rgb, weights); + float Lright = dot(texture2D(colorMapG, offset[1].xy).rgb, weights); + float Lbottom = dot(texture2D(colorMapG, offset[1].zw).rgb, weights); + + vec4 delta = abs(vec4(L) - vec4(Lleft, Ltop, Lright, Lbottom)); + vec4 edges = step(vec4(threshold), delta); + + if (dot(edges, vec4(1.0)) == 0.0) + discard; + + gl_FragColor = edges; +} diff --git a/data/shaders/mlaa_neigh3.frag b/data/shaders/mlaa_neigh3.frag new file mode 100644 index 000000000..6f9bfabb0 --- /dev/null +++ b/data/shaders/mlaa_neigh3.frag @@ -0,0 +1,38 @@ +varying vec4 offset[2]; + +uniform sampler2D blendMap; +uniform sampler2D colorMap; + +void main() { + // Fetch the blending weights for current pixel: + vec4 topLeft = texture2D(blendMap, gl_TexCoord[0].xy); + float bottom = texture2D(blendMap, offset[1].zw).g; + float right = texture2D(blendMap, offset[1].xy).a; + vec4 a = vec4(topLeft.r, bottom, topLeft.b, right); + + // Up to 4 lines can be crossing a pixel (one in each edge). So, we perform + // a weighted average, where the weight of each line is 'a' cubed, which + // favors blending and works well in practice. + vec4 w = a * a * a; + + // There is some blending weight with a value greater than 0.0? + float sum = dot(w, vec4(1.0)); + if (sum < 1e-5) + discard; + + vec4 color = vec4(0.0); + + // Add the contributions of the possible 4 lines that can cross this pixel: + vec4 C = texture2D(colorMap, gl_TexCoord[0].xy); + vec4 Cleft = texture2D(colorMap, offset[0].xy); + vec4 Ctop = texture2D(colorMap, offset[0].zw); + vec4 Cright = texture2D(colorMap, offset[1].xy); + vec4 Cbottom = texture2D(colorMap, offset[1].zw); + color = mix(C, Ctop, a.r) * w.r + color; + color = mix(C, Cbottom, a.g) * w.g + color; + color = mix(C, Cleft, a.b) * w.b + color; + color = mix(C, Cright, a.a) * w.a + color; + + // Normalize the resulting color and we are finished! + gl_FragColor = color / sum; +} diff --git a/data/shaders/mlaa_offset.vert b/data/shaders/mlaa_offset.vert new file mode 100644 index 000000000..a0b03702e --- /dev/null +++ b/data/shaders/mlaa_offset.vert @@ -0,0 +1,12 @@ +varying vec4 offset[2]; +uniform vec2 PIXEL_SIZE; + +void main() { + gl_Position = ftransform(); + vec4 invy = gl_MultiTexCoord0; +// invy.y = 1.0 - invy.y; + gl_TexCoord[0] = invy; + + offset[0] = invy.xyxy + PIXEL_SIZE.xyxy * vec4(-1.0, 0.0, 0.0, 1.0); + offset[1] = invy.xyxy + PIXEL_SIZE.xyxy * vec4( 1.0, 0.0, 0.0, -1.0); +} diff --git a/data/shaders/motion_blur.frag b/data/shaders/motion_blur.frag index c57abbf59..aef0843fb 100644 --- a/data/shaders/motion_blur.frag +++ b/data/shaders/motion_blur.frag @@ -41,7 +41,7 @@ uniform float mask_radius; uniform float max_tex_height; // Number of samples used for blurring -#define NB_SAMPLES 12 +#define NB_SAMPLES 8 void main() { @@ -50,14 +50,6 @@ void main() // Sample the color buffer vec3 color = texture2D(color_buffer, texcoords).rgb; - // If no motion blur is needed, don't do any of the blur computation, - // just return the color from the texture. - if(boost_amount==0.0) - { - gl_FragColor = vec4(color, 1.0); - return; - } - // Compute the blur direction. // IMPORTANT: we don't normalize it so that it avoids a glitch around 'center', // plus it naturally scales the motion blur in a cool way :) diff --git a/data/shaders/multiply.frag b/data/shaders/multiply.frag new file mode 100644 index 000000000..9394e9595 --- /dev/null +++ b/data/shaders/multiply.frag @@ -0,0 +1,10 @@ +uniform sampler2D tex1; +uniform sampler2D tex2; + +void main() +{ + vec4 col1 = texture2D(tex1, gl_TexCoord[0].xy); + vec4 col2 = vec4(vec3(texture2D(tex2, gl_TexCoord[0].xy).x), 1.0); + + gl_FragColor = col1 * col2; +} diff --git a/data/shaders/normalmap.frag b/data/shaders/normalmap.frag index dfc10424b..1040e1662 100644 --- a/data/shaders/normalmap.frag +++ b/data/shaders/normalmap.frag @@ -4,7 +4,7 @@ uniform sampler2D BumpTex; //The bump-map uniform sampler2D DecalTex; //The texture uniform sampler2D LightMapTex; - int HasLightMap; +uniform int HasLightMap; // New bumpmapping varying vec3 lightVec; @@ -19,18 +19,18 @@ void main() normal = normalize (normal); // compute diffuse lighting - float lamberFactor = max (dot (lightVec, normal), 0.0) ; + float lamberFactor = max (dot (lightVec, normal), 0.0); vec4 diffuseMaterial; - diffuseMaterial = texture2D (DecalTex, gl_TexCoord[0].st); + diffuseMaterial = texture2D (DecalTex, gl_TexCoord[0].st); - if (HasLightMap < 1) - { - // 0.5 is the ambient light - gl_FragColor = diffuseMaterial * (0.5 + lamberFactor*0.5); - } - else - { - gl_FragColor = diffuseMaterial * (0.5 + lamberFactor*0.5) * texture2D(LightMapTex, gl_TexCoord[0].st); - } + if (HasLightMap < 1) + { + // 0.5 is the ambient light + gl_FragColor = diffuseMaterial * (0.5 + lamberFactor*0.5); + } + else + { + gl_FragColor = diffuseMaterial * (0.5 + lamberFactor*0.5) * texture2D(LightMapTex, gl_TexCoord[0].st); + } } diff --git a/data/shaders/objectpass.frag b/data/shaders/objectpass.frag new file mode 100644 index 000000000..c557894d2 --- /dev/null +++ b/data/shaders/objectpass.frag @@ -0,0 +1,40 @@ +varying vec3 nor; + +uniform sampler2D tex; +uniform sampler2D lighttex; +uniform float far; +uniform int hastex; +uniform int haslightmap; +uniform float objectid; + +const float near = 1.0; + +vec4 encdepth(float v) { + vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v; + enc = fract(enc); + enc -= enc.yzww * vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0); + return enc; +} + +void main() { + + float linear_z = (2.0 * near) / (far + near - gl_FragCoord.z * (far - near)); + + // Tune for better inside range without losing outdoors + linear_z *= 2.0; + + vec4 light = vec4(1.0); + + if (haslightmap != 0) { + light = texture2D(lighttex, gl_TexCoord[1].xy); + } + + if (hastex != 0) + gl_FragData[0] = texture2D(tex, gl_TexCoord[0].xy) * light; + else + gl_FragData[0] = gl_Color; + + gl_FragData[1] = vec4(nor, linear_z); + gl_FragData[2] = vec4(encdepth(gl_FragCoord.z).xyz, objectid); +} + diff --git a/data/shaders/objectpass.vert b/data/shaders/objectpass.vert new file mode 100644 index 000000000..76e749908 --- /dev/null +++ b/data/shaders/objectpass.vert @@ -0,0 +1,14 @@ +varying vec3 nor; +uniform mat4 invtworldm; + +void main() { + + nor = (invtworldm * vec4(gl_Normal, 0.0)).xyz; + nor = normalize(nor); + nor = nor * 0.5 + 0.5; + + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_TexCoord[1] = gl_MultiTexCoord1; + gl_Position = ftransform(); + gl_FrontColor = gl_Color; +} diff --git a/data/shaders/objectpass_ref.frag b/data/shaders/objectpass_ref.frag new file mode 100644 index 000000000..daa022752 --- /dev/null +++ b/data/shaders/objectpass_ref.frag @@ -0,0 +1,37 @@ +varying vec3 nor; +uniform sampler2D tex; +uniform float far; +uniform int hastex; +uniform float objectid; + +const float near = 1.0; + +vec4 encdepth(float v) { + vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v; + enc = fract(enc); + enc -= enc.yzww * vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0); + return enc; +} + +void main() { + + float linear_z = (2.0 * near) / (far + near - gl_FragCoord.z * (far - near)); + + // Tune for better inside range without losing outdoors + linear_z *= 2.0; + + if (hastex != 0) { + vec4 col = texture2D(tex, gl_TexCoord[0].xy); + + if (col.a < 0.5) + discard; + + gl_FragData[0] = col; + } else { + gl_FragData[0] = gl_Color; + } + + gl_FragData[1] = vec4(nor, linear_z); + gl_FragData[2] = vec4(encdepth(gl_FragCoord.z).xyz, objectid); +} + diff --git a/data/shaders/objectpass_rimlit.frag b/data/shaders/objectpass_rimlit.frag new file mode 100644 index 000000000..5979f2214 --- /dev/null +++ b/data/shaders/objectpass_rimlit.frag @@ -0,0 +1,45 @@ +varying vec3 nor; +uniform sampler2D tex; +uniform float far; +uniform int hastex; +uniform float objectid; + +varying vec3 eyenor; +varying vec3 viewpos; + +const float near = 1.0; + +vec4 encdepth(float v) { + vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v; + enc = fract(enc); + enc -= enc.yzww * vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0); + return enc; +} + +void main() { + + float linear_z = (2.0 * near) / (far + near - gl_FragCoord.z * (far - near)); + + // Tune for better inside range without losing outdoors + linear_z *= 2.0; + + float rim = 1.0 - dot(eyenor, viewpos); + rim = smoothstep(0.5, 1.5, rim) * 0.35; + + if (hastex != 0) { + vec4 col = texture2D(tex, gl_TexCoord[0].xy); + + if (col.a < 0.5) + discard; + + col.xyz += rim; + + gl_FragData[0] = col; + } else { + gl_FragData[0] = gl_Color + vec4(vec3(rim), 0.0); + } + + gl_FragData[1] = vec4(nor, linear_z); + gl_FragData[2] = vec4(encdepth(gl_FragCoord.z).xyz, objectid); +} + diff --git a/data/shaders/objectpass_rimlit.vert b/data/shaders/objectpass_rimlit.vert new file mode 100644 index 000000000..b3d98e449 --- /dev/null +++ b/data/shaders/objectpass_rimlit.vert @@ -0,0 +1,19 @@ +varying vec3 nor; +uniform mat4 invtworldm; + +varying vec3 eyenor; +varying vec3 viewpos; + +void main() { + + nor = (invtworldm * vec4(gl_Normal, 0.0)).xyz; + nor = normalize(nor); + nor = nor * 0.5 + 0.5; + + eyenor = gl_NormalMatrix * gl_Normal; + viewpos = -normalize((gl_ModelViewMatrix * gl_Vertex).xyz); + + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ftransform(); + gl_FrontColor = gl_Color; +} diff --git a/data/shaders/objectpass_spheremap.frag b/data/shaders/objectpass_spheremap.frag new file mode 100644 index 000000000..f8abac686 --- /dev/null +++ b/data/shaders/objectpass_spheremap.frag @@ -0,0 +1,42 @@ +varying vec3 nor; +uniform sampler2D tex; +uniform float far; +uniform float objectid; + +varying vec3 eyenor; +varying vec3 viewpos; + +const float near = 1.0; + +vec4 encdepth(float v) { + vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v; + enc = fract(enc); + enc -= enc.yzww * vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0); + return enc; +} + +void main() { + + float linear_z = (2.0 * near) / (far + near - gl_FragCoord.z * (far - near)); + + // Tune for better inside range without losing outdoors + linear_z *= 2.0; + + // Calculate the spherical UV + const vec3 forward = vec3(0.0, 0.0, 1.0); + + // get the angle between the forward vector and the horizontal portion of the normal + vec3 normal_x = normalize(vec3(eyenor.x, 0.0, eyenor.z)); + float sin_theta_x = length(cross( forward, normal_x )) * eyenor.x/abs(eyenor.x); + + // get the angle between the forward vector and the vertical portion of the normal + vec3 normal_y = normalize(vec3(0.0, eyenor.y, eyenor.z)); + float sin_theta_y = length(cross( forward, normal_y )) * eyenor.y/abs(eyenor.y); + + vec4 detail0 = texture2D(tex, vec2(0.5 + sin_theta_x*0.5, 0.5 + sin_theta_y*0.5)); + + gl_FragData[0] = detail0 * gl_Color; + + gl_FragData[1] = vec4(nor, linear_z); + gl_FragData[2] = vec4(encdepth(gl_FragCoord.z).xyz, objectid); +} diff --git a/data/shaders/pass.frag b/data/shaders/pass.frag new file mode 100644 index 000000000..10f94ce0d --- /dev/null +++ b/data/shaders/pass.frag @@ -0,0 +1,6 @@ +uniform sampler2D tex; + +void main() +{ + gl_FragColor = texture2D(tex, gl_TexCoord[0].xy); +} diff --git a/data/shaders/pass.vert b/data/shaders/pass.vert new file mode 100644 index 000000000..2fd32c1ac --- /dev/null +++ b/data/shaders/pass.vert @@ -0,0 +1,6 @@ +void main() { + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_TexCoord[1] = gl_MultiTexCoord1; + gl_Position = ftransform(); + gl_FrontColor = gl_Color; +} diff --git a/data/shaders/penumbrah.frag b/data/shaders/penumbrah.frag new file mode 100644 index 000000000..822c73e56 --- /dev/null +++ b/data/shaders/penumbrah.frag @@ -0,0 +1,52 @@ +uniform sampler2D tex; +uniform vec2 pixel; + +// Separated penumbra, horizontal + +void main() +{ + float sum = 0.0; + vec4 tmp; + float X = gl_TexCoord[0].x; + float Y = gl_TexCoord[0].y; + float width = 0.0; + float zsum = 0.00001; + + tmp = texture2D(tex, vec2(X - 5.13333 * pixel.x, Y)); + sum += tmp.x * 0.00640869; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X - 3.26667 * pixel.x, Y)); + sum += tmp.x * 0.083313; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X - 1.4 * pixel.x, Y)); + sum += tmp.x * 0.305481; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X, Y)); + sum += tmp.x * 0.209473; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X + 1.4 * pixel.x, Y)); + sum += tmp.x * 0.305481; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X + 3.26667 * pixel.x, Y)); + sum += tmp.x * 0.083313; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X + 5.13333 * pixel.x, Y)); + sum += tmp.x * 0.00640869; + zsum += tmp.z; + width += tmp.y; + + float hasz = step(0.7, zsum); + gl_FragColor = vec4(sum, (width / zsum) * hasz, hasz, 1.0); +} diff --git a/data/shaders/penumbrav.frag b/data/shaders/penumbrav.frag new file mode 100644 index 000000000..6a6ef2ca0 --- /dev/null +++ b/data/shaders/penumbrav.frag @@ -0,0 +1,52 @@ +uniform sampler2D tex; +uniform vec2 pixel; + +// Separated penumbra, vertical + +void main() +{ + float sum = 0.0; + vec4 tmp; + float X = gl_TexCoord[0].x; + float Y = gl_TexCoord[0].y; + float width = 0.0; + float zsum = 0.00001; + + tmp = texture2D(tex, vec2(X, Y - 5.13333 * pixel.y)); + sum += tmp.x * 0.00640869; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X, Y - 3.26667 * pixel.y)); + sum += tmp.x * 0.083313; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X, Y - 1.4 * pixel.y)); + sum += tmp.x * 0.305481; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X, Y)); + sum += tmp.x * 0.209473; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X, Y + 1.4 * pixel.y)); + sum += tmp.x * 0.305481; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X, Y + 3.26667 * pixel.y)); + sum += tmp.x * 0.083313; + zsum += tmp.z; + width += tmp.y; + + tmp = texture2D(tex, vec2(X, Y + 5.13333 * pixel.y)); + sum += tmp.x * 0.00640869; + zsum += tmp.z; + width += tmp.y; + + float hasz = step(0.7, zsum); + gl_FragColor = vec4(sum, (width / zsum) * hasz, hasz, 1.0); +} diff --git a/data/shaders/pointlight.frag b/data/shaders/pointlight.frag new file mode 100644 index 000000000..facc40c0e --- /dev/null +++ b/data/shaders/pointlight.frag @@ -0,0 +1,50 @@ +uniform sampler2D ntex; +uniform sampler2D dtex; + +uniform vec3 center; +uniform vec3 col; +uniform vec3 campos; +uniform float r; +uniform float spec; +uniform vec2 screen; +uniform mat4 invprojview; + +float decdepth(vec4 rgba) { + return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0)); +} + +void main() { + + vec2 texc = gl_FragCoord.xy / screen; + float z = decdepth(vec4(texture2D(dtex, texc).xyz, 0.0)); + + if (z < 0.03) discard; + + vec3 tmp = vec3(texc, z); + tmp = tmp * 2.0 - 1.0; + + vec4 xpos = vec4(tmp, 1.0); + xpos = invprojview * xpos; + xpos.xyz /= xpos.w; + + float d = distance(center, xpos.xyz); + if (d > r) discard; + + float att = 1.0 - smoothstep(0.0, r, d); + + vec3 norm = texture2D(ntex, texc).xyz; + norm = (norm - 0.5) * 2.0; + + vec3 camdir = normalize(campos - xpos.xyz); + + vec3 L = normalize(center - xpos.xyz); + vec3 H = normalize(L + camdir); + + float NdotL = max(0.0, dot(norm, L)) * att; + if (NdotL < 0.01) discard; + float NdotH = max(0.0, dot(norm, H)); + NdotH = pow(NdotH, spec); + NdotH += 0.05; // offset so that the alpha test doesn't kill us + + gl_FragColor = NdotL * vec4(col, NdotH); +} diff --git a/data/shaders/ppdisplace.frag b/data/shaders/ppdisplace.frag new file mode 100644 index 000000000..a06293649 --- /dev/null +++ b/data/shaders/ppdisplace.frag @@ -0,0 +1,26 @@ +uniform sampler2D tex; +uniform sampler2D dtex; + +uniform int viz; + +void main() +{ + vec2 tc = gl_TexCoord[0].xy; + + vec4 shiftval = texture2D(dtex, tc) / vec4(50.0); + vec2 shift; + shift.x = -shiftval.x + shiftval.y; + shift.y = -shiftval.z + shiftval.w; + + tc += shift; + + vec4 newcol = texture2D(tex, tc); + + if (viz < 1) + { + gl_FragColor = newcol; + } else + { + gl_FragColor = shiftval * vec4(50.0); + } +} diff --git a/data/shaders/rain.frag b/data/shaders/rain.frag new file mode 100644 index 000000000..10f94ce0d --- /dev/null +++ b/data/shaders/rain.frag @@ -0,0 +1,6 @@ +uniform sampler2D tex; + +void main() +{ + gl_FragColor = texture2D(tex, gl_TexCoord[0].xy); +} diff --git a/data/shaders/rain.vert b/data/shaders/rain.vert new file mode 100644 index 000000000..f2a764ede --- /dev/null +++ b/data/shaders/rain.vert @@ -0,0 +1,33 @@ +uniform float screenw; +uniform float time; +uniform mat4 viewm; +uniform vec3 campos; + +void main() +{ + const float size = 0.5; + + // This simulation will run accurately for a bit under five days. + vec4 start = gl_Vertex; + start.y -= time; + + // How many times has it fell? + float count = floor(start.y / 24.0); + start.x += sin(count); + start.z += cos(count); + + vec2 signs = sign(start.xz); + start.xz = mod(start.xz, 17.5) * signs; + + start.y = mod(start.y, 24.0) - 3.0; + + start.xyz += campos; + + vec4 eyepos = viewm * start; + vec4 projCorner = gl_ProjectionMatrix * vec4(vec2(size), eyepos.z, eyepos.w); + + gl_PointSize = screenw * projCorner.x / projCorner.w; + gl_Position = gl_ProjectionMatrix * eyepos; + + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/data/shaders/shadowgen.frag b/data/shaders/shadowgen.frag new file mode 100644 index 000000000..6c2d8501a --- /dev/null +++ b/data/shaders/shadowgen.frag @@ -0,0 +1,44 @@ +uniform sampler2D halft; // half is a reserved word +uniform sampler2D quarter; +uniform sampler2D eighth; + +void main() +{ + vec3 val[3]; + val[0] = texture2D(halft, gl_TexCoord[0].xy).xyz; + val[1] = texture2D(quarter, gl_TexCoord[0].xy).xyz; + val[2] = texture2D(eighth, gl_TexCoord[0].xy).xyz; + + // Find the first level with a penumbra value + int i; + float q = 0.0; + float outval = 1.0; + + float hasshadow = dot(vec3(1.0), vec3(val[0].z, val[1].z, val[2].z)); + + if (hasshadow > 0.9) + { + for (i = 0; i < 3; i++) + { + if (val[i].z > 0.9) + { + q = val[i].y; + break; + } + } + + q *= 8.0; + q = max(1.0, q); + q = log2(q); + q = min(1.9, q); + + // q is now between 0 and 1.9. + int down = int(floor(q)); + int up = down + 1; + float interp = q - float(down); + + outval = 1.0 - mix(val[down].x, val[up].x, interp); + } + + gl_FragColor = vec4(vec3(outval), 1.0); +} diff --git a/data/shaders/shadowimportance.frag b/data/shaders/shadowimportance.frag new file mode 100644 index 000000000..190d40418 --- /dev/null +++ b/data/shaders/shadowimportance.frag @@ -0,0 +1,70 @@ +uniform sampler2D ntex; +uniform sampler2D ctex; +uniform vec3 campos; +uniform int low; + +varying vec3 wpos; +varying vec2 texc; + +float luminanceImp() +{ + // A full-res fetch kills on low-end + if (low > 0) return 1.0; + + const vec3 weights = vec3(0.2126, 0.7152, 0.0722); // ITU-R BT. 709 + vec3 col = texture2D(ctex, texc).xyz; + + float luma = dot(weights, col); + + // Dark surfaces need less resolution + float f = smoothstep(0.1, 0.4, luma); + f = max(0.05, f); + + return f; +} + +float normalImp(vec3 normal) +{ + vec3 camdir = normalize(campos - wpos); + vec3 N = normalize(normal); + + // Boost surfaces facing the viewer directly + float f = 2.0 * max(0.0, dot(N, camdir)); + + return f; +} + +float depthImp(float linearz) +{ +/* const float skip = 0.7; + + float f = min(linearz, skip); + f *= 1.0/skip;*/ + + float z = log(1.0 + linearz * 9.0) / log(10.0); + + float f = 1.0 - (z * 0.9); + + return f; +} + +void main() +{ + vec4 ntmp = texture2D(ntex, texc); + vec3 normal = ntmp.xyz * 2.0 - 1.0; + float linearz = ntmp.a; + + float importance = normalImp(normal) * depthImp(linearz) * luminanceImp(); + importance = clamp(importance, 0.0, 1.0); + + float low = step(0.001, importance); + + // Quantize it + const float steps = 16.0; + importance *= steps; + importance = ceil(importance) * low; + importance /= steps; + + gl_FragColor = vec4(importance); + gl_FragDepth = 1.0 - importance; +} diff --git a/data/shaders/shadowimportance.vert b/data/shaders/shadowimportance.vert new file mode 100644 index 000000000..87ab5c783 --- /dev/null +++ b/data/shaders/shadowimportance.vert @@ -0,0 +1,30 @@ +uniform sampler2D dtex; +uniform mat4 ipvmat; +uniform mat4 shadowmat; + +varying vec3 wpos; +varying vec2 texc; + +float decdepth(vec4 rgba) { + return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0)); +} + +void main() +{ + texc = gl_Vertex.xy / vec2(32767.0); + float z = decdepth(vec4(texture2D(dtex, texc).xyz, 0.0)); + + vec3 tmp = vec3(texc, z); + tmp = tmp * 2.0 - 1.0; + + vec4 xpos = vec4(tmp, 1.0); + xpos = ipvmat * xpos; + xpos.xyz /= xpos.w; + + wpos = xpos.xyz; + + // Now we have this pixel's world-space position. Convert to shadow space. + vec4 pos = shadowmat * vec4(xpos.xyz, 1.0); + + gl_Position = pos; +} diff --git a/data/shaders/shadowpass.frag b/data/shaders/shadowpass.frag new file mode 100644 index 000000000..974cce97f --- /dev/null +++ b/data/shaders/shadowpass.frag @@ -0,0 +1,34 @@ +uniform sampler2D tex; +uniform int hastex; +uniform int viz; +uniform int wireframe; +uniform float objectid; + +vec4 encdepth(float v) { + vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v; + enc = fract(enc); + enc -= enc.yzww * vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0); + return enc; +} + +void main() { + + if (hastex != 0) { + float alpha = texture2D(tex, gl_TexCoord[0].xy).a; + + if (alpha < 0.5) + discard; + } + + if (viz < 1) + { + gl_FragColor = vec4(encdepth(gl_FragCoord.z).xyz, objectid); + } + else { + if (wireframe > 0) + gl_FragColor = vec4(1.0); + else + gl_FragColor = texture2D(tex, gl_TexCoord[0].xy); + } +} + diff --git a/data/shaders/shadowpass.vert b/data/shaders/shadowpass.vert new file mode 100644 index 000000000..631dbb5a6 --- /dev/null +++ b/data/shaders/shadowpass.vert @@ -0,0 +1,25 @@ +uniform sampler2D warpx; +uniform sampler2D warpy; + +float decdepth(vec4 rgba) { + return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0)); +} + +void main() +{ + vec4 pos = ftransform(); + gl_TexCoord[0] = gl_MultiTexCoord0; + + vec2 tc = pos.xy * vec2(0.5) + vec2(0.5); + + float movex = decdepth(texture2D(warpx, tc)); + float movey = decdepth(texture2D(warpy, tc)); + + float dx = movex * 2.0 - 1.0; + float dy = movey * 2.0 - 1.0; + + dx *= 2.0; + dy *= 2.0; + + gl_Position = pos + vec4(dx, dy, vec2(0.0)); +} diff --git a/data/shaders/shadowwarph.frag b/data/shaders/shadowwarph.frag new file mode 100644 index 000000000..e7e9d5632 --- /dev/null +++ b/data/shaders/shadowwarph.frag @@ -0,0 +1,54 @@ +uniform sampler2D tex; +uniform int size; +uniform vec2 pixel; + +vec4 encdepth(float v) { + vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v; + enc = fract(enc); + enc -= enc.yzww * vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0); + return enc; +} + +void main() +{ + vec2 origtc = gl_TexCoord[0].xy; + + // Get total sum + float first = 1.0, last = 0.0; + float lower = 0.0; + float total = 0.0; + vec2 tc = 0.5 * pixel; + + for (int i = 0; i < size; i++) + { + float col = texture2D(tex, tc).x; + + lower += col * step(tc.x, origtc.x); + total += col; + + if (col > 0.0001) + { + first = min(first, tc.x); + last = max(last, tc.x); + } + + tc += pixel; + } + + float res = (lower / total) - origtc.x; + + // Outside the edges? + if (origtc.x <= first) + { + res = origtc.x * -2.1; + } + else if (origtc.x >= last) + { + res = (1.0 - origtc.x) * 2.1; + } + + res = res * 0.5 + 0.5; + res = clamp(res, 0.01, 0.99); + + gl_FragColor = encdepth(res); +} diff --git a/data/shaders/shadowwarpv.frag b/data/shaders/shadowwarpv.frag new file mode 100644 index 000000000..6998c61e7 --- /dev/null +++ b/data/shaders/shadowwarpv.frag @@ -0,0 +1,54 @@ +uniform sampler2D tex; +uniform int size; +uniform vec2 pixel; + +vec4 encdepth(float v) { + vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v; + enc = fract(enc); + enc -= enc.yzww * vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0); + return enc; +} + +void main() +{ + vec2 origtc = gl_TexCoord[0].xy; + + // Get total sum + float first = 1.0, last = 0.0; + float lower = 0.0; + float total = 0.0; + vec2 tc = pixel * 0.5; + + for (int i = 0; i < size; i++) + { + float col = texture2D(tex, tc).x; + + lower += col * step(tc.y, origtc.y); + total += col; + + if (col > 0.0001) + { + first = min(first, tc.y); + last = max(last, tc.y); + } + + tc += pixel; + } + + float res = (lower / total) - origtc.y; + + // Outside the edges? + if (origtc.y <= first) + { + res = origtc.y * -2.1; + } + else if (origtc.y >= last) + { + res = (1.0 - origtc.y) * 2.1; + } + + res = res * 0.5 + 0.5; + res = clamp(res, 0.01, 0.99); + + gl_FragColor = encdepth(res); +} diff --git a/data/shaders/snow.frag b/data/shaders/snow.frag new file mode 100644 index 000000000..3fddd77ec --- /dev/null +++ b/data/shaders/snow.frag @@ -0,0 +1,18 @@ +uniform sampler2D tex; +uniform float time; + +void main() +{ + vec2 change; + change.x = abs(sin(time * gl_Color.r)); + change.y = abs(cos(time * gl_Color.g)); + + change = smoothstep(0.0, 1.0, change) * 0.5; + + vec2 tc = gl_TexCoord[0].xy; + tc = smoothstep(0.5 - change, 0.5 + change, tc); + + vec4 tcol = texture2D(tex, tc); + + gl_FragColor = tcol; +} diff --git a/data/shaders/snow.vert b/data/shaders/snow.vert new file mode 100644 index 000000000..b0d8dfd55 --- /dev/null +++ b/data/shaders/snow.vert @@ -0,0 +1,7 @@ +void main() +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ftransform(); + + gl_FrontColor = gl_Color; +} diff --git a/data/shaders/splatting.frag b/data/shaders/splatting.frag index 2fc3de57d..ac5e9f7ac 100644 --- a/data/shaders/splatting.frag +++ b/data/shaders/splatting.frag @@ -1,44 +1,48 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 the SuperTuxKart team -// -// This program 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 3 -// of the License, or (at your option) any later version. -// -// This program 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 this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - +varying vec3 nor; +uniform float far; +uniform float objectid; uniform sampler2D tex_layout; uniform sampler2D tex_detail0; uniform sampler2D tex_detail1; uniform sampler2D tex_detail2; uniform sampler2D tex_detail3; -uniform sampler2D tex_detail4; -varying vec3 normal; -varying vec3 lightdir2; -varying vec4 vertex_color; +//uniform sampler2D tex_detail4; -void main() -{ - vec4 splatting = texture2D(tex_layout, gl_TexCoord[1].st); - vec4 detail0 = texture2D(tex_detail0, gl_TexCoord[0].st); - vec4 detail1 = texture2D(tex_detail1, gl_TexCoord[0].st); - vec4 detail2 = texture2D(tex_detail2, gl_TexCoord[0].st); - vec4 detail3 = texture2D(tex_detail3, gl_TexCoord[0].st); - vec4 detail4 = texture2D(tex_detail4, gl_TexCoord[0].st); +const float near = 1.0; - gl_FragColor = (splatting.r * detail0 + - splatting.g * detail1 + - splatting.b * detail2 + - (1.0 - splatting.r - splatting.g - splatting.b) * detail3 + - (1.0 - splatting.a) * detail4) - * min(1.0, 0.2 + dot(lightdir2, normal)) * vertex_color; // 0.2 is the ambient light. +vec4 encdepth(float v) { + vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * v; + enc = fract(enc); + enc -= enc.yzww * vec4(1.0/255.0, 1.0/255.0, 1.0/255.0, 0.0); + return enc; +} + +void main() { + + float linear_z = (2.0 * near) / (far + near - gl_FragCoord.z * (far - near)); + + // Tune for better inside range without losing outdoors + linear_z *= 2.0; + + // Splatting part + vec4 splatting = texture2D(tex_layout, gl_TexCoord[1].st); + vec4 detail0 = texture2D(tex_detail0, gl_TexCoord[0].st); + vec4 detail1 = texture2D(tex_detail1, gl_TexCoord[0].st); + vec4 detail2 = texture2D(tex_detail2, gl_TexCoord[0].st); + vec4 detail3 = texture2D(tex_detail3, gl_TexCoord[0].st); +// vec4 detail4 = texture2D(tex_detail4, gl_TexCoord[0].st); + vec4 detail4 = vec4(0.0); + + vec4 splatted = (splatting.r * detail0 + + splatting.g * detail1 + + splatting.b * detail2 + + (1.0 - splatting.r - splatting.g - splatting.b) * detail3 + + (1.0 - splatting.a) * detail4) + * gl_Color; + + gl_FragData[0] = splatted; + + gl_FragData[1] = vec4(nor, linear_z); + gl_FragData[2] = vec4(encdepth(gl_FragCoord.z).xyz, objectid); } diff --git a/data/shaders/ssao.frag b/data/shaders/ssao.frag new file mode 100644 index 000000000..833364bf9 --- /dev/null +++ b/data/shaders/ssao.frag @@ -0,0 +1,78 @@ +#version 120 + +uniform sampler2D tex; +uniform sampler2D oldtex; + +const float totStrength = 2.38; +const float strength = 0.07; +const float falloff = 0.000002; + +#define SAMPLES 16 + +const float invSamples = 1.0 / SAMPLES; + +void main(void) +{ + // A set of Random(tm) vec2's. 8 1s, 6 0.7s, 2 0.4 + // Again not using const because of broken Intel Windows drivers + vec2 vecs[16] = vec2[](vec2(0.43589, -0.9), vec2(-0.9, 0.43589), + vec2(-0.8, -0.6), vec2(0.6, 0.8), + vec2(0.866025, -0.5), vec2(-0.5, 0.866025), + vec2(-0.3, -0.953939), vec2(0.953939, 0.3), + vec2(0.3, -0.781025), vec2(-0.781025, 0.3), + vec2(-0.56, -0.621611), vec2(0.621611, 0.56), + vec2(0.734847, -0.4), vec2(-0.4, 0.734847), + vec2(-0.2, -0.6), vec2(0.6, 0.2)); + + vec2 uv = gl_TexCoord[0].xy; + + vec4 cur = texture2D(tex, uv); + float curdepth = cur.a; + + // Will we skip this pixel? (if it's the sky) + float len = dot(vec3(1.0), abs(cur.xyz)); + if (len < 0.2 || curdepth > 0.8) discard; + + float mytotstrength = 3.0 * totStrength * curdepth * (1.0 - curdepth); + + // get the normal of current fragment + vec3 norm = normalize(cur.xyz * vec3(2.0) - vec3(1.0)); + + float bl = 0.0; + + // adjust for the depth, 0.1 close, 0.01 far + float radD = 0.10 - 0.09 * smoothstep(0.0, 0.2, curdepth); + + for(int i = 0; i < SAMPLES; ++i) { + + vec2 ray = uv + radD * vecs[i]; + + // get the depth of the occluder fragment + vec4 occluderFragment = texture2D(tex, ray); + float normAcceptable = step(0.2, dot(vec3(1.0), abs(occluderFragment.xyz))); + + // get the normal of the occluder fragment + vec3 occNorm = normalize(occluderFragment.xyz * vec3(2.0) - vec3(1.0)); + + // if depthDifference is negative = occluder is behind current fragment + float depthDifference = curdepth - occluderFragment.a; + + // calculate the difference between the normals as a weight + float normDiff = 1.0 - max(dot(occNorm, norm), 0.0); + normDiff = smoothstep(0.1, 0.3, normDiff); + + // the falloff equation, starts at falloff and is kind of 1/x^2 falling + bl += step(falloff, depthDifference) * normDiff * normAcceptable * + (1.0 - smoothstep(falloff, strength, depthDifference)); + } + + // output the result + float ao = 1.0 - mytotstrength * bl * invSamples; + + // Mix with old result to avoid flicker + float oldao = texture2D(oldtex, uv).x; + + ao = mix(ao, oldao, 0.3); + + gl_FragColor = vec4(vec3(ao), curdepth); +} diff --git a/data/shaders/sunlight.frag b/data/shaders/sunlight.frag new file mode 100644 index 000000000..1553bfc0c --- /dev/null +++ b/data/shaders/sunlight.frag @@ -0,0 +1,58 @@ +uniform sampler2D ntex; +uniform sampler2D dtex; +uniform sampler2D cloudtex; + +uniform vec3 center; +uniform vec3 col; +uniform vec2 screen; +uniform mat4 invprojview; +uniform int hasclouds; +uniform vec2 wind; + +float decdepth(vec4 rgba) { + return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0)); +} + +void main() { + + vec2 texc = gl_FragCoord.xy / screen; + float z = decdepth(vec4(texture2D(dtex, texc).xyz, 0.0)); + + if (z < 0.03) + { + // Skyboxes are fully lit + gl_FragData[0] = vec4(1.0); + gl_FragData[1] = vec4(1.0); + return; + } + + vec3 norm = texture2D(ntex, texc).xyz; + norm = (norm - 0.5) * 2.0; + + // Normalized on the cpu + vec3 L = center; + + float NdotL = max(0.0, dot(norm, L)); + if (NdotL < 0.01) discard; + + vec3 outcol = NdotL * col; + + if (hasclouds == 1) + { + vec3 tmp = vec3(texc, z); + tmp = tmp * 2.0 - 1.0; + + vec4 xpos = vec4(tmp, 1.0); + xpos = invprojview * xpos; + xpos.xyz /= xpos.w; + + vec2 cloudcoord = (xpos.xz * 0.00833333) + wind; + float cloud = texture2D(cloudtex, cloudcoord).x; + //float cloud = step(0.5, cloudcoord.x) * step(0.5, cloudcoord.y); + + outcol *= cloud; + } + + gl_FragData[0] = vec4(outcol, 0.05); + gl_FragData[1] = vec4(1.0); +} diff --git a/data/shaders/sunlightshadow.frag b/data/shaders/sunlightshadow.frag new file mode 100644 index 000000000..89bc576f9 --- /dev/null +++ b/data/shaders/sunlightshadow.frag @@ -0,0 +1,106 @@ +uniform sampler2D ntex; +uniform sampler2D dtex; +uniform sampler2D cloudtex; +uniform sampler2D shadowtex; +uniform sampler2D warpx; +uniform sampler2D warpy; + +uniform vec3 center; +uniform vec3 col; +uniform vec2 screen; +uniform mat4 invprojview; +uniform mat4 shadowmat; +uniform int hasclouds; +uniform vec2 wind; +uniform float shadowoffset; + +float decdepth(vec4 rgba) { + return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0)); +} + +void main() { + + vec2 texc = gl_FragCoord.xy / screen; + vec4 depthread = texture2D(dtex, texc); + float z = decdepth(vec4(depthread.xyz, 0.0)); + + if (z < 0.03) + { + // Skyboxes are fully lit + gl_FragData[0] = vec4(1.0); + gl_FragData[1] = vec4(0.0); + return; + } + + vec3 norm = texture2D(ntex, texc).xyz; + norm = (norm - 0.5) * 2.0; + + // Normalized on the cpu + vec3 L = center; + + float NdotL = max(0.0, dot(norm, L)); + if (NdotL < 0.01) discard; + + vec3 outcol = NdotL * col; + + // World-space position + vec3 tmp = vec3(texc, z); + tmp = tmp * 2.0 - 1.0; + + vec4 xpos = vec4(tmp, 1.0); + xpos = invprojview * xpos; + xpos.xyz /= xpos.w; + + if (hasclouds == 1) + { + vec2 cloudcoord = (xpos.xz * 0.00833333) + wind; + float cloud = texture2D(cloudtex, cloudcoord).x; + //float cloud = step(0.5, cloudcoord.x) * step(0.5, cloudcoord.y); + + outcol *= cloud; + } + + // Shadows + vec3 shadowcoord = (shadowmat * vec4(xpos.xyz, 1.0)).xyz; + shadowcoord = (shadowcoord * 0.5) + vec3(0.5); + + float movex = decdepth(texture2D(warpx, shadowcoord.xy)); + float movey = decdepth(texture2D(warpy, shadowcoord.xy)); + float dx = movex * 2.0 - 1.0; + float dy = movey * 2.0 - 1.0; + shadowcoord.xy += vec2(dx, dy); + + vec4 shadowread = texture2D(shadowtex, shadowcoord.xy); + float shadowmapz = decdepth(vec4(shadowread.xyz, 0.0)); + + float moved = (abs(dx) + abs(dy)) * 0.5; + + float bias = 0.002 * tan(acos(NdotL)); // According to the slope + bias += smoothstep(0.001, 0.1, moved) * 0.014; // According to the warping + bias = clamp(bias, 0.001, 0.014); + + // This ID, and four IDs around this must match for a shadow pixel + float right = texture2D(shadowtex, shadowcoord.xy + vec2(shadowoffset, 0.0)).a; + float left = texture2D(shadowtex, shadowcoord.xy + vec2(-shadowoffset, 0.0)).a; + float up = texture2D(shadowtex, shadowcoord.xy + vec2(0.0, shadowoffset)).a; + float down = texture2D(shadowtex, shadowcoord.xy + vec2(0.0, -shadowoffset)).a; + + float matching = ((right + left + up + down) * 0.25) - shadowread.a; + matching = abs(matching) * 400.0; + + // If the ID is different, we're likely in shadow - cut the bias to cut peter panning + float off = 7.0 - step(abs(shadowread.a - depthread.a) - matching, 0.004) * 6.0; + bias /= off; + + const float softness = 8.0; // How soft is the light? + float shadowed = step(shadowmapz + bias, shadowcoord.z); + float dist = (shadowcoord.z / shadowmapz) - 1.0; + float penumbra = dist * softness / gl_FragCoord.z; + penumbra *= shadowed; + +/* outcol.r = (shadowcoord.z - shadowmapz) * 50.0; + outcol.g = moved;*/ + + gl_FragData[0] = vec4(outcol, 0.05); + gl_FragData[1] = vec4(shadowed, penumbra, shadowed, shadowed); +} diff --git a/data/shaders/water.frag b/data/shaders/water.frag index 70899ea2e..3f36b8b72 100644 --- a/data/shaders/water.frag +++ b/data/shaders/water.frag @@ -16,11 +16,11 @@ void main() { // lookup normal from normal map, move from [0,1] to [-1, 1] range, normalize vec3 normal = 2.0 * texture2D (BumpTex1, gl_TexCoord[0].st + delta1).rgb - 1.0; - vec3 normal2 = 2.0 * texture2D (BumpTex2, gl_TexCoord[0].st + delta2).rgb - 1.0; + vec3 normal2 = 2.0 * texture2D (BumpTex2, gl_TexCoord[0].st + delta2).rgb - 1.0; - // scale normals - normal.y = 4.0*normal.y; - normal2.y = 4.0*normal2.y; + // scale normals + normal.y = 4.0*normal.y; + normal2.y = 4.0*normal2.y; normal = (normalize(normal) + normalize(normal2))/2.0; @@ -29,31 +29,28 @@ void main() vec4 diffuseMaterial; vec4 diffuseLight; - diffuseMaterial = texture2D (DecalTex, gl_TexCoord[0].st + vec2(delta1.x, 0.0)); - diffuseLight = vec4(1.0, 1.0, 1.0, 1.0); + diffuseMaterial = texture2D (DecalTex, gl_TexCoord[0].st + vec2(delta1.x, 0.0)); + diffuseLight = vec4(1.0, 1.0, 1.0, 1.0); - //if (lamberFactor < 0.7) - //{ - // lamberFactor = 0.0; - //} + vec3 col = diffuseMaterial.xyz * (0.3 + lamberFactor*0.7); - gl_FragColor = diffuseMaterial * (0.3 + lamberFactor*0.7); + // specular (phong) + vec3 R = normalize(reflect(lightVec, normal)); + float specular = max(dot(R, eyeVec), 0.0); - // specular (phong) - vec3 R = normalize(reflect(lightVec, normal)); - float specular = max(dot(R,eyeVec),0.0); + // weak specular + specular = specular*specular; + specular = specular*specular; + float specular_weak = specular*0.05; + col += vec3(specular_weak, specular_weak, specular_weak); - if (specular > 0.0) - { - // weak specular - specular = specular*specular; - specular = specular*specular; - float specular_weak = specular*0.05; - gl_FragColor += vec4(specular_weak, specular_weak, specular_weak, 0.0); + // strong specular + specular = specular*specular; + float specular_strong = specular*0.3; + col += vec3(specular_strong, specular_strong, specular_strong); - // strong specular - specular = specular*specular; - float specular_strong = specular*0.3; - gl_FragColor += vec4(specular_strong, specular_strong, specular_strong, 0.0); - } + float summed = dot(vec3(1.0), col) / 3.0; + float alpha = 0.9 + 0.1 * smoothstep(0.0, 1.0, summed); + + gl_FragColor = vec4(col, alpha); } diff --git a/data/shaders/water.vert b/data/shaders/water.vert index 9b88f362d..5a58fda94 100644 --- a/data/shaders/water.vert +++ b/data/shaders/water.vert @@ -1,25 +1,30 @@ // Shader based on work by Fabien Sanglard // Released under the terms of CC-BY 3.0 +uniform float speed; +uniform float height; +uniform float length; + +uniform vec3 lightdir; + varying vec3 lightVec; varying vec3 halfVec; varying vec3 eyeVec; -uniform vec3 lightdir; - void main() { + vec4 pos = gl_Vertex; - gl_TexCoord[0] = gl_MultiTexCoord0; + pos.y += (sin(pos.x/length + speed) + cos(pos.z/length + speed)) * height; + + vec3 vertexPosition = vec3(gl_ModelViewMatrix * pos); // Building the matrix Eye Space -> Tangent Space vec3 n = normalize (gl_NormalMatrix * gl_Normal); - // gl_MultiTexCoord1.xyz + // gl_MultiTexCoord1.xyz vec3 t = normalize (gl_NormalMatrix * vec3(1.0, 0.0, 0.0)); // tangent vec3 b = cross (n, t); - vec3 vertexPosition = vec3(gl_ModelViewMatrix * gl_Vertex); - // transform light and half angle vectors by tangent basis vec3 v; v.x = dot (lightdir, t); @@ -29,7 +34,7 @@ void main() vertexPosition = normalize(vertexPosition); - eyeVec = normalize(-vertexPosition); // we are in Eye Coordinates, so EyePos is (0,0,0) + eyeVec = normalize(-vertexPosition); // we are in Eye Coordinates, so EyePos is (0,0,0) // Normalize the halfVector to pass it to the fragment shader @@ -44,5 +49,7 @@ void main() //normalize (v); halfVec = v ; - gl_Position = ftransform(); -} \ No newline at end of file + gl_Position = gl_ModelViewProjectionMatrix * pos; + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_TexCoord[1] = gl_MultiTexCoord1; +} diff --git a/data/shaders/water_fog.frag b/data/shaders/water_fog.frag deleted file mode 100644 index 63a8f5a70..000000000 --- a/data/shaders/water_fog.frag +++ /dev/null @@ -1,75 +0,0 @@ -// Shader based on work by Fabien Sanglard -// Released under the terms of CC-BY 3.0 - -uniform sampler2D BumpTex1; // Normal map 1 -uniform sampler2D BumpTex2; // Normal map 2 -uniform sampler2D DecalTex; //The texture - -uniform vec2 delta1; -uniform vec2 delta2; - -varying vec3 lightVec; -varying vec3 halfVec; -varying vec3 eyeVec; -varying vec4 coord; - -uniform vec4 fogColor; -uniform float fogFrom; -uniform float fogTo; - -void main() -{ - // lookup normal from normal map, move from [0,1] to [-1, 1] range, normalize - vec3 normal = 2.0 * texture2D (BumpTex1, gl_TexCoord[0].st + delta1).rgb - 1.0; - vec3 normal2 = 2.0 * texture2D (BumpTex2, gl_TexCoord[0].st + delta2).rgb - 1.0; - - // scale normals - normal.y = 4.0*normal.y; - normal2.y = 4.0*normal2.y; - - normal = (normalize(normal) + normalize(normal2))/2.0; - - // compute diffuse lighting - float lamberFactor = max (dot (lightVec, normal), 0.0); - vec4 diffuseMaterial; - vec4 diffuseLight; - - diffuseMaterial = texture2D (DecalTex, gl_TexCoord[0].st + vec2(delta1.x, 0.0)); - diffuseLight = vec4(1.0, 1.0, 1.0, 1.0); - - //if (lamberFactor < 0.7) - //{ - // lamberFactor = 0.0; - //} - - gl_FragColor = diffuseMaterial * (0.3 + lamberFactor*0.7); - - // specular (phong) - vec3 R = normalize(reflect(lightVec, normal)); - float specular = max(dot(R,eyeVec),0.0); - - if (specular > 0.0) - { - // weak specular - specular = specular*specular; - specular = specular*specular; - float specular_weak = specular*0.05; - gl_FragColor += vec4(specular_weak, specular_weak, specular_weak, 0.0); - - // strong specular - specular = specular*specular; - float specular_strong = specular*0.3; - gl_FragColor += vec4(specular_strong, specular_strong, specular_strong, 0.0); - } - - if (coord.z > fogTo) - { - gl_FragColor = fogColor; - } - else if (coord.z > fogFrom) - { - float fogIntensity = (coord.z - fogFrom) / (fogTo - fogFrom); - gl_FragColor = fogIntensity*fogColor + (1.0 - fogIntensity)*gl_FragColor; - } -} - diff --git a/data/shaders/water_fog.vert b/data/shaders/water_fog.vert deleted file mode 100644 index 4419ca428..000000000 --- a/data/shaders/water_fog.vert +++ /dev/null @@ -1,49 +0,0 @@ -// Shader based on work by Fabien Sanglard -// Released under the terms of CC-BY 3.0 - -varying vec3 lightVec; -varying vec3 halfVec; -varying vec3 eyeVec; -varying vec4 coord; -uniform vec3 lightdir; - -void main() -{ - - gl_TexCoord[0] = gl_MultiTexCoord0; - - // Building the matrix Eye Space -> Tangent Space - vec3 n = normalize (gl_NormalMatrix * gl_Normal); - // gl_MultiTexCoord1.xyz - vec3 t = normalize (gl_NormalMatrix * vec3(1.0, 0.0, 0.0)); // tangent - vec3 b = cross (n, t); - - vec3 vertexPosition = vec3(gl_ModelViewMatrix * gl_Vertex); - - // transform light and half angle vectors by tangent basis - vec3 v; - v.x = dot (lightdir, t); - v.y = dot (lightdir, b); - v.z = dot (lightdir, n); - lightVec = normalize (v); - - vertexPosition = normalize(vertexPosition); - - eyeVec = normalize(-vertexPosition); // we are in Eye Coordinates, so EyePos is (0,0,0) - - // Normalize the halfVector to pass it to the fragment shader - - // No need to divide by two, the result is normalized anyway. - // vec3 halfVector = normalize((vertexPosition + lightDir) / 2.0); - vec3 halfVector = normalize(vertexPosition + lightdir); - v.x = dot (halfVector, t); - v.y = dot (halfVector, b); - v.z = dot (halfVector, n); - - // No need to normalize, t,b,n and halfVector are normal vectors. - //normalize (v); - halfVec = v ; - - gl_Position = ftransform(); - coord = gl_Position; -} diff --git a/data/shaders/white.frag b/data/shaders/white.frag new file mode 100644 index 000000000..1cc07d303 --- /dev/null +++ b/data/shaders/white.frag @@ -0,0 +1,4 @@ +void main() +{ + gl_FragColor = vec4(1.0); +} diff --git a/data/stk_config.xml b/data/stk_config.xml index 18d1cb51c..5bed7c8eb 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -135,6 +135,9 @@ + + + diff --git a/doc/graphics_views.txt b/doc/graphics_views.txt new file mode 100644 index 000000000..d96268a6e --- /dev/null +++ b/doc/graphics_views.txt @@ -0,0 +1,21 @@ +Graphics debug views +==================== + +There are some graphics debug views, to be used both by artists when developing, +and by users when reporting bugs. + +These should be available in normal (non-artist) mode +to enable easier bug reports (go there, press this key, screenshot) +without requiring editing the UTF-32 config files (which is inconvenient, most editors +do not support that weird encoding). + +They don't give gameplay advantages like the item keys, so there should be little harm +leaving them available. Accidental keypresses ought to be minimized by their location. + +Home - wireframe view +End - mipmap visualization (is a texture too high or low resolution, red = too high) +Del - normal view +PgDown - SSAO view +PgUp - light view +Ins - shadow view +ScrlLock - displacement view diff --git a/doc/graphics_xml.txt b/doc/graphics_xml.txt new file mode 100644 index 000000000..ba9062611 --- /dev/null +++ b/doc/graphics_xml.txt @@ -0,0 +1,157 @@ +Graphics GSOC XML additions +=========================== + +This document will list in depth all new XML values added during the graphics GSOC, for use +by the blender exporter scripts. + +Glow colors +----------- + +The glow colors for nitro bottles and boxes are settable in stk_config.xml. +They are three-value RGB colors. + +Example: + + +Particle wind +------------- + +Particles may be affected by wind. This is used with the snow particles. + +Flips is a boolean controlling whether each particle will spin about its own two axis. +It is only applicable to symmetric textures, such as snow flakes. + +Speed is a float in no real units. + +Example: + + +Forced bloom objects +-------------------- + +Any object may be marked as forced bloom. This will include the object in the bloom pass +regardless of its brightness. + +Example: forcedbloom="Y" inside the tag, in scene.xml. + +Forced bloom objects may optionally include a multiplier, ranging from 0.5 to 10: +bloompower="2.5" + + +Glowing objects +--------------- + +Any object may be marked as glowing. The glow is a RGB value. + +Example: glow="0 255 0" inside the tag, in scene.xml. + + +Caustics +-------- + +A material effect, ie GE_CAUSTICS, to mark a texture as receiving caustics. To be used +for the ocean floor, puddle floor, etc. + +Example: graphics-effect="caustics" in materials.xml. + + +Refractions/reflections +----------------------- + +A per-object boolean flag, typically set for subsea windows or the ocean surface. + +Example: displacing="Y" in the tag in scene.xml. + + + + Per-track tags + -------------- + +These are all specified inside track.xml, among the track's author, music, etc. + +Cloud shadows +------------- + +Boolean whether to have the sun blocked by cloud shadows, moving with the wind. +Disabled by default. + +The effect is completely fake, doesn't correspond to any real or simulated clouds, but +nobody's checking, so it looks nice. + +Example: clouds="Y" inside the tag. + + +Bloom +----- + +Boolean whether to enable global bloom for this track. Enabled by default. + +Example: bloom="Y" inside the tag. + + +Bloom threshold +--------------- + +Float that specifies the minimum luminance needed for a pixel to participate in the bloom. +The default is 0.75. + +Example: bloom-threshold="0.75" + + +Lens flare +---------- + +Boolean that specifies whether a lens flare is shown when the player looks at the sun. +The strength and angle depend on the relation of the camera to the sun. Disabled by default. + +Example: lens-flare="Y" + + +Dynamic shadows +--------------- + +Boolean on whether this track should use dynamic shadows. Enabled by default. + +If disabled, the fallback fake kart shadows will be used. + +Example: shadows="N" + + +God rays +-------- + +Boolean on rendering god rays when the player looks at the sun. Disabled by default. + +Example: god-rays="Y" + + +Displacement speed +------------------ + +Float on the relative speed of any displacing objects in this level. Default 1.0. +2.0 = double speed, 0.5 = half speed, etc. + +Example: displacement-speed="1.5" + + +Caustics speed +-------------- + +Float on the relative speed of any caustics objects in this level. Default 1.0. +2.0 = double speed, 0.5 = half speed, etc. + +Example: caustics-speed="1.5" + + +Fog +--- + +The density tag was removed (it was unused anyway). +The max, height start, and height end tags were added. + +fog-max: float capping the amount of fog to apply, default 1.0. +fog-start-height: minimum height of fog, default 0.0. +fog-end-height: maximum height of fog, default 100.0. + +The fog scales smoothly according to both the height, and the distance from +camera. diff --git a/doc/pipeline_overview.txt b/doc/pipeline_overview.txt new file mode 100644 index 000000000..2a50dd298 --- /dev/null +++ b/doc/pipeline_overview.txt @@ -0,0 +1,44 @@ +New pipeline overview +===================== + +Organized by RTTs +----------------- + +To color: + - initialize the glow representations (no rendering yet) + - render the 3d skybox, if any (includes the usual skybox) + +To the MRT (color, normals, depth): + - solids + +To quarter1: + - glowmap + +To various shadow maps: + - shadows + +To tmp1: + - lights + +To color: + - lights from tmp1 are multiplicatively blended + - skybox if there is no 3d skybox + - lens flare/god rays occlusion query (no rendering) + - solid post-processing + - transparents + +To displace: + - displacing nodes, if any + +To the screen: + - the post-processing chain + - GUI + + +Organized by passes +------------------- + +Init: glow init -> 3d skybox +Main: solids -> glows -> shadows -> lights -> occlusion query -> solid PP +Transparent: transparents -> displacing -> PP +GUI: gui diff --git a/sources.cmake b/sources.cmake index eff433e36..dcc1e6c8b 100644 --- a/sources.cmake +++ b/sources.cmake @@ -25,12 +25,16 @@ src/config/player.cpp src/config/saved_grand_prix.cpp src/config/stk_config.cpp src/config/user_config.cpp +src/graphics/callbacks.cpp src/graphics/camera.cpp src/graphics/CBatchingMesh.cpp src/graphics/explosion.cpp +src/graphics/glow.cpp src/graphics/hardware_skinning.cpp src/graphics/hit_sfx.cpp src/graphics/irr_driver.cpp +src/graphics/lens_flare.cpp +src/graphics/light.cpp src/graphics/lod_node.cpp src/graphics/material.cpp src/graphics/material_manager.cpp @@ -43,11 +47,19 @@ src/graphics/per_camera_node.cpp src/graphics/post_processing.cpp src/graphics/rain.cpp src/graphics/referee.cpp +src/graphics/render.cpp +src/graphics/rtts.cpp +src/graphics/screenquad.cpp +src/graphics/shaders.cpp src/graphics/shadow.cpp +src/graphics/shadow_importance.cpp src/graphics/show_curve.cpp src/graphics/skid_marks.cpp src/graphics/slip_stream.cpp src/graphics/stars.cpp +src/graphics/sun.cpp +src/graphics/water.cpp +src/graphics/wind.cpp src/guiengine/abstract_state_manager.cpp src/guiengine/abstract_top_level_container.cpp src/guiengine/CGUISpriteBank.cpp @@ -234,6 +246,7 @@ src/tracks/track_object_presentation.cpp src/tracks/track_sector.cpp src/utils/constants.cpp src/utils/crash_reporting.cpp +src/utils/helpers.cpp src/utils/leak_check.cpp src/utils/log.cpp src/utils/profiler.cpp @@ -274,17 +287,24 @@ src/config/player.hpp src/config/saved_grand_prix.hpp src/config/stk_config.hpp src/config/user_config.hpp +src/graphics/callbacks.hpp src/graphics/camera.hpp src/graphics/CBatchingMesh.hpp src/graphics/explosion.hpp +src/graphics/glow.hpp +src/graphics/glwrap.hpp src/graphics/hardware_skinning.hpp src/graphics/hit_effect.hpp src/graphics/hit_sfx.hpp src/graphics/irr_driver.hpp +src/graphics/large_mesh_buffer.hpp +src/graphics/lens_flare.hpp +src/graphics/light.hpp src/graphics/lod_node.hpp src/graphics/material.hpp src/graphics/material_manager.hpp src/graphics/mesh_tools.hpp +src/graphics/mlaa_areamap.hpp src/graphics/moving_texture.hpp src/graphics/particle_emitter.hpp src/graphics/particle_kind.hpp @@ -293,11 +313,18 @@ src/graphics/per_camera_node.hpp src/graphics/post_processing.hpp src/graphics/rain.hpp src/graphics/referee.hpp +src/graphics/rtts.hpp +src/graphics/screenquad.hpp +src/graphics/shaders.hpp src/graphics/shadow.hpp +src/graphics/shadow_importance.hpp src/graphics/show_curve.hpp src/graphics/skid_marks.hpp src/graphics/slip_stream.hpp src/graphics/stars.hpp +src/graphics/sun.hpp +src/graphics/water.hpp +src/graphics/wind.hpp src/guiengine/abstract_state_manager.hpp src/guiengine/abstract_top_level_container.hpp src/guiengine/engine.hpp @@ -499,6 +526,7 @@ src/tracks/track_object_presentation.hpp src/tracks/track_sector.hpp src/utils/aligned_array.hpp src/utils/constants.hpp +src/utils/helpers.hpp src/utils/interpolation_array.hpp src/utils/crash_reporting.hpp src/utils/leak_check.hpp @@ -512,4 +540,5 @@ src/utils/synchronised.hpp src/utils/time.hpp src/utils/translation.hpp src/utils/vec3.hpp +src/utils/vs.hpp ) diff --git a/src/Makefile.am b/src/Makefile.am index 16177fb07..40d714555 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -69,10 +69,14 @@ supertuxkart_SOURCES = \ config/device_config.hpp \ graphics/CBatchingMesh.cpp \ graphics/CBatchingMesh.hpp \ + graphics/callbacks.cpp \ + graphics/callbacks.hpp \ graphics/camera.cpp \ graphics/camera.hpp \ graphics/explosion.cpp \ graphics/explosion.hpp \ + graphics/glow.cpp \ + graphics/glow.hpp \ graphics/hardware_skinning.cpp \ graphics/hardware_skinning.hpp \ graphics/hit_effect.hpp \ @@ -80,6 +84,11 @@ supertuxkart_SOURCES = \ graphics/hit_sfx.hpp \ graphics/irr_driver.cpp \ graphics/irr_driver.hpp \ + graphics/large_mesh_buffer.hpp \ + graphics/lens_flare.cpp \ + graphics/lens_flare.hpp \ + graphics/light.hpp \ + graphics/light.cpp \ graphics/lod_node.cpp \ graphics/lod_node.hpp \ graphics/material.cpp \ @@ -102,10 +111,19 @@ supertuxkart_SOURCES = \ graphics/post_processing.hpp \ graphics/rain.cpp \ graphics/rain.hpp \ + graphics/render.cpp \ graphics/referee.cpp \ graphics/referee.hpp \ + graphics/rtts.hpp \ + graphics/rtts.cpp \ + graphics/screenquad.cpp \ + graphics/screenquad.hpp \ + graphics/shaders.cpp \ + graphics/shaders.hpp \ graphics/shadow.cpp \ graphics/shadow.hpp \ + graphics/shadow_importance.cpp \ + graphics/shadow_importance.hpp \ graphics/show_curve.cpp \ graphics/show_curve.hpp \ graphics/skid_marks.cpp \ @@ -114,6 +132,12 @@ supertuxkart_SOURCES = \ graphics/slip_stream.hpp \ graphics/stars.cpp \ graphics/stars.hpp \ + graphics/sun.hpp \ + graphics/sun.cpp \ + graphics/water.hpp \ + graphics/water.cpp \ + graphics/wind.hpp \ + graphics/wind.cpp \ guiengine/CGUISpriteBank.cpp \ guiengine/CGUISpriteBank.h \ guiengine/abstract_state_manager.cpp \ @@ -496,6 +520,8 @@ supertuxkart_SOURCES = \ utils/aligned_array.hpp \ utils/constants.hpp \ utils/constants.cpp \ + utils/helpers.hpp \ + utils/helpers.cpp \ utils/leak_check.cpp \ utils/leak_check.hpp \ utils/log.cpp \ @@ -518,7 +544,8 @@ supertuxkart_SOURCES = \ utils/utf8/core.h \ utils/utf8/unchecked.h \ utils/vec3.cpp \ - utils/vec3.hpp + utils/vec3.hpp \ + utils/vs.hpp # Link in the specific gcc 4.1 bug work around supertuxkart_LDADD = \ diff --git a/src/addons/network_http.cpp b/src/addons/network_http.cpp index d5b36d7f1..569e2e6dc 100644 --- a/src/addons/network_http.cpp +++ b/src/addons/network_http.cpp @@ -24,14 +24,7 @@ #include #include #include - -#if defined(WIN32) && !defined(__CYGWIN__) -# include -# define isnan _isnan -#else -# include -# include -#endif +#include #include "addons/news_manager.hpp" #include "addons/request.hpp" @@ -42,6 +35,7 @@ #include "utils/string_utils.hpp" #include "utils/time.hpp" #include "utils/translation.hpp" +#include "utils/vs.hpp" // ---------------------------------------------------------------------------- /** Create a thread that handles all network functions independent of the diff --git a/src/animations/animation_base.cpp b/src/animations/animation_base.cpp index 4d5fbbbc5..cd51bf3c1 100644 --- a/src/animations/animation_base.cpp +++ b/src/animations/animation_base.cpp @@ -21,14 +21,10 @@ #include "animations/ipo.hpp" #include "io/file_manager.hpp" #include "io/xml_node.hpp" +#include "utils/vs.hpp" #include - -#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) -# define isnan _isnan -#else -# include -#endif +#include AnimationBase::AnimationBase(const XMLNode &node) diff --git a/src/animations/ipo.cpp b/src/animations/ipo.cpp index 3094329ce..d5c4db071 100644 --- a/src/animations/ipo.cpp +++ b/src/animations/ipo.cpp @@ -19,15 +19,11 @@ #include "animations/ipo.hpp" #include "io/xml_node.hpp" +#include "utils/vs.hpp" #include #include - -#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) -# define isnan _isnan -#else -# include -#endif +#include const std::string Ipo::m_all_channel_names[IPO_MAX] = {"LocX", "LocY", "LocZ", "LocXYZ", diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index c60e0daf5..d65cab865 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -181,6 +181,13 @@ void STKConfig::init_defaults() m_disable_steer_while_unskid = false; m_camera_follow_skid = false; + m_nitro_glow_color[0] = 1.0f; + m_nitro_glow_color[1] = 1.0f; + m_nitro_glow_color[2] = 1.0f; + m_box_glow_color[0] = 1.0f; + m_box_glow_color[1] = 1.0f; + m_box_glow_color[2] = 1.0f; + m_score_increase.clear(); m_leader_intervals.clear(); m_switch_items.clear(); @@ -362,6 +369,25 @@ void STKConfig::getAllData(const XMLNode * root) replay_node->get("delta-pos", &m_replay_delta_pos2 ); replay_node->get("delta-t", &m_replay_dt ); } + + if(const XMLNode *colors = root->getNode("glow-colors")) + { + video::SColor tmpcol; + if (colors->get("nitro", &tmpcol)) + { + m_nitro_glow_color[0] = tmpcol.getRed() / 255.0f; + m_nitro_glow_color[1] = tmpcol.getGreen() / 255.0f; + m_nitro_glow_color[2] = tmpcol.getBlue() / 255.0f; + } + + if (colors->get("box", &tmpcol)) + { + m_box_glow_color[0] = tmpcol.getRed() / 255.0f; + m_box_glow_color[1] = tmpcol.getGreen() / 255.0f; + m_box_glow_color[2] = tmpcol.getBlue() / 255.0f; + } + } + // Get the default KartProperties // ------------------------------ const XMLNode *node = root -> getNode("general-kart-defaults"); diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp index 2fcdbeed5..1d394f571 100644 --- a/src/config/stk_config.hpp +++ b/src/config/stk_config.hpp @@ -148,6 +148,11 @@ public: * be generated. */ float m_replay_delta_angle; + /** Colors for glows */ + float m_nitro_glow_color[3]; + + float m_box_glow_color[3]; + private: /** True if stk_config has been loaded. This is necessary if the * --stk-config command line parameter has been specified to avoid diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 3f1d1ddfe..055b1f6b8 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -510,10 +510,6 @@ namespace UserConfigParams #define FBO_DEFAULT true #endif - PARAM_PREFIX BoolUserConfigParam m_fbo - PARAM_DEFAULT( BoolUserConfigParam(FBO_DEFAULT, "fbo", - &m_graphics_quality, "Use frame buffer objects (FBOs)") ); - PARAM_PREFIX BoolUserConfigParam m_graphical_effects PARAM_DEFAULT( BoolUserConfigParam(true, "anim_gfx", &m_graphics_quality, "Scenery animations") ); @@ -552,11 +548,22 @@ namespace UserConfigParams PARAM_DEFAULT( BoolUserConfigParam(true, "pixel_shaders", &m_graphics_quality, "Whether to enable pixel shaders (splatting, normal maps, ...)") ); - PARAM_PREFIX BoolUserConfigParam m_postprocess_enabled + PARAM_PREFIX BoolUserConfigParam m_motionblur PARAM_DEFAULT( BoolUserConfigParam(false, - "postprocess_enabled", &m_graphics_quality, - "Whether post-processing (motion blur...) should " - "be enabled") ); + "motionblur_enabled", &m_graphics_quality, + "Whether motion blur should be enabled") ); + PARAM_PREFIX BoolUserConfigParam m_mlaa + PARAM_DEFAULT( BoolUserConfigParam(false, + "mlaa", &m_graphics_quality, + "Whether MLAA should be enabled") ); + PARAM_PREFIX IntUserConfigParam m_ssao + PARAM_DEFAULT( IntUserConfigParam(0, + "ssao", &m_graphics_quality, + "Whether SSAO is enabled (0 = disabled, 1 = low, 2 = high") ); + PARAM_PREFIX IntUserConfigParam m_shadows + PARAM_DEFAULT( IntUserConfigParam(0, + "shadows", &m_graphics_quality, + "Whether shadows are enabled (0 = disabled, 1 = low, 2 = high") ); // ---- Misc PARAM_PREFIX BoolUserConfigParam m_cache_overworld diff --git a/src/graphics/callbacks.cpp b/src/graphics/callbacks.cpp new file mode 100644 index 000000000..cab38eb3c --- /dev/null +++ b/src/graphics/callbacks.cpp @@ -0,0 +1,775 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/callbacks.hpp" +#include "graphics/irr_driver.hpp" +#include "graphics/wind.hpp" +#include "guiengine/engine.hpp" +#include "modes/world.hpp" +#include "tracks/track.hpp" +#include "utils/helpers.hpp" + +using namespace video; +using namespace core; + +//------------------------------------- + +void NormalMapProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + if (!firstdone) + { + s32 decaltex = 0; + srv->setPixelShaderConstant("DecalTex", &decaltex, 1); + + s32 bumptex = 1; + srv->setPixelShaderConstant("BumpTex", &bumptex, 1); + + s32 lightmapTex = (m_with_lightmap ? 2 : 0); + srv->setPixelShaderConstant("LightMapTex", &lightmapTex, 1); + + s32 hasLightMap = (m_with_lightmap ? 1 : 0); + srv->setPixelShaderConstant("HasLightMap", &hasLightMap, 1); + + // We could calculate light direction as coming from the sun (then we'd need to + // transform it into camera space). But I find that pretending light + // comes from the camera gives good results + const float lightdir[] = {0.1852f, -0.1852f, -0.9259f}; + srv->setVertexShaderConstant("lightdir", lightdir, 3); + + + firstdone = true; + } +} + +//------------------------------------- + +void WaterShaderProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + + float strength = time; + strength = 1.4f - fabsf(noise2d(strength / 30.0f + 133)) * 0.8f; + + m_dx_1 += GUIEngine::getLatestDt() * m_water_shader_speed_1 * strength; + m_dy_1 += GUIEngine::getLatestDt() * m_water_shader_speed_1 * strength; + + m_dx_2 += GUIEngine::getLatestDt() * m_water_shader_speed_2 * strength; + m_dy_2 -= GUIEngine::getLatestDt() * m_water_shader_speed_2 * strength; + + if (m_dx_1 > 1.0f) m_dx_1 -= 1.0f; + if (m_dy_1 > 1.0f) m_dy_1 -= 1.0f; + if (m_dx_2 > 1.0f) m_dx_2 -= 1.0f; + if (m_dy_2 < 0.0f) m_dy_2 += 1.0f; + + const float d1[2] = { m_dx_1, m_dy_1 }; + const float d2[2] = { m_dx_2, m_dy_2 }; + + srv->setVertexShaderConstant("delta1", d1, 2); + srv->setVertexShaderConstant("delta2", d2, 2); + + const float speed = irr_driver->getDevice()->getTimer()->getTime() / m_speed; + const float height = m_height * strength; + + srv->setVertexShaderConstant("height", &height, 1); + srv->setVertexShaderConstant("speed", &speed, 1); + srv->setVertexShaderConstant("length", &m_length, 1); + + // Can't use the firstdone optimization, as the callback is shared + //if (!firstdone) + { + s32 decaltex = 0; + srv->setPixelShaderConstant("DecalTex", &decaltex, 1); + + s32 bumptex = 1; + srv->setPixelShaderConstant("BumpTex1", &bumptex, 1); + + bumptex = 2; + srv->setPixelShaderConstant("BumpTex2", &bumptex, 1); + + // Calculate light direction as coming from the sun. + matrix4 normalm = srv->getVideoDriver()->getTransform(ETS_VIEW); + normalm.makeInverse(); + normalm = normalm.getTransposed(); + vector3df tmp = m_sunpos; + normalm.transformVect(tmp); + tmp.normalize(); + + const float lightdir[] = {tmp.X, tmp.Y, tmp.Z}; + srv->setVertexShaderConstant("lightdir", lightdir, 3); + + firstdone = true; + } +} + +//------------------------------------- + +void GrassShaderProvider::OnSetConstants(IMaterialRendererServices *srv, int userData) +{ + IVideoDriver * const drv = srv->getVideoDriver(); + const core::vector3df pos = drv->getTransform(ETS_WORLD).getTranslation(); + const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + + float strength = (pos.X + pos.Y + pos.Z) * 1.2f + time * m_speed; + strength = noise2d(strength / 10.0f) * m_amplitude * 5; + // * 5 is to work with the existing amplitude values. + + // Pre-multiply on the cpu + vector3df wind = irr_driver->getWind() * strength; + + srv->setVertexShaderConstant("windDir", &wind.X, 3); + + if (!firstdone) + { + s32 tex = 0; + srv->setVertexShaderConstant("tex", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void SplattingProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const float camfar = irr_driver->getSceneManager()->getActiveCamera()->getFarValue(); + srv->setVertexShaderConstant("far", &camfar, 1); + + // The normal is transformed by the inverse transposed world matrix + // because we want world-space normals + matrix4 invtworldm = irr_driver->getVideoDriver()->getTransform(ETS_WORLD); + invtworldm.makeInverse(); + invtworldm = invtworldm.getTransposed(); + + srv->setVertexShaderConstant("invtworldm", invtworldm.pointer(), 16); + + float objectid = 0; + const stringc name = mat.TextureLayer[0].Texture->getName().getPath(); + objectid = shash8((const u8 *) name.c_str(), name.size()) / 255.0f; + srv->setVertexShaderConstant("objectid", &objectid, 1); + + if (!firstdone) + { + s32 tex_layout = 1; + srv->setPixelShaderConstant("tex_layout", &tex_layout, 1); + + s32 tex_detail0 = 2; + srv->setPixelShaderConstant("tex_detail0", &tex_detail0, 1); + + s32 tex_detail1 = 3; + srv->setPixelShaderConstant("tex_detail1", &tex_detail1, 1); + + s32 tex_detail2 = 4; + srv->setPixelShaderConstant("tex_detail2", &tex_detail2, 1); + + s32 tex_detail3 = 5; + srv->setPixelShaderConstant("tex_detail3", &tex_detail3, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void BubbleEffectProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const float start = fabsf(mat.MaterialTypeParam2); + const bool visible = mat.MaterialTypeParam2 > 0; + const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + float transparency; + + const float diff = (time - start) / 3.0f; + + if (visible) + { + transparency = diff; + } + else + { + transparency = 1.0 - diff; + } + + transparency = clampf(transparency, 0, 1); + + srv->setVertexShaderConstant("time", &time, 1); + srv->setVertexShaderConstant("transparency", &transparency, 1); +} + +//------------------------------------- + +void RainEffectProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const float screenw = UserConfigParams::m_width; + const float time = irr_driver->getDevice()->getTimer()->getTime() / 90.0f; + const matrix4 viewm = srv->getVideoDriver()->getTransform(ETS_VIEW); + const vector3df campos = irr_driver->getSceneManager()->getActiveCamera()->getPosition(); + + srv->setVertexShaderConstant("screenw", &screenw, 1); + srv->setVertexShaderConstant("time", &time, 1); + srv->setVertexShaderConstant("viewm", viewm.pointer(), 16); + srv->setVertexShaderConstant("campos", &campos.X, 3); +} + +//------------------------------------- + +void SnowEffectProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + + srv->setVertexShaderConstant("time", &time, 1); +} + +//------------------------------------- + +void MotionBlurProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + // We need the maximum texture coordinates: + float max_tex_height = m_maxheight[m_current_camera]; + srv->setPixelShaderConstant("max_tex_height", &max_tex_height, 1); + + // Scale the boost time to get a usable boost amount: + float boost_amount = m_boost_time[m_current_camera] * 0.7f; + + // Especially for single screen the top of the screen is less blurred + // in the fragment shader by multiplying the blurr factor by + // (max_tex_height - texcoords.t), where max_tex_height is the maximum + // texture coordinate (1.0 or 0.5). In split screen this factor is too + // small (half the value compared with non-split screen), so we + // multiply this by 2. + if(Camera::getNumCameras() > 1) + boost_amount *= 2.0f; + + srv->setPixelShaderConstant("boost_amount", &boost_amount, 1); + srv->setPixelShaderConstant("center", + &(m_center[m_current_camera].X), 2); + srv->setPixelShaderConstant("direction", + &(m_direction[m_current_camera].X), 2); + + // Use a radius of 0.15 when showing a single kart, otherwise (2-4 karts + // on splitscreen) use only 0.75. + float radius = Camera::getNumCameras()==1 ? 0.15f : 0.075f; + srv->setPixelShaderConstant("mask_radius", &radius, 1); + + const int texunit = 0; + srv->setPixelShaderConstant("color_buffer", &texunit, 1); +} + +//------------------------------------- + +void GaussianBlurProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + srv->setVertexShaderConstant("pixel", m_pixel, 2); +} + +//------------------------------------- + +void MipVizProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const ITexture * const tex = mat.TextureLayer[0].Texture; + + const int notex = (mat.TextureLayer[0].Texture == NULL); + srv->setVertexShaderConstant("notex", ¬ex, 1); + if (!tex) return; + + const dimension2du size = tex->getSize(); + + const float texsize[2] = { + size.Width, + size.Height + }; + + srv->setVertexShaderConstant("texsize", texsize, 2); +} + +//------------------------------------- + +void ColorizeProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + srv->setVertexShaderConstant("col", m_color, 3); +} + +//------------------------------------- + +void GlowProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + srv->setVertexShaderConstant("res", m_res, 2); +} + +//------------------------------------- + +void ObjectPassProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const float camfar = irr_driver->getSceneManager()->getActiveCamera()->getFarValue(); + srv->setVertexShaderConstant("far", &camfar, 1); + + // The normal is transformed by the inverse transposed world matrix + // because we want world-space normals + matrix4 invtworldm = irr_driver->getVideoDriver()->getTransform(ETS_WORLD); + invtworldm.makeInverse(); + invtworldm = invtworldm.getTransposed(); + + srv->setVertexShaderConstant("invtworldm", invtworldm.pointer(), 16); + + const int hastex = mat.TextureLayer[0].Texture != NULL; + srv->setVertexShaderConstant("hastex", &hastex, 1); + + const int haslightmap = mat.TextureLayer[1].Texture != NULL; + srv->setVertexShaderConstant("haslightmap", &haslightmap, 1); + + float objectid = 0; + if (hastex) + { + const stringc name = mat.TextureLayer[0].Texture->getName().getPath(); + objectid = shash8((const u8 *) name.c_str(), name.size()) / 255.0f; + } + srv->setVertexShaderConstant("objectid", &objectid, 1); + + //if (!firstdone) + // Can't use the firstdone optimization, as this callback is used for multiple shaders + { + int tex = 0; + srv->setVertexShaderConstant("tex", &tex, 1); + + tex = 1; + srv->setVertexShaderConstant("lighttex", &tex, 1); + } +} + +//------------------------------------- + +void LightBlendProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const SColorf s = irr_driver->getSceneManager()->getAmbientLight(); + + float ambient[3] = { s.r, s.g, s.b }; + srv->setVertexShaderConstant("ambient", ambient, 3); + + int spectex = 1; + srv->setVertexShaderConstant("spectex", &spectex, 1); +} + +//------------------------------------- + +void PointLightProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + srv->setVertexShaderConstant("screen", m_screen, 2); + srv->setVertexShaderConstant("spec", &m_specular, 1); + srv->setVertexShaderConstant("col", m_color, 3); + srv->setVertexShaderConstant("campos", m_campos, 3); + srv->setVertexShaderConstant("center", m_pos, 3); + srv->setVertexShaderConstant("r", &m_radius, 1); + srv->setVertexShaderConstant("invprojview", m_invprojview.pointer(), 16); + + if (!firstdone) + { + int tex = 0; + srv->setVertexShaderConstant("ntex", &tex, 1); + + tex = 1; + srv->setVertexShaderConstant("dtex", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void SunLightProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const int hasclouds = World::getWorld()->getTrack()->hasClouds() && + UserConfigParams::m_weather_effects; + + srv->setVertexShaderConstant("screen", m_screen, 2); + srv->setVertexShaderConstant("col", m_color, 3); + srv->setVertexShaderConstant("center", m_pos, 3); + srv->setVertexShaderConstant("invprojview", m_invprojview.pointer(), 16); + srv->setVertexShaderConstant("hasclouds", &hasclouds, 1); + + const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + + float strength = time; + strength = fabsf(noise2d(strength / 10.0f)) * 0.003f; + + const vector3df winddir = irr_driver->getWind() * strength; + m_wind[0] += winddir.X; + m_wind[1] += winddir.Z; + srv->setVertexShaderConstant("wind", m_wind, 2); + + if (UserConfigParams::m_shadows) + { + srv->setVertexShaderConstant("shadowmat", m_shadowmat.pointer(), 16); + } + + // Can't use the firstdone optimization, as this callback is used for multiple shaders + //if (!firstdone) + { + int tex = 0; + srv->setVertexShaderConstant("ntex", &tex, 1); + + tex = 1; + srv->setVertexShaderConstant("dtex", &tex, 1); + + tex = 2; + srv->setVertexShaderConstant("cloudtex", &tex, 1); + + tex = 3; + srv->setVertexShaderConstant("shadowtex", &tex, 1); + + tex = 4; + srv->setVertexShaderConstant("warpx", &tex, 1); + + tex = 5; + srv->setVertexShaderConstant("warpy", &tex, 1); + + const float shadowoffset = 1.0f / irr_driver->getRTT(RTT_SHADOW)->getSize().Width; + srv->setVertexShaderConstant("shadowoffset", &shadowoffset, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void BloomProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + srv->setVertexShaderConstant("low", &m_threshold, 1); +} + +//------------------------------------- + +void MLAAColor1Provider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + if (!firstdone) + { + const float pixels[2] = { + 1.0f / UserConfigParams::m_width, + 1.0f / UserConfigParams::m_height + }; + + srv->setPixelShaderConstant("PIXEL_SIZE", pixels, 2); + + firstdone = true; + } +} + +//------------------------------------- + +void MLAABlend2Provider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + if (!firstdone) + { + const float pixels[2] = { + 1.0f / UserConfigParams::m_width, + 1.0f / UserConfigParams::m_height + }; + + srv->setPixelShaderConstant("PIXEL_SIZE", pixels, 2); + + + int tex = 0; + srv->setPixelShaderConstant("edgesMap", &tex, 1); + + tex = 1; + srv->setPixelShaderConstant("areaMap", &tex, 1); + + + firstdone = true; + } +} + +//------------------------------------- + +void MLAANeigh3Provider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + if (!firstdone) + { + const float pixels[2] = { + 1.0f / UserConfigParams::m_width, + 1.0f / UserConfigParams::m_height + }; + + srv->setPixelShaderConstant("PIXEL_SIZE", pixels, 2); + + + int tex = 0; + srv->setPixelShaderConstant("blendMap", &tex, 1); + + tex = 1; + srv->setPixelShaderConstant("colorMap", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void SSAOProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + if (!firstdone) + { + int tex = 0; + srv->setPixelShaderConstant("tex", &tex, 1); + + tex = 1; + srv->setPixelShaderConstant("oldtex", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void GodRayProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + srv->setPixelShaderConstant("sunpos", m_sunpos, 2); +} + +//------------------------------------- + +void ShadowPassProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const int hastex = mat.TextureLayer[0].Texture != NULL; + srv->setVertexShaderConstant("hastex", &hastex, 1); + + int viz = irr_driver->getShadowViz(); + srv->setVertexShaderConstant("viz", &viz, 1); + + int wireframe = mat.Wireframe; + srv->setVertexShaderConstant("wireframe", &wireframe, 1); + + float objectid = 0; + if (hastex) + { + const stringc name = mat.TextureLayer[0].Texture->getName().getPath(); + objectid = shash8((const u8 *) name.c_str(), name.size()) / 255.0f; + } + srv->setVertexShaderConstant("objectid", &objectid, 1); + + //if (!firstdone) + // Can't use the firstdone optimization, as this callback is used for multiple shaders + { + int tex = 0; + srv->setVertexShaderConstant("tex", &tex, 1); + + tex = 1; + srv->setVertexShaderConstant("warpx", &tex, 1); + tex = 2; + srv->setVertexShaderConstant("warpy", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void ShadowImportanceProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + srv->setVertexShaderConstant("shadowmat", m_shadowmat.pointer(), 16); + srv->setVertexShaderConstant("ipvmat", m_invprojview.pointer(), 16); + + srv->setVertexShaderConstant("campos", m_campos, 3); + + int low = UserConfigParams::m_shadows == 1; + srv->setVertexShaderConstant("low", &low, 1); + + if (!firstdone) + { + int tex = 0; + srv->setVertexShaderConstant("ntex", &tex, 1); + + tex = 1; + srv->setVertexShaderConstant("dtex", &tex, 1); + + tex = 2; + srv->setVertexShaderConstant("ctex", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void CollapseProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + srv->setVertexShaderConstant("pixel", m_pixel, 2); + srv->setVertexShaderConstant("multi", m_multi, 2); + srv->setVertexShaderConstant("size", &m_size, 1); + + //if (!firstdone) + // Can't use the firstdone optimization, as this callback is used for multiple shaders + { + int tex = 0; + srv->setVertexShaderConstant("tex", &tex, 1); + + tex = 1; + srv->setVertexShaderConstant("oldtex", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void BloomPowerProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + srv->setVertexShaderConstant("power", &m_power, 1); +} + +//------------------------------------- + +void MultiplyProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + if (!firstdone) + { + int tex = 0; + srv->setVertexShaderConstant("tex1", &tex, 1); + + tex = 1; + srv->setVertexShaderConstant("tex2", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void ShadowGenProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + if (!firstdone) + { + int tex = 0; + srv->setVertexShaderConstant("halft", &tex, 1); + + tex = 1; + srv->setVertexShaderConstant("quarter", &tex, 1); + + tex = 2; + srv->setVertexShaderConstant("eighth", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void CausticsProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + const float speed = World::getWorld()->getTrack()->getCausticsSpeed(); + + float strength = time; + strength = fabsf(noise2d(strength / 10.0f)) * 0.006f + 0.001f; + + vector3df wind = irr_driver->getWind() * strength * speed; + m_dir[0] += wind.X; + m_dir[1] += wind.Z; + + strength = time * 0.56f + sinf(time); + strength = fabsf(noise2d(0.0, strength / 6.0f)) * 0.0095f + 0.001f; + + wind = irr_driver->getWind() * strength * speed; + wind.rotateXZBy(cosf(time)); + m_dir2[0] += wind.X; + m_dir2[1] += wind.Z; + + srv->setVertexShaderConstant("dir", m_dir, 2); + srv->setVertexShaderConstant("dir2", m_dir2, 2); + + if (!firstdone) + { + int tex = 0; + srv->setVertexShaderConstant("tex", &tex, 1); + + tex = 1; + srv->setVertexShaderConstant("caustictex", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void DisplaceProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + const float speed = World::getWorld()->getTrack()->getDisplacementSpeed(); + + float strength = time; + strength = fabsf(noise2d(strength / 10.0f)) * 0.006f + 0.002f; + + vector3df wind = irr_driver->getWind() * strength * speed; + m_dir[0] += wind.X; + m_dir[1] += wind.Z; + + strength = time * 0.56f + sinf(time); + strength = fabsf(noise2d(0.0, strength / 6.0f)) * 0.0095f + 0.0025f; + + wind = irr_driver->getWind() * strength * speed; + wind.rotateXZBy(cosf(time)); + m_dir2[0] += wind.X; + m_dir2[1] += wind.Z; + + srv->setVertexShaderConstant("dir", m_dir, 2); + srv->setVertexShaderConstant("dir2", m_dir2, 2); + + srv->setVertexShaderConstant("screen", m_screen, 2); +} + +//------------------------------------- + +void PPDisplaceProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + int viz = irr_driver->getDistortViz(); + srv->setPixelShaderConstant("viz", &viz, 1); + + if (!firstdone) + { + int tex = 0; + srv->setPixelShaderConstant("tex", &tex, 1); + + tex = 1; + srv->setPixelShaderConstant("dtex", &tex, 1); + + firstdone = true; + } +} + +//------------------------------------- + +void FogProvider::OnSetConstants(IMaterialRendererServices *srv, int) +{ + const Track * const track = World::getWorld()->getTrack(); + + // This function is only called once per frame - thus no need for setters. + const float fogmax = track->getFogMax(); + const float startH = track->getFogStartHeight(); + const float endH = track->getFogEndHeight(); + const float start = track->getFogStart(); + const float end = track->getFogEnd(); + const SColor tmpcol = track->getFogColor(); + + const float col[3] = { tmpcol.getRed() / 255.0f, + tmpcol.getGreen() / 255.0f, + tmpcol.getBlue() / 255.0f }; + + srv->setPixelShaderConstant("fogmax", &fogmax, 1); + srv->setPixelShaderConstant("startH", &startH, 1); + srv->setPixelShaderConstant("endH", &endH, 1); + srv->setPixelShaderConstant("start", &start, 1); + srv->setPixelShaderConstant("end", &end, 1); + srv->setPixelShaderConstant("col", col, 3); + srv->setVertexShaderConstant("ipvmat", m_invprojview.pointer(), 16); + srv->setVertexShaderConstant("campos", m_campos, 3); +} diff --git a/src/graphics/callbacks.hpp b/src/graphics/callbacks.hpp new file mode 100644 index 000000000..6bdee62f2 --- /dev/null +++ b/src/graphics/callbacks.hpp @@ -0,0 +1,712 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_CALLBACKS_HPP +#define HEADER_CALLBACKS_HPP + +#include "config/user_config.hpp" +#include "graphics/irr_driver.hpp" + +#include +#include +#include +#include +#include +#include +#include + +using namespace irr; + +class CallBase: public video::IShaderConstantSetCallBack +{ +public: + CallBase() + { + firstdone = 0; + } + + virtual void OnSetMaterial(const video::SMaterial &material) + { + mat = material; + } + +protected: + bool firstdone; + video::SMaterial mat; +}; + +// + +class NormalMapProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + NormalMapProvider(bool withLightmap) + { + m_with_lightmap = withLightmap; + } + +private: + bool m_with_lightmap; +}; + +// + +class WaterShaderProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void setSpeed(const float s1, const float s2) + { + m_water_shader_speed_1 = s1; + m_water_shader_speed_2 = s2; + } + + WaterShaderProvider() + { + m_dx_1 = 0.0f; + m_dx_2 = 0.0f; + m_dy_1 = 0.0f; + m_dy_2 = 0.0f; + + m_water_shader_speed_1 = + m_water_shader_speed_2 = 0.0f; + } + + void setSunPosition(const core::vector3df &in) + { + m_sunpos = in; + m_sunpos.normalize(); + } + + void setSpeed(float speed) { m_speed = speed; } + void setHeight(float height) { m_height = height; } + void setLength(float length) { m_length = length; } + +private: + core::vector3df m_sunpos; + + float m_dx_1, m_dy_1, m_dx_2, m_dy_2; + float m_water_shader_speed_1; + float m_water_shader_speed_2; + + float m_speed; + float m_height; + float m_length; +}; + +// + +class GrassShaderProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + GrassShaderProvider() + { + m_amplitude = + m_speed = 0.0f; + } + + void setSpeed(float speed) + { + m_speed = speed; + } + + void setAmplitude(float amp) + { + m_amplitude = amp; + } + +private: + float m_amplitude, m_speed; +}; + +// + +class SplattingProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class BubbleEffectProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + BubbleEffectProvider() + { + } + + // We hijack the material type param 2 of bubbles. + // It's time to start the fade, negative if fade out, positive if in. + // It'd be unused otherwise. + + void onMadeVisible(scene::IMeshBuffer * const mb) + { + if (!contains(mb)) + return; + + video::SMaterial &mat = mb->getMaterial(); + mat.MaterialTypeParam2 = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + } + + void onHidden(scene::IMeshBuffer * const mb) + { + if (!contains(mb)) + return; + + video::SMaterial &mat = mb->getMaterial(); + mat.MaterialTypeParam2 = irr_driver->getDevice()->getTimer()->getTime() / -1000.0f; + } + + void isInitiallyHidden(scene::IMeshBuffer * const mb) + { + if (!contains(mb)) + return; + + video::SMaterial &mat = mb->getMaterial(); + mat.MaterialTypeParam2 = irr_driver->getDevice()->getTimer()->getTime() / -1000.0f; + } + + void removeBubble(const scene::IMeshBuffer * const mb) + { + m_bubbles.erase(mb); + } + + void addBubble(scene::IMeshBuffer * const mb) + { + m_bubbles.insert(mb); + + video::SMaterial &mat = mb->getMaterial(); + mat.MaterialTypeParam2 = 1; + } + + bool contains(const scene::IMeshBuffer * const mb) const + { + return m_bubbles.count(mb); + } + +private: + std::set m_bubbles; +}; + +// + +class RainEffectProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class SnowEffectProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class MotionBlurProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void setMaxHeight(u32 who, float height) + { + assert(who < MAX_PLAYER_COUNT); + m_maxheight[who] = height; + } + + void setBoostTime(u32 who, float time) + { + assert(who < MAX_PLAYER_COUNT); + m_boost_time[who] = time; + } + + void setCenter(u32 who, float X, float Y) + { + assert(who < MAX_PLAYER_COUNT); + m_center[who].X = X; + m_center[who].Y = Y; + } + + void setDirection(u32 who, float X, float Y) + { + assert(who < MAX_PLAYER_COUNT); + m_direction[who].X = X; + m_direction[who].Y = Y; + } + + void setCurrentCamera(u32 who) + { + m_current_camera = who; + } + +private: + float m_maxheight[MAX_PLAYER_COUNT]; + u32 m_current_camera; + float m_boost_time[MAX_PLAYER_COUNT]; + core::vector2df m_center[MAX_PLAYER_COUNT]; + core::vector2df m_direction[MAX_PLAYER_COUNT]; +}; + +// + +class GaussianBlurProvider: public CallBase +{ +public: + GaussianBlurProvider() + { + m_pixel[0] = 1.0f / UserConfigParams::m_width; + m_pixel[1] = 1.0f / UserConfigParams::m_height; + } + + void setResolution(float x, float y) + { + m_pixel[0] = 1.0f / x; + m_pixel[1] = 1.0f / y; + } + + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + +private: + float m_pixel[2]; +}; + +// + +class MipVizProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class ColorizeProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void setColor(float r, float g, float b) + { + m_color[0] = r; + m_color[1] = g; + m_color[2] = b; + } + +private: + float m_color[3]; +}; + +// + +class GlowProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void setResolution(float x, float y) + { + m_res[0] = x; + m_res[1] = y; + } + +private: + float m_res[2]; +}; + +// + +class ObjectPassProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class LightBlendProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class PointLightProvider: public CallBase +{ +public: + PointLightProvider() + { + m_screen[0] = UserConfigParams::m_width; + m_screen[1] = UserConfigParams::m_height; + + m_specular = 200; + } + + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void setColor(float r, float g, float b) + { + m_color[0] = r; + m_color[1] = g; + m_color[2] = b; + } + + void setPosition(float x, float y, float z) + { + m_pos[0] = x; + m_pos[1] = y; + m_pos[2] = z; + } + + void setRadius(float r) + { + m_radius = r; + } + + void setSpecular(float s) + { + m_specular = s; + } + + void updateIPVMatrix() + { + // Update the campos and IPV matrix, only once per frame since it's costly + const core::vector3df &campos = + irr_driver->getSceneManager()->getActiveCamera()->getAbsolutePosition(); + m_campos[0] = campos.X; + m_campos[1] = campos.Y; + m_campos[2] = campos.Z; + + const video::IVideoDriver * const drv = irr_driver->getVideoDriver(); + + m_invprojview = drv->getTransform(video::ETS_PROJECTION); + m_invprojview *= drv->getTransform(video::ETS_VIEW); + m_invprojview.makeInverse(); + } + +private: + core::matrix4 m_invprojview; + + float m_campos[3]; + float m_color[3]; + float m_pos[3]; + float m_screen[2]; + float m_radius; + float m_specular; +}; + +// + +class SunLightProvider: public CallBase +{ +public: + SunLightProvider() + { + m_screen[0] = UserConfigParams::m_width; + m_screen[1] = UserConfigParams::m_height; + + m_wind[0] = m_wind[1] = 0; + } + + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void setColor(float r, float g, float b) + { + m_color[0] = r; + m_color[1] = g; + m_color[2] = b; + } + + void setPosition(float x, float y, float z) + { + m_pos[0] = x; + m_pos[1] = y; + m_pos[2] = z; + } + + void updateIPVMatrix() + { + // Update the IPV matrix, only once per frame since it's costly + const video::IVideoDriver * const drv = irr_driver->getVideoDriver(); + + m_invprojview = drv->getTransform(video::ETS_PROJECTION); + m_invprojview *= drv->getTransform(video::ETS_VIEW); + m_invprojview.makeInverse(); + } + + void setShadowMatrix(const core::matrix4 &mat) + { + m_shadowmat = mat; + } + +private: + core::matrix4 m_invprojview, m_shadowmat; + float m_color[3]; + float m_pos[3]; + float m_screen[2]; + float m_wind[2]; +}; + +// + +class BloomProvider: public CallBase +{ +public: + BloomProvider() { m_threshold = 0.75f; } + + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void setThreshold(const float f) { m_threshold = f; } + +private: + float m_threshold; +}; + +// + +class MLAAColor1Provider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class MLAABlend2Provider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class MLAANeigh3Provider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class SSAOProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class GodRayProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + // In texcoords + void setSunPosition(float x, float y) { m_sunpos[0] = x; m_sunpos[1] = y; } + +private: + float m_sunpos[2]; +}; + +// + +class ShadowPassProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class ShadowImportanceProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void updateIPVMatrix() + { + // Update the IPV matrix, only once per frame since it's costly + const video::IVideoDriver * const drv = irr_driver->getVideoDriver(); + + const core::vector3df &campos = + irr_driver->getSceneManager()->getActiveCamera()->getAbsolutePosition(); + m_campos[0] = campos.X; + m_campos[1] = campos.Y; + m_campos[2] = campos.Z; + + m_invprojview = drv->getTransform(video::ETS_PROJECTION); + m_invprojview *= drv->getTransform(video::ETS_VIEW); + m_invprojview.makeInverse(); + } + + void setShadowMatrix(const core::matrix4 &mat) + { + m_shadowmat = mat; + } + +private: + core::matrix4 m_invprojview, m_shadowmat; + float m_campos[3]; +}; + +// + +class CollapseProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void setResolution(const float x, const float y) + { + m_pixel[0] = 1.0f / x; + m_pixel[1] = 1.0f / y; + + m_multi[0] = m_multi[1] = 1; + + if (x < 2 || y < 2) + { + u32 i; + for (i = 0; i < 2; i++) + { + // No increase for the other direction + if (m_pixel[i] > 0.9f) m_pixel[i] = m_multi[i] = 0; + } + + std::swap(m_multi[0], m_multi[1]); + } + + m_size = std::max(x, y); + } + +private: + float m_pixel[2]; + int m_size; + float m_multi[2]; +}; + +// + +class BloomPowerProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void setPower(float power) + { + m_power = power / 10.0f; + } + +private: + float m_power; +}; + +// + +class MultiplyProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class ShadowGenProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class CausticsProvider: public CallBase +{ +public: + CausticsProvider() { m_dir[0] = m_dir[1] = m_dir2[0] = m_dir2[1] = 0; } + + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + +private: + float m_dir[2], m_dir2[2]; +}; + +// + +class DisplaceProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + DisplaceProvider() + { + m_screen[0] = UserConfigParams::m_width; + m_screen[1] = UserConfigParams::m_height; + + m_dir[0] = m_dir[1] = m_dir2[0] = m_dir2[1] = 0; + } + +private: + float m_screen[2]; + float m_dir[2], m_dir2[2]; +}; + +// + +class PPDisplaceProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); +}; + +// + +class FogProvider: public CallBase +{ +public: + virtual void OnSetConstants(video::IMaterialRendererServices *srv, int); + + void updateIPVMatrix() + { + // Update the campos and IPV matrix, only once per frame since it's costly + const core::vector3df &campos = + irr_driver->getSceneManager()->getActiveCamera()->getAbsolutePosition(); + m_campos[0] = campos.X; + m_campos[1] = campos.Y; + m_campos[2] = campos.Z; + + const video::IVideoDriver * const drv = irr_driver->getVideoDriver(); + + m_invprojview = drv->getTransform(video::ETS_PROJECTION); + m_invprojview *= drv->getTransform(video::ETS_VIEW); + m_invprojview.makeInverse(); + } + +private: + core::matrix4 m_invprojview; + float m_campos[3]; +}; + +#endif diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp index 89d9bdae7..0e9026e85 100644 --- a/src/graphics/camera.cpp +++ b/src/graphics/camera.cpp @@ -19,11 +19,7 @@ #include "graphics/camera.hpp" -#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) -# define isnan _isnan -#else -# include -#endif +#include #include "audio/music_manager.hpp" #include "config/user_config.hpp" @@ -40,6 +36,7 @@ #include "tracks/track.hpp" #include "utils/aligned_array.hpp" #include "utils/constants.hpp" +#include "utils/vs.hpp" #include "ICameraSceneNode.h" #include "ISceneManager.h" diff --git a/src/graphics/glow.cpp b/src/graphics/glow.cpp new file mode 100644 index 000000000..780c506b0 --- /dev/null +++ b/src/graphics/glow.cpp @@ -0,0 +1,85 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/glow.hpp" + +#include "graphics/callbacks.hpp" +#include "graphics/glwrap.hpp" +#include "graphics/irr_driver.hpp" +#include "graphics/material_manager.hpp" +#include "graphics/material.hpp" +#include "graphics/rtts.hpp" +#include "graphics/shaders.hpp" + +using namespace video; +using namespace scene; +using namespace core; + +IMesh * GlowNode::sphere = NULL; +SMaterial GlowNode::mat; +aabbox3df GlowNode::box; + + +GlowNode::GlowNode(scene::ISceneManager* mgr, float radius): ISceneNode(mgr->getRootSceneNode(), mgr, -1) +{ + if (!sphere) + { + mat.Lighting = false; + mat.MaterialType = irr_driver->getShader(ES_GLOW); + + mat.setTexture(0, irr_driver->getRTT(RTT_QUARTER1)); + mat.TextureLayer[0].TextureWrapU = + mat.TextureLayer[0].TextureWrapV = ETC_CLAMP_TO_EDGE; + mat.setFlag(EMF_TRILINEAR_FILTER, true); + mat.BlendOperation = EBO_ADD; + + sphere = mgr->getGeometryCreator()->createSphereMesh(1, 4, 4); + box = sphere->getBoundingBox(); + } + + setScale(vector3df(radius)); +} + +GlowNode::~GlowNode() +{ +} + +void GlowNode::render() +{ + IVideoDriver * const drv = irr_driver->getVideoDriver(); + drv->setTransform(ETS_WORLD, AbsoluteTransformation); + drv->setMaterial(mat); + + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, 0, ~0); + glEnable(GL_STENCIL_TEST); + + drv->drawMeshBuffer(sphere->getMeshBuffer(0)); + + glDisable(GL_STENCIL_TEST); +} + +void GlowNode::OnRegisterSceneNode() +{ + if (IsVisible) + { + SceneManager->registerNodeForRendering(this, ESNRP_TRANSPARENT); + } + + ISceneNode::OnRegisterSceneNode(); +} diff --git a/src/graphics/glow.hpp b/src/graphics/glow.hpp new file mode 100644 index 000000000..8d9fa12f9 --- /dev/null +++ b/src/graphics/glow.hpp @@ -0,0 +1,53 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_GLOW_HPP +#define HEADER_GLOW_HPP + +#include +#include + +using namespace irr; + +// The actual node +class GlowNode: public scene::ISceneNode +{ +public: + GlowNode(scene::ISceneManager* mgr, float radius); + ~GlowNode(); + + virtual void render(); + + virtual const core::aabbox3d& getBoundingBox() const + { + return box; + } + + virtual void OnRegisterSceneNode(); + + virtual u32 getMaterialCount() const { return 1; } + virtual video::SMaterial& getMaterial(u32 i) { return mat; } + +private: + static video::SMaterial mat; + static core::aabbox3df box; + + static scene::IMesh *sphere; +}; + +#endif diff --git a/src/graphics/glwrap.hpp b/src/graphics/glwrap.hpp new file mode 100644 index 000000000..fcac96621 --- /dev/null +++ b/src/graphics/glwrap.hpp @@ -0,0 +1,21 @@ +#ifndef GLWRAP_HEADER_H +#define GLWRAP_HEADER_H + +#if defined(__APPLE__) +# include +#elif defined(ANDROID) +# include +#elif defined(WIN32) +# define _WINSOCKAPI_ +// has to be included before gl.h because of WINGDIAPI and APIENTRY definitions +# include +# include +#else +# include +#endif + +// already includes glext.h, which defines useful GL constants. +// COpenGLDriver has already loaded the extension GL functions we use (e.g glBeginQuery) +#include "../../lib/irrlicht/source/Irrlicht/COpenGLDriver.h" + +#endif diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 3df8c8af4..22ed46a45 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -19,13 +19,23 @@ #include "graphics/irr_driver.hpp" #include "config/user_config.hpp" +#include "graphics/callbacks.hpp" #include "graphics/camera.hpp" +#include "graphics/glwrap.hpp" #include "graphics/hardware_skinning.hpp" +#include "graphics/lens_flare.hpp" +#include "graphics/light.hpp" #include "graphics/material_manager.hpp" #include "graphics/particle_kind_manager.hpp" #include "graphics/per_camera_node.hpp" #include "graphics/post_processing.hpp" #include "graphics/referee.hpp" +#include "graphics/shaders.hpp" +#include "graphics/shadow_importance.hpp" +#include "graphics/sun.hpp" +#include "graphics/rtts.hpp" +#include "graphics/water.hpp" +#include "graphics/wind.hpp" #include "guiengine/engine.hpp" #include "guiengine/modaldialog.hpp" #include "guiengine/scalable_font.hpp" @@ -47,6 +57,7 @@ #include "utils/constants.hpp" #include "utils/log.hpp" #include "utils/profiler.hpp" +#include "utils/vs.hpp" #include @@ -62,19 +73,12 @@ using namespace irr; -#ifndef round -# define round(x) (floor(x+0.5f)) -#endif - #ifdef WIN32 #include #endif #if defined(__linux__) && !defined(ANDROID) -namespace X11 -{ - #include - #include -} +#include +#include #endif /** singleton */ @@ -96,6 +100,11 @@ IrrDriver::IrrDriver() m_resolution_changing = RES_CHANGE_NONE; m_device = createDevice(video::EDT_NULL); m_request_screenshot = false; + m_shaders = NULL; + m_rtts = NULL; + m_wind = new Wind(); + m_mipviz = m_wireframe = m_normals = m_ssaoviz = \ + m_lightviz = m_shadowviz = m_distortviz = 0; } // IrrDriver // ---------------------------------------------------------------------------- @@ -117,6 +126,9 @@ IrrDriver::~IrrDriver() m_device->drop(); m_device = NULL; m_modes.clear(); + + delete m_shaders; + delete m_wind; } // ~IrrDriver // ---------------------------------------------------------------------------- @@ -124,7 +136,7 @@ IrrDriver::~IrrDriver() */ void IrrDriver::reset() { - m_post_processing->reset(); + if (m_glsl) m_post_processing->reset(); } // reset // ---------------------------------------------------------------------------- @@ -135,22 +147,22 @@ Returns the parent window of "window" (i.e. the ancestor of window that is a direct child of the root, or window itself if it is a direct child). If window is the root window, returns window. */ -X11::Window get_toplevel_parent(X11::Display* display, X11::Window window) +Window get_toplevel_parent(Display* display, Window window) { - X11::Window parent; - X11::Window root; - X11::Window * children; + Window parent; + Window root; + Window * children; unsigned int num_children; while (true) { - if (0 == X11::XQueryTree(display, window, &root, + if (0 == XQueryTree(display, window, &root, &parent, &children, &num_children)) { Log::fatal("irr_driver", "XQueryTree error\n"); } if (children) { //must test for null - X11::XFree(children); + XFree(children); } if (window == root || parent == root) { return window; @@ -201,7 +213,6 @@ void IrrDriver::updateConfigIfRelevant() Log::warn("irr_driver", "Could not retrieve window location\n"); } #elif defined(__linux__) && !defined(ANDROID) - using namespace X11; const video::SExposedVideoData& videoData = m_device->getVideoDriver()->getExposedVideoData(); Display* display = (Display*)videoData.OpenGLLinux.X11Display; @@ -384,7 +395,8 @@ void IrrDriver::initDevice() m_gui_env = m_device->getGUIEnvironment(); m_video_driver = m_device->getVideoDriver(); m_glsl = m_video_driver->queryFeature(video::EVDF_ARB_GLSL) && - m_video_driver->queryFeature(video::EVDF_TEXTURE_NPOT); + m_video_driver->queryFeature(video::EVDF_TEXTURE_NPOT) && + UserConfigParams::m_pixel_shaders; // This remaps the window, so it has to be done before the clear to avoid flicker m_device->setResizable(false); @@ -396,6 +408,44 @@ void IrrDriver::initDevice() if (m_glsl) { Log::info("irr_driver", "GLSL supported."); + + // Order matters, create RTTs as soon as possible, as they are the largest blocks. + m_rtts = new RTT(); + m_shaders = new Shaders(); + m_shadow_importance = new ShadowImportance(); + + m_mrt.clear(); + m_mrt.reallocate(3); + m_mrt.push_back(m_rtts->getRTT(RTT_COLOR)); + m_mrt.push_back(m_rtts->getRTT(RTT_NORMAL)); + m_mrt.push_back(m_rtts->getRTT(RTT_DEPTH)); + + irr::video::COpenGLDriver* gl_driver = (irr::video::COpenGLDriver*)m_device->getVideoDriver(); + gl_driver->extGlGenQueries(1, &m_lensflare_query); + + scene::IMesh * const sphere = m_scene_manager->getGeometryCreator()->createSphereMesh(1, 16, 16); + m_sun_interposer = m_scene_manager->addMeshSceneNode(sphere); + m_sun_interposer->grab(); + m_sun_interposer->setParent(NULL); + m_sun_interposer->setScale(core::vector3df(20)); + + m_sun_interposer->getMaterial(0).Lighting = false; + m_sun_interposer->getMaterial(0).ColorMask = video::ECP_NONE; + m_sun_interposer->getMaterial(0).ZWriteEnable = false; + m_sun_interposer->getMaterial(0).MaterialType = m_shaders->getShader(ES_PASSFAR); + + sphere->drop(); + + m_lensflare = new scene::CLensFlareSceneNode(NULL, m_scene_manager, -1); + video::ITexture * const tex = + m_video_driver->getTexture((file_manager->getTextureDir() + "lensflare.png").c_str()); + if (!tex) Log::fatal("irr_driver", "Cannot find lens flare texture"); + m_lensflare->setMaterialTexture(0, tex); + m_lensflare->setAutomaticCulling(scene::EAC_OFF); + + m_suncam = m_scene_manager->addCameraSceneNode(0, vector3df(0), vector3df(0), -1, false); + m_suncam->grab(); + m_suncam->setParent(NULL); } else { @@ -407,7 +457,6 @@ void IrrDriver::initDevice() { #if defined(__linux__) && !defined(ANDROID) // Set class hints on Linux, used by Window Managers. - using namespace X11; const video::SExposedVideoData& videoData = m_video_driver ->getExposedVideoData(); XClassHint* classhint = XAllocClassHint(); @@ -423,11 +472,6 @@ void IrrDriver::initDevice() ->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true); m_device->getVideoDriver() ->setTextureCreationFlag(video::ETCF_OPTIMIZED_FOR_QUALITY, true); - if (!UserConfigParams::m_fbo) - { - m_device->getVideoDriver() - ->disableFeature(video::EVDF_FRAMEBUFFER_OBJECT); - } // Force creation of mipmaps even if the mipmaps flag in a b3d file // does not set the 'enable mipmap' flag. @@ -526,7 +570,6 @@ bool IrrDriver::moveWindow(const int x, const int y) return false; } #elif defined(__linux__) && !defined(ANDROID) - using namespace X11; const video::SExposedVideoData& videoData = m_video_driver->getExposedVideoData(); // TODO: Actually handle possible failure XMoveWindow((Display*)videoData.OpenGLLinux.X11Display, @@ -771,6 +814,7 @@ void IrrDriver::setAllMaterialFlags(scene::IMesh *mesh) const * \param wave_length Lenght of a water wave. */ scene::ISceneNode* IrrDriver::addWaterNode(scene::IMesh *mesh, + scene::IMesh **welded, float wave_height, float wave_speed, float wave_length) @@ -778,11 +822,24 @@ scene::ISceneNode* IrrDriver::addWaterNode(scene::IMesh *mesh, mesh->setMaterialFlag(video::EMF_GOURAUD_SHADING, true); scene::IMesh* welded_mesh = m_scene_manager->getMeshManipulator() ->createMeshWelded(mesh); - scene::ISceneNode* out = m_scene_manager->addWaterSurfaceSceneNode(welded_mesh, + scene::ISceneNode* out = NULL; + + if (!m_glsl) + { + out = m_scene_manager->addWaterSurfaceSceneNode(welded_mesh, wave_height, wave_speed, wave_length); + } else + { + out = new WaterNode(m_scene_manager, welded_mesh, wave_height, wave_speed, + wave_length); + } + out->getMaterial(0).setFlag(video::EMF_GOURAUD_SHADING, true); welded_mesh->drop(); // The scene node keeps a reference + + *welded = welded_mesh; + return out; } // addWaterNode @@ -841,11 +898,22 @@ PerCameraNode *IrrDriver::addPerCameraMesh(scene::IMesh* mesh, scene::ICameraSceneNode* camera, scene::ISceneNode *parent) { + scene::ISceneNode *node = m_scene_manager->addMeshSceneNode(mesh); + return new PerCameraNode((parent ? parent : m_scene_manager->getRootSceneNode()), - m_scene_manager, -1, camera, mesh); + m_scene_manager, -1, camera, node); } // addMesh +PerCameraNode *IrrDriver::addPerCameraNode(scene::ISceneNode* node, + scene::ICameraSceneNode* camera, + scene::ISceneNode *parent) +{ + return new PerCameraNode((parent ? parent + : m_scene_manager->getRootSceneNode()), + m_scene_manager, -1, camera, node); +} // addNode + // ---------------------------------------------------------------------------- /** Adds a billboard node to scene. @@ -1627,6 +1695,8 @@ void IrrDriver::update(float dt) m_resolution_changing = RES_CHANGE_NONE; } + m_wind->update(); + World *world = World::getWorld(); // Handle cut scenes (which do not have any karts in it) @@ -1651,97 +1721,24 @@ void IrrDriver::update(float dt) m_video_driver->endScene(); return; } - - const bool inRace = world!=NULL; - - if (inRace) + else if (!world) { - // Start the RTT for post-processing. - // We do this before beginScene() because we want to capture the glClear() - // because of tracks that do not have skyboxes (generally add-on tracks) - m_post_processing->beginCapture(); - } - m_video_driver->beginScene(/*backBuffer clear*/ true, /*zBuffer*/ true, - world ? world->getClearColor() - : video::SColor(255,100,101,140)); + video::SColor(255,100,101,140)); - if (inRace) - { - irr_driver->getVideoDriver()->enableMaterial2D(); - - RaceGUIBase *rg = world->getRaceGUI(); - if (rg) rg->update(dt); - - - for(unsigned int i=0; iactivate(); - rg->preRenderCallback(camera); // adjusts start referee - m_scene_manager->drawAll(); - - PROFILER_POP_CPU_MARKER(); - - // Note that drawAll must be called before rendering - // the bullet debug view, since otherwise the camera - // is not set up properly. This is only used for - // the bullet debug view. - if (UserConfigParams::m_artist_debug_mode) - World::getWorld()->getPhysics()->draw(); - } // for igetNumKarts() - - // Stop capturing for the post-processing - m_post_processing->endCapture(); - - // Render the post-processed scene - m_post_processing->render(); - - // Set the viewport back to the full screen for race gui - m_video_driver->setViewPort(core::recti(0, 0, - UserConfigParams::m_width, - UserConfigParams::m_height)); - - for(unsigned int i=0; irenderPlayerView(camera, dt); - - PROFILER_POP_CPU_MARKER(); - } // for iendScene(); + return; } - -#ifdef DEBUG - drawDebugMeshes(); -#endif - - m_video_driver->endScene(); + if (m_glsl) + renderGLSL(dt); + else + renderFixed(dt); if (m_request_screenshot) doScreenShot(); - getPostProcessing()->update(dt); - // Enable this next print statement to get render information printed // E.g. number of triangles rendered, culled etc. The stats is only // printed while the race is running and not while the in-game menu @@ -1775,7 +1772,7 @@ bool IrrDriver::OnEvent(const irr::SEvent &event) // Ignore 'normal' messages if (event.LogEvent.Level > 1) { - printf("[IrrDriver Temp Logger] Level %d: %s\n", + Log::warn("[IrrDriver Temp Logger]", "Level %d: %s\n", event.LogEvent.Level,event.LogEvent.Text); } return true; @@ -1791,7 +1788,7 @@ bool IrrDriver::OnEvent(const irr::SEvent &event) bool IrrDriver::supportsSplatting() { - return UserConfigParams::m_pixel_shaders && m_glsl; + return m_glsl; } // ---------------------------------------------------------------------------- @@ -1977,6 +1974,11 @@ video::ITexture* IrrDriver::RTTProvider::renderToTexture(float angle, if (angle != -1 && m_rtt_main_node != NULL) m_rtt_main_node->setRotation( core::vector3df(0, angle, 0) ); + video::SOverrideMaterial &overridemat = m_video_driver->getOverrideMaterial(); + overridemat.EnablePasses = scene::ESNRP_SOLID; + overridemat.EnableFlags = video::EMF_MATERIAL_TYPE; + overridemat.Material.MaterialType = video::EMT_SOLID; + if (m_rtt_main_node == NULL) { irr_driver->getSceneManager()->drawAll(); @@ -1990,6 +1992,129 @@ video::ITexture* IrrDriver::RTTProvider::renderToTexture(float angle, m_light->setVisible(false); } + overridemat.EnablePasses = 0; + m_video_driver->setRenderTarget(0, false, false); return m_render_target_texture; } + +void IrrDriver::applyObjectPassShader(scene::ISceneNode * const node, bool rimlit) +{ + if (!m_glsl) + return; + + // Don't override sky + if (node->getType() == scene::ESNT_SKY_DOME || + node->getType() == scene::ESNT_SKY_BOX) + return; + + const u32 mcount = node->getMaterialCount(); + u32 i; + const video::E_MATERIAL_TYPE ref = rimlit ? m_shaders->getShader(ES_OBJECTPASS_RIMLIT): + m_shaders->getShader(ES_OBJECTPASS_REF); + const video::E_MATERIAL_TYPE pass = rimlit ? m_shaders->getShader(ES_OBJECTPASS_RIMLIT): + m_shaders->getShader(ES_OBJECTPASS); + + const video::E_MATERIAL_TYPE origref = m_shaders->getShader(ES_OBJECTPASS_REF); + const video::E_MATERIAL_TYPE origpass = m_shaders->getShader(ES_OBJECTPASS); + + bool viamb = false; + scene::IMesh *mesh = NULL; + if (node->getType() == scene::ESNT_ANIMATED_MESH) + { + viamb = ((scene::IAnimatedMeshSceneNode *) node)->isReadOnlyMaterials(); + mesh = ((scene::IAnimatedMeshSceneNode *) node)->getMesh(); + } + else if (node->getType() == scene::ESNT_MESH) + { + viamb = ((scene::IMeshSceneNode *) node)->isReadOnlyMaterials(); + mesh = ((scene::IMeshSceneNode *) node)->getMesh(); + } + + for (i = 0; i < mcount; i++) + { + video::SMaterial &nodemat = node->getMaterial(i); + video::SMaterial &mbmat = mesh ? mesh->getMeshBuffer(i)->getMaterial() : nodemat; + video::SMaterial *mat = &nodemat; + + if (viamb) + mat = &mbmat; + + if (mat->MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF || + mat->MaterialType == origref) + mat->MaterialType = ref; + else if (mat->MaterialType == video::EMT_SOLID || + mat->MaterialType == origpass || + (mat->MaterialType >= video::EMT_LIGHTMAP && + mat->MaterialType <= video::EMT_LIGHTMAP_LIGHTING_M4)) + mat->MaterialType = pass; + } + + + core::list kids = node->getChildren(); + scene::ISceneNodeList::Iterator it = kids.begin(); + for (; it != kids.end(); ++it) + { + applyObjectPassShader(*it, rimlit); + } +} + +void IrrDriver::applyObjectPassShader() +{ + if (!m_glsl) + return; + + applyObjectPassShader(m_scene_manager->getRootSceneNode()); +} + +scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos, float radius, + float r, float g, float b, bool sun) +{ + if (m_glsl) + { + LightNode *light = NULL; + + if (!sun) + light = new LightNode(m_scene_manager, radius, r, g, b); + else + light = new SunNode(m_scene_manager, r, g, b); + + light->grab(); + light->setParent(NULL); + + light->setPosition(pos); + light->updateAbsolutePosition(); + + m_lights.push_back(light); + + if (sun) { + m_sun_interposer->setPosition(pos); + m_sun_interposer->updateAbsolutePosition(); + + m_lensflare->setPosition(pos); + m_lensflare->updateAbsolutePosition(); + + m_suncam->setPosition(pos); + m_suncam->updateAbsolutePosition(); + + ((WaterShaderProvider *) m_shaders->m_callbacks[ES_WATER])->setSunPosition(pos); + } + + return light; + } else + { + return m_scene_manager->addLightSceneNode(NULL, pos, video::SColorf(r, g, b), radius); + } +} + +void IrrDriver::clearLights() +{ + u32 i; + const u32 max = m_lights.size(); + for (i = 0; i < max; i++) + { + m_lights[i]->drop(); + } + + m_lights.clear(); +} diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index c5497f8d4..fdcf4d9f6 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -39,11 +39,15 @@ namespace irr { namespace scene { class ISceneManager; class IMesh; class IAnimatedMeshSceneNode; class IAnimatedMesh; - class IMeshSceneNode; class IParticleSystemSceneNode; class ICameraSceneNode; class ILightSceneNode; } + class IMeshSceneNode; class IParticleSystemSceneNode; class ICameraSceneNode; class ILightSceneNode; + class CLensFlareSceneNode; } namespace gui { class IGUIEnvironment; class IGUIFont; } } using namespace irr; +#include "graphics/rtts.hpp" +#include "graphics/shaders.hpp" +#include "graphics/wind.hpp" #include "utils/aligned_array.hpp" #include "utils/no_copy.hpp" #include "utils/ptr_vector.hpp" @@ -53,6 +57,8 @@ class AbstractKart; class Camera; class PerCameraNode; class PostProcessing; +class LightNode; +class ShadowImportance; /** * \brief class that creates the irrLicht device and offers higher-level @@ -74,11 +80,22 @@ private: gui::IGUIFont *m_race_font; /** Post-processing. */ PostProcessing *m_post_processing; + /** Shaders. */ + Shaders *m_shaders; + /** Wind. */ + Wind *m_wind; + /** RTTs. */ + RTT *m_rtts; + /** Shadow importance. */ + ShadowImportance *m_shadow_importance; /** Additional details to be shown in case that a texture is not found. * This is used to specify details like: "while loading kart '...'" */ std::string m_texture_error_message; + /** The main MRT setup. */ + core::array m_mrt; + /** Flag to indicate if a resolution change is pending (which will be * acted upon in the next update). None means no change, yes means * change to new resolution and trigger confirmation dialog. @@ -99,6 +116,12 @@ public: int getWidth() const {return m_width; } int getHeight() const {return m_height; } }; // VideoMode + + struct BloomData { + scene::ISceneNode * node; + float power; + }; + private: std::vector m_modes; @@ -116,6 +139,34 @@ private: bool m_request_screenshot; + bool m_wireframe; + bool m_mipviz; + bool m_normals; + bool m_ssaoviz; + bool m_shadowviz; + bool m_lightviz; + bool m_distortviz; + u32 m_renderpass; + u32 m_lensflare_query; + scene::IMeshSceneNode *m_sun_interposer; + scene::CLensFlareSceneNode *m_lensflare; + scene::ICameraSceneNode *m_suncam; + + struct GlowData { + scene::ISceneNode * node; + float r, g, b; + }; + + std::vector m_glowing; + + std::vector m_lights; + + std::vector m_forcedbloom; + + std::vector m_displacing; + + std::vector m_background; + #ifdef DEBUG /** Used to visualise skeletons. */ std::vector m_debug_meshes; @@ -126,6 +177,9 @@ private: irr::scene::ISkinnedMesh* mesh, int id); #endif + void renderFixed(float dt); + void renderGLSL(float dt); + void doScreenShot(); public: IrrDriver(); @@ -151,7 +205,8 @@ public: bool create_one_quad=false); scene::IMesh *createTexturedQuadMesh(const video::SMaterial *material, const double w, const double h); - scene::ISceneNode *addWaterNode(scene::IMesh *mesh, float wave_height, + scene::ISceneNode *addWaterNode(scene::IMesh *mesh, scene::IMesh **welded, + float wave_height, float wave_speed, float wave_length); scene::IMeshSceneNode*addOctTree(scene::IMesh *mesh); scene::IMeshSceneNode*addSphere(float radius, @@ -161,6 +216,9 @@ public: PerCameraNode *addPerCameraMesh(scene::IMesh* mesh, scene::ICameraSceneNode* node, scene::ISceneNode *parent = NULL); + PerCameraNode *addPerCameraNode(scene::ISceneNode* node, + scene::ICameraSceneNode* cam, + scene::ISceneNode *parent = NULL); scene::ISceneNode *addBillboard(const core::dimension2d< f32 > size, video::ITexture *texture, scene::ISceneNode* parent=NULL, bool alphaTesting = false); @@ -286,9 +344,86 @@ public: /** Returns a pointer to the post processing object. */ inline PostProcessing* getPostProcessing() {return m_post_processing;} // ------------------------------------------------------------------------ - + inline core::vector3df getWind() {return m_wind->getWind();} + // ------------------------------------------------------------------------ + inline video::E_MATERIAL_TYPE getShader(const ShaderType num) {return m_shaders->getShader(num);} + // ------------------------------------------------------------------------ + inline video::IShaderConstantSetCallBack* getCallback(const ShaderType num) {return m_shaders->m_callbacks[num];} + // ------------------------------------------------------------------------ + inline video::ITexture* getRTT(TypeRTT which) {return m_rtts->getRTT(which);} + // ------------------------------------------------------------------------ inline bool isGLSL() const { return m_glsl; } // ------------------------------------------------------------------------ + void toggleWireframe() { m_wireframe ^= 1; } + // ------------------------------------------------------------------------ + void toggleMipVisualization() { m_mipviz ^= 1; } + // ------------------------------------------------------------------------ + void toggleNormals() { m_normals ^= 1; } + // ------------------------------------------------------------------------ + bool getNormals() { return m_normals; } + // ------------------------------------------------------------------------ + void toggleSSAOViz() { m_ssaoviz ^= 1; } + // ------------------------------------------------------------------------ + void toggleLightViz() { m_lightviz ^= 1; } + // ------------------------------------------------------------------------ + bool getSSAOViz() { return m_ssaoviz; } + // ------------------------------------------------------------------------ + void toggleShadowViz() { m_shadowviz ^= 1; } + // ------------------------------------------------------------------------ + bool getShadowViz() { return m_shadowviz; } + // ------------------------------------------------------------------------ + void toggleDistortViz() { m_distortviz ^= 1; } + // ------------------------------------------------------------------------ + bool getDistortViz() { return m_distortviz; } + // ------------------------------------------------------------------------ + u32 getRenderPass() { return m_renderpass; } + // ------------------------------------------------------------------------ + void addGlowingNode(scene::ISceneNode *n, float r = 1.0f, float g = 1.0f, float b = 1.0f) + { + GlowData dat; + dat.node = n; + dat.r = r; + dat.g = g; + dat.b = b; + + m_glowing.push_back(dat); + } + // ------------------------------------------------------------------------ + void clearGlowingNodes() { m_glowing.clear(); } + // ------------------------------------------------------------------------ + void addForcedBloomNode(scene::ISceneNode *n, float power = 1) + { + BloomData dat; + dat.node = n; + dat.power = power; + + m_forcedbloom.push_back(dat); + } + // ------------------------------------------------------------------------ + void clearForcedBloom() { m_forcedbloom.clear(); } + // ------------------------------------------------------------------------ + const std::vector &getForcedBloom() const { return m_forcedbloom; } + // ------------------------------------------------------------------------ + void clearDisplacingNodes() { m_displacing.clear(); } + // ------------------------------------------------------------------------ + const std::vector &getDisplacingNodes() const { return m_displacing; } + // ------------------------------------------------------------------------ + void addDisplacingNode(scene::ISceneNode * const n) { m_displacing.push_back(n); } + // ------------------------------------------------------------------------ + void clearBackgroundNodes() { m_background.clear(); } + // ------------------------------------------------------------------------ + void addBackgroundNode(scene::ISceneNode * const n) { m_background.push_back(n); } + // ------------------------------------------------------------------------ + void applyObjectPassShader(); + void applyObjectPassShader(scene::ISceneNode * const node, bool rimlit = false); + // ------------------------------------------------------------------------ + scene::ISceneNode *addLight(const core::vector3df &pos, float radius = 1.0f, float r = 1.0f, + float g = 1.0f, float b = 1.0f, bool sun = false); + // ------------------------------------------------------------------------ + void clearLights(); + // ------------------------------------------------------------------------ + scene::IMeshSceneNode *getSunInterposer() { return m_sun_interposer; } + #ifdef DEBUG /** Removes debug meshes. */ void clearDebugMesh() { m_debug_meshes.clear(); } diff --git a/src/graphics/large_mesh_buffer.hpp b/src/graphics/large_mesh_buffer.hpp new file mode 100644 index 000000000..84c77fd17 --- /dev/null +++ b/src/graphics/large_mesh_buffer.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __LARGE_MESH_BUFFER_H_INCLUDED__ +#define __LARGE_MESH_BUFFER_H_INCLUDED__ + +#include "irrArray.h" +#include "IMeshBuffer.h" +#include "CMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + //! A SMeshBuffer with 32-bit indices + class LargeMeshBuffer : public SMeshBuffer + { + public: + //! Get type of index data which is stored in this meshbuffer. + /** \return Index type of this buffer. */ + virtual video::E_INDEX_TYPE getIndexType() const + { + return video::EIT_32BIT; + } + + //! Get pointer to indices + /** \return Pointer to indices. */ + virtual const u16* getIndices() const + { + return (u16 *) Indices.const_pointer(); + } + + + //! Get pointer to indices + /** \return Pointer to indices. */ + virtual u16* getIndices() + { + return (u16 *) Indices.pointer(); + } + + + //! Get number of indices + /** \return Number of indices. */ + virtual u32 getIndexCount() const + { + return Indices.size(); + } + + //! Indices into the vertices of this buffer. + core::array Indices; + }; +} // end namespace scene +} // end namespace irr + +#endif + + diff --git a/src/graphics/lens_flare.cpp b/src/graphics/lens_flare.cpp new file mode 100644 index 000000000..eebc27d16 --- /dev/null +++ b/src/graphics/lens_flare.cpp @@ -0,0 +1,264 @@ +/* TODO: copyright */ + +#include "graphics/lens_flare.hpp" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "ISceneCollisionManager.h" + +namespace irr +{ +namespace scene +{ + +CLensFlareSceneNode::CLensFlareSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id) : + scene::ISceneNode(parent, mgr, id) +{ + #ifdef _DEBUG + setDebugName("CLensFlareSceneNode"); + #endif + + // set the bounding box + BBox.MaxEdge.set(0,0,0); + BBox.MinEdge.set(0,0,0); + + // set the initial Strength + Strength = 1.0f; + + // setup the vertices + Vertices[0] = video::S3DVertex(-1.f, -1.f, 0.f, 0.f, 0.f, 1.f, 0xffffffff, 0.f, 1.f); + Vertices[1] = video::S3DVertex(-1.f, 1.f, 0.f, 0.f, 0.f, 1.f, 0xffffffff, 0.f, 0.f); + Vertices[2] = video::S3DVertex( 1.f, 1.f, 0.f, 0.f, 0.f, 1.f, 0xffffffff, 1.f, 0.f); + Vertices[3] = video::S3DVertex( 1.f, -1.f, 0.f, 0.f, 0.f, 1.f, 0xffffffff, 1.f, 1.f); + + // setup the indices + Indices[0] = 0; + Indices[1] = 1; + Indices[2] = 2; + Indices[3] = 2; + Indices[4] = 3; + Indices[5] = 0; + + // set the default material properties + Material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; + Material.Lighting = false; + Material.ZBuffer = video::ECFN_NEVER; + + FlareData.reallocate(30); + + // prepare the flare data array + // circles, halos and ring behind the sun + FlareData.push_back(SFlareData(EFT_CIRCLE, 0.5f, 0.12f, video::SColor(120, 60, 180, 35))); + FlareData.push_back(SFlareData(EFT_HALO, 0.45f, 0.4f, video::SColor(200, 100, 200, 60))); + FlareData.push_back(SFlareData(EFT_CIRCLE, 0.4f, 0.17f, video::SColor(240, 120, 220, 40))); + FlareData.push_back(SFlareData(EFT_CIRCLE, 0.2f, 0.35f, video::SColor(175, 175, 255, 20))); + FlareData.push_back(SFlareData(EFT_RING, 0.15f, 0.2f, video::SColor(120, 60, 255, 100))); + + // sun and glow effect at sun position + FlareData.push_back(SFlareData(EFT_SUN, 0.0f, 0.75f, video::SColor(255, 255, 255, 255))); +// FlareData.push_back(SFlareData(EFT_STREAKS, 0.0f, 2.9f, video::SColor(255, 255, 255, 255))); + FlareData.push_back(SFlareData(EFT_GLOW, 0.0f, 3.5f, video::SColor(255, 255, 255, 255))); +// FlareData.push_back(SFlareData(EFT_RING, 0.0f, 1.5f, video::SColor(120, 120, 120, 150))); + + // some lenses, halos and circles + FlareData.push_back(SFlareData(EFT_LENS, -0.15f, 0.15f, video::SColor(255, 60, 60, 90))); + FlareData.push_back(SFlareData(EFT_HALO, -0.3f, 0.3f, video::SColor(120, 60, 255, 180))); + FlareData.push_back(SFlareData(EFT_HALO, -0.4f, 0.2f, video::SColor(220, 80, 80, 98))); + FlareData.push_back(SFlareData(EFT_CIRCLE, -0.45f, 0.1f, video::SColor(220, 80, 80, 85))); + FlareData.push_back(SFlareData(EFT_RING, -0.42f, 0.3f, video::SColor(180, 60, 255, 110))); + + // some small lenses, halos and rings + FlareData.push_back(SFlareData(EFT_LENS, -0.55f, 0.2f, video::SColor(255, 60, 60, 130))); + FlareData.push_back(SFlareData(EFT_HALO, -0.6f, 0.3f, video::SColor(120, 60, 255, 80))); + FlareData.push_back(SFlareData(EFT_LENS, -0.7f, 0.2f, video::SColor(200, 60, 60, 130))); + FlareData.push_back(SFlareData(EFT_LENS, -0.71f, 0.2f, video::SColor(200, 60, 130, 60))); + FlareData.push_back(SFlareData(EFT_LENS, -0.72f, 0.2f, video::SColor(200, 130, 130, 60))); + FlareData.push_back(SFlareData(EFT_LENS, -0.74f, 0.2f, video::SColor(200, 130, 60, 60))); + + // some polyons, lenses and circle + FlareData.push_back(SFlareData(scene::EFT_POLY, -0.79f, 0.2f, video::SColor(200, 60, 130, 60))); + FlareData.push_back(SFlareData(scene::EFT_POLY, -0.86f, 0.3f, video::SColor(200, 130, 130, 60))); + FlareData.push_back(SFlareData(scene::EFT_LENS, -0.87f, 0.3f, video::SColor(180,255,192,178))); + FlareData.push_back(SFlareData(scene::EFT_CIRCLE, -0.9f, 0.1f, video::SColor(200, 60, 60, 130))); + FlareData.push_back(SFlareData(scene::EFT_POLY, -0.93f, 0.4f, video::SColor(200, 130, 60, 60))); + + // finally som polygons + FlareData.push_back(SFlareData(EFT_POLY, -0.95f, 0.6f, video::SColor(120, 60, 255, 120))); + FlareData.push_back(SFlareData(EFT_POLY, -1.0f, 0.15f, video::SColor(120, 20, 255, 85))); +} + +CLensFlareSceneNode::~CLensFlareSceneNode() +{ +} + +u32 CLensFlareSceneNode::getMaterialCount() const +{ + // return the material count (always one in our case) + return 1; +} + +video::SMaterial& CLensFlareSceneNode::getMaterial(u32 i) +{ + // return the material + return Material; +} + +core::array& CLensFlareSceneNode::getFlareData() +{ + // return the flare data array + return FlareData; +} + +void CLensFlareSceneNode::OnRegisterSceneNode() +{ + // if node is visible and Strength is greater than 0 register it for the ESNRP_TRANSPARENT_EFFECT pass + if(IsVisible && Strength > 0.0f) + { + SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT_EFFECT); + } + + // call base OnRegisterSceneNode + ISceneNode::OnRegisterSceneNode(); +} + +void CLensFlareSceneNode::render() +{ + // get the videodriver and the active camera + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + ICameraSceneNode* camera = SceneManager->getActiveCamera(); + + // return if we don't have a valid driver or a valid camera + // or if we have no texture attached to the material + if (!camera || !driver || !Material.getTexture(0)) + return; + + // get screencenter + const core::vector2d screenCenter = core::vector2d( + SceneManager->getVideoDriver()->getScreenSize().Width, + SceneManager->getVideoDriver()->getScreenSize().Height)/2; + + // get screencoordinates of the node + const core::vector2d lightPos = SceneManager->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition( + getAbsolutePosition(), + camera); + + // store old projection matrix + core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION); + + // store old view matrix + core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW); + + // clear the projection matrix + driver->setTransform(video::ETS_PROJECTION, core::IdentityMatrix); + + // clear the view matrix + driver->setTransform(video::ETS_VIEW, core::IdentityMatrix); + + // set the transform + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + + // set the material + driver->setMaterial(Material); + + // calculate some handy constants + const f32 texPos = 1.0f/EFT_COUNT; + const s32 texHeight = s32(Material.getTexture(0)->getSize().Height*0.5f); + const f32 screenWidth = f32(driver->getScreenSize().Width); + const f32 screenHeight = f32(driver->getScreenSize().Height); + + // render the flares + for (u32 i=0; iflarePos = screenCenter.getInterpolated(lightPos, -2.0*flare.Position); + + // calculate flareposition in vertex coordinates using the scalefactor of the flare + s32 flareScale = s32((texHeight*flare.Scale)); + core::rect flareRect = core::rect( + -1.f + 2.f * f32(flarePos.X-flareScale) / screenWidth, + -1.f + 2.f * f32(screenHeight-flarePos.Y-flareScale) / screenHeight, + -1.f + 2.f * f32(flarePos.X+flareScale) / screenWidth, + -1.f + 2.f * f32(screenHeight-flarePos.Y+flareScale) / screenHeight); + + // calculate flarecolor in dependence of occlusion + f32 flareAlpha = f32(flare.Color.getAlpha()) / 255.f; + video::SColor flareColor(255, + (u32)(Strength * flareAlpha * flare.Color.getRed()), + (u32)(Strength * flareAlpha * flare.Color.getGreen()), + (u32)(Strength * flareAlpha * flare.Color.getBlue())); + + // set vertex colors + Vertices[0].Color = flareColor; + Vertices[1].Color = flareColor; + Vertices[2].Color = flareColor; + Vertices[3].Color = flareColor; + + // set texture coordinates + Vertices[0].TCoords.set( flare.Type * texPos, 1.0f); + Vertices[1].TCoords.set( flare.Type * texPos, 0.0f); + Vertices[2].TCoords.set((flare.Type+1) * texPos, 0.0f); + Vertices[3].TCoords.set((flare.Type+1) * texPos, 1.0f); + + // set vertex positions + Vertices[0].Pos.set(flareRect.UpperLeftCorner.X, flareRect.UpperLeftCorner.Y, 0); + Vertices[1].Pos.set(flareRect.UpperLeftCorner.X, flareRect.LowerRightCorner .Y, 0); + Vertices[2].Pos.set(flareRect.LowerRightCorner.X, flareRect.LowerRightCorner.Y, 0); + Vertices[3].Pos.set(flareRect.LowerRightCorner.X, flareRect.UpperLeftCorner.Y, 0); + + //draw the mesh + driver->drawIndexedTriangleList(Vertices, 4, Indices, 2); + } + + // restore view matrix + driver->setTransform(video::ETS_VIEW, oldViewMat); + + // restore projection matrix + driver->setTransform(video::ETS_PROJECTION, oldProjMat); +} + +const core::aabbox3df& CLensFlareSceneNode::getBoundingBox() const +{ + // return the bounding box + return BBox; +} + +ESCENE_NODE_TYPE CLensFlareSceneNode::getType() const +{ + // return type of the scene node + // (important when using with a custom scene node factory) + return scene::ESNT_UNKNOWN; //(ESCENE_NODE_TYPE) ECSNT_LENSFLARE; +} + +void CLensFlareSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + // write attributes of the scene node. + ISceneNode::serializeAttributes(out, options); +} + +void CLensFlareSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + // read attributes of the scene node. + ISceneNode::deserializeAttributes(in, options); +} + +ISceneNode* CLensFlareSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CLensFlareSceneNode* nb = new CLensFlareSceneNode(newParent, newManager, ID); + + nb->cloneMembers(this, newManager); + nb->Material = Material; + + nb->drop(); + return nb; +} + +}// end irr namespace +}// end scene namespace + diff --git a/src/graphics/lens_flare.hpp b/src/graphics/lens_flare.hpp new file mode 100644 index 000000000..50d7145b0 --- /dev/null +++ b/src/graphics/lens_flare.hpp @@ -0,0 +1,117 @@ +#ifndef _CLENSFLARESCENENODE_H +#define _CLENSFLARESCENENODE_H + +#include +#include + +namespace irr +{ +namespace scene +{ + // enum with different flare types (used by SFlareData) + enum E_FLARE_TYPE + { + EFT_SUN = 0, + EFT_GLOW, + EFT_LENS, + EFT_STREAKS, + EFT_RING, + EFT_HALO, + EFT_CIRCLE, + EFT_POLY, + EFT_COUNT + }; + + // struct holding the flare specification + struct SFlareData + { + public: + // constructor + SFlareData(const E_FLARE_TYPE type, const float position, + const float scale, const video::SColor &color) + { + Type = type; + Position = position; + Scale = scale; + Color = color; + } + + // flare type + E_FLARE_TYPE Type; + // position + f32 Position; + // flare scale + f32 Scale; + // flare color + video::SColor Color; + }; + + class CLensFlareSceneNode : public ISceneNode + { + public: + // constructor + CLensFlareSceneNode(ISceneNode* parent, scene::ISceneManager* mgr, s32 id = -1); + + // destructor + virtual ~CLensFlareSceneNode(); + + protected: + // material of the node + video::SMaterial Material; + + // Bounding box + core::aabbox3d BBox; + + // vertices and indices of a flare element + video::S3DVertex Vertices[4]; + u16 Indices[6]; + + // flare data array + core::array FlareData; + + // Strength of the flare effect (between 0 and 1) + f32 Strength; + + public: + // typical OnRegisterSceneNode function + virtual void OnRegisterSceneNode(); + + // renders the node + virtual void render(); + + // returns the bounding box + virtual const core::aabbox3d& getBoundingBox() const; + + // returns the node type + virtual ESCENE_NODE_TYPE getType() const; + + // returns the material count + virtual u32 getMaterialCount() const; + + // returns the material + virtual video::SMaterial& getMaterial(u32 i); + + // writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options = 0) const; + + // reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options = 0); + + // clones the node + virtual ISceneNode* clone(ISceneNode* newParent = 0, ISceneManager* newManager = 0); + + // returns the flare data array + core::array& getFlareData(); + + // returns the strength (visibility) of the flares + f32 getStrength() { return Strength; } + + // sets the strength (visibility) of the flares + void setStrength(f32 strength) { Strength = core::clamp(strength, 0.0f, 0.7f); } + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/src/graphics/light.cpp b/src/graphics/light.cpp new file mode 100644 index 000000000..bbc0d0da6 --- /dev/null +++ b/src/graphics/light.cpp @@ -0,0 +1,93 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/light.hpp" + +#include "graphics/callbacks.hpp" +#include "graphics/glwrap.hpp" +#include "graphics/irr_driver.hpp" +#include "graphics/material_manager.hpp" +#include "graphics/material.hpp" +#include "graphics/rtts.hpp" +#include "graphics/shaders.hpp" + +using namespace video; +using namespace scene; +using namespace core; + +IMesh * LightNode::sphere = NULL; +SMaterial LightNode::mat; +aabbox3df LightNode::box; + + +LightNode::LightNode(scene::ISceneManager* mgr, float radius, float r, float g, float b): + ISceneNode(mgr->getRootSceneNode(), mgr, -1) +{ + if (!sphere) + { + mat.Lighting = false; + mat.MaterialType = irr_driver->getShader(ES_POINTLIGHT); + + mat.setTexture(0, irr_driver->getRTT(RTT_NORMAL)); + mat.setTexture(1, irr_driver->getRTT(RTT_DEPTH)); + + for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i) + { + mat.TextureLayer[i].TextureWrapU = + mat.TextureLayer[i].TextureWrapV = ETC_CLAMP_TO_EDGE; + } + + mat.setFlag(EMF_BILINEAR_FILTER, false); + mat.setFlag(EMF_ZWRITE_ENABLE, false); + + mat.MaterialTypeParam = pack_textureBlendFunc(EBF_ONE, EBF_ONE); + mat.BlendOperation = EBO_ADD; + + sphere = mgr->getGeometryCreator()->createSphereMesh(1, 16, 16); + box = sphere->getBoundingBox(); + } + + setScale(vector3df(radius)); + m_radius = radius; + + m_color[0] = r; + m_color[1] = g; + m_color[2] = b; +} + +LightNode::~LightNode() +{ +} + +void LightNode::render() +{ + PointLightProvider * const cb = (PointLightProvider *) irr_driver->getCallback(ES_POINTLIGHT); + cb->setColor(m_color[0], m_color[1], m_color[2]); + cb->setPosition(getPosition().X, getPosition().Y, getPosition().Z); + cb->setRadius(m_radius); + + IVideoDriver * const drv = irr_driver->getVideoDriver(); + drv->setTransform(ETS_WORLD, AbsoluteTransformation); + drv->setMaterial(mat); + + drv->drawMeshBuffer(sphere->getMeshBuffer(0)); +} + +void LightNode::OnRegisterSceneNode() +{ // This node is only drawn manually. +} diff --git a/src/graphics/light.hpp b/src/graphics/light.hpp new file mode 100644 index 000000000..245a3250e --- /dev/null +++ b/src/graphics/light.hpp @@ -0,0 +1,64 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_LIGHT_HPP +#define HEADER_LIGHT_HPP + +#include +#include + +using namespace irr; + +namespace irr +{ + namespace scene { class IMesh; } +} + +// The actual node +class LightNode: public scene::ISceneNode +{ +public: + LightNode(scene::ISceneManager* mgr, float radius, float r, float g, float b); + virtual ~LightNode(); + + virtual void render() OVERRIDE; + + virtual const core::aabbox3d& getBoundingBox() const OVERRIDE + { + return box; + } + + virtual void OnRegisterSceneNode() OVERRIDE; + + virtual u32 getMaterialCount() const OVERRIDE { return 1; } + virtual video::SMaterial& getMaterial(u32 i) OVERRIDE { return mat; } + + float getRadius() const { return m_radius; } + void getColor(float out[3]) const { memcpy(out, m_color, 3 * sizeof(float)); } + +protected: + static video::SMaterial mat; + static core::aabbox3df box; + + static scene::IMesh *sphere; + + float m_radius; + float m_color[3]; +}; + +#endif diff --git a/src/graphics/lod_node.cpp b/src/graphics/lod_node.cpp index 5943d632e..f8820d69d 100644 --- a/src/graphics/lod_node.cpp +++ b/src/graphics/lod_node.cpp @@ -49,6 +49,7 @@ LODNode::LODNode(std::string group_name, scene::ISceneNode* parent, drop(); m_forced_lod = -1; + m_last_tick = 0; } LODNode::~LODNode() @@ -81,6 +82,11 @@ int LODNode::getLevel() if (dist < m_detail[n]) return n; } + + // If it's the shadow pass, and we would have otherwise hidden the item, show the min one + if (curr_cam->isOrthogonal()) + return m_detail.size() - 1; + return -1; } // getLevel @@ -139,9 +145,12 @@ void LODNode::OnRegisterSceneNode() shown = true; } + const u32 now = irr_driver->getDevice()->getTimer()->getTime(); + // support an optional, mostly hard-coded fade-in/out effect for objects with a single level if (m_nodes.size() == 1 && (m_nodes[0]->getType() == scene::ESNT_MESH || - m_nodes[0]->getType() == scene::ESNT_ANIMATED_MESH)) + m_nodes[0]->getType() == scene::ESNT_ANIMATED_MESH) && + now > m_last_tick) { if (m_previous_visibility == WAS_HIDDEN && shown) { @@ -237,6 +246,7 @@ void LODNode::OnRegisterSceneNode() } m_previous_visibility = (shown ? WAS_SHOWN : WAS_HIDDEN); + m_last_tick = now; // If this node has children other than the LOD nodes, draw them core::list::Iterator it; @@ -279,7 +289,13 @@ void LODNode::add(int level, scene::ISceneNode* node, bool reparent) if(UserConfigParams::m_hw_skinning_enabled && node->getType() == scene::ESNT_ANIMATED_MESH) HardwareSkinning::prepareNode((scene::IAnimatedMeshSceneNode*)node); + if (node->getType() == scene::ESNT_ANIMATED_MESH) + ((scene::IAnimatedMeshSceneNode *) node)->setReadOnlyMaterials(true); + if (node->getType() == scene::ESNT_MESH) + ((scene::IMeshSceneNode *) node)->setReadOnlyMaterials(true); + node->drop(); node->updateAbsolutePosition(); + irr_driver->applyObjectPassShader(node); } diff --git a/src/graphics/lod_node.hpp b/src/graphics/lod_node.hpp index c3c3adc2d..3cca1bc28 100644 --- a/src/graphics/lod_node.hpp +++ b/src/graphics/lod_node.hpp @@ -71,6 +71,8 @@ private: PreviousVisibility m_previous_visibility; + u32 m_last_tick; + public: LODNode(std::string group_name, scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id=-1); diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index 70e3f9709..33babb91b 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -27,8 +27,10 @@ #include "config/user_config.hpp" #include "config/stk_config.hpp" #include "guiengine/engine.hpp" +#include "graphics/callbacks.hpp" #include "graphics/irr_driver.hpp" #include "graphics/particle_kind_manager.hpp" +#include "graphics/shaders.hpp" #include "io/file_manager.hpp" #include "io/xml_node.hpp" #include "utils/string_utils.hpp" @@ -36,7 +38,6 @@ #include "tracks/track.hpp" #include "utils/log.hpp" -#include #include #include #include @@ -46,351 +47,6 @@ using namespace irr::video; const unsigned int UCLAMP = 1; const unsigned int VCLAMP = 2; -//----------------------------------------------------------------------------- - -class NormalMapProvider : public video::IShaderConstantSetCallBack -{ - bool m_with_lightmap; - -public: - LEAK_CHECK() - - NormalMapProvider(bool withLightmap) - { - m_with_lightmap = withLightmap; - } - - virtual void OnSetConstants( - irr::video::IMaterialRendererServices *services, - s32 userData) - { - s32 decaltex = 0; - services->setPixelShaderConstant("DecalTex", &decaltex, 1); - - s32 bumptex = 1; - services->setPixelShaderConstant("BumpTex", &bumptex, 1); - - s32 lightmapTex = (m_with_lightmap ? 2 : 0); - services->setPixelShaderConstant("LightMapTex", &lightmapTex, 1); - - s32 hasLightMap = (m_with_lightmap ? 1 : 0); - services->setPixelShaderConstant("HasLightMap", &hasLightMap, 1); - - // We could calculate light direction as coming from the sun (then we'd need to - // transform it into camera space). But I find that pretending light - // comes from the camera gives good results - const float lightdir[] = {0.1852f, -0.1852f, -0.9259f}; - services->setVertexShaderConstant("lightdir", lightdir, 3); - } -}; - - -//----------------------------------------------------------------------------- - -class WaterShaderProvider : public video::IShaderConstantSetCallBack -{ - float m_dx_1, m_dy_1, m_dx_2, m_dy_2; - float m_water_shader_speed_1; - float m_water_shader_speed_2; - bool m_fog; - -public: - LEAK_CHECK() - - void enableFog(bool enable) - { - m_fog = enable; - } - - - WaterShaderProvider(float water_shader_speed_1, - float water_shader_speed_2) - { - m_dx_1 = 0.0f; - m_dy_1 = 0.0f; - m_dx_2 = 0.0f; - m_dy_2 = 0.0f; - - m_water_shader_speed_1 = water_shader_speed_1/100.0f; - m_water_shader_speed_2 = water_shader_speed_2/100.0f; - - m_fog = false; - } - - virtual void OnSetConstants( - irr::video::IMaterialRendererServices *services, - s32 userData) - { - m_dx_1 += GUIEngine::getLatestDt()*m_water_shader_speed_1; - m_dy_1 += GUIEngine::getLatestDt()*m_water_shader_speed_1; - - m_dx_2 += GUIEngine::getLatestDt()*m_water_shader_speed_2; - m_dy_2 -= GUIEngine::getLatestDt()*m_water_shader_speed_2; - - if (m_dx_1 > 1.0f) m_dx_1 -= 1.0f; - if (m_dy_1 > 1.0f) m_dy_1 -= 1.0f; - if (m_dx_2 > 1.0f) m_dx_2 -= 1.0f; - if (m_dy_2 < 0.0f) m_dy_2 += 1.0f; - - s32 decaltex = 0; - services->setPixelShaderConstant("DecalTex", &decaltex, 1); - - s32 bumptex = 1; - services->setPixelShaderConstant("BumpTex1", &bumptex, 1); - - bumptex = 2; - services->setPixelShaderConstant("BumpTex2", &bumptex, 1); - - // We could calculate light direction as coming from the sun (then we'd need to - // transform it into camera space). But I find that pretending light - // comes from the camera gives good results - const float lightdir[] = {-0.315f, 0.91f, -0.3f}; - services->setVertexShaderConstant("lightdir", lightdir, 3); - - services->setVertexShaderConstant("delta1", &m_dx_1, 2); - services->setVertexShaderConstant("delta2", &m_dx_2, 2); - - if (m_fog) - { - Track* t = World::getWorld()->getTrack(); - - float fogStart = t->getFogStart(); - services->setPixelShaderConstant("fogFrom", &fogStart, 1); - - float fogEnd = t->getFogEnd(); - services->setPixelShaderConstant("fogTo", &fogEnd, 1); - - video::SColor fogColor = t->getFogColor(); - float fogColorVec[] = {fogColor.getRed()/255.0f, - fogColor.getGreen()/255.0f, - fogColor.getBlue()/255.0f, 1.0f}; - services->setVertexShaderConstant("fogColor", fogColorVec, 4); - } - } -}; - -//----------------------------------------------------------------------------- - -// FIXME: refactor this hack to get per-instance properties, and apply the -// clean fix to all shaders why we're at it...... -std::map grass_shaders_times; -int grass_shaders_times_index = 0; - -class GrassShaderProvider : public video::IShaderConstantSetCallBack -{ - bool m_fog; - float m_angle; - float m_amplitude; - float m_speed; - -public: - LEAK_CHECK() - - - GrassShaderProvider(float amplitude, float speed) - { - m_fog = false; - m_angle = 0.0f; - m_amplitude = amplitude; - m_speed = speed; - } - - - void enableFog(bool enable) - { - m_fog = enable; - } - - void update(float dt) - { - m_angle += GUIEngine::getLatestDt()*m_speed; - if (m_angle > M_PI*2) m_angle -= M_PI*2; - } - - virtual void OnSetConstants(irr::video::IMaterialRendererServices *services, - s32 userData) - { - grass_shaders_times[userData] += GUIEngine::getLatestDt()*m_speed; - if (grass_shaders_times[userData] > M_PI*2) grass_shaders_times[userData] -= M_PI*2; - - services->setVertexShaderConstant("angle", &grass_shaders_times[userData], 1); - - int fog = (m_fog ? 1 : 0); - services->setVertexShaderConstant("fog", &fog, 1); - - s32 tex = 0; - services->setVertexShaderConstant("tex", &tex, 1); - - services->setVertexShaderConstant("amplitude", &m_amplitude, 1); - - if (m_fog) - { - Track* t = World::getWorld()->getTrack(); - - float fogStart = t->getFogStart(); - services->setPixelShaderConstant("fogFrom", &fogStart, 1); - - float fogEnd = t->getFogEnd(); - services->setPixelShaderConstant("fogTo", &fogEnd, 1); - - video::SColor fogColor = t->getFogColor(); - float fogColorVec[] = {fogColor.getRed()/255.0f, - fogColor.getGreen()/255.0f, - fogColor.getBlue()/255.0f, 1.0f}; - services->setVertexShaderConstant("fogColor", fogColorVec, 4); - } - } -}; - -//----------------------------------------------------------------------------- - -#if 0 -#pragma mark - -#endif - -class SplattingProvider : public video::IShaderConstantSetCallBack -{ - core::vector3df m_light_direction; - bool m_light_dir_calculated; - bool m_lightmap; - -public: - LEAK_CHECK() - - SplattingProvider(bool lightmap) - { - m_light_dir_calculated = false; - m_lightmap = lightmap; - } - - virtual void OnSetConstants( - irr::video::IMaterialRendererServices *services, - s32 userData) - { - if (!m_light_dir_calculated) - { - m_light_dir_calculated = true; - m_light_direction = -World::getWorld()->getTrack()->getSunRotation().rotationToDirection(); - } - - s32 tex_layout = 1; - services->setPixelShaderConstant("tex_layout", &tex_layout, 1); - - s32 tex_detail0 = 2; - services->setPixelShaderConstant("tex_detail0", &tex_detail0, 1); - - s32 tex_detail1 = 3; - services->setPixelShaderConstant("tex_detail1", &tex_detail1, 1); - - s32 tex_detail2 = 4; - services->setPixelShaderConstant("tex_detail2", &tex_detail2, 1); - - s32 tex_detail3 = 5; - services->setPixelShaderConstant("tex_detail3", &tex_detail3, 1); - - if (m_lightmap) - { - s32 tex_lightmap = 6; - services->setPixelShaderConstant("tex_lightmap", &tex_lightmap, 1); - } - - services->setVertexShaderConstant("lightdir", &m_light_direction.X, 3); - } -}; - -//----------------------------------------------------------------------------- - -#if 0 -#pragma mark - -#endif - -class SphereMapProvider: public video::IShaderConstantSetCallBack -{ - core::vector3df m_light_direction; - -public: - LEAK_CHECK() - - SphereMapProvider() - { - m_light_direction = core::vector3df(-0.6f, -0.5f, -0.63f); - //m_light_direction = core::vector3df(-0.315f, 0.91f, -0.3f); - } - - virtual void OnSetConstants( - irr::video::IMaterialRendererServices *services, - s32 userData) - { - s32 texture = 0; - services->setPixelShaderConstant("texture", &texture, 1); - - services->setVertexShaderConstant("lightdir", &m_light_direction.X, 3); - } -}; - -//----------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif - -class BubbleEffectProvider : public video::IShaderConstantSetCallBack -{ - irr::u32 initial_time; - float m_transparency; - bool m_is_visible; - -public: - LEAK_CHECK() - - BubbleEffectProvider() - { - initial_time = irr_driver->getDevice()->getTimer()->getRealTime(); - m_transparency = 1.0f; - m_is_visible = true; - } - - virtual void OnSetConstants( - irr::video::IMaterialRendererServices *services, - s32 userData) - { - if (m_is_visible && m_transparency < 1.0f) - { - m_transparency += GUIEngine::getLatestDt()*0.3f; - if (m_transparency > 1.0f) m_transparency = 1.0f; - } - else if (!m_is_visible && m_transparency > 0.0f) - { - m_transparency -= GUIEngine::getLatestDt()*0.3f; - if (m_transparency < 0.0f) m_transparency = 0.0f; - } - - float time = (irr_driver->getDevice()->getTimer()->getRealTime() - initial_time) / 1000.0f; - services->setVertexShaderConstant("time", &time, 1); - services->setVertexShaderConstant("transparency", &m_transparency, 1); - } - - void onMadeVisible() - { - m_is_visible = true; - } - - void onHidden() - { - m_is_visible = false; - m_transparency = 0.0f; - } - - void isInitiallyHidden() - { - m_is_visible = false; - m_transparency = 0.0f; - } -}; - -#if 0 -#pragma mark - -#endif - //----------------------------------------------------------------------------- /** Create a new material using the parameters specified in the xml file. * \param node Node containing the parameters for this material. @@ -568,7 +224,10 @@ Material::Material(const XMLNode *node, int index, bool deprecated) node->get("splatting-texture-2", &m_splatting_texture_2); node->get("splatting-texture-3", &m_splatting_texture_3); node->get("splatting-texture-4", &m_splatting_texture_4); - node->get("splatting-lightmap", &m_splatting_lightmap); + } + else if (s == "caustics") + { + m_graphical_effect = GE_CAUSTICS; } else if (s == "none") { @@ -740,8 +399,6 @@ void Material::init(unsigned int index) m_water_splash = false; m_is_jump_texture = false; - m_shaders.resize(SHADER_COUNT, NULL); - for (int n=0; nremoveTexture(m_texture); } - for (unsigned int n=0; ndrop(); - } - } - - for (std::map::iterator it = m_bubble_provider.begin(); - it != m_bubble_provider.end(); it++) - { - it->second->drop(); - } - // If a special sfx is installed (that isn't part of stk itself), the // entry needs to be removed from the sfx_manager's mapping, since other // tracks might use the same name. @@ -1032,24 +675,10 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m } if (m_smooth_reflection_shader) { - if (UserConfigParams::m_pixel_shaders && - irr_driver->isGLSL()) + if (irr_driver->isGLSL()) { - if (m_shaders[SHADER_SPHERE_MAP] == NULL) - { - m_shaders[SHADER_SPHERE_MAP] = new SphereMapProvider(); + m->MaterialType = irr_driver->getShader(ES_SPHERE_MAP); } - // Material and shaders - IGPUProgrammingServices* gpu = - irr_driver->getVideoDriver()->getGPUProgrammingServices(); - s32 material_type = gpu->addHighLevelShaderMaterialFromFiles( - (file_manager->getShaderDir() + "spheremap.vert").c_str(), - "main", video::EVST_VS_2_0, - (file_manager->getShaderDir() + "spheremap.frag").c_str(), - "main", video::EPST_PS_2_0, - m_shaders[SHADER_SPHERE_MAP], video::EMT_SOLID_2_LAYER ); - m->MaterialType = (E_MATERIAL_TYPE)material_type; - } else { m->MaterialType = video::EMT_SPHERE_MAP; @@ -1068,6 +697,12 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m } if (m_graphical_effect == GE_SPHERE_MAP) { + if (irr_driver->isGLSL()) + { + m->MaterialType = irr_driver->getShader(ES_SPHERE_MAP); + } + else + { m->MaterialType = video::EMT_SPHERE_MAP; // sphere map + alpha blending is a supported combination so in @@ -1081,7 +716,8 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m modes++; } } -#if !LIGHTMAP_VISUALISATION + } + if (m_lightmap) { m->MaterialType = video::EMT_LIGHTMAP; @@ -1092,7 +728,7 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m m->MaterialType = video::EMT_LIGHTMAP_ADD; modes++; } -#endif + if (m_add) { //m->MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; @@ -1111,8 +747,7 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m if (m_graphical_effect == GE_NORMAL_MAP) { IVideoDriver* video_driver = irr_driver->getVideoDriver(); - if (UserConfigParams::m_pixel_shaders && - irr_driver->isGLSL()) + if (irr_driver->isGLSL()) { ITexture* tex = irr_driver->getTexture(m_normal_map_tex); if (m_is_heightmap) @@ -1130,37 +765,9 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m with_lightmap = true; } - if (with_lightmap) - { - if (m_shaders[SHADER_NORMAL_MAP_WITH_LIGHTMAP] == NULL) - { - m_shaders[SHADER_NORMAL_MAP_WITH_LIGHTMAP] = - new NormalMapProvider(true); - } - } - else - { - if (m_shaders[SHADER_NORMAL_MAP] == NULL) - { - m_shaders[SHADER_NORMAL_MAP] = new NormalMapProvider(false); - } - } - - const char* vertex_shader = "normalmap.vert"; - const char* pixel_shader = "normalmap.frag"; - // Material and shaders - IGPUProgrammingServices* gpu = - video_driver->getGPUProgrammingServices(); - s32 material_type = gpu->addHighLevelShaderMaterialFromFiles( - (file_manager->getShaderDir() + vertex_shader).c_str(), - "main", video::EVST_VS_2_0, - (file_manager->getShaderDir() + pixel_shader).c_str(), - "main", video::EPST_PS_2_0, - m_shaders[with_lightmap ? SHADER_NORMAL_MAP_WITH_LIGHTMAP - : SHADER_NORMAL_MAP], - video::EMT_SOLID_2_LAYER ); - m->MaterialType = (E_MATERIAL_TYPE)material_type; + m->MaterialType = irr_driver->getShader( + with_lightmap ? ES_NORMAL_MAP_LIGHTMAP : ES_NORMAL_MAP ); m->Lighting = false; m->ZWriteEnable = true; @@ -1210,64 +817,20 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m } m->setTexture(5, tex); - if (m_splatting_lightmap.size() > 0) - { - tex = irr_driver->getTexture(m_splatting_lightmap); - } - m->setTexture(6, tex); - - if (m_splatting_lightmap.size() > 0) - { - if (m_shaders[SHADER_SPLATTING_LIGHTMAP] == NULL) - { - m_shaders[SHADER_SPLATTING_LIGHTMAP] = - new SplattingProvider(true); - } - } - else - { - if (m_shaders[SHADER_SPLATTING] == NULL) - { - m_shaders[SHADER_SPLATTING] = new SplattingProvider(false); - } - } - - // Material and shaders - IGPUProgrammingServices* gpu = - irr_driver->getVideoDriver()->getGPUProgrammingServices(); - - if (m_splatting_lightmap.size() > 0) - { - s32 material_type = gpu->addHighLevelShaderMaterialFromFiles( - (file_manager->getShaderDir() - + "splatting_lightmap.vert").c_str(), - "main",video::EVST_VS_2_0, - (file_manager->getShaderDir() - + "splatting_lightmap.frag").c_str(), - "main",video::EPST_PS_2_0, - m_shaders[SHADER_SPLATTING_LIGHTMAP], - video::EMT_SOLID ); - m->MaterialType = (E_MATERIAL_TYPE)material_type; + m->MaterialType = irr_driver->getShader(ES_SPLATTING); } else { - s32 material_type = gpu->addHighLevelShaderMaterialFromFiles( - (file_manager->getShaderDir() - + "splatting.vert").c_str(), - "main",video::EVST_VS_2_0, - (file_manager->getShaderDir() - + "splatting.frag").c_str(), - "main",video::EPST_PS_2_0, - m_shaders[SHADER_SPLATTING], video::EMT_SOLID ); - m->MaterialType = (E_MATERIAL_TYPE)material_type; + m->MaterialType = video::EMT_SOLID; } } - else + if (m_graphical_effect == GE_CAUSTICS && irr_driver->isGLSL()) { - m->MaterialType = video::EMT_SOLID; + m->MaterialType = irr_driver->getShader(ES_CAUSTICS); + + m->setTexture(1, irr_driver->getTexture((file_manager->getTextureDir() + "caustics.png").c_str())); } - } // Modify lightmap materials so that vertex colors are taken into account. @@ -1284,26 +847,14 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m if (m_graphical_effect == GE_BUBBLE && mb != NULL) { - IVideoDriver* video_driver = irr_driver->getVideoDriver(); - if (UserConfigParams::m_pixel_shaders && - irr_driver->isGLSL()) + if (irr_driver->isGLSL()) { - if (m_bubble_provider.find(mb) == m_bubble_provider.end()) - { - m_bubble_provider[mb] = new BubbleEffectProvider(); - } + BubbleEffectProvider * bubble = (BubbleEffectProvider *) + irr_driver->getCallback(ES_BUBBLES); + bubble->addBubble(mb); - // Material and shaders - IGPUProgrammingServices* gpu = video_driver->getGPUProgrammingServices(); - s32 material_type = gpu->addHighLevelShaderMaterialFromFiles( - (file_manager->getShaderDir() + "bubble.vert").c_str(), - "main", video::EVST_VS_2_0, - (file_manager->getShaderDir() + "bubble.frag").c_str(), - "main", video::EPST_PS_2_0, - m_bubble_provider[mb], - (m_alpha_blending ? video::EMT_TRANSPARENT_ALPHA_CHANNEL - : video::EMT_SOLID) ); - m->MaterialType = (E_MATERIAL_TYPE)material_type; + m->MaterialType = irr_driver->getShader(ES_BUBBLES); + m->BlendOperation = video::EBO_ADD; // alpha blending and bubble shading can work together so when both are enabled // don't increment the 'modes' counter to not get the 'too many modes' warning @@ -1317,70 +868,40 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m if (m_graphical_effect == GE_WATER_SHADER) { - if (UserConfigParams::m_pixel_shaders && - irr_driver->isGLSL()) + if (irr_driver->isGLSL()) { - if (m_shaders[SHADER_WATER] == NULL) - { - m_shaders[SHADER_WATER] = - new WaterShaderProvider(m_water_shader_speed_1, - m_water_shader_speed_2); - } - m->setTexture(1, irr_driver->getTexture(file_manager->getTextureFile("waternormals.jpg"))); m->setTexture(2, irr_driver->getTexture(file_manager->getTextureFile("waternormals2.jpg"))); - bool fog = World::getWorld()->getTrack()->isFogEnabled(); - const char* vertex_shader = (fog ? "water_fog.vert" : "water.vert"); - const char* pixel_shader = (fog ? "water_fog.frag" : "water.frag"); + ((WaterShaderProvider *) irr_driver->getCallback(ES_WATER))-> + setSpeed(m_water_shader_speed_1/100.0f, m_water_shader_speed_2/100.0f); - ((WaterShaderProvider*)m_shaders[SHADER_WATER])->enableFog(fog); - - // Material and shaders - IGPUProgrammingServices* gpu = - irr_driver->getVideoDriver()->getGPUProgrammingServices(); - s32 material_type = gpu->addHighLevelShaderMaterialFromFiles( - (file_manager->getShaderDir() + vertex_shader).c_str(), - "main", video::EVST_VS_2_0, - (file_manager->getShaderDir() + pixel_shader ).c_str(), - "main", video::EPST_PS_2_0, - m_shaders[SHADER_WATER], - video::EMT_TRANSPARENT_ALPHA_CHANNEL); - m->MaterialType = (E_MATERIAL_TYPE)material_type; + m->MaterialType = irr_driver->getShader(ES_WATER); } modes++; } if (m_graphical_effect == GE_GRASS) { - if (UserConfigParams::m_pixel_shaders && + if (UserConfigParams::m_weather_effects && irr_driver->isGLSL()) { - if (m_shaders[SHADER_GRASS] == NULL) - { - m_shaders[SHADER_GRASS] = - new GrassShaderProvider(m_grass_amplitude, m_grass_speed); - } - - bool fog = World::getWorld()->getTrack()->isFogEnabled(); - ((GrassShaderProvider*)m_shaders[SHADER_GRASS])->enableFog(fog); - - grass_shaders_times[grass_shaders_times_index] = (rand() % 500)/500.0f * M_PI * 2.0f; + // Only one grass speed & amplitude per map for now + ((GrassShaderProvider *) irr_driver->getCallback(ES_GRASS))-> + setSpeed(m_grass_speed); + ((GrassShaderProvider *) irr_driver->getCallback(ES_GRASS))-> + setAmplitude(m_grass_amplitude); // Material and shaders - IGPUProgrammingServices* gpu = - irr_driver->getVideoDriver()->getGPUProgrammingServices(); - s32 material_type = gpu->addHighLevelShaderMaterialFromFiles( - (file_manager->getShaderDir() + "grass.vert").c_str(), - "main", video::EVST_VS_2_0, - (file_manager->getShaderDir() + "grass.frag").c_str(), - "main", video::EPST_PS_2_0, - m_shaders[SHADER_GRASS], - video::EMT_TRANSPARENT_ALPHA_CHANNEL, - grass_shaders_times_index); - m->MaterialType = (E_MATERIAL_TYPE)material_type; + if (m_alpha_testing) + { + m->MaterialType = irr_driver->getShader(ES_GRASS_REF); + } + else { + m->MaterialType = irr_driver->getShader(ES_GRASS); + m->BlendOperation = video::EBO_ADD; + } - grass_shaders_times_index++; } } @@ -1475,6 +996,10 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m void Material::adjustForFog(scene::ISceneNode* parent, video::SMaterial *m, bool use_fog) const { + // The new pipeline does fog as a post-process effect. + if (irr_driver->isGLSL()) + return; + m->setFlag(video::EMF_FOG_ENABLE, m_fog && use_fog); if (parent != NULL) @@ -1488,10 +1013,9 @@ void Material::adjustForFog(scene::ISceneNode* parent, video::SMaterial *m, /** Callback from LOD nodes to create some effects */ void Material::onMadeVisible(scene::IMeshBuffer* who) { - if (m_bubble_provider.find(who) != m_bubble_provider.end()) - { - m_bubble_provider[who]->onMadeVisible(); - } + BubbleEffectProvider * bubble = (BubbleEffectProvider *) + irr_driver->getCallback(ES_BUBBLES); + bubble->onMadeVisible(who); } //----------------------------------------------------------------------------- @@ -1499,20 +1023,18 @@ void Material::onMadeVisible(scene::IMeshBuffer* who) /** Callback from LOD nodes to create some effects */ void Material::onHidden(scene::IMeshBuffer* who) { - if (m_bubble_provider.find(who) != m_bubble_provider.end()) - { - m_bubble_provider[who]->onHidden(); - } + BubbleEffectProvider * bubble = (BubbleEffectProvider *) + irr_driver->getCallback(ES_BUBBLES); + bubble->onHidden(who); } //----------------------------------------------------------------------------- void Material::isInitiallyHidden(scene::IMeshBuffer* who) { - if (m_bubble_provider.find(who) != m_bubble_provider.end()) - { - m_bubble_provider[who]->isInitiallyHidden(); - } + BubbleEffectProvider * bubble = (BubbleEffectProvider *) + irr_driver->getCallback(ES_BUBBLES); + bubble->isInitiallyHidden(who); } //----------------------------------------------------------------------------- diff --git a/src/graphics/material.hpp b/src/graphics/material.hpp index 3c6a342e1..c56bc980a 100644 --- a/src/graphics/material.hpp +++ b/src/graphics/material.hpp @@ -28,8 +28,6 @@ #include -#define LIGHTMAP_VISUALISATION 0 - namespace irr { @@ -42,10 +40,6 @@ class XMLNode; class SFXBase; class ParticleKind; -class NormalMapProvider; -class SplattingProvider; -class BubbleEffectProvider; - /** * \ingroup graphics */ @@ -60,7 +54,8 @@ public: GE_WATER_SHADER, GE_SPHERE_MAP, GE_SPLATTING, - GE_NORMAL_MAP}; + GE_NORMAL_MAP, + GE_CAUSTICS}; enum ParticleConditions { @@ -80,18 +75,6 @@ public: private: - enum Shaders - { - SHADER_NORMAL_MAP, - SHADER_NORMAL_MAP_WITH_LIGHTMAP, - SHADER_SPLATTING, - SHADER_WATER, - SHADER_SPHERE_MAP, - SHADER_SPLATTING_LIGHTMAP, - SHADER_GRASS, - SHADER_COUNT - }; - video::ITexture *m_texture; unsigned int m_index; std::string m_texname; @@ -234,13 +217,6 @@ private: /** If m_splatting is true, indicates the fourth splatting texture */ std::string m_splatting_texture_4; - std::string m_splatting_lightmap; - - std::vector m_shaders; - - /** Only used if bubble effect is enabled */ - std::map m_bubble_provider; - bool m_deprecated; void init (unsigned int index); diff --git a/src/graphics/material_manager.cpp b/src/graphics/material_manager.cpp index a8b85f69a..553ec4a22 100644 --- a/src/graphics/material_manager.cpp +++ b/src/graphics/material_manager.cpp @@ -60,10 +60,6 @@ MaterialManager::~MaterialManager() m_materials.clear(); } // ~MaterialManager -#if LIGHTMAP_VISUALISATION -std::set g_processed; -#endif - //----------------------------------------------------------------------------- Material* MaterialManager::getMaterialFor(video::ITexture* t, diff --git a/src/graphics/mlaa_areamap.hpp b/src/graphics/mlaa_areamap.hpp new file mode 100644 index 000000000..f5c636f68 --- /dev/null +++ b/src/graphics/mlaa_areamap.hpp @@ -0,0 +1,200 @@ +#ifndef AREAMAP_H +#define AREAMAP_H + +static const unsigned char AreaMap33[] = { +0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, +0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa5, +0x08, 0x04, 0x00, 0x00, 0x00, 0x97, 0x22, 0xf5, 0x51, 0x00, 0x00, 0x00, +0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, +0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, +0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, +0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, +0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xdb, 0x06, 0x07, 0x09, 0x17, 0x12, +0x5f, 0x51, 0x45, 0x04, 0x00, 0x00, 0x08, 0x87, 0x49, 0x44, 0x41, 0x54, +0x78, 0xda, 0xed, 0x5d, 0x4b, 0x6e, 0xdb, 0x48, 0x14, 0x2c, 0x89, 0x2f, +0x4e, 0xe2, 0x09, 0x30, 0x9b, 0x38, 0x5b, 0xf9, 0x24, 0x73, 0xbb, 0xb9, +0x49, 0x6e, 0x32, 0x67, 0x98, 0x7d, 0xbc, 0xf2, 0xc2, 0x18, 0x78, 0x31, +0x81, 0xc6, 0xa6, 0xc4, 0xd7, 0xc3, 0x8f, 0x1a, 0x0d, 0x9a, 0x92, 0x5b, +0x64, 0x91, 0x7a, 0x1d, 0xa1, 0xab, 0x41, 0x28, 0x41, 0x80, 0x42, 0xd5, +0x63, 0x93, 0x32, 0x9c, 0x42, 0x35, 0xc0, 0x63, 0x03, 0x73, 0x6c, 0x60, +0x8f, 0x35, 0x78, 0xdc, 0xe3, 0x16, 0x2c, 0x78, 0x09, 0x57, 0x31, 0xca, +0x6f, 0xb8, 0xc3, 0x0d, 0x68, 0xd8, 0x4b, 0xb0, 0x1f, 0xe5, 0x2d, 0xbe, +0xe2, 0x77, 0x08, 0x48, 0xd8, 0x4b, 0xb0, 0x1f, 0xe5, 0x47, 0x7c, 0xa9, +0x7d, 0xfc, 0x86, 0x02, 0x06, 0x48, 0x46, 0x02, 0x64, 0x16, 0x8e, 0xcf, +0xb5, 0x8b, 0x17, 0x54, 0xd8, 0x42, 0x41, 0xc0, 0x5a, 0x82, 0xfd, 0x28, +0x0b, 0x7c, 0xac, 0x9d, 0xdc, 0x62, 0x07, 0xc5, 0x0b, 0xe1, 0xc4, 0x5c, +0x82, 0xfd, 0x28, 0xd7, 0xb8, 0xa9, 0x9d, 0x7c, 0xc2, 0x2b, 0xf6, 0x70, +0x78, 0x25, 0x9c, 0x98, 0x4b, 0xb0, 0x1f, 0xa5, 0x1c, 0x9c, 0xec, 0xa1, +0x50, 0x94, 0x70, 0x20, 0x60, 0x27, 0xc1, 0x7e, 0x94, 0x2b, 0x14, 0xf8, +0x50, 0xaf, 0xda, 0x4b, 0xeb, 0x04, 0x84, 0x13, 0x73, 0x09, 0xf6, 0xa3, +0x94, 0xd6, 0x47, 0x59, 0x3b, 0x51, 0x28, 0x1c, 0x76, 0x84, 0x13, 0x53, +0x09, 0xf6, 0xa3, 0x2c, 0xf0, 0xa1, 0xf5, 0xb2, 0xc7, 0xbe, 0xf5, 0xe1, +0xb0, 0x27, 0x9c, 0x98, 0x49, 0xb0, 0x1f, 0xe5, 0x1a, 0xd2, 0x38, 0xf1, +0x3e, 0x5a, 0x27, 0x20, 0x9c, 0x18, 0x4a, 0xb0, 0x1f, 0x65, 0xe7, 0x44, +0xda, 0x6d, 0x51, 0x1d, 0x9c, 0x38, 0x54, 0x84, 0x13, 0x13, 0x09, 0xf6, +0xa3, 0xf4, 0x4e, 0xe4, 0xe0, 0xc4, 0xfb, 0x00, 0xe1, 0xc4, 0x40, 0x82, +0xfd, 0x28, 0x81, 0x35, 0x8a, 0x6e, 0xb5, 0x3e, 0x2a, 0x54, 0x84, 0x13, +0x53, 0x09, 0xf6, 0xbb, 0xd2, 0x6f, 0x8a, 0xe0, 0x26, 0xf8, 0x70, 0xa8, +0xc0, 0x23, 0x7d, 0x09, 0x90, 0x79, 0x9c, 0xf4, 0x3c, 0x54, 0xa8, 0xda, +0x4f, 0x77, 0x58, 0x20, 0x9c, 0x18, 0x48, 0xb0, 0x1f, 0xa5, 0xf7, 0xb2, +0x46, 0xd8, 0x14, 0xda, 0xba, 0x00, 0xe1, 0xc4, 0x48, 0x82, 0xfd, 0x03, +0x1e, 0x9e, 0x30, 0x6d, 0x2f, 0x47, 0x6c, 0x8b, 0x5f, 0x4d, 0x02, 0x64, +0x36, 0x27, 0xc1, 0xc5, 0x3a, 0xf8, 0x68, 0x2e, 0x62, 0x5b, 0x18, 0x48, +0xb0, 0x1e, 0x25, 0x06, 0x9b, 0xa2, 0x7a, 0xe3, 0xc3, 0x2d, 0xe8, 0x84, +0x90, 0x90, 0xe6, 0xbb, 0xb2, 0xbf, 0x0a, 0x68, 0xbb, 0x0a, 0xb8, 0x76, +0x15, 0x40, 0xfb, 0xa9, 0x60, 0xc1, 0x4b, 0x48, 0xfb, 0x5d, 0x39, 0xd8, +0x14, 0x55, 0xf7, 0x19, 0x5e, 0x54, 0x07, 0x2f, 0x20, 0x9c, 0x18, 0x48, +0xb0, 0x7a, 0xc0, 0xfb, 0x4e, 0xb4, 0x59, 0xfe, 0x6f, 0xde, 0x05, 0xe1, +0x24, 0x79, 0x09, 0x32, 0xf3, 0x17, 0xa8, 0x77, 0x12, 0xf4, 0xf7, 0x9f, +0x2e, 0x47, 0x38, 0x31, 0x90, 0x60, 0xbd, 0x2b, 0x87, 0xab, 0xf0, 0x5e, +0x88, 0x6d, 0x91, 0xbc, 0x04, 0x99, 0xd7, 0xc5, 0x09, 0x2f, 0xae, 0xbd, +0xc2, 0x96, 0x70, 0x11, 0x27, 0x56, 0x12, 0xec, 0xbf, 0x76, 0x06, 0x4f, +0x58, 0x70, 0x13, 0x5e, 0x53, 0x7d, 0x17, 0x88, 0x38, 0xb1, 0x95, 0x60, +0xbf, 0x2b, 0x7b, 0x0e, 0x56, 0x6f, 0x36, 0x44, 0xe1, 0x5d, 0xb4, 0x9f, +0x8e, 0x70, 0x62, 0x20, 0xc1, 0xe0, 0x5d, 0x79, 0xf4, 0x09, 0x53, 0xac, +0xfb, 0xef, 0x7d, 0x62, 0x5b, 0x24, 0x2c, 0x41, 0xe6, 0x77, 0x32, 0xfc, +0x1a, 0xed, 0xd4, 0x7b, 0x3f, 0xde, 0x07, 0xe1, 0x24, 0x49, 0x09, 0x32, +0xf7, 0x4f, 0xc8, 0xde, 0x4b, 0xcf, 0x55, 0x70, 0xb1, 0x1e, 0xf8, 0x70, +0x70, 0xd7, 0x21, 0x61, 0x85, 0x0d, 0xee, 0xf1, 0x0d, 0xb7, 0xf8, 0x08, +0x41, 0x71, 0xb8, 0x9d, 0x61, 0x85, 0x37, 0x3a, 0xfc, 0xe7, 0xe0, 0x4f, +0x7f, 0x61, 0x45, 0x32, 0xfc, 0x09, 0x12, 0x9b, 0xcd, 0x03, 0xe9, 0x62, +0xf3, 0x9d, 0x65, 0x10, 0x3c, 0xe0, 0x09, 0x77, 0xf8, 0x8a, 0x2f, 0xf8, +0x5c, 0xd3, 0xdc, 0xb4, 0x44, 0x85, 0x27, 0xeb, 0x11, 0x22, 0x90, 0xf6, +0xc8, 0x57, 0xf8, 0x1b, 0x3f, 0x28, 0x06, 0x1a, 0xf7, 0x0f, 0x4f, 0x4f, +0x5b, 0xca, 0x05, 0xcf, 0x20, 0x00, 0xb6, 0x78, 0xc4, 0xb6, 0xcd, 0xd4, +0x75, 0x24, 0x1f, 0x5a, 0x1a, 0x69, 0x49, 0x8a, 0x37, 0x3f, 0x5d, 0xe0, +0x08, 0xe1, 0x37, 0xfc, 0xc0, 0x3f, 0x0c, 0xc3, 0x2c, 0x51, 0xd5, 0xed, +0xe3, 0x63, 0x49, 0x68, 0xe0, 0x19, 0x04, 0x0d, 0x4a, 0x3c, 0xd7, 0xd7, +0x0b, 0x6e, 0xf1, 0xa9, 0x26, 0xf9, 0xd0, 0xae, 0x8e, 0xa4, 0xe8, 0xd1, +0xd4, 0xd7, 0x60, 0x75, 0x39, 0xd1, 0x2d, 0xfe, 0x25, 0x18, 0x38, 0x78, +0x09, 0xe5, 0xf3, 0xf3, 0x7e, 0xb2, 0x06, 0x9e, 0x41, 0xd0, 0x61, 0x8f, +0x9f, 0xa8, 0xb0, 0xc3, 0x6b, 0x4d, 0x72, 0x53, 0x2f, 0x39, 0x90, 0x14, +0x07, 0x1a, 0xbf, 0x56, 0x43, 0xa2, 0x43, 0x4e, 0xb4, 0xc4, 0x7f, 0x93, +0x19, 0x58, 0x78, 0x09, 0xfb, 0x9f, 0x3f, 0xab, 0x89, 0x1a, 0x78, 0x06, +0x81, 0x47, 0x97, 0xf2, 0xdc, 0xd7, 0xeb, 0x23, 0xca, 0xf6, 0x7e, 0x88, +0x7f, 0x5f, 0xf4, 0x49, 0x06, 0xf7, 0xe5, 0x16, 0x3e, 0x27, 0xfa, 0x32, +0x8d, 0x61, 0xc6, 0xa8, 0x6a, 0xb5, 0xdd, 0xea, 0x24, 0x0d, 0x73, 0x30, +0x04, 0x68, 0xcd, 0xe4, 0xa0, 0x0d, 0x49, 0x4b, 0x25, 0x81, 0x24, 0xdc, +0x93, 0x01, 0xc9, 0xba, 0x97, 0x13, 0x2d, 0xa7, 0x30, 0xcc, 0x1a, 0x55, +0xd5, 0x97, 0x17, 0x9d, 0xa0, 0x81, 0x67, 0x90, 0x9e, 0x22, 0xc5, 0x2b, +0xb4, 0x59, 0x2d, 0x85, 0xbf, 0x1f, 0xd2, 0x12, 0x78, 0x8a, 0x21, 0x4d, +0x3f, 0x27, 0xba, 0x1b, 0xcf, 0x30, 0x73, 0x54, 0x55, 0x5f, 0x5f, 0x75, +0xb4, 0x06, 0x9e, 0x41, 0xd0, 0x87, 0xa2, 0x04, 0xd0, 0xd1, 0x54, 0x6d, +0xf8, 0xa6, 0x40, 0xd5, 0x11, 0x9c, 0x22, 0x19, 0xe4, 0x44, 0x77, 0x63, +0x19, 0x66, 0x8f, 0xaa, 0x6a, 0x59, 0xba, 0x91, 0x1a, 0x78, 0x06, 0xc1, +0x5b, 0x38, 0x94, 0x70, 0xf5, 0xf2, 0x34, 0xd2, 0x50, 0x44, 0xb6, 0xf7, +0xdb, 0x9c, 0xe8, 0x6e, 0x1c, 0xc3, 0x02, 0x51, 0x55, 0x57, 0x8f, 0x62, +0x94, 0x06, 0x9e, 0x41, 0x30, 0x84, 0xeb, 0x8d, 0x42, 0xfd, 0xff, 0xce, +0xfb, 0x3b, 0xe3, 0x29, 0x02, 0xd1, 0x91, 0x9c, 0xe8, 0x7e, 0x0c, 0xc3, +0x22, 0x51, 0x55, 0xb7, 0xdb, 0xb9, 0x11, 0x1a, 0x78, 0x06, 0xc1, 0x11, +0xb4, 0xa3, 0x00, 0x3c, 0x8d, 0x34, 0x34, 0xed, 0x52, 0xac, 0x9b, 0xab, +0x4f, 0x72, 0x22, 0x27, 0x5a, 0xa1, 0x3c, 0x97, 0x61, 0xa1, 0xa8, 0xaa, +0xdb, 0xef, 0xdd, 0xd9, 0x2e, 0x78, 0x06, 0xc1, 0x71, 0x74, 0xfb, 0xca, +0x2f, 0xf5, 0x2b, 0x50, 0x04, 0xa2, 0x13, 0x39, 0xd1, 0x12, 0xd5, 0xb9, +0x0c, 0x8b, 0x45, 0x55, 0x9b, 0x51, 0x9c, 0xa9, 0x81, 0x67, 0x10, 0x1c, +0x87, 0x8f, 0x7f, 0x79, 0x0a, 0xff, 0x59, 0x34, 0x57, 0x9f, 0xe2, 0x9d, +0x9c, 0xa8, 0x62, 0x77, 0x0e, 0xc3, 0x82, 0x51, 0x55, 0x57, 0x55, 0xee, +0x2c, 0x17, 0x3c, 0x83, 0x00, 0x91, 0x61, 0x06, 0x1a, 0x45, 0xd1, 0xfd, +0x8e, 0xaa, 0x4f, 0xf1, 0x4e, 0x4e, 0x74, 0x07, 0xc5, 0x3e, 0xce, 0xb0, +0x68, 0x54, 0xb5, 0x1d, 0x45, 0x5c, 0x03, 0xcf, 0x20, 0x40, 0x64, 0x98, +0x2d, 0x1b, 0x9c, 0x5f, 0x03, 0x8a, 0xf5, 0xbb, 0x39, 0xd1, 0x3d, 0x14, +0xbb, 0x18, 0xc3, 0x62, 0x51, 0xd5, 0x30, 0x8a, 0xa8, 0x0b, 0x9e, 0x41, +0x80, 0xe8, 0x30, 0x71, 0x94, 0xa2, 0x80, 0xeb, 0xde, 0x17, 0x91, 0x9c, +0xe8, 0x2e, 0xce, 0xb0, 0x78, 0x54, 0xd5, 0x55, 0x51, 0x0d, 0x3c, 0x83, +0x20, 0x8e, 0xaa, 0xa5, 0xf0, 0x44, 0x45, 0x77, 0x75, 0x44, 0xed, 0x67, +0x3c, 0x27, 0x1a, 0x67, 0x58, 0x3e, 0xaa, 0x1a, 0xd1, 0xc0, 0x33, 0x08, +0xce, 0x81, 0xbf, 0x23, 0x05, 0xd0, 0x11, 0xf4, 0x62, 0x0f, 0x91, 0x9c, +0x68, 0x9c, 0xe1, 0x42, 0x51, 0xd5, 0x88, 0x06, 0x96, 0x41, 0x80, 0x11, +0xc3, 0x0c, 0x34, 0xcd, 0xea, 0x48, 0xf4, 0x9c, 0x9c, 0x68, 0x84, 0xe1, +0x52, 0x51, 0xd5, 0x77, 0x34, 0xf0, 0x0c, 0x82, 0x73, 0x51, 0xf5, 0xee, +0x87, 0x27, 0x51, 0xac, 0xe3, 0x39, 0xd1, 0x18, 0xc3, 0x05, 0xa3, 0xaa, +0x27, 0x35, 0xf0, 0x0c, 0x82, 0xf3, 0x51, 0x21, 0x44, 0x1b, 0x3c, 0xf7, +0x1a, 0xee, 0xbc, 0x9c, 0x68, 0x84, 0xe1, 0x72, 0x51, 0xd5, 0x13, 0x1a, +0x78, 0x06, 0xc1, 0x18, 0x28, 0x02, 0x05, 0x0e, 0x44, 0xeb, 0xb1, 0x39, +0xd1, 0x21, 0xc3, 0x85, 0xa3, 0xaa, 0x47, 0x35, 0xf0, 0x0c, 0x82, 0x71, +0x50, 0x04, 0xb8, 0x6e, 0x11, 0x39, 0x51, 0xff, 0xaf, 0x97, 0x8e, 0xaa, +0x1e, 0xd1, 0xc0, 0x33, 0x08, 0x30, 0x71, 0x98, 0xce, 0xaf, 0xa9, 0x39, +0xd1, 0xc0, 0x60, 0x10, 0x55, 0x1d, 0x68, 0xe0, 0x19, 0x04, 0x98, 0x34, +0x4c, 0x47, 0xe7, 0x44, 0x9d, 0x71, 0x54, 0xd5, 0x6b, 0x20, 0x19, 0xd8, +0xa0, 0x8b, 0xf6, 0xee, 0xc7, 0xc4, 0x9c, 0x68, 0x60, 0x30, 0x8a, 0xaa, +0xf6, 0x34, 0xf0, 0x0c, 0x82, 0x69, 0xd0, 0xab, 0x88, 0xaa, 0xea, 0x9c, +0x0c, 0x82, 0xa9, 0xd0, 0xab, 0x88, 0xaa, 0xea, 0x7c, 0x0c, 0x42, 0xe8, +0xd7, 0xab, 0x88, 0xaa, 0xea, 0x5c, 0x0c, 0x02, 0x06, 0x7a, 0x15, 0x51, +0x55, 0x9d, 0x87, 0x41, 0xc0, 0x41, 0xe1, 0xe8, 0x9c, 0xa8, 0x33, 0x8f, +0xaa, 0x2a, 0x1c, 0xcf, 0x20, 0x60, 0xe1, 0xae, 0x22, 0xaa, 0xea, 0xc0, +0x33, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, +0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, +0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, +0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x83, 0x15, 0x5f, 0xaa, +0xfa, 0x7d, 0x73, 0xff, 0x60, 0x5c, 0xaa, 0x8a, 0x3f, 0xb0, 0x32, 0x77, +0x21, 0x7c, 0xa9, 0xea, 0xc3, 0xfd, 0xd3, 0xd3, 0xdd, 0x96, 0x61, 0xe0, +0xc1, 0x17, 0xbb, 0xf2, 0x2e, 0x84, 0x2f, 0x55, 0xc5, 0xb7, 0xed, 0xdd, +0xe3, 0xe3, 0xb6, 0x24, 0x18, 0x68, 0xf0, 0xc5, 0xae, 0xbc, 0x0b, 0x61, +0x4b, 0x55, 0xbb, 0x4a, 0xd3, 0x72, 0xfb, 0xfc, 0x5c, 0xee, 0x8d, 0x4a, +0x55, 0x43, 0xb1, 0xab, 0xa9, 0x0b, 0xe1, 0x4b, 0x55, 0xbb, 0x4a, 0xd3, +0x7d, 0xd9, 0xf4, 0x91, 0x1a, 0x95, 0xaa, 0x86, 0x62, 0x57, 0x43, 0x17, +0xc2, 0x97, 0xaa, 0xfa, 0x4a, 0xd3, 0xae, 0x8f, 0x74, 0x0a, 0x03, 0x0f, +0xa1, 0x8b, 0x5d, 0x79, 0x17, 0xc2, 0x97, 0xaa, 0x86, 0x4a, 0xd3, 0xa6, +0x8f, 0xd4, 0xe9, 0x78, 0x06, 0x1e, 0x7c, 0xb1, 0x2b, 0xef, 0x42, 0xe8, +0x52, 0xd5, 0x5e, 0xa5, 0xa9, 0xba, 0xa6, 0x8f, 0x74, 0x2c, 0x03, 0x0f, +0xbe, 0xd8, 0x95, 0x77, 0x21, 0x7c, 0xa9, 0x6a, 0xbf, 0xd2, 0x54, 0xb5, +0x2c, 0xe1, 0xc6, 0x31, 0xf0, 0xe0, 0x8b, 0x5d, 0x79, 0x17, 0x42, 0x97, +0xaa, 0x0e, 0x2a, 0x4d, 0x1d, 0x9a, 0x3e, 0xd2, 0x31, 0x0c, 0x3c, 0xf8, +0x62, 0x57, 0xde, 0x85, 0xf0, 0xa5, 0xaa, 0xc3, 0x4a, 0xd3, 0xae, 0x8f, +0x74, 0x04, 0x03, 0x0d, 0xbe, 0xd8, 0x95, 0x77, 0x21, 0x74, 0xa9, 0xea, +0xd1, 0x4a, 0xd3, 0xa6, 0x8f, 0x14, 0xee, 0x5c, 0x06, 0x1e, 0x7c, 0xb1, +0x2b, 0xef, 0x42, 0xe8, 0x52, 0xd5, 0x13, 0x95, 0xa6, 0x0e, 0x4d, 0x1f, +0xe9, 0x79, 0x0c, 0x3c, 0xf8, 0x62, 0x57, 0xde, 0x85, 0xd0, 0xa5, 0xaa, +0x27, 0x2b, 0x4d, 0xdb, 0xa2, 0x42, 0x77, 0x0e, 0x03, 0x0f, 0xbe, 0xd8, +0x95, 0x77, 0x21, 0x7c, 0xa9, 0xea, 0xe9, 0x4a, 0x53, 0x87, 0x46, 0x46, +0x9c, 0x81, 0x07, 0x5f, 0xec, 0xca, 0xbb, 0x10, 0xba, 0x54, 0xf5, 0x44, +0xa5, 0x69, 0x90, 0xe1, 0x5c, 0x8c, 0x81, 0x07, 0x5f, 0xec, 0xca, 0xbb, +0x10, 0xba, 0x54, 0x35, 0x52, 0x69, 0xda, 0x3c, 0x20, 0x31, 0x06, 0x1e, +0x7c, 0xb1, 0x2b, 0xef, 0x42, 0xf8, 0x52, 0xd5, 0x78, 0xa5, 0x69, 0x55, +0x45, 0x18, 0x48, 0x44, 0x25, 0x5c, 0xc4, 0x85, 0xf0, 0xa5, 0xaa, 0xf1, +0x4a, 0xd3, 0x46, 0x46, 0x84, 0x81, 0x44, 0x5c, 0xc2, 0xf2, 0x2e, 0x84, +0x2e, 0x55, 0x3d, 0xb3, 0xd2, 0xb4, 0xaa, 0x4e, 0x32, 0xcc, 0xf5, 0x80, +0x47, 0x24, 0x2c, 0xed, 0x42, 0xe8, 0x52, 0xd5, 0xb3, 0x2b, 0x4d, 0xab, +0x6a, 0xb9, 0x52, 0xd5, 0xb8, 0x84, 0xe5, 0x5d, 0x08, 0x5d, 0xaa, 0x3a, +0xa2, 0xd2, 0xb4, 0xaa, 0x16, 0x2c, 0x55, 0x8d, 0x4b, 0x58, 0xd8, 0x85, +0xd0, 0xa5, 0xaa, 0xa3, 0x2a, 0x4d, 0x55, 0x8f, 0x31, 0x5c, 0xb4, 0x55, +0x75, 0x31, 0x17, 0x42, 0x97, 0xaa, 0x8e, 0xac, 0x34, 0x55, 0x1d, 0x32, +0x5c, 0xb0, 0x55, 0x75, 0x41, 0x17, 0x42, 0x97, 0xaa, 0x8e, 0xae, 0x34, +0x55, 0x7d, 0xcb, 0x60, 0xd0, 0xaa, 0xba, 0x80, 0x0b, 0x99, 0x58, 0xaa, +0x4a, 0x55, 0x9a, 0xaa, 0x7a, 0x06, 0x93, 0x56, 0xd5, 0x85, 0x5c, 0x08, +0x5d, 0xaa, 0x3a, 0xa9, 0xd2, 0x54, 0xb5, 0xc7, 0x60, 0xd0, 0xaa, 0x3a, +0xbf, 0x0b, 0xc1, 0x24, 0x28, 0x5d, 0x69, 0xaa, 0xd6, 0xad, 0xaa, 0xb3, +0xbb, 0x10, 0x4c, 0x84, 0xd2, 0x95, 0xa6, 0x6a, 0xd9, 0xaa, 0xba, 0x80, +0x0b, 0xc1, 0x64, 0x28, 0x5d, 0x69, 0xaa, 0xb6, 0xad, 0xaa, 0x33, 0xbb, +0x10, 0x10, 0x50, 0xba, 0xd2, 0x54, 0x2d, 0x5b, 0x55, 0x67, 0x76, 0x21, +0x74, 0xa9, 0x2a, 0x59, 0x69, 0xaa, 0xea, 0x60, 0xdd, 0xaa, 0xca, 0xbb, +0x68, 0x5c, 0x08, 0x48, 0x38, 0xba, 0xd2, 0xd4, 0xd9, 0xb7, 0xaa, 0xce, +0xe2, 0x62, 0x05, 0x1a, 0x1b, 0xc3, 0xa8, 0x6a, 0xd0, 0xf0, 0x70, 0x0f, +0x63, 0x11, 0x02, 0x16, 0x49, 0x44, 0x55, 0xf9, 0xe3, 0xfb, 0x01, 0xfb, +0x51, 0x26, 0x11, 0x55, 0xe5, 0x8f, 0xef, 0xb7, 0x1f, 0x65, 0x22, 0x51, +0x55, 0xfe, 0xf8, 0xfe, 0x14, 0x46, 0x99, 0x44, 0x54, 0x95, 0x3f, 0xbe, +0x3f, 0x85, 0x51, 0x26, 0x11, 0x55, 0x25, 0x8e, 0xef, 0x4f, 0x68, 0x94, +0x49, 0x44, 0x55, 0xf9, 0xe3, 0xfb, 0x53, 0x18, 0x65, 0x12, 0x51, 0x55, +0xfe, 0xf8, 0xfe, 0x44, 0x46, 0x69, 0x1f, 0x55, 0x65, 0x8f, 0xef, 0x4f, +0x63, 0x94, 0x49, 0x44, 0x55, 0x89, 0xe3, 0xfb, 0xd3, 0x1a, 0xa5, 0x7d, +0x54, 0x95, 0x3f, 0xbe, 0x3f, 0x91, 0x51, 0xda, 0x47, 0x55, 0xf9, 0xe3, +0xfb, 0x13, 0x19, 0xa5, 0x7d, 0x54, 0x95, 0x39, 0xbe, 0x3f, 0xa9, 0x51, +0xda, 0x47, 0x55, 0x89, 0xe3, 0xfb, 0x59, 0x11, 0xf3, 0x8e, 0xd2, 0x3e, +0xaa, 0x4a, 0x1c, 0xdf, 0x9f, 0xd0, 0x28, 0x93, 0x88, 0xaa, 0xf2, 0xc7, +0xf7, 0xa7, 0x30, 0xca, 0x24, 0xa2, 0xaa, 0xdc, 0xf1, 0xfd, 0xa9, 0x8c, +0x32, 0x89, 0xa8, 0x2a, 0x7f, 0x7c, 0x7f, 0x4a, 0xa3, 0x4c, 0x3f, 0xaa, +0x1a, 0xc9, 0xaa, 0xda, 0x8f, 0x32, 0x89, 0xa8, 0x2a, 0x7f, 0x7c, 0x7f, +0x0a, 0xa3, 0x4c, 0x22, 0xaa, 0xca, 0x1f, 0xdf, 0x9f, 0xc8, 0x28, 0xed, +0xa3, 0xaa, 0xfc, 0xf1, 0xfd, 0x89, 0x8c, 0xd2, 0x3e, 0xaa, 0xca, 0x1f, +0xdf, 0x9f, 0xc2, 0x28, 0x7f, 0xc5, 0xa8, 0xaa, 0x22, 0x20, 0xa1, 0xaf, +0x9d, 0x5f, 0x33, 0xaa, 0xaa, 0x7e, 0x90, 0xf6, 0xa3, 0xfc, 0xf5, 0xa3, +0xaa, 0x8a, 0x99, 0x45, 0xc8, 0xc5, 0x73, 0xa2, 0xe9, 0x44, 0x55, 0x35, +0x8d, 0x07, 0xfc, 0x3a, 0xa2, 0xaa, 0x9a, 0xc6, 0xae, 0xbc, 0x8e, 0xa8, +0xaa, 0xa6, 0x31, 0xca, 0xeb, 0x88, 0xaa, 0x6a, 0x1a, 0xa3, 0xbc, 0x8e, +0xa8, 0xaa, 0xa6, 0x32, 0xca, 0x6b, 0x88, 0xaa, 0x6a, 0x1a, 0x5f, 0x3b, +0xd7, 0x11, 0x55, 0x75, 0xa0, 0xf1, 0x3f, 0x19, 0xc2, 0xb4, 0x90, 0x78, +0xb9, 0x76, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, +0x42, 0x60, 0x82, +}; + +#endif diff --git a/src/graphics/particle_emitter.cpp b/src/graphics/particle_emitter.cpp index 56fc1cbc3..46bcbadb1 100644 --- a/src/graphics/particle_emitter.cpp +++ b/src/graphics/particle_emitter.cpp @@ -22,9 +22,12 @@ #include "graphics/material_manager.hpp" #include "graphics/particle_kind.hpp" #include "graphics/irr_driver.hpp" +#include "graphics/shaders.hpp" +#include "graphics/wind.hpp" #include "io/file_manager.hpp" #include "tracks/track.hpp" #include "utils/constants.hpp" +#include "utils/helpers.hpp" #include #include @@ -174,6 +177,46 @@ public: } }; +// ============================================================================ + +class WindAffector : public scene::IParticleAffector +{ + /** (Squared) distance from camera at which a particle is completely faded out */ + float m_speed; + float m_seed; + +public: + WindAffector(float speed): m_speed(speed) + { + m_seed = (rand() % 1000) - 500; + } + + // ------------------------------------------------------------------------ + + virtual void affect(u32 now, scene::SParticle* particlearray, u32 count) + { + const float time = irr_driver->getDevice()->getTimer()->getTime() / 10000.0f; + core::vector3df dir = irr_driver->getWind(); + dir *= m_speed * std::min(noise2d(time, m_seed), -0.2f); + + for (u32 n = 0; n < count; n++) + { + scene::SParticle& cur = particlearray[n]; + + cur.pos += dir; + } // for naddAffector(faa); faa->drop(); } - + if (type->hasScaleAffector()) { core::dimension2df factor = core::dimension2df(type->getScaleAffectorFactorX(), @@ -499,6 +542,21 @@ void ParticleEmitter::setParticleType(const ParticleKind* type) m_node->addAffector(scale_affector); scale_affector->drop(); } + + const float windspeed = type->getWindSpeed(); + if (windspeed > 0.01f) + { + WindAffector *waf = new WindAffector(windspeed); + m_node->addAffector(waf); + waf->drop(); + } + + const bool flips = type->getFlips(); + if (flips) + { + m_node->getMaterial(0).MaterialType = irr_driver->getShader(ES_SNOW); + m_node->getMaterial(0).BlendOperation = video::EBO_ADD; + } } } // setParticleType diff --git a/src/graphics/particle_kind.cpp b/src/graphics/particle_kind.cpp index d84b3374a..9d4370b18 100644 --- a/src/graphics/particle_kind.cpp +++ b/src/graphics/particle_kind.cpp @@ -54,6 +54,8 @@ ParticleKind::ParticleKind(const std::string file) : m_min_start_color(255,255,2 m_has_scale_affector = NULL; m_scale_affector_factor_x = 0.0f; m_scale_affector_factor_y = 0.0f; + m_wind_speed = 0; + m_flips = false; // ----- Read XML file @@ -219,6 +221,14 @@ ParticleKind::ParticleKind(const std::string file) : m_min_start_color(255,255,2 m_material_file = material_manager->getLatestMaterial()->getTexFname(); } + // ------------------------------------------------------------------------ + + const XMLNode* wind = xml->getNode("wind"); + if (wind != NULL) + { + wind->get("speed", &m_wind_speed); + wind->get("flips", &m_flips); + } // ------------------------------------------------------------------------ diff --git a/src/graphics/particle_kind.hpp b/src/graphics/particle_kind.hpp index af9718e6b..64c5c8f80 100644 --- a/src/graphics/particle_kind.hpp +++ b/src/graphics/particle_kind.hpp @@ -86,6 +86,11 @@ private: int m_emission_decay_rate; + /** Wind. < 0.01 if disabled. */ + float m_wind_speed; + + bool m_flips; + std::string m_name; std::string m_material_file; @@ -148,11 +153,14 @@ public: int getEmissionDecayRate() const { return m_emission_decay_rate; } - bool hasScaleAffector() const { return m_has_scale_affector; } float getScaleAffectorFactorX() const { return m_scale_affector_factor_x; } float getScaleAffectorFactorY() const { return m_scale_affector_factor_y; }; + float getWindSpeed() const { return m_wind_speed; } + + bool getFlips() const { return m_flips; } + std::string getName() const { return m_name; } }; diff --git a/src/graphics/per_camera_node.cpp b/src/graphics/per_camera_node.cpp index 010e0142e..6bccd7f41 100644 --- a/src/graphics/per_camera_node.cpp +++ b/src/graphics/per_camera_node.cpp @@ -24,7 +24,7 @@ #include PerCameraNode::PerCameraNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, - scene::ICameraSceneNode* camera, scene::IMesh* mesh) + scene::ICameraSceneNode* camera, scene::ISceneNode *node) : IDummyTransformationSceneNode(parent, mgr, id) { #ifdef DEBUG @@ -33,7 +33,10 @@ PerCameraNode::PerCameraNode(scene::ISceneNode* parent, scene::ISceneManager* mg #endif m_camera = camera; - m_child = mgr->addMeshSceneNode(mesh, this); + + node->setParent(this); + m_child = node; + //m_child = mgr->addCubeSceneNode(0.5f, this, -1, core::vector3df(0,0,0), core::vector3df(0,0,0), core::vector3df(3.0f,0.2f,3.0f)); //RelativeTransformationMatrix.setTranslation( core::vector3df(-0.5,-1,3) ); diff --git a/src/graphics/per_camera_node.hpp b/src/graphics/per_camera_node.hpp index 23455f727..1a7542af6 100644 --- a/src/graphics/per_camera_node.hpp +++ b/src/graphics/per_camera_node.hpp @@ -54,7 +54,7 @@ private: public: PerCameraNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, - scene::ICameraSceneNode* camera, scene::IMesh* mesh); + scene::ICameraSceneNode* camera, scene::ISceneNode* node); virtual ~PerCameraNode(); //! returns the axis aligned bounding box of this node diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index d29b1c82b..789fd88a8 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -19,69 +19,46 @@ #include "config/user_config.hpp" #include "io/file_manager.hpp" +#include "graphics/callbacks.hpp" +#include "graphics/glwrap.hpp" #include "graphics/irr_driver.hpp" +#include "graphics/mlaa_areamap.hpp" +#include "graphics/shaders.hpp" +#include "karts/abstract_kart.hpp" +#include "karts/kart_model.hpp" +#include "modes/world.hpp" #include "race/race_manager.hpp" +#include "tracks/track.hpp" #include "utils/log.hpp" -#include -#include - -#define MOTION_BLUR_FACTOR (1.0f/15.0f) -#define MOTION_BLUR_OFFSET 20.0f +#include using namespace video; using namespace scene; -PostProcessing::PostProcessing(video::IVideoDriver* video_driver) +PostProcessing::PostProcessing(IVideoDriver* video_driver) { - // Check if post-processing is supported on this hardware - m_supported = false; - if( irr_driver->isGLSL() ) - { - m_supported = true; - } - - //Check which texture dimensions are supported on this hardware - bool nonsquare = video_driver->queryFeature(video::EVDF_TEXTURE_NSQUARE); - bool nonpower = video_driver->queryFeature(video::EVDF_TEXTURE_NPOT); - if (!nonpower) { - Log::warn("PostProcessing", - "Only power of two textures are supported."); - } - if (!nonsquare) { - Log::warn("PostProcessing", "Only square textures are supported."); - } // Initialization - if(m_supported) + m_material.Wireframe = false; + m_material.Lighting = false; + m_material.ZWriteEnable = false; + m_material.ZBuffer = ECFN_ALWAYS; + m_material.setFlag(EMF_TRILINEAR_FILTER, true); + + for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i) { - // Render target - core::dimension2du opt = video_driver->getScreenSize() - .getOptimalSize(!nonpower, !nonsquare); - m_render_target = - video_driver->addRenderTargetTexture(opt, "postprocess"); - if(!m_render_target) - { - Log::warn("PostProcessing", "Couldn't create the render target " - "for post-processing, disabling it."); - UserConfigParams::m_postprocess_enabled = false; + m_material.TextureLayer[i].TextureWrapU = + m_material.TextureLayer[i].TextureWrapV = ETC_CLAMP_TO_EDGE; } - // Material and shaders - IGPUProgrammingServices* gpu = - video_driver->getGPUProgrammingServices(); - s32 material_type = gpu->addHighLevelShaderMaterialFromFiles( - (file_manager->getShaderDir() + "motion_blur.vert").c_str(), - "main", video::EVST_VS_2_0, - (file_manager->getShaderDir() + "motion_blur.frag").c_str(), - "main", video::EPST_PS_2_0, - this, video::EMT_SOLID); - m_blur_material.MaterialType = (E_MATERIAL_TYPE)material_type; - m_blur_material.setTexture(0, m_render_target); - m_blur_material.Wireframe = false; - m_blur_material.Lighting = false; - m_blur_material.ZWriteEnable = false; + // Load the MLAA area map + io::IReadFile *areamap = irr_driver->getDevice()->getFileSystem()-> + createMemoryReadFile((void *) AreaMap33, sizeof(AreaMap33), + "AreaMap33", false); + if (!areamap) Log::fatal("postprocessing", "Failed to load the areamap"); + m_areamap = irr_driver->getVideoDriver()->getTexture(areamap); + areamap->drop(); - } } // PostProcessing // ---------------------------------------------------------------------------- @@ -96,12 +73,15 @@ PostProcessing::~PostProcessing() */ void PostProcessing::reset() { - unsigned int n = Camera::getNumCameras(); + const u32 n = Camera::getNumCameras(); m_boost_time.resize(n); m_vertices.resize(n); m_center.resize(n); m_direction.resize(n); + MotionBlurProvider * const cb = (MotionBlurProvider *) irr_driver-> + getCallback(ES_MOTIONBLUR); + for(unsigned int i=0; isetDirection(i, m_direction[i].X, m_direction[i].Y); + cb->setMaxHeight(i, m_vertices[i].v1.TCoords.Y); } // for i + getCallback(ES_MOTIONBLUR); - bool any_boost = false; - for(unsigned int i=0; i0.0f; + const float tex_height = m_vertices[num].v1.TCoords.Y - m_vertices[num].v0.TCoords.Y; + m_center[num].Y = m_vertices[num].v0.TCoords.Y + y * tex_height; - // Don't capture the input when we have no post-processing to add - // it will be faster and this ay we won't lose anti-aliasing - if(!any_boost) - { - m_used_pp_this_frame = false; - return; - } - - m_used_pp_this_frame = true; - irr_driver->getVideoDriver()->setRenderTarget(m_render_target, true, true); -} // beginCapture + cb->setCenter(num, m_center[num].X, m_center[num].Y); +} // ---------------------------------------------------------------------------- -/** Restore the framebuffer render target. +/** Setup some PP data. */ -void PostProcessing::endCapture() +void PostProcessing::begin() { - if(!m_supported || !UserConfigParams::m_postprocess_enabled || - !m_used_pp_this_frame) - return; - - irr_driver->getVideoDriver()->setRenderTarget(video::ERT_FRAME_BUFFER, - true, true, 0); -} // endCapture + m_any_boost = false; + for (u32 i = 0; i < m_boost_time.size(); i++) + m_any_boost |= m_boost_time[i] > 0.01f; +} // beginCapture // ---------------------------------------------------------------------------- /** Set the boost amount according to the speed of the camera */ void PostProcessing::giveBoost(unsigned int camera_index) { m_boost_time[camera_index] = 0.75f; + + MotionBlurProvider * const cb = (MotionBlurProvider *) irr_driver-> + getCallback(ES_MOTIONBLUR); + cb->setBoostTime(camera_index, m_boost_time[camera_index]); } // giveBoost // ---------------------------------------------------------------------------- @@ -203,6 +174,9 @@ void PostProcessing::giveBoost(unsigned int camera_index) */ void PostProcessing::update(float dt) { + MotionBlurProvider * const cb = (MotionBlurProvider *) irr_driver-> + getCallback(ES_MOTIONBLUR); + for(unsigned int i=0; i 0.0f) @@ -210,68 +184,571 @@ void PostProcessing::update(float dt) m_boost_time[i] -= dt; if (m_boost_time[i] < 0.0f) m_boost_time[i] = 0.0f; } + + cb->setBoostTime(i, m_boost_time[i]); } } // update +// ---------------------------------------------------------------------------- +/** Render the post-processed scene, solids only, color to color, no stencil */ +void PostProcessing::renderSolid(const u32 cam) +{ + // Early out: do nothing if at all possible + if (UserConfigParams::m_ssao < 1 && !World::getWorld()->getTrack()->isFogEnabled()) + return; + + static u8 tick = 0; + + IVideoDriver * const drv = irr_driver->getVideoDriver(); + drv->setTransform(ETS_WORLD, core::IdentityMatrix); + drv->setTransform(ETS_VIEW, core::IdentityMatrix); + drv->setTransform(ETS_PROJECTION, core::IdentityMatrix); + + GaussianBlurProvider * const gacb = (GaussianBlurProvider *) irr_driver-> + getCallback(ES_GAUSSIAN3H); + + const TypeRTT curssao = tick ? RTT_SSAO2 : RTT_SSAO1; + + if (World::getWorld()->getTrack()->isFogEnabled()) + { + m_material.MaterialType = irr_driver->getShader(ES_FOG); + m_material.setTexture(0, irr_driver->getRTT(RTT_DEPTH)); + + // Overlay + m_material.BlendOperation = EBO_ADD; + m_material.MaterialTypeParam = pack_textureBlendFunc(EBF_SRC_ALPHA, EBF_ONE_MINUS_SRC_ALPHA); + + drv->setRenderTarget(irr_driver->getRTT(RTT_COLOR), false, false); + drawQuad(cam, m_material); + + m_material.BlendOperation = EBO_NONE; + m_material.MaterialTypeParam = 0; + } + + if (UserConfigParams::m_ssao == 1) // SSAO low + { + m_material.MaterialType = irr_driver->getShader(ES_SSAO); + m_material.setTexture(0, irr_driver->getRTT(RTT_NORMAL)); + m_material.setTexture(1, irr_driver->getRTT(tick ? RTT_SSAO1 : RTT_SSAO2)); + + drv->setRenderTarget(irr_driver->getRTT(curssao), true, false, + SColor(255, 255, 255, 255)); + + drawQuad(cam, m_material); + + // Blur it to reduce noise. + { + gacb->setResolution(UserConfigParams::m_width / 4, + UserConfigParams::m_height / 4); + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN3V); + m_material.setTexture(0, irr_driver->getRTT(curssao)); + drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER2), true, false); + + drawQuad(cam, m_material); + + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN3H); + m_material.setTexture(0, irr_driver->getRTT(RTT_QUARTER2)); + drv->setRenderTarget(irr_driver->getRTT(curssao), false, false); + + drawQuad(cam, m_material); + } + + // Overlay + m_material.MaterialType = EMT_ONETEXTURE_BLEND; + m_material.setTexture(0, irr_driver->getRTT(curssao)); + m_material.setTexture(1, 0); + m_material.BlendOperation = EBO_ADD; + m_material.MaterialTypeParam = pack_textureBlendFunc(EBF_DST_COLOR, EBF_ZERO); + + drv->setRenderTarget(irr_driver->getRTT(RTT_COLOR), false, false); + drawQuad(cam, m_material); + + m_material.BlendOperation = EBO_NONE; + m_material.MaterialTypeParam = 0; + + } else if (UserConfigParams::m_ssao == 2) // SSAO high + { + m_material.MaterialType = irr_driver->getShader(ES_SSAO); + m_material.setTexture(0, irr_driver->getRTT(RTT_NORMAL)); + m_material.setTexture(1, irr_driver->getRTT(tick ? RTT_SSAO1 : RTT_SSAO2)); + + drv->setRenderTarget(irr_driver->getRTT(curssao), true, false, + SColor(255, 255, 255, 255)); + + drawQuad(cam, m_material); + + // Blur it to reduce noise. + { + gacb->setResolution(UserConfigParams::m_width, + UserConfigParams::m_height); + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN6V); + m_material.setTexture(0, irr_driver->getRTT(curssao)); + drv->setRenderTarget(irr_driver->getRTT(RTT_TMP3), true, false); + + drawQuad(cam, m_material); + + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN6H); + m_material.setTexture(0, irr_driver->getRTT(RTT_TMP3)); + drv->setRenderTarget(irr_driver->getRTT(curssao), false, false); + + drawQuad(cam, m_material); + } + + // Overlay + m_material.MaterialType = EMT_ONETEXTURE_BLEND; + m_material.setTexture(0, irr_driver->getRTT(curssao)); + m_material.setTexture(1, 0); + m_material.BlendOperation = EBO_ADD; + m_material.MaterialTypeParam = pack_textureBlendFunc(EBF_DST_COLOR, EBF_ZERO); + + drv->setRenderTarget(irr_driver->getRTT(RTT_COLOR), false, false); + drawQuad(cam, m_material); + + m_material.BlendOperation = EBO_NONE; + m_material.MaterialTypeParam = 0; + } + + tick++; + tick %= 2; +} + // ---------------------------------------------------------------------------- /** Render the post-processed scene */ void PostProcessing::render() { - if(!m_supported || !UserConfigParams::m_postprocess_enabled) - return; + IVideoDriver * const drv = irr_driver->getVideoDriver(); + drv->setTransform(ETS_WORLD, core::IdentityMatrix); + drv->setTransform(ETS_VIEW, core::IdentityMatrix); + drv->setTransform(ETS_PROJECTION, core::IdentityMatrix); - if (!m_used_pp_this_frame) + MotionBlurProvider * const mocb = (MotionBlurProvider *) irr_driver-> + getCallback(ES_MOTIONBLUR); + GaussianBlurProvider * const gacb = (GaussianBlurProvider *) irr_driver-> + getCallback(ES_GAUSSIAN3H); + + const u32 cams = Camera::getNumCameras(); + for(u32 cam = 0; cam < cams; cam++) { - return; + scene::ICameraSceneNode * const camnode = + Camera::getCamera(cam)->getCameraSceneNode(); + mocb->setCurrentCamera(cam); + ITexture *in = irr_driver->getRTT(RTT_COLOR); + ITexture *out = irr_driver->getRTT(RTT_TMP1); + // Each effect uses these as named, and sets them up for the next effect. + // This allows chaining effects where some may be disabled. + + // As the original color shouldn't be touched, the first effect can't be disabled. + + if (1) // bloom + { + // Blit the base to tmp1 + m_material.MaterialType = EMT_SOLID; + m_material.setTexture(0, in); + drv->setRenderTarget(out, true, false); + + drawQuad(cam, m_material); + + const bool globalbloom = World::getWorld()->getTrack()->getBloom(); + + BloomPowerProvider * const bloomcb = (BloomPowerProvider *) + irr_driver-> + getCallback(ES_BLOOM_POWER); + + if (globalbloom) + { + const float threshold = World::getWorld()->getTrack()->getBloomThreshold(); + ((BloomProvider *) irr_driver->getCallback(ES_BLOOM))->setThreshold(threshold); + + // Catch bright areas, and progressively minify + m_material.MaterialType = irr_driver->getShader(ES_BLOOM); + m_material.setTexture(0, in); + drv->setRenderTarget(irr_driver->getRTT(RTT_TMP3), true, false); + + drawQuad(cam, m_material); + } + + // Do we have any forced bloom nodes? If so, draw them now + const std::vector &blooms = irr_driver->getForcedBloom(); + const u32 bloomsize = blooms.size(); + + if (!globalbloom && bloomsize) + drv->setRenderTarget(irr_driver->getRTT(RTT_TMP3), true, false); + + + if (globalbloom || bloomsize) + { + // Clear the alpha to a suitable value, stencil + glClearColor(0, 0, 0, 0.1); + glColorMask(0, 0, 0, 1); + + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glClearColor(0, 0, 0, 0); + glColorMask(1, 1, 1, 1); + + // The forced-bloom objects are drawn again, to know which pixels to pick. + // While it's more drawcalls, there's a cost to using four MRTs over three, + // and there shouldn't be many such objects in a track. + // The stencil is already in use for the glow. The alpha channel is best + // reserved for other use (specular, etc). + // + // They are drawn with depth and color writes off, giving 4x-8x drawing speed. + if (bloomsize) + { + const core::aabbox3df &cambox = camnode-> + getViewFrustum()-> + getBoundingBox(); + + irr_driver->getSceneManager()->setCurrentRendertime(ESNRP_SOLID); + SOverrideMaterial &overridemat = drv->getOverrideMaterial(); + overridemat.EnablePasses = ESNRP_SOLID; + overridemat.EnableFlags = EMF_MATERIAL_TYPE | EMF_ZWRITE_ENABLE | EMF_COLOR_MASK; + overridemat.Enabled = true; + + overridemat.Material.MaterialType = irr_driver->getShader(ES_BLOOM_POWER); + overridemat.Material.ZWriteEnable = false; + overridemat.Material.ColorMask = ECP_ALPHA; + + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 1, ~0); + glEnable(GL_STENCIL_TEST); + + camnode->render(); + + for (u32 i = 0; i < bloomsize; i++) + { + scene::ISceneNode * const cur = blooms[i].node; + + // Quick box-based culling + const core::aabbox3df nodebox = cur->getTransformedBoundingBox(); + if (!nodebox.intersectsWithBox(cambox)) + continue; + + bloomcb->setPower(blooms[i].power); + + cur->render(); + } + + // Second pass for transparents. No-op for solids. + irr_driver->getSceneManager()->setCurrentRendertime(ESNRP_TRANSPARENT); + for (u32 i = 0; i < bloomsize; i++) + { + scene::ISceneNode * const cur = blooms[i].node; + + // Quick box-based culling + const core::aabbox3df nodebox = cur->getTransformedBoundingBox(); + if (!nodebox.intersectsWithBox(cambox)) + continue; + + bloomcb->setPower(blooms[i].power); + + cur->render(); + } + + overridemat.Enabled = 0; + overridemat.EnablePasses = 0; + + // Ok, we have the stencil; now use it to blit from color to bloom tex + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, 1, ~0); + m_material.MaterialType = EMT_SOLID; + m_material.setTexture(0, irr_driver->getRTT(RTT_COLOR)); + + // Just in case. + glColorMask(1, 1, 1, 0); + drv->setRenderTarget(irr_driver->getRTT(RTT_TMP3), false, false); + + m_material.ColorMask = ECP_RGB; + drawQuad(cam, m_material); + m_material.ColorMask = ECP_ALL; + + glColorMask(1, 1, 1, 1); + glDisable(GL_STENCIL_TEST); + } // end forced bloom + + // To half + m_material.MaterialType = EMT_SOLID; + m_material.setTexture(0, irr_driver->getRTT(RTT_TMP3)); + drv->setRenderTarget(irr_driver->getRTT(RTT_HALF1), true, false); + + drawQuad(cam, m_material); + + // To quarter + m_material.MaterialType = EMT_SOLID; + m_material.setTexture(0, irr_driver->getRTT(RTT_HALF1)); + drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER1), true, false); + + drawQuad(cam, m_material); + + // To eighth + m_material.MaterialType = EMT_SOLID; + m_material.setTexture(0, irr_driver->getRTT(RTT_QUARTER1)); + drv->setRenderTarget(irr_driver->getRTT(RTT_EIGHTH1), true, false); + + drawQuad(cam, m_material); + + // Blur it for distribution. + { + gacb->setResolution(UserConfigParams::m_width / 8, + UserConfigParams::m_height / 8); + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN6V); + m_material.setTexture(0, irr_driver->getRTT(RTT_EIGHTH1)); + drv->setRenderTarget(irr_driver->getRTT(RTT_EIGHTH2), true, false); + + drawQuad(cam, m_material); + + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN6H); + m_material.setTexture(0, irr_driver->getRTT(RTT_EIGHTH2)); + drv->setRenderTarget(irr_driver->getRTT(RTT_EIGHTH1), false, false); + + drawQuad(cam, m_material); + } + + // Additively blend on top of tmp1 + m_material.BlendOperation = EBO_ADD; + m_material.MaterialType = irr_driver->getShader(ES_BLOOM_BLEND); + m_material.setTexture(0, irr_driver->getRTT(RTT_EIGHTH1)); + drv->setRenderTarget(out, false, false); + + drawQuad(cam, m_material); + + m_material.BlendOperation = EBO_NONE; + } // end if bloom + + in = irr_driver->getRTT(RTT_TMP1); + out = irr_driver->getRTT(RTT_TMP2); + } + + if (World::getWorld()->getTrack()->hasGodRays() && m_sunpixels > 30) // god rays + { + // Grab the sky + drv->setRenderTarget(out, true, false); + irr_driver->getSceneManager()->drawAll(ESNRP_SKY_BOX); + + // Set the sun's color + ColorizeProvider * const colcb = (ColorizeProvider *) irr_driver->getCallback(ES_COLORIZE); + const SColor col = World::getWorld()->getTrack()->getSunColor(); + colcb->setColor(col.getRed() / 255.0f, col.getGreen() / 255.0f, col.getBlue() / 255.0f); + + // The sun interposer + IMeshSceneNode * const sun = irr_driver->getSunInterposer(); + sun->getMaterial(0).ColorMask = ECP_ALL; + irr_driver->getSceneManager()->drawAll(ESNRP_CAMERA); + irr_driver->getSceneManager()->setCurrentRendertime(ESNRP_SOLID); + + sun->render(); + + sun->getMaterial(0).ColorMask = ECP_NONE; + + // Fade to quarter + m_material.MaterialType = irr_driver->getShader(ES_GODFADE); + m_material.setTexture(0, out); + drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER1), false, false); + + drawQuad(cam, m_material); + + // Blur + { + gacb->setResolution(UserConfigParams::m_width / 4, + UserConfigParams::m_height / 4); + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN3V); + m_material.setTexture(0, irr_driver->getRTT(RTT_QUARTER1)); + drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER2), true, false); + + drawQuad(cam, m_material); + + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN3H); + m_material.setTexture(0, irr_driver->getRTT(RTT_QUARTER2)); + drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER1), false, false); + + drawQuad(cam, m_material); + } + + // Calculate the sun's position in texcoords + const core::vector3df pos = sun->getPosition(); + float ndc[4]; + core::matrix4 trans = camnode->getProjectionMatrix(); + trans *= camnode->getViewMatrix(); + + trans.transformVect(ndc, pos); + + const float texh = m_vertices[cam].v1.TCoords.Y - m_vertices[cam].v0.TCoords.Y; + const float texw = m_vertices[cam].v3.TCoords.X - m_vertices[cam].v0.TCoords.X; + + const float sunx = ((ndc[0] / ndc[3]) * 0.5f + 0.5f) * texw; + const float suny = ((ndc[1] / ndc[3]) * 0.5f + 0.5f) * texh; + + ((GodRayProvider *) irr_driver->getCallback(ES_GODRAY))-> + setSunPosition(sunx, suny); + + // Rays please + m_material.MaterialType = irr_driver->getShader(ES_GODRAY); + m_material.setTexture(0, irr_driver->getRTT(RTT_QUARTER1)); + drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER2), true, false); + + drawQuad(cam, m_material); + + // Blur + { + gacb->setResolution(UserConfigParams::m_width / 4, + UserConfigParams::m_height / 4); + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN3V); + m_material.setTexture(0, irr_driver->getRTT(RTT_QUARTER2)); + drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER1), true, false); + + drawQuad(cam, m_material); + + m_material.MaterialType = irr_driver->getShader(ES_GAUSSIAN3H); + m_material.setTexture(0, irr_driver->getRTT(RTT_QUARTER1)); + drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER2), false, false); + + drawQuad(cam, m_material); + } + + // Overlay + m_material.MaterialType = EMT_TRANSPARENT_ADD_COLOR; + m_material.setTexture(0, irr_driver->getRTT(RTT_QUARTER2)); + drv->setRenderTarget(in, false, false); + + drawQuad(cam, m_material); + } + + if (UserConfigParams::m_motionblur && m_any_boost) // motion blur + { + // Calculate the kart's Y position on screen + const core::vector3df pos = + Camera::getCamera(cam)->getKart()->getNode()->getPosition(); + float ndc[4]; + core::matrix4 trans = camnode->getProjectionMatrix(); + trans *= camnode->getViewMatrix(); + + trans.transformVect(ndc, pos); + const float karty = (ndc[1] / ndc[3]) * 0.5f + 0.5f; + setMotionBlurCenterY(cam, karty); + + + m_material.MaterialType = irr_driver->getShader(ES_MOTIONBLUR); + m_material.setTexture(0, in); + drv->setRenderTarget(out, true, false); + + drawQuad(cam, m_material); + + ITexture *tmp = in; + in = out; + out = tmp; + } + + if (irr_driver->getDisplacingNodes().size()) // Displacement + { + m_material.MaterialType = irr_driver->getShader(ES_PPDISPLACE); + m_material.setFlag(EMF_BILINEAR_FILTER, false); + m_material.setTexture(0, in); + m_material.setTexture(1, irr_driver->getRTT(RTT_DISPLACE)); + drv->setRenderTarget(out, true, false); + + drawQuad(cam, m_material); + + m_material.setTexture(1, 0); + m_material.setFlag(EMF_BILINEAR_FILTER, true); + + ITexture *tmp = in; + in = out; + out = tmp; + } + + if (UserConfigParams::m_mlaa) // MLAA. Must be the last pp filter. + { + drv->setRenderTarget(out, false, false); + + glEnable(GL_STENCIL_TEST); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glStencilFunc(GL_ALWAYS, 1, ~0); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + // Pass 1: color edge detection + m_material.setFlag(EMF_BILINEAR_FILTER, false); + m_material.setFlag(EMF_TRILINEAR_FILTER, false); + m_material.MaterialType = irr_driver->getShader(ES_MLAA_COLOR1); + m_material.setTexture(0, in); + + drawQuad(cam, m_material); + m_material.setFlag(EMF_BILINEAR_FILTER, true); + m_material.setFlag(EMF_TRILINEAR_FILTER, true); + + glStencilFunc(GL_EQUAL, 1, ~0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + // Pass 2: blend weights + drv->setRenderTarget(irr_driver->getRTT(RTT_TMP3), true, false); + + m_material.MaterialType = irr_driver->getShader(ES_MLAA_BLEND2); + m_material.setTexture(0, out); + m_material.setTexture(1, m_areamap); + m_material.TextureLayer[1].BilinearFilter = false; + m_material.TextureLayer[1].TrilinearFilter = false; + + drawQuad(cam, m_material); + + m_material.TextureLayer[1].BilinearFilter = true; + m_material.TextureLayer[1].TrilinearFilter = true; + m_material.setTexture(1, 0); + + // Pass 3: gather + drv->setRenderTarget(in, false, false); + + m_material.setFlag(EMF_BILINEAR_FILTER, false); + m_material.setFlag(EMF_TRILINEAR_FILTER, false); + m_material.MaterialType = irr_driver->getShader(ES_MLAA_NEIGH3); + m_material.setTexture(0, irr_driver->getRTT(RTT_TMP3)); + m_material.setTexture(1, irr_driver->getRTT(RTT_COLOR)); + + drawQuad(cam, m_material); + + m_material.setFlag(EMF_BILINEAR_FILTER, true); + m_material.setFlag(EMF_TRILINEAR_FILTER, true); + m_material.setTexture(1, 0); + + // Done. + glDisable(GL_STENCIL_TEST); + } + + // Final blit + + if (irr_driver->getNormals()) + { + m_material.MaterialType = irr_driver->getShader(ES_FLIP); + m_material.setTexture(0, irr_driver->getRTT(RTT_NORMAL)); + } else if (irr_driver->getSSAOViz()) + { + m_material.MaterialType = irr_driver->getShader(ES_FLIP); + m_material.setTexture(0, irr_driver->getRTT(RTT_SSAO1)); + } else if (irr_driver->getShadowViz()) + { + m_material.MaterialType = irr_driver->getShader(ES_FLIP); + m_material.setTexture(0, irr_driver->getRTT(RTT_SHADOW)); + } else + { + m_material.MaterialType = irr_driver->getShader(ES_FLIP); + m_material.setTexture(0, in); + } + + drv->setRenderTarget(ERT_FRAME_BUFFER, false, false); + + drawQuad(cam, m_material); } - - u16 indices[6] = {0, 1, 2, 3, 0, 2}; - - for(m_current_camera=0; m_current_cameragetVideoDriver(); - video_driver->setMaterial(m_blur_material); - video_driver->drawIndexedTriangleList(&(m_vertices[m_current_camera].v0), - 4, &indices[0], 2); - } - } // render -// ---------------------------------------------------------------------------- -/** Implement IShaderConstantsSetCallback. Shader constants setter for - * post-processing */ -void PostProcessing::OnSetConstants(video::IMaterialRendererServices *services, - s32 user_data) +void PostProcessing::drawQuad(u32 cam, const SMaterial &mat) { - // We need the maximum texture coordinates: - float max_tex_height = m_vertices[m_current_camera].v1.TCoords.Y; - services->setPixelShaderConstant("max_tex_height", &max_tex_height, 1); + const u16 indices[6] = {0, 1, 2, 3, 0, 2}; + IVideoDriver * const drv = irr_driver->getVideoDriver(); - // Scale the boost time to get a usable boost amount: - float boost_amount = m_boost_time[m_current_camera] * 0.7f; + drv->setTransform(ETS_WORLD, core::IdentityMatrix); + drv->setTransform(ETS_VIEW, core::IdentityMatrix); + drv->setTransform(ETS_PROJECTION, core::IdentityMatrix); - // Especially for single screen the top of the screen is less blurred - // in the fragment shader by multiplying the blurr factor by - // (max_tex_height - texcoords.t), where max_tex_height is the maximum - // texture coordinate (1.0 or 0.5). In split screen this factor is too - // small (half the value compared with non-split screen), so we - // multiply this by 2. - if(m_boost_time.size()>1) - boost_amount *= 2.0f; - - services->setPixelShaderConstant("boost_amount", &boost_amount, 1); - services->setPixelShaderConstant("center", - &(m_center[m_current_camera].X), 2); - services->setPixelShaderConstant("direction", - &(m_direction[m_current_camera].X), 2); - - // Use a radius of 0.15 when showing a single kart, otherwise (2-4 karts - // on splitscreen) use only 0.75. - float radius = Camera::getNumCameras()==1 ? 0.15f : 0.075f; - services->setPixelShaderConstant("mask_radius", &radius, 1); - const int texunit = 0; - services->setPixelShaderConstant("color_buffer", &texunit, 1); -} // OnSetConstants + drv->setMaterial(mat); + drv->drawIndexedTriangleList(&(m_vertices[cam].v0), + 4, indices, 2); +} diff --git a/src/graphics/post_processing.hpp b/src/graphics/post_processing.hpp index e9145e865..020cb3ffc 100644 --- a/src/graphics/post_processing.hpp +++ b/src/graphics/post_processing.hpp @@ -33,61 +33,58 @@ using namespace irr; /** \brief Handles post processing, eg motion blur * \ingroup graphics */ -class PostProcessing : public video::IShaderConstantSetCallBack +class PostProcessing: public IReferenceCounted { private: - video::ITexture *m_render_target; - /** Material to be used when blurring is used. */ - video::SMaterial m_blur_material; - - bool m_supported; + video::SMaterial m_material; /** Boost time, how long the boost should be displayed. This also * affects the strength of the effect: longer boost time will * have a stronger effect. */ std::vector m_boost_time; + bool m_any_boost; + /** The center of blurring, in texture coordinates [0,1]).*/ std::vector m_center; /** The center to which the blurring is aimed at, in [0,1]. */ std::vector m_direction; - /** True if any of the cameras is using post processing. */ - bool m_used_pp_this_frame; - - /** Currently active camera during post-processing, needed in the - * OnSetConstants callback. */ - unsigned int m_current_camera; - - struct Quad { video::S3DVertex v0, v1, v2, v3; }; /** The vertices for the rectangle used for each camera. This includes * the vertex position, normal, and texture coordinate. */ std::vector m_vertices; + video::ITexture *m_areamap; + + u32 m_sunpixels; + + void setMotionBlurCenterY(const u32 num, const float y); + public: PostProcessing(video::IVideoDriver* video_driver); virtual ~PostProcessing(); void reset(); /** Those should be called around the part where we render the scene to be post-processed */ - void beginCapture(); - void endCapture(); + void begin(); void update(float dt); + /** Render the post-processed scene, solids only, color to color, no stencil */ + void renderSolid(const u32 cam); + /** Render the post-processed scene */ void render(); - /** Is the hardware able to use post-processing? */ - inline bool isSupported() const {return m_supported;} + /** Draw the quad for this camera */ + void drawQuad(u32 cam, const video::SMaterial &mat); /** Use motion blur for a short time */ void giveBoost(unsigned int cam_index); - /** Implement IShaderConstantsSetCallback. Shader constants setter for post-processing */ - virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 user_data); + void setSunPixels(const u32 in) { m_sunpixels = in; } }; #endif // HEADER_POST_PROCESSING_HPP diff --git a/src/graphics/rain.cpp b/src/graphics/rain.cpp index 27945a5c8..9d0127872 100644 --- a/src/graphics/rain.cpp +++ b/src/graphics/rain.cpp @@ -18,28 +18,117 @@ #include "audio/sfx_base.hpp" #include "audio/sfx_manager.hpp" +#include "graphics/glwrap.hpp" #include "graphics/irr_driver.hpp" #include "graphics/material_manager.hpp" #include "graphics/material.hpp" #include "graphics/per_camera_node.hpp" #include "graphics/rain.hpp" +#include "graphics/shaders.hpp" #include "modes/world.hpp" #include "states_screens/race_gui.hpp" #include "utils/constants.hpp" #include "utils/random_generator.hpp" +#include #include -#include -const float RAIN_RADIUS[RAIN_RING_COUNT] = { 1.0f, 3.0f, 6.0f, 12.0f, 24.0f }; -const float RAIN_Y_TO = 25.0f; -const float RAIN_Y_FROM = -10.0f; -const float RAIN_DY = 2.5f; -const float RAIN_DX = 0.0f; +using namespace video; +using namespace scene; +using namespace core; -const float TEXTURE_X_TILES[RAIN_RING_COUNT] = { 2.0f, 2.5f, 3.5f, 5.0f, 8.0f }; -const float TEXTURE_Y_TILES[RAIN_RING_COUNT] = { 8.0f, 7.0f, 6.0f, 4.0f, 4.0f }; +// The actual rain node +class RainNode: public scene::ISceneNode +{ +public: + RainNode(scene::ISceneManager* mgr, ITexture *tex) + : scene::ISceneNode(0, mgr, -1) + { + mat.Lighting = false; + mat.ZWriteEnable = false; + mat.MaterialType = irr_driver->getShader(ES_RAIN); + mat.Thickness = 200; + mat.BlendOperation = EBO_ADD; + mat.setTexture(0, tex); + mat.TextureLayer[0].TextureWrapU = + mat.TextureLayer[0].TextureWrapV = ETC_CLAMP_TO_EDGE; + + count = 2500; + area = 3500; + + // Fill in the mesh buffer + buf.Vertices.clear(); + buf.Indices.clear(); + + buf.Vertices.set_used(count); + buf.Indices.set_used(count); + + buf.Primitive = EPT_POINT_SPRITES; + buf.setHardwareMappingHint(EHM_STATIC); + + u32 i; + float x, y, z; + for (i = 0; i < count; i++) + { + x = ((rand() % area) - area/2) / 100.0f; + y = ((rand() % 2400)) / 100.0f; + z = ((rand() % area) - area/2) / 100.0f; + + buf.Indices[i] = i; + buf.Vertices[i] = S3DVertex(x, y, z, 0, 0, 0, SColor(255, 255, 0, 0), 0, 0); + } + + box.addInternalPoint(vector3df(-area/2)); + box.addInternalPoint(vector3df(area/2)); + } + + ~RainNode() + { + } + + virtual void render() + { + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + + IVideoDriver * const drv = irr_driver->getVideoDriver(); + drv->setTransform(ETS_WORLD, AbsoluteTransformation); + drv->setMaterial(mat); + + drv->drawMeshBuffer(&buf); + + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); + } + + virtual const core::aabbox3d& getBoundingBox() const + { + return box; + } + + virtual void OnRegisterSceneNode() + { + if (IsVisible && + (irr_driver->getRenderPass() & ESNRP_TRANSPARENT) == ESNRP_TRANSPARENT) + { + SceneManager->registerNodeForRendering(this, ESNRP_TRANSPARENT); + } + + ISceneNode::OnRegisterSceneNode(); + } + + virtual u32 getMaterialCount() const { return 1; } + virtual video::SMaterial& getMaterial(u32 i) { return mat; } + +private: + video::SMaterial mat; + core::aabbox3d box; + u32 count; + s32 area; + + scene::SMeshBuffer buf; +}; + +// The rain manager Rain::Rain(Camera *camera, irr::scene::ISceneNode* parent) { @@ -54,80 +143,17 @@ Rain::Rain(Camera *camera, irr::scene::ISceneNode* parent) RandomGenerator g; m_next_lightning = (float)g.get(35); - for (int r=0; rMaterial.setTexture(0, m->getTexture()); - m->setMaterialProperties(&buffer->Material, NULL); - buffer->Material.ZWriteEnable = false; - buffer->Material.BackfaceCulling = false; - - m_materials.push_back(&buffer->Material); - - video::S3DVertex v; - v.Color.set(255,255,255,255); - - // create a cylinder mesh - const int VERTICES = 17; - - for (int vid=0; vidVertices.push_back(v); - - v.Pos.Y = RAIN_Y_FROM; - - v.TCoords.Y = 0.0f; - buffer->Vertices.push_back(v); - - if (vid > 0) - { - buffer->Indices.push_back(vid-2); - buffer->Indices.push_back(vid-1); - buffer->Indices.push_back(vid); - buffer->Indices.push_back(vid-1); - buffer->Indices.push_back(vid); - buffer->Indices.push_back(vid+1); - } - } - - scene::SMesh* mesh = new scene::SMesh(); - mesh->addMeshBuffer(buffer); - mesh->recalculateBoundingBox(); - - m_node[r] = irr_driver->addPerCameraMesh(mesh, - camera->getCameraSceneNode(), - parent); - m_node[r]->setAutomaticCulling(0); - mesh->drop(); - - buffer->drop(); - } + RainNode *node = new RainNode(irr_driver->getSceneManager(), m->getTexture()); + m_node = irr_driver->addPerCameraNode(node, camera->getCameraSceneNode(), parent); + m_node->setAutomaticCulling(0); } // Rain // ---------------------------------------------------------------------------- Rain::~Rain() { - for (int r=0; rdrop(); // drop STK's reference - m_node[r]->remove(); // Then remove it from the scene graph. - } + m_node->drop(); // drop STK's reference + m_node->remove(); // Then remove it from the scene graph. if (m_lightning && m_thunder_sound != NULL) sfx_manager->deleteSFX(m_thunder_sound); } @@ -136,19 +162,6 @@ Rain::~Rain() void Rain::update(float dt) { - //const int count = m_materials.size(); - for (int m=0; m 1.0f) m_x[m] = fmod(m_x[m], 1.0f); - if (m_y[m] > 1.0f) m_y[m] = fmod(m_y[m], 1.0f); - - core::matrix4& matrix = m_node[m]->getChild()->getMaterial(0).getTextureMatrix(0); - - matrix.setTextureTranslate(m_x[m], m_y[m]); - } - if (m_lightning) { m_next_lightning -= dt; @@ -173,15 +186,12 @@ void Rain::update(float dt) void Rain::setPosition(const core::vector3df& position) { - for (int m=0; mgetChild()->setPosition(position); - } + m_node->getChild()->setPosition(position); } // setPosition // ---------------------------------------------------------------------------- void Rain::setCamera(scene::ICameraSceneNode* camera) { - for (int n=0; nsetCamera(camera); + m_node->setCamera(camera); } diff --git a/src/graphics/rain.hpp b/src/graphics/rain.hpp index b05fa2c60..b8408c2a8 100644 --- a/src/graphics/rain.hpp +++ b/src/graphics/rain.hpp @@ -25,23 +25,16 @@ class PerCameraNode; #include namespace irr { - namespace video { class SMaterial; } + namespace video { class SMaterial; class ITexture; } namespace scene { class ICameraSceneNode; class ISceneNode; } } using namespace irr; -const int RAIN_RING_COUNT = 5; - class SFXBase; class Rain { - PerCameraNode* m_node[RAIN_RING_COUNT]; - - std::vector m_materials; - - float m_x[RAIN_RING_COUNT]; - float m_y[RAIN_RING_COUNT]; + PerCameraNode* m_node; float m_next_lightning; bool m_lightning; @@ -49,7 +42,7 @@ class Rain public: Rain(Camera* camera, irr::scene::ISceneNode* parent); - ~Rain(); + virtual ~Rain(); void update(float dt); void setPosition(const irr::core::vector3df& position); diff --git a/src/graphics/referee.cpp b/src/graphics/referee.cpp index 021925085..4579991cc 100644 --- a/src/graphics/referee.cpp +++ b/src/graphics/referee.cpp @@ -173,6 +173,8 @@ Referee::Referee() m_scene_node->setScale(m_st_scale.toIrrVector()); m_scene_node->setFrameLoop(m_st_first_start_frame, m_st_last_start_frame); + + irr_driver->applyObjectPassShader(m_scene_node); } // Referee // ---------------------------------------------------------------------------- @@ -197,6 +199,8 @@ Referee::Referee(const AbstractKart &kart) m_scene_node->setPosition(core::vector3df(0, kart.getKartHeight() + 0.4f, 0)); m_scene_node->setFrameLoop(m_st_first_rescue_frame, m_st_last_rescue_frame); + + irr_driver->applyObjectPassShader(m_scene_node); } // Referee // ---------------------------------------------------------------------------- diff --git a/src/graphics/referee.hpp b/src/graphics/referee.hpp index 98c10b17b..93941f051 100644 --- a/src/graphics/referee.hpp +++ b/src/graphics/referee.hpp @@ -19,7 +19,10 @@ #ifndef HEADER_REFEREE_HPP #define HEADER_REFEREE_HPP -#include "irrlicht.h" +#include +#include +#include +#include using namespace irr; #include "utils/vec3.hpp" diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp new file mode 100644 index 000000000..d4531d9b4 --- /dev/null +++ b/src/graphics/render.cpp @@ -0,0 +1,826 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009 Joerg Henrichs +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/irr_driver.hpp" + +#include "config/user_config.hpp" +#include "graphics/callbacks.hpp" +#include "graphics/camera.hpp" +#include "graphics/glow.hpp" +#include "graphics/glwrap.hpp" +#include "graphics/lens_flare.hpp" +#include "graphics/light.hpp" +#include "graphics/lod_node.hpp" +#include "graphics/material_manager.hpp" +#include "graphics/particle_kind_manager.hpp" +#include "graphics/per_camera_node.hpp" +#include "graphics/post_processing.hpp" +#include "graphics/referee.hpp" +#include "graphics/rtts.hpp" +#include "graphics/screenquad.hpp" +#include "graphics/shaders.hpp" +#include "graphics/shadow_importance.hpp" +#include "graphics/wind.hpp" +#include "io/file_manager.hpp" +#include "items/item.hpp" +#include "items/item_manager.hpp" +#include "modes/world.hpp" +#include "physics/physics.hpp" +#include "tracks/track.hpp" +#include "utils/constants.hpp" +#include "utils/helpers.hpp" +#include "utils/log.hpp" +#include "utils/profiler.hpp" + +void IrrDriver::renderGLSL(float dt) +{ + World *world = World::getWorld(); // Never NULL. + + // Overrides + video::SOverrideMaterial &overridemat = m_video_driver->getOverrideMaterial(); + overridemat.EnablePasses = scene::ESNRP_SOLID | scene::ESNRP_TRANSPARENT; + overridemat.EnableFlags = 0; + + if (m_wireframe) + { + overridemat.Material.Wireframe = 1; + overridemat.EnableFlags |= video::EMF_WIREFRAME; + } + if (m_mipviz) + { + overridemat.Material.MaterialType = m_shaders->getShader(ES_MIPVIZ); + overridemat.EnableFlags |= video::EMF_MATERIAL_TYPE; + overridemat.EnablePasses = scene::ESNRP_SOLID; + } + + // Get a list of all glowing things. The driver's list contains the static ones, + // here we add items, as they may disappear each frame. + std::vector glows = m_glowing; + std::vector transparent_glow_nodes; + + ItemManager * const items = ItemManager::get(); + const u32 itemcount = items->getNumberOfItems(); + u32 i; + + // For each static node, give it a glow representation + const u32 staticglows = glows.size(); + for (i = 0; i < staticglows; i++) + { + scene::ISceneNode * const node = glows[i].node; + + const float radius = (node->getBoundingBox().getExtent().getLength() / 2) * 2.0f; + GlowNode * const repnode = new GlowNode(irr_driver->getSceneManager(), radius); + repnode->setPosition(node->getTransformedBoundingBox().getCenter()); + transparent_glow_nodes.push_back(repnode); + } + + for (i = 0; i < itemcount; i++) + { + Item * const item = items->getItem(i); + if (!item) continue; + const Item::ItemType type = item->getType(); + + if (type != Item::ITEM_NITRO_BIG && type != Item::ITEM_NITRO_SMALL && + type != Item::ITEM_BONUS_BOX) + continue; + + LODNode * const lod = (LODNode *) item->getSceneNode(); + if (!lod->isVisible()) continue; + + const int level = lod->getLevel(); + if (level < 0) continue; + + scene::ISceneNode * const node = lod->getAllNodes()[level]; + node->updateAbsolutePosition(); + + GlowData dat; + dat.node = node; + + dat.r = 1.0f; + dat.g = 1.0f; + dat.b = 1.0f; + + // Item colors + switch (type) + { + case Item::ITEM_NITRO_BIG: + case Item::ITEM_NITRO_SMALL: + dat.r = stk_config->m_nitro_glow_color[0]; + dat.g = stk_config->m_nitro_glow_color[1]; + dat.b = stk_config->m_nitro_glow_color[2]; + break; + case Item::ITEM_BONUS_BOX: + dat.r = stk_config->m_box_glow_color[0]; + dat.g = stk_config->m_box_glow_color[1]; + dat.b = stk_config->m_box_glow_color[2]; + break; + default: + Log::fatal("render", "Unknown item type got through"); + break; + } + + glows.push_back(dat); + + // Push back its representation too + const float radius = (node->getBoundingBox().getExtent().getLength() / 2) * 2.0f; + GlowNode * const repnode = new GlowNode(irr_driver->getSceneManager(), radius); + repnode->setPosition(node->getTransformedBoundingBox().getCenter()); + transparent_glow_nodes.push_back(repnode); + } + + // Start the RTT for post-processing. + // We do this before beginScene() because we want to capture the glClear() + // because of tracks that do not have skyboxes (generally add-on tracks) + m_post_processing->begin(); + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_COLOR), false, false); + + m_video_driver->beginScene(/*backBuffer clear*/ true, /*zBuffer*/ true, + world->getClearColor()); + + // Clear normal and depth to zero + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_NORMAL), true, false, video::SColor(0,0,0,0)); + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_DEPTH), true, false, video::SColor(0,0,0,0)); + + irr_driver->getVideoDriver()->enableMaterial2D(); + RaceGUIBase *rg = world->getRaceGUI(); + if (rg) rg->update(dt); + + + for(unsigned int cam = 0; cam < Camera::getNumCameras(); cam++) + { + Camera * const camera = Camera::getCamera(cam); + scene::ICameraSceneNode * const camnode = camera->getCameraSceneNode(); + +#ifdef ENABLE_PROFILER + std::ostringstream oss; + oss << "drawAll() for kart " << cam << std::flush; + PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), (cam+1)*60, + 0x00, 0x00); +#endif + camera->activate(); + rg->preRenderCallback(camera); // adjusts start referee + + const u32 bgnodes = m_background.size(); + if (bgnodes) + { + // If there are background nodes (3d skybox), draw them now. + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_COLOR), false, false); + + m_renderpass = scene::ESNRP_SKY_BOX; + m_scene_manager->drawAll(m_renderpass); + + const video::SOverrideMaterial prev = overridemat; + overridemat.Enabled = 1; + overridemat.EnableFlags = video::EMF_MATERIAL_TYPE; + overridemat.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + + for (i = 0; i < bgnodes; i++) + { + m_background[i]->setPosition(camnode->getPosition() * 0.97f); + m_background[i]->updateAbsolutePosition(); + m_background[i]->render(); + } + + overridemat = prev; + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_COLOR), false, true); + } + + // Fire up the MRT + m_video_driver->setRenderTarget(m_mrt, false, false); + + m_renderpass = scene::ESNRP_CAMERA | scene::ESNRP_SOLID; + m_scene_manager->drawAll(m_renderpass); + + ShadowImportanceProvider * const sicb = (ShadowImportanceProvider *) + irr_driver->getCallback(ES_SHADOW_IMPORTANCE); + sicb->updateIPVMatrix(); + + // Used to cull glowing items & lights + const core::aabbox3df cambox = camnode->getViewFrustum()->getBoundingBox(); + + // Render anything glowing. + if (!m_mipviz && !m_wireframe) + { + m_scene_manager->setCurrentRendertime(scene::ESNRP_SOLID); + + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_TMP1), false, false); + glClearColor(0, 0, 0, 0); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + const u32 glowcount = glows.size(); + ColorizeProvider * const cb = (ColorizeProvider *) m_shaders->m_callbacks[ES_COLORIZE]; + + GlowProvider * const glowcb = (GlowProvider *) m_shaders->m_callbacks[ES_GLOW]; + glowcb->setResolution(UserConfigParams::m_width, + UserConfigParams::m_height); + + overridemat.Material.MaterialType = m_shaders->getShader(ES_COLORIZE); + overridemat.EnableFlags = video::EMF_MATERIAL_TYPE; + overridemat.EnablePasses = scene::ESNRP_SOLID; + overridemat.Enabled = true; + + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 1, ~0); + glEnable(GL_STENCIL_TEST); + + for (u32 i = 0; i < glowcount; i++) + { + const GlowData &dat = glows[i]; + scene::ISceneNode * const cur = dat.node; + + // Quick box-based culling + const core::aabbox3df nodebox = cur->getTransformedBoundingBox(); + if (!nodebox.intersectsWithBox(cambox)) + continue; + + cb->setColor(dat.r, dat.g, dat.b); + cur->render(); + } + + // Second round for transparents; it's a no-op for solids + m_scene_manager->setCurrentRendertime(scene::ESNRP_TRANSPARENT); + overridemat.Material.MaterialType = m_shaders->getShader(ES_COLORIZE_REF); + for (u32 i = 0; i < glowcount; i++) + { + const GlowData &dat = glows[i]; + scene::ISceneNode * const cur = dat.node; + + // Quick box-based culling + const core::aabbox3df nodebox = cur->getTransformedBoundingBox(); + if (!nodebox.intersectsWithBox(cambox)) + continue; + + cb->setColor(dat.r, dat.g, dat.b); + cur->render(); + } + overridemat.Enabled = false; + overridemat.EnablePasses = 0; + + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glDisable(GL_STENCIL_TEST); + + // Cool, now we have the colors set up. Progressively minify. + video::SMaterial minimat; + minimat.Lighting = false; + minimat.ZWriteEnable = false; + minimat.ZBuffer = video::ECFN_ALWAYS; + minimat.setFlag(video::EMF_TRILINEAR_FILTER, true); + + minimat.TextureLayer[0].TextureWrapU = + minimat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + + // To half + minimat.setTexture(0, m_rtts->getRTT(RTT_TMP1)); + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_HALF1), false, false); + m_post_processing->drawQuad(cam, minimat); + + // To quarter + minimat.setTexture(0, m_rtts->getRTT(RTT_HALF1)); + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_QUARTER1), false, false); + m_post_processing->drawQuad(cam, minimat); + + // Blur it + ((GaussianBlurProvider *) m_shaders->m_callbacks[ES_GAUSSIAN3H])->setResolution( + UserConfigParams::m_width / 4, + UserConfigParams::m_height / 4); + + minimat.MaterialType = m_shaders->getShader(ES_GAUSSIAN6H); + minimat.setTexture(0, m_rtts->getRTT(RTT_QUARTER1)); + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_QUARTER2), false, false); + m_post_processing->drawQuad(cam, minimat); + + minimat.MaterialType = m_shaders->getShader(ES_GAUSSIAN6V); + minimat.setTexture(0, m_rtts->getRTT(RTT_QUARTER2)); + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_QUARTER1), false, false); + m_post_processing->drawQuad(cam, minimat); + + // The glows will be rendered in the transparent phase + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_COLOR), false, false); + + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glDisable(GL_STENCIL_TEST); + } // end glow + + // Shadows + if (!m_mipviz && !m_wireframe && UserConfigParams::m_shadows && + World::getWorld()->getTrack()->hasShadows()) + { + m_scene_manager->setCurrentRendertime(scene::ESNRP_SOLID); + static u8 tick = 0; + + const Vec3 *vmin, *vmax; + World::getWorld()->getTrack()->getAABB(&vmin, &vmax); + core::aabbox3df trackbox(vmin->toIrrVector(), vmax->toIrrVector() - + core::vector3df(0, 30, 0)); + + const float oldfar = camnode->getFarValue(); + camnode->setFarValue(std::min(100.0f, oldfar)); + camnode->render(); + const core::aabbox3df smallcambox = camnode-> + getViewFrustum()->getBoundingBox(); + camnode->setFarValue(oldfar); + camnode->render(); + + // Set up a nice ortho projection that contains our camera frustum + core::matrix4 ortho; + core::aabbox3df box = smallcambox; + box = box.intersect(trackbox); + + m_suncam->getViewMatrix().transformBoxEx(box); + m_suncam->getViewMatrix().transformBoxEx(trackbox); + + core::vector3df extent = trackbox.getExtent(); + const float w = fabsf(extent.X); + const float h = fabsf(extent.Y); + float z = box.MaxEdge.Z; + + // Snap to texels + const float units_per_w = w / m_rtts->getRTT(RTT_SHADOW)->getSize().Width; + const float units_per_h = h / m_rtts->getRTT(RTT_SHADOW)->getSize().Height; + + float left = box.MinEdge.X; + float right = box.MaxEdge.X; + float up = box.MaxEdge.Y; + float down = box.MinEdge.Y; + + left -= fmodf(left, units_per_w); + right -= fmodf(right, units_per_w); + up -= fmodf(up, units_per_h); + down -= fmodf(down, units_per_h); + z -= fmodf(z, 0.5f); + + // FIXME: quick and dirt (and wrong) workaround to avoid division by zero + if (left == right) right += 0.1f; + if (up == down) down += 0.1f; + if (z == 30) z += 0.1f; + + ortho.buildProjectionMatrixOrthoLH(left, right, + up, down, + 30, z); + + m_suncam->setProjectionMatrix(ortho, true); + m_scene_manager->setActiveCamera(m_suncam); + m_suncam->render(); + + ortho *= m_suncam->getViewMatrix(); + ((SunLightProvider *) m_shaders->m_callbacks[ES_SUNLIGHT])->setShadowMatrix(ortho); + sicb->setShadowMatrix(ortho); + + overridemat.Enabled = 0; + + // Render the importance map + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_COLLAPSE), true, true); + + m_shadow_importance->render(); + + CollapseProvider * const colcb = (CollapseProvider *) + m_shaders-> + m_callbacks[ES_COLLAPSE]; + ScreenQuad sq(m_video_driver); + sq.setMaterialType(m_shaders->getShader(ES_COLLAPSE)); + sq.setTexture(m_rtts->getRTT(RTT_COLLAPSE)); + sq.getMaterial().setFlag(EMF_BILINEAR_FILTER, false); + + const TypeRTT oldh = tick ? RTT_COLLAPSEH : RTT_COLLAPSEH2; + const TypeRTT oldv = tick ? RTT_COLLAPSEV : RTT_COLLAPSEV2; + const TypeRTT curh = tick ? RTT_COLLAPSEH2 : RTT_COLLAPSEH; + const TypeRTT curv = tick ? RTT_COLLAPSEV2 : RTT_COLLAPSEV; + + colcb->setResolution(1, m_rtts->getRTT(RTT_WARPV)->getSize().Height); + sq.setTexture(m_rtts->getRTT(oldh), 1); + sq.render(m_rtts->getRTT(RTT_WARPH)); + + colcb->setResolution(m_rtts->getRTT(RTT_WARPV)->getSize().Height, 1); + sq.setTexture(m_rtts->getRTT(oldv), 1); + sq.render(m_rtts->getRTT(RTT_WARPV)); + + sq.setTexture(0, 1); + ((GaussianBlurProvider *) m_shaders->m_callbacks[ES_GAUSSIAN3H])->setResolution( + m_rtts->getRTT(RTT_WARPV)->getSize().Height, + m_rtts->getRTT(RTT_WARPV)->getSize().Height); + + sq.setMaterialType(m_shaders->getShader(ES_GAUSSIAN6H)); + sq.setTexture(m_rtts->getRTT(RTT_WARPH)); + sq.render(m_rtts->getRTT(curh)); + + sq.setMaterialType(m_shaders->getShader(ES_GAUSSIAN6V)); + sq.setTexture(m_rtts->getRTT(RTT_WARPV)); + sq.render(m_rtts->getRTT(curv)); + + // Convert importance maps to warp maps + // + // It should be noted that while they do repeated work + // calculating the min, max, and total, it's several hundred us + // faster to do that than to do it once in a separate shader + // (shader switch overhead, measured). + colcb->setResolution(m_rtts->getRTT(RTT_WARPV)->getSize().Height, + m_rtts->getRTT(RTT_WARPV)->getSize().Height); + + sq.setMaterialType(m_shaders->getShader(ES_SHADOW_WARPH)); + sq.setTexture(m_rtts->getRTT(curh)); + sq.render(m_rtts->getRTT(RTT_WARPH)); + + sq.setMaterialType(m_shaders->getShader(ES_SHADOW_WARPV)); + sq.setTexture(m_rtts->getRTT(curv)); + sq.render(m_rtts->getRTT(RTT_WARPV)); + + // Actual shadow map + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_SHADOW), true, true); + overridemat.Material.MaterialType = m_shaders->getShader(ES_SHADOWPASS); + overridemat.EnableFlags = video::EMF_MATERIAL_TYPE | video::EMF_TEXTURE1 | + video::EMF_TEXTURE2; + overridemat.EnablePasses = scene::ESNRP_SOLID; + overridemat.Material.setTexture(1, m_rtts->getRTT(RTT_WARPH)); + overridemat.Material.setTexture(2, m_rtts->getRTT(RTT_WARPV)); + overridemat.Material.TextureLayer[1].TextureWrapU = + overridemat.Material.TextureLayer[1].TextureWrapV = + overridemat.Material.TextureLayer[2].TextureWrapU = + overridemat.Material.TextureLayer[2].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + overridemat.Material.TextureLayer[1].BilinearFilter = + overridemat.Material.TextureLayer[2].BilinearFilter = true; + overridemat.Material.TextureLayer[1].TrilinearFilter = + overridemat.Material.TextureLayer[2].TrilinearFilter = false; + overridemat.Material.TextureLayer[1].AnisotropicFilter = + overridemat.Material.TextureLayer[2].AnisotropicFilter = 0; + overridemat.Material.Wireframe = 1; + overridemat.Enabled = true; + + m_scene_manager->drawAll(scene::ESNRP_SOLID); + + if (m_shadowviz) + { + overridemat.EnableFlags |= video::EMF_WIREFRAME; + m_scene_manager->drawAll(scene::ESNRP_SOLID); + } + + overridemat.EnablePasses = 0; + overridemat.Enabled = false; + camera->activate(); + + tick++; + tick %= 2; + } + + // Lights + if (!m_lightviz) + { + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_TMP1), true, false, + video::SColor(1, 0, 0, 0)); + } else + { + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_COLOR), false, false); + } + + const vector3df camcenter = cambox.getCenter(); + const float camradius = cambox.getExtent().getLength() / 2; + const vector3df campos = camnode->getPosition(); + const float camnear = camnode->getNearValue(); + + m_scene_manager->drawAll(scene::ESNRP_CAMERA); + PointLightProvider * const pcb = (PointLightProvider *) irr_driver-> + getCallback(ES_POINTLIGHT); + pcb->updateIPVMatrix(); + SunLightProvider * const scb = (SunLightProvider *) irr_driver-> + getCallback(ES_SUNLIGHT); + scb->updateIPVMatrix(); + FogProvider * const fogcb = (FogProvider *) irr_driver-> + getCallback(ES_FOG); + fogcb->updateIPVMatrix(); + + const u32 lightcount = m_lights.size(); + for (i = 0; i < lightcount; i++) + { + // Sphere culling + const float distance_sq = (m_lights[i]->getPosition() - camcenter).getLengthSQ(); + float radius_sum = camradius + m_lights[i]->getRadius(); + radius_sum *= radius_sum; + if (radius_sum < distance_sq) + continue; + + bool inside = false; + + const float camdistance_sq = (m_lights[i]->getPosition() - campos).getLengthSQ(); + float adjusted_radius = m_lights[i]->getRadius() + camnear; + adjusted_radius *= adjusted_radius; + + // Camera inside the light's radius? Needs adjustment for the near plane. + if (camdistance_sq < adjusted_radius) + { + inside = true; + + video::SMaterial &m = m_lights[i]->getMaterial(0); + m.FrontfaceCulling = true; + m.BackfaceCulling = false; + m.ZBuffer = video::ECFN_GREATER; + } + + if (m_lightviz) + { + overridemat.Enabled = true; + overridemat.EnableFlags = video::EMF_MATERIAL_TYPE | video::EMF_WIREFRAME | + video::EMF_FRONT_FACE_CULLING | + video::EMF_BACK_FACE_CULLING | + video::EMF_ZBUFFER; + overridemat.Material.MaterialType = m_shaders->getShader(ES_COLORIZE); + overridemat.Material.Wireframe = true; + overridemat.Material.BackfaceCulling = false; + overridemat.Material.FrontfaceCulling = false; + overridemat.Material.ZBuffer = video::ECFN_LESSEQUAL; + + + ColorizeProvider * const cb = (ColorizeProvider *) m_shaders->m_callbacks[ES_COLORIZE]; + float col[3]; + m_lights[i]->getColor(col); + cb->setColor(col[0], col[1], col[2]); + } + + // Action + m_lights[i]->render(); + + // Reset the inside change + if (inside) + { + video::SMaterial &m = m_lights[i]->getMaterial(0); + m.FrontfaceCulling = false; + m.BackfaceCulling = true; + m.ZBuffer = video::ECFN_LESSEQUAL; + } + + if (m_lightviz) + { + overridemat.Enabled = false; + } + + } // for i in lights + + // Blend lights to the image + video::SMaterial lightmat; + lightmat.Lighting = false; + lightmat.ZWriteEnable = false; + lightmat.ZBuffer = video::ECFN_ALWAYS; + lightmat.setFlag(video::EMF_BILINEAR_FILTER, false); + lightmat.setTexture(0, m_rtts->getRTT(RTT_TMP1)); + // Specular mapping + lightmat.setTexture(1, m_rtts->getRTT(RTT_COLOR)); + lightmat.MaterialType = m_shaders->getShader(ES_LIGHTBLEND); + lightmat.MaterialTypeParam = video::pack_textureBlendFunc(video::EBF_DST_COLOR, video::EBF_ZERO); + lightmat.BlendOperation = video::EBO_ADD; + + lightmat.TextureLayer[0].TextureWrapU = + lightmat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_COLOR), false, false); + if (!m_mipviz) + m_post_processing->drawQuad(cam, lightmat); + + if (!bgnodes) + { + // If there are no BG nodes, it's more efficient to do the skybox here. + m_renderpass = scene::ESNRP_SKY_BOX; + m_scene_manager->drawAll(m_renderpass); + } + + // Is the lens flare enabled & visible? Check last frame's query. + const bool hasflare = World::getWorld()->getTrack()->hasLensFlare(); + const bool hasgodrays = World::getWorld()->getTrack()->hasGodRays(); + if (hasflare | hasgodrays) + { + irr::video::COpenGLDriver* gl_driver = (irr::video::COpenGLDriver*)m_device->getVideoDriver(); + + GLuint res; + gl_driver->extGlGetQueryObjectuiv(m_lensflare_query, GL_QUERY_RESULT, &res); + m_post_processing->setSunPixels(res); + + // Prepare the query for the next frame. + gl_driver->extGlBeginQuery(GL_SAMPLES_PASSED_ARB, m_lensflare_query); + m_scene_manager->setCurrentRendertime(scene::ESNRP_SOLID); + m_scene_manager->drawAll(scene::ESNRP_CAMERA); + m_sun_interposer->render(); + gl_driver->extGlEndQuery(GL_SAMPLES_PASSED_ARB); + + m_lensflare->setStrength(res / 4000.0f); + + if (hasflare) + m_lensflare->OnRegisterSceneNode(); + + // Make sure the color mask is reset + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + + // Render the post-processed scene for solids + m_post_processing->renderSolid(cam); + + // We need to re-render camera due to the per-cam-node hack. + m_renderpass = scene::ESNRP_CAMERA | scene::ESNRP_TRANSPARENT | + scene::ESNRP_TRANSPARENT_EFFECT; + m_scene_manager->drawAll(m_renderpass); + + // Handle displacing nodes, if any + const u32 displacingcount = m_displacing.size(); + if (displacingcount) + { + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_DISPLACE), false, false); + glClearColor(0, 0, 0, 0); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 1, ~0); + glEnable(GL_STENCIL_TEST); + + overridemat.Enabled = 1; + overridemat.EnableFlags = video::EMF_MATERIAL_TYPE | video::EMF_TEXTURE0; + overridemat.Material.MaterialType = m_shaders->getShader(ES_DISPLACE); + + overridemat.Material.TextureLayer[0].Texture = + irr_driver->getTexture((file_manager->getTextureDir() + "displace.png").c_str()); + overridemat.Material.TextureLayer[0].BilinearFilter = + overridemat.Material.TextureLayer[0].TrilinearFilter = true; + overridemat.Material.TextureLayer[0].AnisotropicFilter = 0; + overridemat.Material.TextureLayer[0].TextureWrapU = + overridemat.Material.TextureLayer[0].TextureWrapV = video::ETC_REPEAT; + + for (i = 0; i < displacingcount; i++) + { + m_scene_manager->setCurrentRendertime(scene::ESNRP_SOLID); + m_displacing[i]->render(); + + m_scene_manager->setCurrentRendertime(scene::ESNRP_TRANSPARENT); + m_displacing[i]->render(); + } + + overridemat.Enabled = 0; + + // Blur it + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, 1, ~0); + + video::SMaterial minimat; + minimat.Lighting = false; + minimat.ZWriteEnable = false; + minimat.ZBuffer = video::ECFN_ALWAYS; + minimat.setFlag(video::EMF_TRILINEAR_FILTER, true); + + minimat.TextureLayer[0].TextureWrapU = + minimat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + + ((GaussianBlurProvider *) m_shaders->m_callbacks[ES_GAUSSIAN3H])->setResolution( + UserConfigParams::m_width, + UserConfigParams::m_height); + + minimat.MaterialType = m_shaders->getShader(ES_GAUSSIAN3H); + minimat.setTexture(0, m_rtts->getRTT(RTT_DISPLACE)); + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_TMP2), true, false); + m_post_processing->drawQuad(cam, minimat); + + minimat.MaterialType = m_shaders->getShader(ES_GAUSSIAN3V); + minimat.setTexture(0, m_rtts->getRTT(RTT_TMP2)); + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_DISPLACE), true, false); + m_post_processing->drawQuad(cam, minimat); + + glDisable(GL_STENCIL_TEST); + m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_COLOR), false, false); + } + + // Drawing for this cam done, cleanup + const u32 glowrepcount = transparent_glow_nodes.size(); + for (i = 0; i < glowrepcount; i++) + { + transparent_glow_nodes[i]->remove(); + transparent_glow_nodes[i]->drop(); + } + + PROFILER_POP_CPU_MARKER(); + + // Note that drawAll must be called before rendering + // the bullet debug view, since otherwise the camera + // is not set up properly. This is only used for + // the bullet debug view. + if (UserConfigParams::m_artist_debug_mode) + World::getWorld()->getPhysics()->draw(); + } // for igetNumKarts() + + // Render the post-processed scene + m_post_processing->render(); + + // Set the viewport back to the full screen for race gui + m_video_driver->setViewPort(core::recti(0, 0, + UserConfigParams::m_width, + UserConfigParams::m_height)); + + for(unsigned int i=0; irenderPlayerView(camera, dt); + + PROFILER_POP_CPU_MARKER(); + } // for iendScene(); + + getPostProcessing()->update(dt); +} + +// -------------------------------------------- + +void IrrDriver::renderFixed(float dt) +{ + World *world = World::getWorld(); // Never NULL. + + m_video_driver->beginScene(/*backBuffer clear*/ true, /*zBuffer*/ true, + world->getClearColor()); + + irr_driver->getVideoDriver()->enableMaterial2D(); + + RaceGUIBase *rg = world->getRaceGUI(); + if (rg) rg->update(dt); + + + for(unsigned int i=0; iactivate(); + rg->preRenderCallback(camera); // adjusts start referee + + m_renderpass = ~0; + m_scene_manager->drawAll(); + + PROFILER_POP_CPU_MARKER(); + + // Note that drawAll must be called before rendering + // the bullet debug view, since otherwise the camera + // is not set up properly. This is only used for + // the bullet debug view. + if (UserConfigParams::m_artist_debug_mode) + World::getWorld()->getPhysics()->draw(); + } // for igetNumKarts() + + // Set the viewport back to the full screen for race gui + m_video_driver->setViewPort(core::recti(0, 0, + UserConfigParams::m_width, + UserConfigParams::m_height)); + + for(unsigned int i=0; irenderPlayerView(camera, dt); + PROFILER_POP_CPU_MARKER(); + + } // for iendScene(); +} diff --git a/src/graphics/rtts.cpp b/src/graphics/rtts.cpp new file mode 100644 index 000000000..2fa92f575 --- /dev/null +++ b/src/graphics/rtts.cpp @@ -0,0 +1,141 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/rtts.hpp" + +#include "config/user_config.hpp" +#include "graphics/glwrap.hpp" +#include "graphics/irr_driver.hpp" +#include "utils/log.hpp" + +RTT::RTT() +{ + using namespace video; + using namespace core; + + IVideoDriver * const drv = irr_driver->getVideoDriver(); + const dimension2du res(UserConfigParams::m_width, UserConfigParams::m_height); + const dimension2du half = res/2; + const dimension2du quarter = res/4; + const dimension2du eighth = res/8; + const dimension2du sixteenth = res/16; + + const dimension2du ssaosize = UserConfigParams::m_ssao == 2 ? res : quarter; + + const u16 shadowside = UserConfigParams::m_shadows == 2 ? 2048 : 512; + const dimension2du shadowsize(shadowside, shadowside); + const dimension2du warpvsize(1, 512); + const dimension2du warphsize(512, 1); + + // The last parameter stands for "has stencil". The name is used in the texture + // cache, and when saving textures to files as the default name. + // + // All RTTs are currently RGBA8 with stencil. The four tmp RTTs are the same size + // as the screen, for use in post-processing. + // + // Optionally, the collapse ones use a smaller format. + + rtts[RTT_TMP1] = drv->addRenderTargetTexture(res, "rtt.tmp1", ECF_A8R8G8B8, true); + rtts[RTT_TMP2] = drv->addRenderTargetTexture(res, "rtt.tmp2", ECF_A8R8G8B8, true); + rtts[RTT_TMP3] = drv->addRenderTargetTexture(res, "rtt.tmp3", ECF_A8R8G8B8, true); + rtts[RTT_TMP4] = drv->addRenderTargetTexture(res, "rtt.tmp4", ECF_A8R8G8B8, true); + rtts[RTT_DEPTH] = drv->addRenderTargetTexture(res, "rtt.depth", ECF_A8R8G8B8, true); + rtts[RTT_NORMAL] = drv->addRenderTargetTexture(res, "rtt.normal", ECF_A8R8G8B8, true); + rtts[RTT_COLOR] = drv->addRenderTargetTexture(res, "rtt.color", ECF_A8R8G8B8, true); + + rtts[RTT_HALF1] = drv->addRenderTargetTexture(half, "rtt.half1", ECF_A8R8G8B8, true); + rtts[RTT_HALF2] = drv->addRenderTargetTexture(half, "rtt.half2", ECF_A8R8G8B8, true); + + rtts[RTT_QUARTER1] = drv->addRenderTargetTexture(quarter, "rtt.q1", ECF_A8R8G8B8, true); + rtts[RTT_QUARTER2] = drv->addRenderTargetTexture(quarter, "rtt.q2", ECF_A8R8G8B8, true); + rtts[RTT_QUARTER3] = drv->addRenderTargetTexture(quarter, "rtt.q3", ECF_A8R8G8B8, true); + + rtts[RTT_EIGHTH1] = drv->addRenderTargetTexture(eighth, "rtt.e1", ECF_A8R8G8B8, true); + rtts[RTT_EIGHTH2] = drv->addRenderTargetTexture(eighth, "rtt.e2", ECF_A8R8G8B8, true); + + rtts[RTT_SIXTEENTH1] = drv->addRenderTargetTexture(sixteenth, "rtt.s1", ECF_A8R8G8B8, true); + rtts[RTT_SIXTEENTH2] = drv->addRenderTargetTexture(sixteenth, "rtt.s2", ECF_A8R8G8B8, true); + + rtts[RTT_SSAO1] = drv->addRenderTargetTexture(ssaosize, "rtt.ssao1", ECF_A8R8G8B8, true); + rtts[RTT_SSAO2] = drv->addRenderTargetTexture(ssaosize, "rtt.ssao2", ECF_A8R8G8B8, true); + + rtts[RTT_SHADOW] = drv->addRenderTargetTexture(shadowsize, "rtt.shadow", ECF_A8R8G8B8, true); + rtts[RTT_WARPV] = drv->addRenderTargetTexture(warpvsize, "rtt.warpv", ECF_A8R8G8B8, true); + rtts[RTT_WARPH] = drv->addRenderTargetTexture(warphsize, "rtt.warph", ECF_A8R8G8B8, true); + + rtts[RTT_DISPLACE] = drv->addRenderTargetTexture(res, "rtt.displace", ECF_A8R8G8B8, true); + + if (((COpenGLDriver *) drv)->queryOpenGLFeature(COpenGLDriver::IRR_ARB_texture_rg)) + { + // Use optimized formats if supported + rtts[RTT_COLLAPSE] = drv->addRenderTargetTexture(shadowsize, "rtt.collapse", ECF_R8, true); + + rtts[RTT_COLLAPSEV] = drv->addRenderTargetTexture(warpvsize, "rtt.collapsev", ECF_R8, true); + rtts[RTT_COLLAPSEH] = drv->addRenderTargetTexture(warphsize, "rtt.collapseh", ECF_R8, true); + rtts[RTT_COLLAPSEV2] = drv->addRenderTargetTexture(warpvsize, "rtt.collapsev2", ECF_R8, true); + rtts[RTT_COLLAPSEH2] = drv->addRenderTargetTexture(warphsize, "rtt.collapseh2", ECF_R8, true); + + rtts[RTT_HALF_SOFT] = drv->addRenderTargetTexture(half, "rtt.halfsoft", ECF_R8, true); + } else + { + rtts[RTT_COLLAPSE] = drv->addRenderTargetTexture(shadowsize, "rtt.collapse", ECF_A8R8G8B8, true); + + rtts[RTT_COLLAPSEV] = drv->addRenderTargetTexture(warpvsize, "rtt.collapsev", ECF_A8R8G8B8, true); + rtts[RTT_COLLAPSEH] = drv->addRenderTargetTexture(warphsize, "rtt.collapseh", ECF_A8R8G8B8, true); + rtts[RTT_COLLAPSEV2] = drv->addRenderTargetTexture(warpvsize, "rtt.collapsev2", ECF_A8R8G8B8, true); + rtts[RTT_COLLAPSEH2] = drv->addRenderTargetTexture(warphsize, "rtt.collapseh2", ECF_A8R8G8B8, true); + + rtts[RTT_HALF_SOFT] = drv->addRenderTargetTexture(half, "rtt.halfsoft", ECF_A8R8G8B8, true); + } + + u32 i; + for (i = 0; i < RTT_COUNT; i++) + { + if (!rtts[i]) + Log::fatal("RTT", "Failed to create a RTT"); + } + + // Clear those that should be cleared + drv->beginScene(false, false); + + drv->setRenderTarget(rtts[RTT_SSAO1], true, false, SColor(255, 255, 255, 255)); + drv->setRenderTarget(rtts[RTT_SSAO2], true, false, SColor(255, 255, 255, 255)); + + drv->setRenderTarget(rtts[RTT_COLLAPSEV], true, false); + drv->setRenderTarget(rtts[RTT_COLLAPSEH], true, false); + drv->setRenderTarget(rtts[RTT_COLLAPSEV2], true, false); + drv->setRenderTarget(rtts[RTT_COLLAPSEH2], true, false); + + drv->setRenderTarget(0, false, false); + + drv->endScene(); +} + +RTT::~RTT() +{ + u32 i; + for (i = 0; i < RTT_COUNT; i++) + { + irr_driver->removeTexture(rtts[i]); + } +} + +ITexture *RTT::getRTT(TypeRTT which) +{ + assert(which < RTT_COUNT); + return rtts[which]; +} diff --git a/src/graphics/rtts.hpp b/src/graphics/rtts.hpp new file mode 100644 index 000000000..8000c02b9 --- /dev/null +++ b/src/graphics/rtts.hpp @@ -0,0 +1,83 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_RTTS_HPP +#define HEADER_RTTS_HPP + +namespace irr { + namespace video { + class ITexture; + }; +}; + +using irr::video::ITexture; + +enum TypeRTT +{ + RTT_TMP1 = 0, + RTT_TMP2, + RTT_TMP3, + RTT_TMP4, + RTT_DEPTH, + RTT_NORMAL, + RTT_COLOR, + + RTT_HALF1, + RTT_HALF2, + + RTT_QUARTER1, + RTT_QUARTER2, + RTT_QUARTER3, + + RTT_EIGHTH1, + RTT_EIGHTH2, + + RTT_SIXTEENTH1, + RTT_SIXTEENTH2, + + RTT_SSAO1, + RTT_SSAO2, + + RTT_SHADOW, + RTT_COLLAPSE, + RTT_COLLAPSEH, + RTT_COLLAPSEV, + RTT_COLLAPSEH2, + RTT_COLLAPSEV2, + RTT_WARPH, + RTT_WARPV, + + RTT_HALF_SOFT, + + RTT_DISPLACE, + + RTT_COUNT +}; + +class RTT +{ +public: + RTT(); + ~RTT(); + + ITexture *getRTT(TypeRTT which); + +private: + ITexture *rtts[RTT_COUNT]; +}; + +#endif + diff --git a/src/graphics/screenquad.cpp b/src/graphics/screenquad.cpp new file mode 100644 index 000000000..da2a8a176 --- /dev/null +++ b/src/graphics/screenquad.cpp @@ -0,0 +1,30 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/screenquad.hpp" + +// Just the static parts to our screenquad + +const u16 ScreenQuad::indices[4] = {0, 1, 2, 3}; + +static const SColor white(255, 255, 255, 255); + +const S3DVertex ScreenQuad::vertices[4] = { + S3DVertex(-1, 1, 0, 0, 1, 0, white, 0, 1), + S3DVertex(1, 1, 0, 0, 1, 0, white, 1, 1), + S3DVertex(-1, -1, 0, 0, 1, 0, white, 0, 0), + S3DVertex(1, -1, 0, 0, 1, 0, white, 1, 0), + }; diff --git a/src/graphics/screenquad.hpp b/src/graphics/screenquad.hpp new file mode 100644 index 000000000..478500946 --- /dev/null +++ b/src/graphics/screenquad.hpp @@ -0,0 +1,91 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_SCREENQUAD_H +#define HEADER_SCREENQUAD_H + +#include "graphics/glwrap.hpp" + +#include +#include + +using namespace irr; +using namespace video; + +class ScreenQuad { + +public: + ScreenQuad(IVideoDriver *xy) + { + vd = xy; + + mat.Lighting = false; + mat.ZBuffer = video::ECFN_ALWAYS; + mat.ZWriteEnable = false; + + for(u32 c = 0; c < MATERIAL_MAX_TEXTURES; c++) + { + mat.TextureLayer[c].TextureWrapU = video::ETC_CLAMP_TO_EDGE; + mat.TextureLayer[c].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + } + } + + SMaterial& getMaterial() { return mat; } + + //Set the texture to render with the quad + void setTexture(ITexture* tex, u32 layer = 0) + { + mat.TextureLayer[layer].Texture = tex; + } + + ITexture* getTexture(u32 layer = 0) const { return mat.TextureLayer[layer].Texture; } + + void setMaterialType(E_MATERIAL_TYPE mt) { mat.MaterialType = mt; } + + void render(bool setRTToFrameBuff = true) const + { + if(setRTToFrameBuff) + vd->setRenderTarget(video::ERT_FRAME_BUFFER); + + sq_dorender(); + } + + void render(ITexture* rt) const + { + vd->setRenderTarget(rt); + + sq_dorender(); + } + +protected: + static const S3DVertex vertices[4]; + static const u16 indices[4]; + SMaterial mat; + + IVideoDriver* vd; + + void sq_dorender() const + { + vd->setMaterial(mat); + vd->setTransform(ETS_WORLD, core::IdentityMatrix); + vd->setTransform(ETS_VIEW, core::IdentityMatrix); + vd->setTransform(ETS_PROJECTION, core::IdentityMatrix); + vd->drawVertexPrimitiveList(vertices, 4, indices, 2, EVT_STANDARD, + scene::EPT_TRIANGLE_STRIP); + } +}; + +#endif diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp new file mode 100644 index 000000000..8a26cab4b --- /dev/null +++ b/src/graphics/shaders.cpp @@ -0,0 +1,260 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#define SHADER_NAMES + +#include "graphics/callbacks.hpp" +#include "graphics/irr_driver.hpp" +#include "graphics/shaders.hpp" +#include "io/file_manager.hpp" +#include "utils/log.hpp" + +#include +#include + +using namespace video; + +Shaders::Shaders() +{ + const std::string &dir = file_manager->getShaderDir(); + + IGPUProgrammingServices * const gpu = irr_driver->getVideoDriver()->getGPUProgrammingServices(); + + #define glsl(a, b, c) gpu->addHighLevelShaderMaterialFromFiles((a).c_str(), (b).c_str(), (IShaderConstantSetCallBack*) c) + #define glslmat(a, b, c, d) gpu->addHighLevelShaderMaterialFromFiles((a).c_str(), (b).c_str(), (IShaderConstantSetCallBack*) c, d) + #define glsl_noinput(a, b) gpu->addHighLevelShaderMaterialFromFiles((a).c_str(), (b).c_str(), (IShaderConstantSetCallBack*) 0) + + // Callbacks + memset(m_callbacks, 0, sizeof(m_callbacks)); + + m_callbacks[ES_NORMAL_MAP_LIGHTMAP] = new NormalMapProvider(true); + m_callbacks[ES_NORMAL_MAP] = new NormalMapProvider(false); + m_callbacks[ES_SPLATTING] = new SplattingProvider(); + m_callbacks[ES_WATER] = new WaterShaderProvider(); + m_callbacks[ES_GRASS] = new GrassShaderProvider(); + m_callbacks[ES_BUBBLES] = new BubbleEffectProvider(); + m_callbacks[ES_RAIN] = new RainEffectProvider(); + m_callbacks[ES_SNOW] = new SnowEffectProvider(); + m_callbacks[ES_MOTIONBLUR] = new MotionBlurProvider(); + m_callbacks[ES_GAUSSIAN3V] = m_callbacks[ES_GAUSSIAN3H] = new GaussianBlurProvider(); + m_callbacks[ES_MIPVIZ] = new MipVizProvider(); + m_callbacks[ES_COLORIZE] = new ColorizeProvider(); + m_callbacks[ES_GLOW] = new GlowProvider(); + m_callbacks[ES_OBJECTPASS] = new ObjectPassProvider(); + m_callbacks[ES_LIGHTBLEND] = new LightBlendProvider(); + m_callbacks[ES_POINTLIGHT] = new PointLightProvider(); + m_callbacks[ES_SUNLIGHT] = new SunLightProvider(); + m_callbacks[ES_BLOOM] = new BloomProvider(); + m_callbacks[ES_MLAA_COLOR1] = new MLAAColor1Provider(); + m_callbacks[ES_MLAA_BLEND2] = new MLAABlend2Provider(); + m_callbacks[ES_MLAA_NEIGH3] = new MLAANeigh3Provider(); + m_callbacks[ES_SSAO] = new SSAOProvider(); + m_callbacks[ES_GODRAY] = new GodRayProvider(); + m_callbacks[ES_SHADOWPASS] = new ShadowPassProvider(); + m_callbacks[ES_SHADOW_IMPORTANCE] = new ShadowImportanceProvider(); + m_callbacks[ES_COLLAPSE] = new CollapseProvider(); + m_callbacks[ES_BLOOM_POWER] = new BloomPowerProvider(); + m_callbacks[ES_MULTIPLY_ADD] = new MultiplyProvider(); + m_callbacks[ES_SHADOWGEN] = new ShadowGenProvider(); + m_callbacks[ES_CAUSTICS] = new CausticsProvider(); + m_callbacks[ES_DISPLACE] = new DisplaceProvider(); + m_callbacks[ES_PPDISPLACE] = new PPDisplaceProvider(); + m_callbacks[ES_FOG] = new FogProvider(); + + // Ok, go + m_shaders[ES_NORMAL_MAP] = glslmat(dir + "normalmap.vert", dir + "normalmap.frag", + m_callbacks[ES_NORMAL_MAP], EMT_SOLID_2_LAYER); + + m_shaders[ES_NORMAL_MAP_LIGHTMAP] = glslmat(dir + "normalmap.vert", dir + "normalmap.frag", + m_callbacks[ES_NORMAL_MAP_LIGHTMAP], EMT_SOLID_2_LAYER); + + m_shaders[ES_SPLATTING] = glsl(dir + "objectpass.vert", dir + "splatting.frag", + m_callbacks[ES_SPLATTING]); + + m_shaders[ES_WATER] = glslmat(dir + "water.vert", dir + "water.frag", + m_callbacks[ES_WATER], EMT_TRANSPARENT_ALPHA_CHANNEL); + m_shaders[ES_WATER_SURFACE] = glsl(dir + "water.vert", dir + "pass.frag", + m_callbacks[ES_WATER]); + + m_shaders[ES_SPHERE_MAP] = glslmat(dir + "objectpass_rimlit.vert", dir + "objectpass_spheremap.frag", + m_callbacks[ES_OBJECTPASS], EMT_SOLID); + + m_shaders[ES_GRASS] = glslmat(dir + "grass.vert", dir + "grass.frag", + m_callbacks[ES_GRASS], EMT_TRANSPARENT_ALPHA_CHANNEL); + m_shaders[ES_GRASS_REF] = glslmat(dir + "grass.vert", dir + "grass.frag", + m_callbacks[ES_GRASS], EMT_TRANSPARENT_ALPHA_CHANNEL_REF); + + m_shaders[ES_BUBBLES] = glslmat(dir + "bubble.vert", dir + "bubble.frag", + m_callbacks[ES_BUBBLES], EMT_TRANSPARENT_ALPHA_CHANNEL); + + m_shaders[ES_RAIN] = glslmat(dir + "rain.vert", dir + "rain.frag", + m_callbacks[ES_RAIN], EMT_TRANSPARENT_ALPHA_CHANNEL); + + m_shaders[ES_SNOW] = glslmat(dir + "snow.vert", dir + "snow.frag", + m_callbacks[ES_SNOW], EMT_TRANSPARENT_ALPHA_CHANNEL); + + m_shaders[ES_MOTIONBLUR] = glsl(std::string(""), dir + "motion_blur.frag", + m_callbacks[ES_MOTIONBLUR]); + + m_shaders[ES_GAUSSIAN3H] = glslmat(std::string(""), dir + "gaussian3h.frag", + m_callbacks[ES_GAUSSIAN3H], EMT_SOLID); + m_shaders[ES_GAUSSIAN3V] = glslmat(std::string(""), dir + "gaussian3v.frag", + m_callbacks[ES_GAUSSIAN3V], EMT_SOLID); + + m_shaders[ES_GAUSSIAN6H] = glslmat(std::string(""), dir + "gaussian6h.frag", + m_callbacks[ES_GAUSSIAN3H], EMT_SOLID); + m_shaders[ES_GAUSSIAN6V] = glslmat(std::string(""), dir + "gaussian6v.frag", + m_callbacks[ES_GAUSSIAN3V], EMT_SOLID); + + m_shaders[ES_MIPVIZ] = glslmat(std::string(""), dir + "mipviz.frag", + m_callbacks[ES_MIPVIZ], EMT_SOLID); + + m_shaders[ES_FLIP] = glslmat(std::string(""), dir + "flip.frag", + 0, EMT_SOLID); + m_shaders[ES_FLIP_ADDITIVE] = glslmat(std::string(""), dir + "flip.frag", + 0, EMT_TRANSPARENT_ADD_COLOR); + + m_shaders[ES_BLOOM] = glslmat(std::string(""), dir + "bloom.frag", + m_callbacks[ES_BLOOM], EMT_SOLID); + + m_shaders[ES_COLORIZE] = glslmat(std::string(""), dir + "colorize.frag", + m_callbacks[ES_COLORIZE], EMT_SOLID); + m_shaders[ES_COLORIZE_REF] = glslmat(std::string(""), dir + "colorize_ref.frag", + m_callbacks[ES_COLORIZE], EMT_SOLID); + + m_shaders[ES_PASS] = glslmat(std::string(""), dir + "pass.frag", + 0, EMT_SOLID); + m_shaders[ES_PASS_ADDITIVE] = glslmat(std::string(""), dir + "pass.frag", + 0, EMT_TRANSPARENT_ADD_COLOR); + + m_shaders[ES_GLOW] = glslmat(std::string(""), dir + "glow.frag", + m_callbacks[ES_GLOW], EMT_TRANSPARENT_ALPHA_CHANNEL); + + m_shaders[ES_OBJECTPASS] = glslmat(dir + "objectpass.vert", dir + "objectpass.frag", + m_callbacks[ES_OBJECTPASS], EMT_SOLID); + m_shaders[ES_OBJECTPASS_REF] = glslmat(dir + "objectpass.vert", dir + "objectpass_ref.frag", + m_callbacks[ES_OBJECTPASS], EMT_SOLID); + m_shaders[ES_OBJECTPASS_RIMLIT] = glslmat(dir + "objectpass_rimlit.vert", dir + "objectpass_rimlit.frag", + m_callbacks[ES_OBJECTPASS], EMT_SOLID); + + m_shaders[ES_LIGHTBLEND] = glslmat(std::string(""), dir + "lightblend.frag", + m_callbacks[ES_LIGHTBLEND], EMT_ONETEXTURE_BLEND); + + m_shaders[ES_POINTLIGHT] = glslmat(std::string(""), dir + "pointlight.frag", + m_callbacks[ES_POINTLIGHT], EMT_ONETEXTURE_BLEND); + + m_shaders[ES_SUNLIGHT] = glslmat(std::string(""), dir + "sunlight.frag", + m_callbacks[ES_SUNLIGHT], EMT_SOLID); + m_shaders[ES_SUNLIGHT_SHADOW] = glslmat(dir + "pass.vert", dir + "sunlightshadow.frag", + m_callbacks[ES_SUNLIGHT], EMT_SOLID); + + m_shaders[ES_MLAA_COLOR1] = glsl(dir + "mlaa_offset.vert", dir + "mlaa_color1.frag", + m_callbacks[ES_MLAA_COLOR1]); + m_shaders[ES_MLAA_BLEND2] = glsl(dir + "pass.vert", dir + "mlaa_blend2.frag", + m_callbacks[ES_MLAA_BLEND2]); + m_shaders[ES_MLAA_NEIGH3] = glsl(dir + "mlaa_offset.vert", dir + "mlaa_neigh3.frag", + m_callbacks[ES_MLAA_NEIGH3]); + + m_shaders[ES_SSAO] = glsl(std::string(""), dir + "ssao.frag", m_callbacks[ES_SSAO]); + + m_shaders[ES_GODFADE] = glsl(std::string(""), dir + "godfade.frag", m_callbacks[ES_COLORIZE]); + m_shaders[ES_GODRAY] = glsl(std::string(""), dir + "godray.frag", m_callbacks[ES_GODRAY]); + + m_shaders[ES_SHADOWPASS] = glsl(dir + "shadowpass.vert", dir + "shadowpass.frag", + m_callbacks[ES_SHADOWPASS]); + + m_shaders[ES_SHADOW_IMPORTANCE] = glsl(dir + "shadowimportance.vert", + dir + "shadowimportance.frag", + m_callbacks[ES_SHADOW_IMPORTANCE]); + + m_shaders[ES_COLLAPSE] = glsl(std::string(""), dir + "collapse.frag", + m_callbacks[ES_COLLAPSE]); + m_shaders[ES_SHADOW_WARPH] = glsl(std::string(""), dir + "shadowwarph.frag", + m_callbacks[ES_COLLAPSE]); + m_shaders[ES_SHADOW_WARPV] = glsl(std::string(""), dir + "shadowwarpv.frag", + m_callbacks[ES_COLLAPSE]); + + m_shaders[ES_BLOOM_POWER] = glsl(std::string(""), dir + "bloompower.frag", + m_callbacks[ES_BLOOM_POWER]); + m_shaders[ES_BLOOM_BLEND] = glslmat(std::string(""), dir + "bloomblend.frag", + 0, EMT_TRANSPARENT_ADD_COLOR); + + m_shaders[ES_MULTIPLY_ADD] = glslmat(std::string(""), dir + "multiply.frag", + m_callbacks[ES_MULTIPLY_ADD], EMT_ONETEXTURE_BLEND); + + m_shaders[ES_PENUMBRAH] = glslmat(std::string(""), dir + "penumbrah.frag", + m_callbacks[ES_GAUSSIAN3H], EMT_SOLID); + m_shaders[ES_PENUMBRAV] = glslmat(std::string(""), dir + "penumbrav.frag", + m_callbacks[ES_GAUSSIAN3H], EMT_SOLID); + m_shaders[ES_SHADOWGEN] = glslmat(std::string(""), dir + "shadowgen.frag", + m_callbacks[ES_SHADOWGEN], EMT_SOLID); + + m_shaders[ES_CAUSTICS] = glslmat(std::string(""), dir + "caustics.frag", + m_callbacks[ES_CAUSTICS], EMT_TRANSPARENT_ALPHA_CHANNEL); + + m_shaders[ES_DISPLACE] = glsl(dir + "displace.vert", dir + "displace.frag", + m_callbacks[ES_DISPLACE]); + m_shaders[ES_PPDISPLACE] = glsl(std::string(""), dir + "ppdisplace.frag", + m_callbacks[ES_PPDISPLACE]); + + m_shaders[ES_PASSFAR] = glsl(dir + "farplane.vert", dir + "colorize.frag", + m_callbacks[ES_COLORIZE]); + + m_shaders[ES_FOG] = glslmat(std::string(""), dir + "fog.frag", + m_callbacks[ES_FOG], EMT_ONETEXTURE_BLEND); + + // Check that all successfully loaded + u32 i; + for (i = 0; i < ES_COUNT; i++) { + + // Old Intel Windows drivers fail here. + // It's an artist option, so not necessary to play. + if (i == ES_MIPVIZ) + continue; + + check(i); + } + + #undef glsl + #undef glslmat + #undef glsl_noinput +} + +Shaders::~Shaders() +{ + u32 i; + for (i = 0; i < ES_COUNT; i++) + { + if (i == ES_GAUSSIAN3V || !m_callbacks[i]) continue; + delete m_callbacks[i]; + } +} + +E_MATERIAL_TYPE Shaders::getShader(const ShaderType num) const +{ + assert(num < ES_COUNT); + + return (E_MATERIAL_TYPE) m_shaders[num]; +} + +void Shaders::check(const int num) const +{ + if (m_shaders[num] == -1) + { + Log::fatal("shaders", "Shader %s failed to load. Update your drivers, if the issue " + "persists, report a bug to us.", shader_names[num] + 3); + } +} diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp new file mode 100644 index 000000000..80794a95f --- /dev/null +++ b/src/graphics/shaders.hpp @@ -0,0 +1,117 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_SHADERS_HPP +#define HEADER_SHADERS_HPP + +#include +#include +#include +using namespace irr; + +#define FOREACH_SHADER(ACT) \ + ACT(ES_NORMAL_MAP) \ + ACT(ES_NORMAL_MAP_LIGHTMAP) \ + ACT(ES_SPLATTING) \ + ACT(ES_WATER) \ + ACT(ES_WATER_SURFACE) \ + ACT(ES_SPHERE_MAP) \ + ACT(ES_GRASS) \ + ACT(ES_GRASS_REF) \ + ACT(ES_BUBBLES) \ + ACT(ES_RAIN) \ + ACT(ES_SNOW) \ + ACT(ES_MOTIONBLUR) \ + ACT(ES_GAUSSIAN3H) \ + ACT(ES_GAUSSIAN3V) \ + ACT(ES_MIPVIZ) \ + ACT(ES_FLIP) \ + ACT(ES_FLIP_ADDITIVE) \ + ACT(ES_BLOOM) \ + ACT(ES_GAUSSIAN6H) \ + ACT(ES_GAUSSIAN6V) \ + ACT(ES_COLORIZE) \ + ACT(ES_COLORIZE_REF) \ + ACT(ES_PASS) \ + ACT(ES_PASS_ADDITIVE) \ + ACT(ES_GLOW) \ + ACT(ES_OBJECTPASS) \ + ACT(ES_OBJECTPASS_REF) \ + ACT(ES_LIGHTBLEND) \ + ACT(ES_POINTLIGHT) \ + ACT(ES_SUNLIGHT) \ + ACT(ES_SUNLIGHT_SHADOW) \ + ACT(ES_OBJECTPASS_RIMLIT) \ + ACT(ES_MLAA_COLOR1) \ + ACT(ES_MLAA_BLEND2) \ + ACT(ES_MLAA_NEIGH3) \ + ACT(ES_SSAO) \ + ACT(ES_GODFADE) \ + ACT(ES_GODRAY) \ + ACT(ES_SHADOWPASS) \ + ACT(ES_SHADOW_IMPORTANCE) \ + ACT(ES_COLLAPSE) \ + ACT(ES_SHADOW_WARPH) \ + ACT(ES_SHADOW_WARPV) \ + ACT(ES_BLOOM_POWER) \ + ACT(ES_BLOOM_BLEND) \ + ACT(ES_MULTIPLY_ADD) \ + ACT(ES_PENUMBRAH) \ + ACT(ES_PENUMBRAV) \ + ACT(ES_SHADOWGEN) \ + ACT(ES_CAUSTICS) \ + ACT(ES_DISPLACE) \ + ACT(ES_PPDISPLACE) \ + ACT(ES_PASSFAR) \ + ACT(ES_FOG) + +#define ENUM(a) a, +#define STR(a) #a, + +enum ShaderType +{ + FOREACH_SHADER(ENUM) + + ES_COUNT +}; + +#ifdef SHADER_NAMES +static const char *shader_names[] = { + FOREACH_SHADER(STR) +}; +#endif + +class Shaders +{ +public: + Shaders(); + ~Shaders(); + + video::E_MATERIAL_TYPE getShader(const ShaderType num) const; + + video::IShaderConstantSetCallBack * m_callbacks[ES_COUNT]; + +private: + void check(const int num) const; + + int m_shaders[ES_COUNT]; +}; + +#undef ENUM +#undef STR +#undef FOREACH_SHADER + +#endif diff --git a/src/graphics/shadow_importance.cpp b/src/graphics/shadow_importance.cpp new file mode 100644 index 000000000..2e09c6a59 --- /dev/null +++ b/src/graphics/shadow_importance.cpp @@ -0,0 +1,169 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "config/user_config.hpp" +#include "graphics/glwrap.hpp" +#include "graphics/irr_driver.hpp" +#include "graphics/large_mesh_buffer.hpp" +#include "graphics/material_manager.hpp" +#include "graphics/material.hpp" +#include "graphics/per_camera_node.hpp" +#include "graphics/shadow_importance.hpp" +#include "graphics/shaders.hpp" +#include "graphics/rtts.hpp" +#include "utils/vs.hpp" + +#include + +using namespace video; +using namespace scene; +using namespace core; + +// The actual ShadowImportance node +class ShadowImportanceNode: public scene::ISceneNode +{ +public: + ShadowImportanceNode(scene::ISceneManager* mgr) + : scene::ISceneNode(0, mgr, -1) + { + mat.Lighting = false; + mat.ZWriteEnable = false; + mat.MaterialType = irr_driver->getShader(ES_SHADOW_IMPORTANCE); + + mat.setTexture(0, irr_driver->getRTT(RTT_NORMAL)); + mat.setTexture(1, irr_driver->getRTT(RTT_DEPTH)); + mat.setTexture(2, irr_driver->getRTT(RTT_COLOR)); + + mat.setFlag(EMF_BILINEAR_FILTER, false); + + u32 i; + for (i = 0; i < MATERIAL_MAX_TEXTURES; i++) + { + mat.TextureLayer[i].TextureWrapU = + mat.TextureLayer[i].TextureWrapV = ETC_CLAMP_TO_EDGE; + } + + // Low shadows only back-project every other pixel + const u32 incr = UserConfigParams::m_shadows < 2 ? 2 : 1; + + count = (UserConfigParams::m_width * UserConfigParams::m_height) / (incr * incr); + + // Fill in the mesh buffer + buf.Vertices.clear(); + buf.Indices.clear(); + + buf.Vertices.set_used(count); + buf.Indices.set_used(count); + + buf.Primitive = EPT_POINTS; + buf.setHardwareMappingHint(EHM_STATIC); + + const float halfx = 0.5f / UserConfigParams::m_width; + const float halfy = 0.5f / UserConfigParams::m_height; + + list = glGenLists(1); + + s32 x, y; + i = 0; + glNewList(list, GL_COMPILE); + glBegin(GL_POINTS); + for (x = 0; x < UserConfigParams::m_width; x += incr) + { + const float xpos = ((float) x) / UserConfigParams::m_width + halfx; + + for (y = 0; y < UserConfigParams::m_height; y += incr) + { + const float ypos = ((float) y) / UserConfigParams::m_height + halfy; + + buf.Indices[i] = i; + buf.Vertices[i] = S3DVertex(xpos, ypos, 0, 0, 0, 0, + SColor(255, 255, 255, 255), 0, 0); + + glVertex2s(roundf(xpos * 32767), roundf(ypos * 32767)); + i++; + } + } + glEnd(); + glEndList(); + + box.addInternalPoint(vector3df(-1)); + box.addInternalPoint(vector3df(1)); + } + + ~ShadowImportanceNode() + { + } + + virtual void render() + { + IVideoDriver * const drv = irr_driver->getVideoDriver(); + drv->setMaterial(mat); + + drv->setTransform(ETS_WORLD, IdentityMatrix); + +// drv->drawMeshBuffer(&buf); + // Setup the env for drawing our list by drawing one point + drv->drawVertexPrimitiveList(buf.getVertices(), 1, buf.getIndices(), 1, + EVT_STANDARD, EPT_POINTS); + glCallList(list); + } + + virtual const core::aabbox3d& getBoundingBox() const + { + return box; + } + + virtual void OnRegisterSceneNode() + { + ISceneNode::OnRegisterSceneNode(); + } + + virtual u32 getMaterialCount() const { return 1; } + virtual video::SMaterial& getMaterial(u32 i) { return mat; } + +private: + video::SMaterial mat; + core::aabbox3d box; + u32 count; + GLuint list; + + scene::LargeMeshBuffer buf; +}; + +// The ShadowImportance manager + +ShadowImportance::ShadowImportance() +{ + m_node = new ShadowImportanceNode(irr_driver->getSceneManager()); + m_node->setAutomaticCulling(0); +} // ShadowImportance + +// ---------------------------------------------------------------------------- + +ShadowImportance::~ShadowImportance() +{ + m_node->drop(); // drop STK's reference + m_node->remove(); // Then remove it from the scene graph. +} + +// ---------------------------------------------------------------------------- + +void ShadowImportance::render() +{ + m_node->render(); +} diff --git a/src/graphics/shadow_importance.hpp b/src/graphics/shadow_importance.hpp new file mode 100644 index 000000000..3d5c2dba0 --- /dev/null +++ b/src/graphics/shadow_importance.hpp @@ -0,0 +1,41 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_SHADOW_IMPORTANCE_HPP +#define HEADER_SHADOW_IMPORTANCE_HPP + +#include +namespace irr +{ + namespace video { class SMaterial; class ITexture; } + namespace scene { class ICameraSceneNode; class ISceneNode; } +} +using namespace irr; + +class ShadowImportance +{ + scene::ISceneNode *m_node; + +public: + ShadowImportance(); + ~ShadowImportance(); + + void render(); +}; + +#endif diff --git a/src/graphics/sun.cpp b/src/graphics/sun.cpp new file mode 100644 index 000000000..e9c029822 --- /dev/null +++ b/src/graphics/sun.cpp @@ -0,0 +1,161 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/sun.hpp" + +#include "graphics/callbacks.hpp" +#include "graphics/glwrap.hpp" +#include "graphics/irr_driver.hpp" +#include "graphics/material_manager.hpp" +#include "graphics/material.hpp" +#include "graphics/rtts.hpp" +#include "graphics/screenquad.hpp" +#include "graphics/shaders.hpp" +#include "io/file_manager.hpp" +#include "modes/world.hpp" +#include "tracks/track.hpp" + +using namespace video; +using namespace scene; +using namespace core; + +SunNode::SunNode(scene::ISceneManager* mgr, float r, float g, float b): + LightNode(mgr, 10000, r, g, b) +{ + + sq = new ScreenQuad(irr_driver->getVideoDriver()); + + SMaterial &m = sq->getMaterial(); + + m.MaterialType = irr_driver->getShader(ES_SUNLIGHT); + m.setTexture(0, irr_driver->getRTT(RTT_NORMAL)); + m.setTexture(1, irr_driver->getRTT(RTT_DEPTH)); + m.setTexture(2, irr_driver->getTexture((file_manager->getTextureDir() + "cloudshadow.png").c_str())); + m.setFlag(EMF_BILINEAR_FILTER, false); + + if (UserConfigParams::m_shadows) + { + m.setTexture(3, irr_driver->getRTT(RTT_SHADOW)); + m.setTexture(4, irr_driver->getRTT(RTT_WARPH)); + m.setTexture(5, irr_driver->getRTT(RTT_WARPV)); + + m.TextureLayer[4].BilinearFilter = + m.TextureLayer[5].BilinearFilter = true; + + m.MaterialType = irr_driver->getShader(ES_SUNLIGHT_SHADOW); + } + + for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; i++) + { + m.TextureLayer[i].TextureWrapU = m.TextureLayer[i].TextureWrapV = + ETC_CLAMP_TO_EDGE; + } + + m.TextureLayer[2].TextureWrapU = m.TextureLayer[2].TextureWrapV = ETC_REPEAT; + + m.TextureLayer[2].TrilinearFilter = true; + + m_color[0] = r; + m_color[1] = g; + m_color[2] = b; +} + +SunNode::~SunNode() +{ + delete sq; +} + +void SunNode::render() +{ + SunLightProvider * const cb = (SunLightProvider *) irr_driver->getCallback(ES_SUNLIGHT); + cb->setColor(m_color[0], m_color[1], m_color[2]); + + vector3df pos = getPosition(); + pos.normalize(); + cb->setPosition(pos.X, pos.Y, pos.Z); + + if (!UserConfigParams::m_shadows || !World::getWorld()->getTrack()->hasShadows()) + { + sq->render(false); + return; + } + + array mrt; + mrt.reallocate(2); + mrt.push_back(irr_driver->getRTT(RTT_TMP2)); + mrt.push_back(irr_driver->getRTT(RTT_TMP3)); + irr_driver->getVideoDriver()->setRenderTarget(mrt, true, false); + + // Render the sun lighting to tmp2, shadow map to tmp3 + sq->render(false); + + // Filter the shadow map for soft shadows + // Note that quarter1 is reserved for glow during this time. + // Having a separate RTT for glow would work, but be wasted VRAM due to less reuse. + ScreenQuad tmpsq(irr_driver->getVideoDriver()); + GaussianBlurProvider * const gcb = (GaussianBlurProvider *) irr_driver->getCallback(ES_GAUSSIAN3H); + + gcb->setResolution(UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); + tmpsq.setMaterialType(irr_driver->getShader(ES_PENUMBRAH)); + tmpsq.setTexture(irr_driver->getRTT(RTT_TMP3)); + tmpsq.render(irr_driver->getRTT(RTT_HALF1)); + tmpsq.setMaterialType(irr_driver->getShader(ES_PENUMBRAV)); + tmpsq.setTexture(irr_driver->getRTT(RTT_HALF1)); + tmpsq.render(irr_driver->getRTT(RTT_HALF2)); + + gcb->setResolution(UserConfigParams::m_width / 4, UserConfigParams::m_height / 4); + tmpsq.setMaterialType(irr_driver->getShader(ES_PENUMBRAH)); + tmpsq.setTexture(irr_driver->getRTT(RTT_HALF2)); + tmpsq.render(irr_driver->getRTT(RTT_QUARTER2)); + tmpsq.setMaterialType(irr_driver->getShader(ES_PENUMBRAV)); + tmpsq.setTexture(irr_driver->getRTT(RTT_QUARTER2)); + tmpsq.render(irr_driver->getRTT(RTT_QUARTER3)); + + gcb->setResolution(UserConfigParams::m_width / 8, UserConfigParams::m_height / 8); + tmpsq.setMaterialType(irr_driver->getShader(ES_PENUMBRAH)); + tmpsq.setTexture(irr_driver->getRTT(RTT_QUARTER3)); + tmpsq.render(irr_driver->getRTT(RTT_EIGHTH1)); + tmpsq.setMaterialType(irr_driver->getShader(ES_PENUMBRAV)); + tmpsq.setTexture(irr_driver->getRTT(RTT_EIGHTH1)); + tmpsq.render(irr_driver->getRTT(RTT_EIGHTH2)); + + // Use these to generate a new soft shadow map + tmpsq.setMaterialType(irr_driver->getShader(ES_SHADOWGEN)); + tmpsq.setTexture(irr_driver->getRTT(RTT_HALF2), 0); + tmpsq.setTexture(irr_driver->getRTT(RTT_QUARTER3), 1); + tmpsq.setTexture(irr_driver->getRTT(RTT_EIGHTH2), 2); + + irr_driver->getVideoDriver()->setRenderTarget(irr_driver->getRTT(RTT_HALF_SOFT), true, false); + tmpsq.render(false); + + tmpsq.setTexture(0, 0); + tmpsq.setTexture(0, 1); + tmpsq.setTexture(0, 2); + tmpsq.setTexture(0, 3); + + // Combine them back to the lighting RTT + tmpsq.setMaterialType(irr_driver->getShader(ES_MULTIPLY_ADD)); + tmpsq.setTexture(irr_driver->getRTT(RTT_TMP2), 0); + tmpsq.setTexture(irr_driver->getRTT(RTT_HALF_SOFT), 1); + + tmpsq.getMaterial().MaterialTypeParam = pack_textureBlendFunc(EBF_ONE, EBF_ONE); + tmpsq.getMaterial().BlendOperation = EBO_ADD; + + irr_driver->getVideoDriver()->setRenderTarget(irr_driver->getRTT(RTT_TMP1), false, false); + tmpsq.render(false); +} diff --git a/src/graphics/sun.hpp b/src/graphics/sun.hpp new file mode 100644 index 000000000..387444c30 --- /dev/null +++ b/src/graphics/sun.hpp @@ -0,0 +1,40 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_SUN_HPP +#define HEADER_SUN_HPP + +#include "graphics/light.hpp" +#include "utils/cpp2011.h" + +class ScreenQuad; + +// The actual rain node +class SunNode: public LightNode +{ +public: + SunNode(scene::ISceneManager* mgr, float r, float g, float b); + virtual ~SunNode(); + + virtual void render() OVERRIDE; + +private: + ScreenQuad *sq; +}; + +#endif diff --git a/src/graphics/water.cpp b/src/graphics/water.cpp new file mode 100644 index 000000000..3ac11d981 --- /dev/null +++ b/src/graphics/water.cpp @@ -0,0 +1,94 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/water.hpp" + +#include "graphics/callbacks.hpp" +#include "graphics/glwrap.hpp" +#include "graphics/irr_driver.hpp" +#include "graphics/material_manager.hpp" +#include "graphics/material.hpp" +#include "graphics/rtts.hpp" +#include "graphics/shaders.hpp" + +using namespace video; +using namespace scene; +using namespace core; + +WaterNode::WaterNode(scene::ISceneManager* mgr, IMesh *mesh, float height, float speed, + float length): + IMeshSceneNode(mgr->getRootSceneNode(), mgr, -1) +{ + m_mat = mesh->getMeshBuffer(0)->getMaterial(); + + m_mat.Lighting = false; + + if (m_mat.MaterialType != irr_driver->getShader(ES_WATER)) + { + m_mat.MaterialType = irr_driver->getShader(ES_WATER_SURFACE); + } else + { + m_mat.BlendOperation = EBO_ADD; + } + + m_mat.setFlag(EMF_ZWRITE_ENABLE, false); + + m_mesh = mesh; + mesh->grab(); + mesh->setHardwareMappingHint(EHM_STATIC); + m_box = mesh->getBoundingBox(); + + m_height = height; + m_speed = speed; + m_length = length; +} + +WaterNode::~WaterNode() +{ + m_mesh->drop(); +} + +void WaterNode::render() +{ + if (SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT) + return; + + WaterShaderProvider * const cb = (WaterShaderProvider *) irr_driver->getCallback(ES_WATER); + cb->setSpeed(m_speed); + cb->setHeight(m_height); + cb->setLength(m_length); + + IVideoDriver * const drv = irr_driver->getVideoDriver(); + drv->setTransform(ETS_WORLD, AbsoluteTransformation); + drv->setMaterial(m_mat); + + const u32 max = m_mesh->getMeshBufferCount(); + for (u32 i = 0; i < max; i++) + { + drv->drawMeshBuffer(m_mesh->getMeshBuffer(i)); + } +} + +void WaterNode::OnRegisterSceneNode() +{ + if (IsVisible) + { + SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); + ISceneNode::OnRegisterSceneNode(); + } +} diff --git a/src/graphics/water.hpp b/src/graphics/water.hpp new file mode 100644 index 000000000..15acacb6f --- /dev/null +++ b/src/graphics/water.hpp @@ -0,0 +1,72 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_WATER_HPP +#define HEADER_WATER_HPP + +#include +#include + +using namespace irr; + +namespace irr +{ + namespace scene { class IMesh; } +} + +// The actual node +class WaterNode: public scene::IMeshSceneNode +{ +public: + WaterNode(scene::ISceneManager* mgr, scene::IMesh *mesh, float height, float speed, + float length); + virtual ~WaterNode(); + + virtual void render() OVERRIDE; + + virtual const core::aabbox3d& getBoundingBox() const OVERRIDE + { + return m_box; + } + + virtual void OnRegisterSceneNode() OVERRIDE; + + virtual u32 getMaterialCount() const OVERRIDE { return 1; } + virtual video::SMaterial& getMaterial(u32 i) OVERRIDE { return m_mat; } + + virtual scene::ESCENE_NODE_TYPE getType() const OVERRIDE { return scene::ESNT_MESH; } + + virtual void setMesh(scene::IMesh *) OVERRIDE {} + virtual scene::IMesh *getMesh() OVERRIDE { return m_mesh; } + virtual void setReadOnlyMaterials(bool) OVERRIDE {} + virtual bool isReadOnlyMaterials() const OVERRIDE { return false; } + virtual scene::IShadowVolumeSceneNode* addShadowVolumeSceneNode + (const scene::IMesh*, int, bool, f32) OVERRIDE { return NULL; } + +protected: + video::SMaterial m_mat; + core::aabbox3df m_box; + + scene::IMesh *m_mesh; + + float m_height; + float m_speed; + float m_length; +}; + +#endif diff --git a/src/graphics/wind.cpp b/src/graphics/wind.cpp new file mode 100644 index 000000000..cab30b15a --- /dev/null +++ b/src/graphics/wind.cpp @@ -0,0 +1,40 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/irr_driver.hpp" +#include "graphics/wind.hpp" +#include "utils/helpers.hpp" + +Wind::Wind() +{ + m_seed = (rand() % 1000) - 500; +} + +vector3df Wind::getWind() const +{ + return m_wind; +} + +void Wind::update() +{ + vector3df dir(0, 0, 1); + const u32 now = irr_driver->getDevice()->getTimer()->getTime(); + + const float rotation = asinf(noise2d(m_seed, now / 100000.0f)) * RAD_TO_DEGREE; + dir.rotateXZBy(rotation); + + m_wind = dir; +} diff --git a/src/graphics/wind.hpp b/src/graphics/wind.hpp new file mode 100644 index 000000000..651258f2b --- /dev/null +++ b/src/graphics/wind.hpp @@ -0,0 +1,38 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_WIND_HPP +#define HEADER_WIND_HPP + +#include +using namespace irr; +using core::vector3df; + +class Wind +{ +public: + Wind(); + + vector3df getWind() const; + void update(); + +private: + vector3df m_wind; + float m_seed; +}; + +#endif + diff --git a/src/guiengine/layout_manager.cpp b/src/guiengine/layout_manager.cpp index e05ce354e..b5cb4634c 100644 --- a/src/guiengine/layout_manager.cpp +++ b/src/guiengine/layout_manager.cpp @@ -33,13 +33,10 @@ using namespace video; #include "io/file_manager.hpp" #include "utils/ptr_vector.hpp" #include "utils/string_utils.hpp" +#include "utils/vs.hpp" using namespace GUIEngine; -#ifndef round -# define round(x) (floor(x+0.5f)) -#endif - /** Like atoi, but on error prints an error message to stderr */ int atoi_p(const char* val) { diff --git a/src/guiengine/widget.cpp b/src/guiengine/widget.cpp index eb60910b6..734b98cbd 100644 --- a/src/guiengine/widget.cpp +++ b/src/guiengine/widget.cpp @@ -34,11 +34,7 @@ using namespace gui; #include "io/file_manager.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" - - -#ifndef round -# define round(x) (floor(x+0.5f)) -#endif +#include "utils/vs.hpp" namespace GUIEngine { diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index d40464cfc..ddaae8673 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -19,6 +19,7 @@ #include "guiengine/widgets/dynamic_ribbon_widget.hpp" #include "io/file_manager.hpp" #include "states_screens/state_manager.hpp" +#include "utils/vs.hpp" #include #include @@ -29,10 +30,6 @@ using namespace GUIEngine; using namespace irr::core; using namespace irr::gui; -#ifndef round -# define round(x) (floor(x+0.5f)) -#endif - DynamicRibbonWidget::DynamicRibbonWidget(const bool combo, const bool multi_row) : Widget(WTYPE_DYNAMIC_RIBBON) { m_scroll_offset = 0; diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index 4ed5efc9a..40c2be3a0 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -28,6 +28,7 @@ #include "io/file_manager.hpp" #include "states_screens/state_manager.hpp" #include "utils/string_utils.hpp" +#include "utils/vs.hpp" #include #include @@ -37,10 +38,6 @@ using namespace GUIEngine; using namespace irr::core; using namespace irr::gui; -#ifndef round -# define round(x) (floor(x+0.5f)) -#endif - const char RibbonWidget::NO_ITEM_ID[] = "?"; diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index be9979bed..5933b4cc7 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -290,15 +290,51 @@ void InputManager::handleStaticAction(int key, int value) UserConfigParams::m_profiler_enabled = !UserConfigParams::m_profiler_enabled; break; + + // Debug views + // These should be available in normal (non-artist) mode + // to enable easier bug reports (go there, press this key, screenshot) + // without requiring editing the UTF-32 config files (which is inconvenient). case KEY_HOME: if (value) { - video::SOverrideMaterial &mat = - irr_driver->getVideoDriver()->getOverrideMaterial(); - - mat.Material.Wireframe ^= 1; - mat.EnableFlags = video::EMF_WIREFRAME; - mat.EnablePasses = scene::ESNRP_SOLID | scene::ESNRP_TRANSPARENT; + irr_driver->toggleWireframe(); + } + break; + case KEY_END: + if (value) + { + irr_driver->toggleMipVisualization(); + } + break; + case KEY_DELETE: + if (value) + { + irr_driver->toggleNormals(); + } + break; + case KEY_NEXT: // pgdown + if (value) + { + irr_driver->toggleSSAOViz(); + } + break; + case KEY_PRIOR: // pgup + if (value) + { + irr_driver->toggleLightViz(); + } + break; + case KEY_INSERT: + if (value) + { + irr_driver->toggleShadowViz(); + } + break; + case KEY_SCROLL: + if (value) + { + irr_driver->toggleDistortViz(); } break; default: diff --git a/src/items/attachment.cpp b/src/items/attachment.cpp index 36ff1512c..ebfd86e03 100644 --- a/src/items/attachment.cpp +++ b/src/items/attachment.cpp @@ -177,6 +177,8 @@ void Attachment::set(AttachmentType type, float time, } } m_node->setVisible(true); + + irr_driver->applyObjectPassShader(m_node); } // set // ----------------------------------------------------------------------------- diff --git a/src/items/flyable.cpp b/src/items/flyable.cpp index d6bbed85f..813b87cdc 100644 --- a/src/items/flyable.cpp +++ b/src/items/flyable.cpp @@ -21,9 +21,6 @@ #include "items/flyable.hpp" -#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) -# define isnan _isnan -#endif #include #include @@ -43,6 +40,7 @@ #include "tracks/track.hpp" #include "utils/constants.hpp" #include "utils/string_utils.hpp" +#include "utils/vs.hpp" // static variables: float Flyable::m_st_speed [PowerupManager::POWERUP_MAX]; @@ -78,6 +76,7 @@ Flyable::Flyable(AbstractKart *kart, PowerupManager::PowerupType type, // Add the graphical model setNode(irr_driver->addMesh(m_st_model[type])); + irr_driver->applyObjectPassShader(getNode()); #ifdef DEBUG std::string debug_name("flyable: "); debug_name += type; diff --git a/src/items/item.cpp b/src/items/item.cpp index f08550002..2a15d4399 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -186,8 +186,11 @@ void Item::switchTo(ItemType type, scene::IMesh *mesh, scene::IMesh *lowmesh) { node = m_node->getAllNodes()[1]; ((scene::IMeshSceneNode*)node)->setMesh(lowmesh); + irr_driver->applyObjectPassShader(m_node->getAllNodes()[1]); } + irr_driver->applyObjectPassShader(m_node->getAllNodes()[0]); + World::getWorld()->getTrack()->adjustForFog(m_node); } // switchTo diff --git a/src/items/rubber_band.cpp b/src/items/rubber_band.cpp index a9291924c..99ad6e16a 100644 --- a/src/items/rubber_band.cpp +++ b/src/items/rubber_band.cpp @@ -67,7 +67,7 @@ const wchar_t* getPlungerString() RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart) : m_plunger(plunger), m_owner(kart) { - video::SColor color(77, 179, 0, 0); + const video::SColor color(77, 179, 0, 0); video::SMaterial m; m.AmbientColor = color; m.DiffuseColor = color; @@ -78,8 +78,19 @@ RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart) m_attached_state = RB_TO_PLUNGER; assert(m_buffer->getVertexType()==video::EVT_STANDARD); + // Set the vertex colors properly, as the new pipeline doesn't use the old light values + u32 i; + scene::IMeshBuffer * const mb = m_mesh->getMeshBuffer(0); + video::S3DVertex * const verts = (video::S3DVertex *) mb->getVertices(); + const u32 max = mb->getVertexCount(); + for (i = 0; i < max; i++) + { + verts[i].Color = color; + } + updatePosition(); m_node = irr_driver->addMesh(m_mesh); + irr_driver->applyObjectPassShader(m_node); #ifdef DEBUG std::string debug_name = m_owner->getIdent()+" (rubber-band)"; m_node->setName(debug_name.c_str()); diff --git a/src/karts/controller/skidding_ai.cpp b/src/karts/controller/skidding_ai.cpp index 0592299f7..53738399f 100644 --- a/src/karts/controller/skidding_ai.cpp +++ b/src/karts/controller/skidding_ai.cpp @@ -61,18 +61,14 @@ #include "tracks/track.hpp" #include "utils/constants.hpp" #include "utils/log.hpp" +#include "utils/vs.hpp" #ifdef AI_DEBUG # include "irrlicht.h" using namespace irr; #endif -#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) -# define isnan _isnan -#else -# include -#endif - +#include #include #include #include diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index d12d0864b..a9d2ba0ed 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -70,6 +70,7 @@ #include "tracks/track_manager.hpp" #include "utils/constants.hpp" #include "utils/log.hpp" //TODO: remove after debugging is done +#include "utils/vs.hpp" @@ -78,12 +79,6 @@ # pragma warning(disable:4355) #endif -#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) -# define isnan _isnan -#else -# include -#endif - /** The kart constructor. * \param ident The identifier for the kart model to use. * \param position The position (or rank) for this kart (between 1 and @@ -1325,13 +1320,18 @@ void Kart::update(float dt) m_kart_model->setAnimation(KartModel::AF_DEFAULT); m_jump_time = 0; } - - if( (!isOnGround() || emergency) && m_shadow_enabled) + + const bool dyn_shadows = World::getWorld()->getTrack()->hasShadows() && + UserConfigParams::m_shadows && + irr_driver->isGLSL(); + + // Disable the fake shadow if real ones are in use, or if we're flying + if( ((!isOnGround() || emergency) && m_shadow_enabled) || dyn_shadows) { m_shadow_enabled = false; m_shadow->disableShadow(); } - if(!m_shadow_enabled && isOnGround() && !emergency) + if(!m_shadow_enabled && isOnGround() && !emergency && !dyn_shadows) { m_shadow->enableShadow(); m_shadow_enabled = true; diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index de120ecad..20419c581 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -373,6 +373,15 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models) if(!m_speed_weighted_objects[i].m_node) continue; m_speed_weighted_objects[i].m_node->setParent(lod_node); } + + // Enable rim lighting for the kart + irr_driver->applyObjectPassShader(lod_node, true); + std::vector &lodnodes = lod_node->getAllNodes(); + const u32 max = lodnodes.size(); + for (u32 i = 0; i < max; i++) + { + irr_driver->applyObjectPassShader(lodnodes[i], true); + } } else { @@ -401,6 +410,7 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models) m_wheel_graphics_radius[i] = 0.5f*(wheel_max.getY() - wheel_min.getY()); m_wheel_node[i]->grab(); + ((scene::IMeshSceneNode *) m_wheel_node[i])->setReadOnlyMaterials(true); #ifdef DEBUG std::string debug_name = m_wheel_filename[i]+" (wheel)"; m_wheel_node[i]->setName(debug_name.c_str()); diff --git a/src/karts/moveable.cpp b/src/karts/moveable.cpp index b985020a3..afeb56e4c 100644 --- a/src/karts/moveable.cpp +++ b/src/karts/moveable.cpp @@ -17,6 +17,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include #include "karts/moveable.hpp" #include "graphics/irr_driver.hpp" diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 626f32e87..1cbed703c 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -183,6 +183,9 @@ void World::init() } // for i + // Now that all models are loaded, apply the overrides + irr_driver->applyObjectPassShader(); + // Must be called after all karts are created m_race_gui->init(); diff --git a/src/physics/kart_motion_state.hpp b/src/physics/kart_motion_state.hpp index df58bcaf3..8e0fa80e0 100644 --- a/src/physics/kart_motion_state.hpp +++ b/src/physics/kart_motion_state.hpp @@ -19,11 +19,8 @@ #ifndef HEADER_KART_MOTION_STATE_HPP #define HEADER_KART_MOTION_STATE_HPP -#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) -# define isnan _isnan -#else -# include -#endif +#include +#include "utils/vs.hpp" #include "LinearMath/btMotionState.h" diff --git a/src/states_screens/dialogs/custom_video_settings.cpp b/src/states_screens/dialogs/custom_video_settings.cpp index 1966ac8af..aef6328af 100644 --- a/src/states_screens/dialogs/custom_video_settings.cpp +++ b/src/states_screens/dialogs/custom_video_settings.cpp @@ -83,7 +83,20 @@ void CustomVideoSettingsialog::beforeAddingWidgets() antialias->addLabel( L"x8" ); // 3 antialias->setValue( UserConfigParams::m_antialiasing ); - getWidget("postprocessing")->setState( UserConfigParams::m_postprocess_enabled ); + SpinnerWidget* ssao = getWidget("ssao"); + ssao->addLabel( _("Disabled") ); // 0 + ssao->addLabel( _("low") ); // 1 + ssao->addLabel( _("high") ); // 2 + ssao->setValue( UserConfigParams::m_ssao ); + + SpinnerWidget* shadows = getWidget("shadows"); + shadows->addLabel( _("Disabled") ); // 0 + shadows->addLabel( _("low") ); // 1 + shadows->addLabel( _("high") ); // 2 + shadows->setValue( UserConfigParams::m_shadows ); + + getWidget("motionblur")->setState( UserConfigParams::m_motionblur ); + getWidget("mlaa")->setState( UserConfigParams::m_mlaa ); getWidget("pixelshaders")->setState( UserConfigParams::m_pixel_shaders ); } @@ -99,12 +112,18 @@ GUIEngine::EventPropagation CustomVideoSettingsialog::processEvent(const std::st getWidget("weather_gfx")->getState(); UserConfigParams::m_antialiasing = getWidget("antialiasing")->getValue(); - UserConfigParams::m_postprocess_enabled = - getWidget("postprocessing")->getState(); + UserConfigParams::m_motionblur = + getWidget("motionblur")->getState(); UserConfigParams::m_show_steering_animations = getWidget("steering_animations")->getValue(); UserConfigParams::m_pixel_shaders = getWidget("pixelshaders")->getState(); + UserConfigParams::m_mlaa = + getWidget("mlaa")->getState(); + UserConfigParams::m_ssao = + getWidget("ssao")->getValue(); + UserConfigParams::m_shadows = + getWidget("shadows")->getValue(); switch (getWidget("filtering")->getValue()) { diff --git a/src/states_screens/feature_unlocked.cpp b/src/states_screens/feature_unlocked.cpp index a1b898434..dcb56b6ce 100644 --- a/src/states_screens/feature_unlocked.cpp +++ b/src/states_screens/feature_unlocked.cpp @@ -300,15 +300,16 @@ void FeatureUnlockedCutScene::init() 120, 120)); const core::vector3df &sun_pos = core::vector3df( 0, 200, 100.0f ); - m_light = - irr_driver->getSceneManager()->addLightSceneNode(NULL, sun_pos, - video::SColorf(1.0f,1.0f,1.0f), - 10000.0f /* radius */); + m_light = irr_driver->addLight(sun_pos, 10000.0f, 1, 1, 1); #ifdef DEBUG m_light->setName("light"); #endif - m_light->getLightData().DiffuseColor = irr::video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); - m_light->getLightData().SpecularColor = irr::video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); + + if (!irr_driver->isGLSL()) + { + ((scene::ILightSceneNode *) m_light)->getLightData().DiffuseColor = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); + ((scene::ILightSceneNode *) m_light)->getLightData().SpecularColor = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); + } const int unlockedStuffCount = m_unlocked_stuff.size(); diff --git a/src/states_screens/feature_unlocked.hpp b/src/states_screens/feature_unlocked.hpp index eeb3a34eb..867825442 100644 --- a/src/states_screens/feature_unlocked.hpp +++ b/src/states_screens/feature_unlocked.hpp @@ -113,7 +113,7 @@ class FeatureUnlockedCutScene : public GUIEngine::Screen, public GUIEngine::Scre irr::scene::IAnimatedMeshSceneNode *m_chest; /** The scene node for the light. */ - irr::scene::ILightSceneNode* m_light; + irr::scene::ISceneNode* m_light; //#define USE_IRRLICHT_BUG_WORKAROUND diff --git a/src/states_screens/grand_prix_lose.cpp b/src/states_screens/grand_prix_lose.cpp index e1e08e6ca..449da86d6 100644 --- a/src/states_screens/grand_prix_lose.cpp +++ b/src/states_screens/grand_prix_lose.cpp @@ -155,11 +155,14 @@ void GrandPrixLose::init() sceneManager->setAmbientLight(video::SColor(255, 120, 120, 120)); const core::vector3df &sun_pos = core::vector3df( 0, 200, 100.0f ); - m_light = irr_driver->getSceneManager()->addLightSceneNode(NULL, sun_pos, - video::SColorf(1.0f,1.0f,1.0f), - 300.0f /* radius */); - m_light->getLightData().DiffuseColor = irr::video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); - m_light->getLightData().SpecularColor = irr::video::SColorf(1.0f, 0.0f, 0.0f, 0.0f); + m_light = irr_driver->addLight(sun_pos, 300.0f, 1, 1, 1); + + if (!irr_driver->isGLSL()) + { + scene::ILightSceneNode *lnode = (scene::ILightSceneNode *) m_light; + lnode->getLightData().DiffuseColor = irr::video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); + lnode->getLightData().SpecularColor = irr::video::SColorf(1.0f, 0.0f, 0.0f, 0.0f); + } } // init // ------------------------------------------------------------------------------------- diff --git a/src/states_screens/grand_prix_lose.hpp b/src/states_screens/grand_prix_lose.hpp index e20097682..7395e5ea0 100644 --- a/src/states_screens/grand_prix_lose.hpp +++ b/src/states_screens/grand_prix_lose.hpp @@ -53,7 +53,7 @@ class GrandPrixLose : public GUIEngine::Screen, public GUIEngine::ScreenSingleto irr::scene::ISceneNode* m_sky; irr::scene::ICameraSceneNode* m_camera; - irr::scene::ILightSceneNode* m_light; + irr::scene::ISceneNode* m_light; /** A copy of the kart model for each kart used. */ std::vector m_all_kart_models; diff --git a/src/states_screens/grand_prix_win.cpp b/src/states_screens/grand_prix_win.cpp index 5e29da0bd..1aed4ba40 100644 --- a/src/states_screens/grand_prix_win.cpp +++ b/src/states_screens/grand_prix_win.cpp @@ -210,14 +210,18 @@ void GrandPrixWin::init() sceneManager->setAmbientLight(video::SColor(255, 95, 95, 95)); const core::vector3df &sun_pos = core::vector3df( 0, 200, 100.0f ); - m_light = irr_driver->getSceneManager()->addLightSceneNode(NULL, sun_pos, - video::SColorf(0.25f,0.25f,0.25f), - 300.0f /* radius */); - m_light->getLightData().DiffuseColor = irr::video::SColorf(0.25f, 0.25f, 0.25f, 1.0f); - m_light->getLightData().AmbientColor = irr::video::SColorf(0.25f, 0.25f, 0.25f, 1.0f); - m_light->getLightData().SpecularColor = irr::video::SColorf(0.0f, 0.0f, 0.0f, 1.0f); + m_light = irr_driver->addLight(sun_pos, 300.0f, 0.25f, 0.25f, 0.25f); m_finish_sound = sfx_manager->quickSound("gp_end"); + if (!irr_driver->isGLSL()) + { + scene::ILightSceneNode *lnode = (scene::ILightSceneNode *) m_light; + lnode->getLightData().DiffuseColor = irr::video::SColorf(0.25f, 0.25f, 0.25f, 1.0f); + lnode->getLightData().AmbientColor = irr::video::SColorf(0.25f, 0.25f, 0.25f, 1.0f); + lnode->getLightData().SpecularColor = irr::video::SColorf(0.0f, 0.0f, 0.0f, 1.0f); + } + + sfx_manager->quickSound("gp_end"); } // init // ------------------------------------------------------------------------------------- diff --git a/src/states_screens/grand_prix_win.hpp b/src/states_screens/grand_prix_win.hpp index a2316220b..8a5ca7e0c 100644 --- a/src/states_screens/grand_prix_win.hpp +++ b/src/states_screens/grand_prix_win.hpp @@ -54,7 +54,7 @@ class GrandPrixWin : public GUIEngine::Screen, public GUIEngine::ScreenSingleton irr::scene::ISceneNode* m_sky; irr::scene::ICameraSceneNode* m_camera; - irr::scene::ILightSceneNode* m_light; + irr::scene::ISceneNode* m_light; GUIEngine::LabelWidget* m_unlocked_label; diff --git a/src/states_screens/options_screen_video.cpp b/src/states_screens/options_screen_video.cpp index bd760f60d..d4a98094e 100644 --- a/src/states_screens/options_screen_video.cpp +++ b/src/states_screens/options_screen_video.cpp @@ -45,15 +45,20 @@ using namespace GUIEngine; DEFINE_SCREEN_SINGLETON( OptionsScreenVideo ); // Look-up table for GFX levels -const bool GFX [] = {false, true, true, true, true, true, true, true}; -const int GFX_ANIM_KARTS[] = {0, 0, 1, 2, 2, 2, 2, 2}; -const bool GFX_WEATHER [] = {false, false, false, false, true, true, true, true}; -const int GFX_ANTIALIAS [] = {0, 0, 0, 0, 0, 2, 2, 3}; -const bool GFX_POSTPROCESSING[] = - {false, false, false, false, false, false, true, true}; -const bool GFX_PIXEL_SHADERS[] = +static const bool GFX [] = {false, true, true, true, true, true, true, true}; +static const int GFX_ANIM_KARTS[] = {0, 1, 2, 2, 2, 2, 2, 2}; +static const bool GFX_WEATHER [] = {false, false, true, true, true, true, true, true}; +static const int GFX_ANTIALIAS [] = {0, 0, 0, 0, 0, 2, 2, 3}; +static const bool GFX_MOTIONBLUR[] = {false, false, false, false, true, true, true, true}; -const int GFX_LEVEL_AMOUNT = 8; +static const bool GFX_PIXEL_SHADERS[] = + {false, false, true, true, true, true, true, true}; +static const bool GFX_MLAA[] = {false, false, false, false, false, true, true, true}; +static const int GFX_SSAO[] = {0, 0, 0, 1, 1, 1, 2, 2}; +static const int GFX_SHADOWS[] = {0, 0, 0, 1, 1, 2, 2, 2}; + + +static const int GFX_LEVEL_AMOUNT = 8; // ---------------------------------------------------------------------------- @@ -102,11 +107,6 @@ void OptionsScreenVideo::init() assert( vsync != NULL ); vsync->setState( UserConfigParams::m_vsync ); - GUIEngine::CheckBoxWidget* fbos = - getWidget("fbos"); - assert( fbos != NULL ); - fbos->setState( UserConfigParams::m_fbo ); - // ---- video modes DynamicRibbonWidget* res = getWidget("resolutions"); @@ -315,7 +315,10 @@ void OptionsScreenVideo::updateGfxSlider() UserConfigParams::m_graphical_effects == GFX[l] && UserConfigParams::m_weather_effects == GFX_WEATHER[l] && UserConfigParams::m_antialiasing == GFX_ANTIALIAS[l] && - UserConfigParams::m_postprocess_enabled == GFX_POSTPROCESSING[l] && + UserConfigParams::m_motionblur == GFX_MOTIONBLUR[l] && + UserConfigParams::m_mlaa == GFX_MLAA[l] && + UserConfigParams::m_ssao == GFX_SSAO[l] && + UserConfigParams::m_shadows == GFX_SHADOWS[l] && UserConfigParams::m_pixel_shaders == GFX_PIXEL_SHADERS[l]) { gfx->setValue(l+1); @@ -345,16 +348,16 @@ void OptionsScreenVideo::updateTooltip() //I18N: in the graphical options tooltip; // indicates a graphical feature is enabled - core::stringw enabled = _LTR("Enabled"); + const core::stringw enabled = _LTR("Enabled"); //I18N: in the graphical options tooltip; // indicates a graphical feature is disabled - core::stringw disabled = _LTR("Disabled"); + const core::stringw disabled = _LTR("Disabled"); //I18N: if all kart animations are enabled - core::stringw all = _LTR("All"); + const core::stringw all = _LTR("All"); //I18N: if some kart animations are enabled - core::stringw me = _LTR("Me Only"); + const core::stringw me = _LTR("Me Only"); //I18N: if no kart animations are enabled - core::stringw none = _LTR("None"); + const core::stringw none = _LTR("None"); core::stringw antialias_label; switch ((int)UserConfigParams::m_antialiasing) @@ -369,6 +372,9 @@ void OptionsScreenVideo::updateTooltip() antialias_label = L"x8"; break; } + //I18N: in graphical options + tooltip = tooltip + L"\n" + _("Pixel shaders : %s", + UserConfigParams::m_pixel_shaders ? enabled : disabled); //I18N: in graphical options tooltip = _("Animated Scenery : %s", UserConfigParams::m_graphical_effects ? enabled : disabled); @@ -384,11 +390,22 @@ void OptionsScreenVideo::updateTooltip() tooltip = tooltip + L"\n" + _("Anti-aliasing (requires restart) : %s", antialias_label); //I18N: in graphical options - tooltip = tooltip + L"\n" + _("Pixel shaders : %s", - UserConfigParams::m_pixel_shaders ? enabled : disabled); + tooltip = tooltip + L"\n" + _("Motion blur: %s", + UserConfigParams::m_motionblur ? enabled : disabled); //I18N: in graphical options - tooltip = tooltip + L"\n" + _("Post-processing (motion blur) : %s", - UserConfigParams::m_postprocess_enabled ? enabled : disabled); + tooltip = tooltip + L"\n" + _("MLAA: %s", + UserConfigParams::m_mlaa ? enabled : disabled); + //I18N: in graphical options + tooltip = tooltip + L"\n" + _("SSAO: %s", + UserConfigParams::m_ssao == 1 ? "low" : UserConfigParams::m_ssao == 2 ? + "high" : disabled); + //I18N: in graphical options + tooltip = tooltip + L"\n" + _("Shadows: %s", + UserConfigParams::m_shadows == 1 ? "low" : UserConfigParams::m_shadows == 2 ? + "high" : disabled); + + + gfx->setTooltip(tooltip); } // updateTooltip @@ -461,8 +478,11 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, UserConfigParams::m_graphical_effects = GFX[level-1]; UserConfigParams::m_weather_effects = GFX_WEATHER[level-1]; UserConfigParams::m_antialiasing = GFX_ANTIALIAS[level-1]; - UserConfigParams::m_postprocess_enabled = GFX_POSTPROCESSING[level-1]; + UserConfigParams::m_motionblur = GFX_MOTIONBLUR[level-1]; UserConfigParams::m_pixel_shaders = GFX_PIXEL_SHADERS[level-1]; + UserConfigParams::m_mlaa = GFX_MLAA[level-1]; + UserConfigParams::m_ssao = GFX_SSAO[level-1]; + UserConfigParams::m_shadows = GFX_SHADOWS[level-1]; updateGfxSlider(); } @@ -473,13 +493,6 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, assert( vsync != NULL ); UserConfigParams::m_vsync = vsync->getState(); } - else if (name == "fbos") - { - GUIEngine::CheckBoxWidget* fbos = - getWidget("fbos"); - assert( fbos != NULL ); - UserConfigParams::m_fbo = fbos->getState(); - } else if (name == "rememberWinpos") { CheckBoxWidget* rememberWinpos = getWidget("rememberWinpos"); diff --git a/src/states_screens/race_gui_base.cpp b/src/states_screens/race_gui_base.cpp index 881f2e398..846024fe7 100644 --- a/src/states_screens/race_gui_base.cpp +++ b/src/states_screens/race_gui_base.cpp @@ -20,21 +20,8 @@ #include "states_screens/race_gui_base.hpp" -#ifdef __APPLE__ -# include -#else -# define _WINSOCKAPI_ -# ifdef WIN32 -# include -# endif -# ifdef ANDROID -# include -# else -# include -# endif -#endif - #include "audio/music_manager.hpp" +#include "graphics/glwrap.hpp" #include "graphics/irr_driver.hpp" #include "graphics/material.hpp" #include "graphics/material_manager.hpp" diff --git a/src/tracks/quad_graph.cpp b/src/tracks/quad_graph.cpp index bdae209ee..e68041a84 100644 --- a/src/tracks/quad_graph.cpp +++ b/src/tracks/quad_graph.cpp @@ -24,7 +24,11 @@ #include #include "config/user_config.hpp" +#include "graphics/callbacks.hpp" #include "graphics/irr_driver.hpp" +#include "graphics/screenquad.hpp" +#include "graphics/shaders.hpp" +#include "graphics/rtts.hpp" #include "io/file_manager.hpp" #include "io/xml_node.hpp" #include "modes/world.hpp" @@ -966,10 +970,12 @@ int QuadGraph::findOutOfRoadSector(const Vec3& xyz, //----------------------------------------------------------------------------- /** Takes a snapshot of the driveline quads so they can be used as minimap. */ -video::ITexture *QuadGraph::makeMiniMap(const core::dimension2du &dimension, +video::ITexture *QuadGraph::makeMiniMap(const core::dimension2du &origdimension, const std::string &name, const video::SColor &fill_color) { + const core::dimension2du dimension = origdimension * 2; + IrrDriver::RTTProvider rttProvider(dimension, name, true); video::SColor red(128, 255, 0, 0); createMesh(/*show_invisible part of the track*/ false, @@ -1047,8 +1053,28 @@ video::ITexture *QuadGraph::makeMiniMap(const core::dimension2du &dimension, { Log::error("Quad Graph", "[makeMiniMap] WARNING: RTT does not appear to work," "mini-map will not be available."); + return NULL; } + if (!irr_driver->isGLSL()) + return texture; + + GaussianBlurProvider * const gacb = (GaussianBlurProvider *) irr_driver->getCallback(ES_GAUSSIAN3H); + gacb->setResolution(UserConfigParams::m_width, UserConfigParams::m_height); + + ScreenQuad sq(irr_driver->getVideoDriver()); + sq.getMaterial().MaterialType = irr_driver->getShader(ES_GAUSSIAN3H); + sq.setTexture(texture); + + // Horizontal pass + sq.render(irr_driver->getRTT(RTT_TMP1)); + + // Vertical pass + sq.getMaterial().MaterialType = irr_driver->getShader(ES_GAUSSIAN3V); + sq.setTexture(irr_driver->getRTT(RTT_TMP1)); + + sq.render(texture); + return texture; } // makeMiniMap diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 9df42d10c..71bdec41f 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -112,6 +112,14 @@ Track::Track(const std::string &filename) m_is_cutscene = false; m_camera_far = 1000.0f; m_mini_map = NULL; + m_bloom = true; + m_bloom_threshold = 0.75f; + m_clouds = false; + m_lensflare = false; + m_godrays = false; + m_displacement_speed = 1.0f; + m_caustics_speed = 1.0f; + m_shadows = true; m_sky_particles = NULL; m_sky_dx = 0.05f; m_sky_dy = 0.0f; @@ -258,6 +266,12 @@ void Track::cleanup() material_manager->popTempMaterial(); } + irr_driver->clearGlowingNodes(); + irr_driver->clearLights(); + irr_driver->clearForcedBloom(); + irr_driver->clearDisplacingNodes(); + irr_driver->clearBackgroundNodes(); + if(UserConfigParams::logMemory()) { Log::debug("track", @@ -309,9 +323,11 @@ void Track::loadTrackInfo() { // Default values m_use_fog = false; - m_fog_density = 1.0f/100.0f; + m_fog_max = 1.0f; m_fog_start = 0.0f; m_fog_end = 1000.0f; + m_fog_height_start = 0.0f; + m_fog_height_end = 100.0f; m_gravity = 9.80665f; m_smooth_normals = false; /* ARGB */ @@ -347,6 +363,14 @@ void Track::loadTrackInfo() root->get("internal", &m_internal); root->get("reverse", &m_reverse_available); root->get("push-back", &m_enable_push_back); + root->get("clouds", &m_clouds); + root->get("bloom", &m_bloom); + root->get("bloom-threshold", &m_bloom_threshold); + root->get("lens-flare", &m_lensflare); + root->get("shadows", &m_shadows); + root->get("god-rays", &m_godrays); + root->get("displacement-speed", &m_displacement_speed); + root->get("caustics-speed", &m_caustics_speed); // Make the default for auto-rescue in battle mode and soccer mode to be false if(m_is_arena || m_is_soccer) @@ -1297,17 +1321,17 @@ void Track::createWater(const XMLNode &node) if (UserConfigParams::m_graphical_effects) { - scene_node = irr_driver->addWaterNode(mesh, + scene::IMesh *welded; + scene_node = irr_driver->addWaterNode(mesh, &welded, wave_height, wave_speed, wave_length); - // 'addWaterNode' welds the mesh so keep both the original and the welded copy mesh->grab(); irr_driver->grabAllTextures(mesh); m_all_cached_meshes.push_back(mesh); - mesh = ((scene::IMeshSceneNode*)scene_node)->getMesh(); + mesh = welded; } else { @@ -1473,9 +1497,11 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) node->get("sun-diffuse", &m_sun_diffuse_color); node->get("fog", &m_use_fog); node->get("fog-color", &m_fog_color); - node->get("fog-density", &m_fog_density); + node->get("fog-max", &m_fog_max); node->get("fog-start", &m_fog_start); node->get("fog-end", &m_fog_end); + node->get("fog-start-height", &m_fog_height_start); + node->get("fog-end-height", &m_fog_height_end); } loadMainTrack(*root); @@ -1555,14 +1581,21 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) video::SColor color; node->get("color", &color); + const video::SColorf colorf(color); float distance = 25.0f; node->get("distance", &distance); + if (irr_driver->isGLSL()) + { + irr_driver->addLight(pos, distance, colorf.r, colorf.g, colorf.b); + } else + { scene::ILightSceneNode* node = irr_driver->getSceneManager()->addLightSceneNode(NULL, pos, color, distance); node->setLightType(video::ELT_POINT); node->enableCastShadow(true); } + } else if(name=="weather") { std::string weather_particles; @@ -1650,14 +1683,14 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) // It's important to execute this BEFORE the code that creates the skycube, // otherwise the skycube node could be modified to have fog enabled, which // we don't want - if (m_use_fog && !UserConfigParams::m_camera_debug) + if (m_use_fog && !UserConfigParams::m_camera_debug && !irr_driver->isGLSL()) { /* NOTE: if LINEAR type, density does not matter, if EXP or EXP2, start and end do not matter */ irr_driver->getVideoDriver()->setFog(m_fog_color, video::EFT_FOG_LINEAR, m_fog_start, m_fog_end, - m_fog_density); + 1.0f); } // Enable for for all track nodes if fog is used @@ -1712,21 +1745,30 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) irr_driver->getSceneManager()->setAmbientLight(m_ambient_color); // ---- Create sun (non-ambient directional light) - m_sun = irr_driver->getSceneManager()->addLightSceneNode(NULL, - m_sun_position, - m_sun_diffuse_color); - m_sun->setLightType(video::ELT_DIRECTIONAL); + if (m_sun_position.getLengthSQ() < 0.03f) + { + m_sun_position = core::vector3df(500, 250, 250); + } + + const video::SColorf tmpf(m_sun_diffuse_color); + m_sun = irr_driver->addLight(m_sun_position, 10000.0f, tmpf.r, tmpf.g, tmpf.b, true); + + if (!irr_driver->isGLSL()) + { + scene::ILightSceneNode *sun = (scene::ILightSceneNode *) m_sun; + sun->setLightType(video::ELT_DIRECTIONAL); // The angle of the light is rather important - let the sun // point towards (0,0,0). - if(m_sun_position.getLengthSQ()==0) + if(m_sun_position.getLengthSQ() < 0.03f) // Backward compatibility: if no sun is specified, use the // old hardcoded default angle m_sun->setRotation( core::vector3df(180, 45, 45) ); else m_sun->setRotation((-m_sun_position).getHorizontalAngle()); - m_sun->getLightData().SpecularColor = m_sun_specular_color; + sun->getLightData().SpecularColor = m_sun_specular_color; + } createPhysicsModel(main_track_count); diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index eb0b2f27d..01db425f5 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -221,7 +221,7 @@ private: #endif PtrVector m_all_emitters; - scene::ILightSceneNode *m_sun; + scene::ISceneNode *m_sun; /** Used to collect the triangles for the bullet mesh. */ TriangleMesh* m_track_mesh; /** Used to collect the triangles which do not have a physical @@ -350,9 +350,11 @@ private: /** True if this track supports using smoothed normals. */ bool m_smooth_normals; - float m_fog_density; + float m_fog_max; float m_fog_start; float m_fog_end; + float m_fog_height_start; + float m_fog_height_end; core::vector3df m_sun_position; /** The current ambient color for each kart. */ video::SColor m_ambient_color; @@ -367,6 +369,18 @@ private: float m_minimap_x_scale; float m_minimap_y_scale; + bool m_clouds; + + bool m_bloom; + float m_bloom_threshold; + + bool m_lensflare; + bool m_godrays; + bool m_shadows; + + float m_displacement_speed; + float m_caustics_speed; + /** List of all bezier curves in the track - for e.g. camera, ... */ std::vector m_all_curves; @@ -534,8 +548,16 @@ public: // ------------------------------------------------------------------------ float getFogEnd() const { return m_fog_end; } // ------------------------------------------------------------------------ + float getFogStartHeight() const { return m_fog_height_start; } + // ------------------------------------------------------------------------ + float getFogEndHeight() const { return m_fog_height_end; } + // ------------------------------------------------------------------------ + float getFogMax() const { return m_fog_max; } + // ------------------------------------------------------------------------ video::SColor getFogColor() const { return m_fog_color; } // ------------------------------------------------------------------------ + video::SColor getSunColor() const { return m_sun_diffuse_color; } + // ------------------------------------------------------------------------ /** Whether this is an "internal" track. If so it won't be offered * in the track selection screen. */ bool isInternal() const { return m_internal; } @@ -557,6 +579,17 @@ public: const std::vector& getSubtitles() const { return m_subtitles; } + bool hasClouds() const { return m_clouds; } + + bool getBloom() const { return m_bloom; } + float getBloomThreshold() const { return m_bloom_threshold; } + + bool hasLensFlare() const { return m_lensflare; } + bool hasGodRays() const { return m_godrays; } + bool hasShadows() const { return m_shadows; } + + float getDisplacementSpeed() const { return m_displacement_speed; } + float getCausticsSpeed() const { return m_caustics_speed; } }; // class Track #endif diff --git a/src/tracks/track_object.cpp b/src/tracks/track_object.cpp index fe101baf7..9d21e413f 100644 --- a/src/tracks/track_object.cpp +++ b/src/tracks/track_object.cpp @@ -26,6 +26,7 @@ #include "items/item_manager.hpp" #include "physics/physical_object.hpp" #include "race/race_manager.hpp" +#include "utils/helpers.hpp" /** A track object: any additional object on the track. This object implements @@ -133,24 +134,59 @@ void TrackObject::init(const XMLNode &xml_node, LODNode* lod_node) } else { + scene::ISceneNode *glownode = NULL; + if (lod_node != NULL) { m_type = "lod"; m_presentation = new TrackObjectPresentationLOD(xml_node, lod_node); + + glownode = lod_node->getAllNodes()[0]; } else { m_type = "mesh"; m_presentation = new TrackObjectPresentationMesh(xml_node, m_enabled); + glownode = ((TrackObjectPresentationMesh *) m_presentation)->getNode(); } - if (m_interaction != "ghost" && m_interaction != "none") + std::string render_pass; + xml_node.get("renderpass", &render_pass); + + if (m_interaction != "ghost" && m_interaction != "none" && render_pass != "skybox") { m_rigid_body = PhysicalObject::fromXML(type == "movable", xml_node, this); } + + video::SColor glow; + if (xml_node.get("glow", &glow) && glownode) + { + float r, g, b; + r = glow.getRed() / 255.0f; + g = glow.getGreen() / 255.0f; + b = glow.getBlue() / 255.0f; + + irr_driver->addGlowingNode(glownode, r, g, b); + } + + bool forcedbloom = false; + if (xml_node.get("forcedbloom", &forcedbloom) && forcedbloom && glownode) + { + float power = 1; + xml_node.get("bloompower", &power); + power = clampf(power, 0.5f, 10); + + irr_driver->addForcedBloomNode(glownode, power); + } + + bool displacing = false; + if (xml_node.get("displacing", &displacing) && displacing && glownode) + { + irr_driver->addDisplacingNode(glownode); + } } diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 9f0b7f5a2..d5f20d0f6 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -150,6 +150,15 @@ TrackObjectPresentationMesh::TrackObjectPresentationMesh(const XMLNode& xml_node std::string model_name; xml_node.get("model", &model_name ); + m_is_in_skybox = false; + std::string render_pass; + xml_node.get("renderpass", &render_pass); + + if(render_pass == "skybox") + { + m_is_in_skybox = true; + } + std::string full_path = World::getWorld()->getTrack()->getTrackFile(model_name); @@ -225,7 +234,19 @@ void TrackObjectPresentationMesh::init(const XMLNode* xml_node, bool enabled) m_mesh->grab(); irr_driver->grabAllTextures(m_mesh); - if (animated) + if (m_is_in_skybox) + { + // Tell the driver that this mesh is a part of the background + scene::IMeshSceneNode * const node = + irr_driver->getSceneManager()->addMeshSceneNode(m_mesh); + node->grab(); + node->setParent(NULL); + + irr_driver->addBackgroundNode(node); + + m_node = node; + } + else if (animated) { scene::IAnimatedMeshSceneNode *node = irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)m_mesh); @@ -576,7 +597,7 @@ TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(const xml_node.get("action", &m_action); m_action_active = true; - + if (m_action.size() == 0) { fprintf(stderr, "[TrackObject] WARNING: action-trigger has no action defined\n"); @@ -588,7 +609,7 @@ TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(const void TrackObjectPresentationActionTrigger::onTriggerItemApproached(Item* who) { if (!m_action_active) return; - + if (m_action == "garage") { new RacePausedDialog(0.8f, 0.6f); diff --git a/src/tracks/track_object_presentation.hpp b/src/tracks/track_object_presentation.hpp index 8e779752c..7894748cc 100644 --- a/src/tracks/track_object_presentation.hpp +++ b/src/tracks/track_object_presentation.hpp @@ -165,6 +165,9 @@ private: /** True if it is a looped animation. */ bool m_is_looped; + /** True if the object is in the skybox */ + bool m_is_in_skybox; + /** Start frame of the animation to be played. */ unsigned int m_frame_start; @@ -281,7 +284,7 @@ public: virtual ~TrackObjectPresentationActionTrigger() {} virtual void onTriggerItemApproached(Item* who) OVERRIDE; - + virtual void reset() OVERRIDE { m_action_active = true; } }; diff --git a/src/utils/helpers.cpp b/src/utils/helpers.cpp new file mode 100644 index 000000000..ed105b023 --- /dev/null +++ b/src/utils/helpers.cpp @@ -0,0 +1,220 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/irr_driver.hpp" +#include "utils/helpers.hpp" + +#include +#include + +float clampf(float in, float low, float high) { + return in > high ? high : in < low ? low : in; +} + +float smootherstep(float e0, float e1, float x) { + x = clampf((x - e0)/(e1 - e0), 0, 1); + + return x*x*x*(x*(x*6 - 15) + 10); +} + +void savetex(ITexture *tex, const char *name) { + + using namespace core; + using namespace video; + + IVideoDriver * const drv = irr_driver->getVideoDriver(); + + IImage * const tmp = drv->createImage(tex, position2di(0,0), tex->getSize()); + + if (!name) + { + stringc namec = tex->getName().getPath(); + namec += ".png"; + drv->writeImageToFile(tmp, namec.c_str()); + } + else + { + drv->writeImageToFile(tmp, name); + } + + tmp->drop(); +} + +float mix(float x, float y, float a) { + return x * (1 - a) + y * a; +} + +unsigned ispow(const unsigned in) { + + if (in < 2) return 0; + + return !(in & (in - 1)); +} + +unsigned npow(unsigned in) { + + if (ispow(in)) return in; + + in |= in >> 1; + in |= in >> 2; + in |= in >> 4; + in |= in >> 8; + in |= in >> 16; + + return in + 1; +} + +// Simple 8-bit hash +u8 shash8(const u8 * const data, const u16 size) { + + u32 out = data[0], i; + + for (i = 1; i < size; i++) { + out += data[i] * ((i + 1) ^ data[i - 1]); + } + + out %= 307; // prime + out %= 256; // eight bits + + return out; +} + + +/* + +Copyright (C) 2011 by Ashima Arts (Simplex noise) +Copyright (C) 2011 by Lauri Kasanen (cpu port) + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +static inline float mod289(float x) { +// return x - floorf(x * (1.0 / 289.0)) * 289.0; + return fmodf(x, 289); +} + +static inline float permute(float x) { + return mod289(((x*34.0f)+1.0f)*x); +} + +// Vectorized 2d simplex noise. +float noise2d(float v1, float v2) { + + const float C[] = { + 0.211324865405187, + 0.366025403784439, + -0.577350269189626, + 0.024390243902439 }; + + // First corner + float i[2]; + i[0] = floorf(v1 + v1*C[1] + v2*C[1]); + i[1] = floorf(v2 + v1*C[1] + v2*C[1]); + + float x0[2]; + x0[0] = v1 - i[0] + i[0]*C[0] + i[1]*C[0]; + x0[1] = v2 - i[1] + i[0]*C[0] + i[1]*C[0]; + + // Other corners + float i1[2]; + if (x0[0] > x0[1]) { + i1[0] = 1; + i1[1] = 0; + } else { + i1[0] = 0; + i1[1] = 1; + } + + float x12[4]; + x12[0] = x0[0] + C[0] - i1[0]; + x12[1] = x0[1] + C[0] - i1[1]; + x12[2] = x0[0] + C[2]; + x12[3] = x0[1] + C[2]; + + // Permutations + i[0] = mod289(i[0]); + i[1] = mod289(i[1]); + + float p[3]; + p[0] = permute(permute(i[1]) + i[0]); + p[1] = permute(permute(i[1] + i1[1]) + i[0] + i1[0]); + p[2] = permute(permute(i[1] + 1) + i[0] + 1); + + float m[3]; + m[0] = std::max(0.5 - x0[0]*x0[0] - x0[1]*x0[1], 0); + m[1] = std::max(0.5 - x12[0]*x12[0] - x12[1]*x12[1], 0); + m[2] = std::max(0.5 - x12[2]*x12[2] - x12[3]*x12[3], 0); + + m[0] = m[0] * m[0] * m[0] * m[0]; + m[1] = m[1] * m[1] * m[1] * m[1]; + m[2] = m[2] * m[2] * m[2] * m[2]; + + // Gradients + float tmp; + + float x[3]; + x[0] = 2 * modff(p[0] * C[3], &tmp) - 1; + x[1] = 2 * modff(p[1] * C[3], &tmp) - 1; + x[2] = 2 * modff(p[2] * C[3], &tmp) - 1; + + float h[3]; + h[0] = fabsf(x[0]) - 0.5f; + h[1] = fabsf(x[1]) - 0.5f; + h[2] = fabsf(x[2]) - 0.5f; + + float ox[3]; + ox[0] = floorf(x[0] + 0.5f); + ox[1] = floorf(x[1] + 0.5f); + ox[2] = floorf(x[2] + 0.5f); + + float a0[3]; + a0[0] = x[0] - ox[0]; + a0[1] = x[1] - ox[1]; + a0[2] = x[2] - ox[2]; + + // Normalize + m[0] *= 1.79284291400159f - 0.85373472095314f * (a0[0]*a0[0] + h[0]*h[0]); + m[1] *= 1.79284291400159f - 0.85373472095314f * (a0[1]*a0[1] + h[1]*h[1]); + m[2] *= 1.79284291400159f - 0.85373472095314f * (a0[2]*a0[2] + h[2]*h[2]); + + // Compute final value + float g[3]; + g[0] = a0[0] * x0[0] + h[0] * x0[1]; + g[1] = a0[1] * x12[0] + h[1] * x12[1]; + g[2] = a0[2] * x12[2] + h[2] * x12[3]; + + return 130 * (m[0] * g[0] + m[1] * g[1] + m[2] * g[2]); +} diff --git a/src/utils/helpers.hpp b/src/utils/helpers.hpp new file mode 100644 index 000000000..c13028666 --- /dev/null +++ b/src/utils/helpers.hpp @@ -0,0 +1,40 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Lauri Kasanen +// +// This program 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 3 +// of the License, or (at your option) any later version. +// +// This program 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 this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HELPERS_H +#define HELPERS_H + +#include + +using irr::video::ITexture; + +float smootherstep(float, float, float); +float clampf(float, float, float); + +float mix(float x, float y, float a); + +unsigned ispow(const unsigned in); +unsigned npow(unsigned in); + +void savetex(ITexture *tex, const char *name = NULL); + +float noise2d(float v1, float v2 = 0); + +u8 shash8(const u8 * const data, const u16 size); + +#endif diff --git a/src/utils/vs.hpp b/src/utils/vs.hpp new file mode 100644 index 000000000..68045956b --- /dev/null +++ b/src/utils/vs.hpp @@ -0,0 +1,12 @@ +// Visual studio workarounds in one place + +#if defined(_MSC_VER) +# include +# include +# include + +# define isnan _isnan +//# define round(x) (floor(x + 0.5f)) +# define roundf(x) (floor(x + 0.5f)) +#endif +