diff --git a/.gitignore b/.gitignore index ca74f1c42..845c64ce0 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,9 @@ data/textures data/tracks data/.svn +# Ignore doxygen output +src/html + *.o *.d *.a diff --git a/TODO.md b/TODO.md index 332f1386c..670dc93c3 100644 --- a/TODO.md +++ b/TODO.md @@ -20,7 +20,7 @@ no particular order): - Esp. different platforms 6. Package creators - Create packages for - - most common Linux Distributors + - most common Linux distributions - Windows 7. Writers - Write documentation, ranging from man page, to diff --git a/data/achievements.xml b/data/achievements.xml index 1e090a61b..1cfd510fa 100644 --- a/data/achievements.xml +++ b/data/achievements.xml @@ -1,17 +1,29 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - diff --git a/data/models/banana-low.b3d b/data/models/banana-low.b3d index 54771fe0c..ec6ee3cae 100644 Binary files a/data/models/banana-low.b3d and b/data/models/banana-low.b3d differ diff --git a/data/models/banana.b3d b/data/models/banana.b3d index 0c800d159..90888d701 100644 Binary files a/data/models/banana.b3d and b/data/models/banana.b3d differ diff --git a/data/models/gift-box-low.b3d b/data/models/gift-box-low.b3d index 99805bbe6..c435fea23 100644 Binary files a/data/models/gift-box-low.b3d and b/data/models/gift-box-low.b3d differ diff --git a/data/models/gift-box.b3d b/data/models/gift-box.b3d index 1eebb0c48..aa89d7c56 100644 Binary files a/data/models/gift-box.b3d and b/data/models/gift-box.b3d differ diff --git a/data/shaders/billboard.frag b/data/shaders/billboard.frag index 80a4942eb..9a9de2c5e 100644 --- a/data/shaders/billboard.frag +++ b/data/shaders/billboard.frag @@ -1,8 +1,13 @@ -#version 330 uniform sampler2D tex; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main(void) { diff --git a/data/shaders/billboard.vert b/data/shaders/billboard.vert index c707ab548..f6ec9e5f1 100644 --- a/data/shaders/billboard.vert +++ b/data/shaders/billboard.vert @@ -1,12 +1,18 @@ -#version 330 uniform mat4 ModelViewMatrix; uniform mat4 ProjectionMatrix; uniform vec3 Position; uniform vec2 Size; +#if __VERSION__ >= 130 in vec2 Corner; in vec2 Texcoord; out vec2 uv; +#else +attribute vec2 Corner; +attribute vec2 Texcoord; +varying vec2 uv; +#endif + void main(void) { diff --git a/data/shaders/bloom.frag b/data/shaders/bloom.frag index 5025f23aa..3be3cb60f 100644 --- a/data/shaders/bloom.frag +++ b/data/shaders/bloom.frag @@ -1,9 +1,14 @@ -#version 330 uniform sampler2D tex; uniform float low; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main() { diff --git a/data/shaders/bloomblend.frag b/data/shaders/bloomblend.frag index edcac3f31..b1003229a 100644 --- a/data/shaders/bloomblend.frag +++ b/data/shaders/bloomblend.frag @@ -1,8 +1,13 @@ -#version 330 uniform sampler2D tex; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main() { diff --git a/data/shaders/bloompower.frag b/data/shaders/bloompower.frag index 0c29ce9b2..dc2e1df5b 100644 --- a/data/shaders/bloompower.frag +++ b/data/shaders/bloompower.frag @@ -1,4 +1,3 @@ -#version 330 compatibility uniform float power; uniform sampler2D tex; diff --git a/data/shaders/bubble.frag b/data/shaders/bubble.frag index 0e1f2d4f9..6f69dfa74 100644 --- a/data/shaders/bubble.frag +++ b/data/shaders/bubble.frag @@ -14,11 +14,18 @@ // 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. -#version 330 + uniform sampler2D tex; uniform float transparency; + +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main() { diff --git a/data/shaders/bubble.vert b/data/shaders/bubble.vert index 6e9981bfb..0d61b7d33 100644 --- a/data/shaders/bubble.vert +++ b/data/shaders/bubble.vert @@ -17,13 +17,21 @@ // Creates a bubble (wave) effect by distorting the texture depending on time -#version 330 + uniform mat4 ModelViewProjectionMatrix; uniform float time; +#if __VERSION__ >= 130 in vec3 Position; in vec2 Texcoord; out vec2 uv; +#else +attribute vec3 Position; +attribute vec2 Texcoord; +varying vec2 uv; +#endif + + void main() { diff --git a/data/shaders/caustics.frag b/data/shaders/caustics.frag index e92e03a8c..203bd2b40 100644 --- a/data/shaders/caustics.frag +++ b/data/shaders/caustics.frag @@ -1,20 +1,32 @@ -#version 330 compatibility -uniform sampler2D tex; +uniform sampler2D Albedo; +uniform sampler2D DiffuseMap; +uniform sampler2D SpecularMap; +uniform sampler2D SSAO; +uniform vec2 screen; +uniform vec3 ambient; uniform sampler2D caustictex; uniform vec2 dir; uniform vec2 dir2; +#if __VERSION__ >= 130 +in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif void main() { - vec2 tc = gl_TexCoord[0].xy; + vec2 tc = gl_FragCoord.xy / screen; + vec3 DiffuseComponent = texture(DiffuseMap, tc).xyz; + vec3 SpecularComponent = texture(SpecularMap, tc).xyz; + vec4 color = texture(Albedo, uv); + float ao = texture(SSAO, tc).x; - vec3 col = texture(tex, tc).xyz; - float caustic = texture(caustictex, tc + dir).x; - float caustic2 = texture(caustictex, (tc.yx + dir2 * vec2(-0.6, 0.3)) * vec2(0.6)).x; + float caustic = texture(caustictex, uv + dir).x; + float caustic2 = texture(caustictex, (uv.yx + dir2 * vec2(-0.6, 0.3)) * vec2(0.6)).x; - col += caustic * caustic2 * 10.0; - - FragColor = vec4(col, 1.0); + vec3 LightFactor = ao * ambient + DiffuseComponent + SpecularComponent + caustic * caustic2 * 10; + FragColor = vec4(color.xyz * LightFactor, 1.); } diff --git a/data/shaders/collapse.frag b/data/shaders/collapse.frag index 573631f9a..e4f0fc4c6 100644 --- a/data/shaders/collapse.frag +++ b/data/shaders/collapse.frag @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D tex; uniform sampler2D oldtex; uniform vec2 pixel; diff --git a/data/shaders/color_levels.frag b/data/shaders/color_levels.frag index 58ccee832..c99d7d4d8 100644 --- a/data/shaders/color_levels.frag +++ b/data/shaders/color_levels.frag @@ -1,20 +1,34 @@ -#version 330 uniform sampler2D tex; +uniform sampler2D dtex; uniform vec3 inlevel; uniform vec2 outlevel; +uniform mat4 invprojm; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + + void main() { - vec2 texc = uv; - //texc.y = 1.0 - texc.y; + vec4 col = texture(tex, uv); + float curdepth = texture(dtex, uv).x; + vec4 FragPos = invprojm * (2.0 * vec4(uv, curdepth, 1.0f) - 1.0f); + FragPos /= FragPos.w; + float depth = clamp(FragPos.z / 180, 0, 1); + depth = (1 - depth); - vec4 col = texture(tex, texc); - - //col = col / (1 - col); + // Compute the vignette + vec2 inside = uv - 0.5; + float vignette = 1 - dot(inside, inside); + vignette = clamp(pow(vignette, 0.8), 0, 1); + vignette = clamp(vignette + vignette - 0.5, 0, 1.15); float inBlack = inlevel.x; float inWhite = inlevel.z; @@ -23,8 +37,11 @@ void main() float outBlack = outlevel.x; float outWhite = outlevel.y; - col.rgb = (pow(((col.rgb * 255.0) - inBlack) / (inWhite - inBlack), + vec3 colSat = (pow(((col.rgb * 255.0) - inBlack) / (inWhite - inBlack), vec3(1.0 / inGamma)) * (outWhite - outBlack) + outBlack) / 255.0; + + vec3 colFinal = colSat * depth + col.rgb * (1 - depth); - FragColor = vec4(col.rgb, 1.0); + FragColor = vec4(colFinal * vignette, 1.0); + //FragColor = vec4(vec3(depth), 1.0); } diff --git a/data/shaders/coloredquad.frag b/data/shaders/coloredquad.frag index 9216e0503..26d01339e 100644 --- a/data/shaders/coloredquad.frag +++ b/data/shaders/coloredquad.frag @@ -1,7 +1,11 @@ -#version 330 uniform ivec4 color; +#if __VERSION__ >= 130 out vec4 FragColor; +#else +#define FragColor gl_FragColor +#endif + void main() { diff --git a/data/shaders/coloredquad.vert b/data/shaders/coloredquad.vert index 31c2a0db1..2864e469a 100644 --- a/data/shaders/coloredquad.vert +++ b/data/shaders/coloredquad.vert @@ -1,8 +1,12 @@ -#version 330 uniform vec2 center; uniform vec2 size; +#if __VERSION__ >= 130 in vec2 position; +#else +attribute vec2 position; +#endif + void main() { diff --git a/data/shaders/colorize.frag b/data/shaders/colorize.frag index b82462c1f..022fe59c0 100644 --- a/data/shaders/colorize.frag +++ b/data/shaders/colorize.frag @@ -1,7 +1,11 @@ -#version 330 uniform vec3 col; +#if __VERSION__ >= 130 out vec4 FragColor; +#else +#define FragColor gl_FragColor +#endif + void main() { diff --git a/data/shaders/colorize_ref.frag b/data/shaders/colorize_ref.frag deleted file mode 100644 index 743f32224..000000000 --- a/data/shaders/colorize_ref.frag +++ /dev/null @@ -1,14 +0,0 @@ -#version 130 -uniform vec3 col; -uniform sampler2D tex; - -out vec4 FragColor; - -void main() -{ - float alpha = texture(tex, gl_TexCoord[0].xy).a; - if (alpha < 0.5) - discard; - - FragColor = vec4(col, 1.0); -} diff --git a/data/shaders/colortexturedquad.frag b/data/shaders/colortexturedquad.frag index 1e14e5985..6c1aa7396 100644 --- a/data/shaders/colortexturedquad.frag +++ b/data/shaders/colortexturedquad.frag @@ -1,9 +1,16 @@ -#version 330 uniform sampler2D tex; +#if __VERSION__ >= 130 in vec2 uv; in vec4 col; out vec4 FragColor; +#else +varying vec2 uv; +varying vec4 col; +#define FragColor gl_FragColor +#endif + + void main() { diff --git a/data/shaders/colortexturedquad.vert b/data/shaders/colortexturedquad.vert index 4489e9cbf..c4e4d41a0 100644 --- a/data/shaders/colortexturedquad.vert +++ b/data/shaders/colortexturedquad.vert @@ -1,14 +1,22 @@ -#version 330 uniform vec2 center; uniform vec2 size; uniform vec2 texcenter; uniform vec2 texsize; +#if __VERSION__ >= 130 in vec2 position; in vec2 texcoord; in uvec4 color; out vec2 uv; out vec4 col; +#else +attribute vec2 position; +attribute vec2 texcoord; +attribute uvec4 color; +varying vec2 uv; +varying vec4 col; +#endif + void main() { diff --git a/data/shaders/detailledobject_pass2.frag b/data/shaders/detailledobject_pass2.frag index 7afaee691..c0c9527d0 100644 --- a/data/shaders/detailledobject_pass2.frag +++ b/data/shaders/detailledobject_pass2.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D Albedo; uniform sampler2D Detail; uniform sampler2D DiffuseMap; @@ -6,9 +5,18 @@ uniform sampler2D SpecularMap; uniform sampler2D SSAO; uniform vec2 screen; uniform vec3 ambient; + +#if __VERSION__ >= 130 in vec2 uv; in vec2 uv_bis; out vec4 FragColor; +#else +varying vec2 uv; +varying vec2 uv_bis; +#define FragColor gl_FragColor +#endif + + void main(void) { diff --git a/data/shaders/diffuseenvmap.frag b/data/shaders/diffuseenvmap.frag new file mode 100644 index 000000000..eb2822598 --- /dev/null +++ b/data/shaders/diffuseenvmap.frag @@ -0,0 +1,52 @@ +uniform float blueLmn[9]; +uniform float greenLmn[9]; +uniform float redLmn[9]; +uniform sampler2D ntex; +uniform mat4 TransposeViewMatrix; + +#if __VERSION__ >= 130 +in vec2 uv; +out vec4 Diff; +out vec4 Spec; +#else +varying vec2 uv; +#define Diff gl_FragData[0] +#define Spec gl_FragData[1] +#endif + +vec3 DecodeNormal(vec2 n) +{ + float z = dot(n, n) * 2. - 1.; + vec2 xy = normalize(n) * sqrt(1. - z * z); + return vec3(xy,z); +} + +mat4 getMatrix(float L[9]) +{ + float c1 = 0.429043, c2 = 0.511664, c3 = 0.743125, c4 = 0.886227, c5 = 0.247708; + + return mat4( + c1 * L[8] /*L22*/, c1 * L[4] /*L2-2*/, c1 * L[7] /*L21*/, c2 * L[3] /*L11*/, + c1 * L[4], - c1 * L[8], c1 * L[5] /*L2-1*/, c2 * L[1] /*L1-1*/, + c1 * L[7], c1 * L[5], c3 * L[6] /*L20*/, c2 * L[2] /*L10*/, + c2 * L[3], c2 * L[1], c2 * L[2], c4 * L[0] /*L00*/ - c5 * L[6] + ); +} + +void main(void) +{ + vec3 normal = normalize(DecodeNormal(2. * texture(ntex, uv).xy - 1.)); + // Convert normal in world space (where SH coordinates were computed) + vec4 extendednormal = TransposeViewMatrix * vec4(normal, 1.); + extendednormal.w = 1.; + mat4 rmat = getMatrix(redLmn); + mat4 gmat = getMatrix(greenLmn); + mat4 bmat = getMatrix(blueLmn); + + float r = dot(extendednormal, rmat * extendednormal); + float g = dot(extendednormal, gmat * extendednormal); + float b = dot(extendednormal, bmat * extendednormal); + + Diff = 0.25 * vec4(r, g, b, .1); + Spec = vec4(0.); +} diff --git a/data/shaders/displace.frag b/data/shaders/displace.frag index 1c22fd42e..c54effa71 100644 --- a/data/shaders/displace.frag +++ b/data/shaders/displace.frag @@ -1,19 +1,29 @@ -#version 330 -uniform sampler2D tex; +uniform sampler2D displacement_tex; +uniform sampler2D mask_tex; +uniform sampler2D color_tex; +uniform vec2 screen; uniform vec2 dir; uniform vec2 dir2; +#if __VERSION__ >= 130 in vec2 uv; in vec2 uv_bis; in float camdist; out vec4 FragColor; +#else +varying vec2 uv; +varying vec2 uv_bis; +varying float camdist; +#define FragColor gl_FragColor +#endif + const float maxlen = 0.02; void main() { - float horiz = texture(tex, uv + dir).x; - float vert = texture(tex, (uv.yx + dir2) * vec2(0.9)).x; + float horiz = texture(displacement_tex, uv + dir).x; + float vert = texture(displacement_tex, (uv.yx + dir2) * vec2(0.9)).x; vec2 offset = vec2(horiz, vert); offset *= 2.0; @@ -30,11 +40,20 @@ void main() offset *= 50.0 * fade * maxlen; - vec4 col; - 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; + vec4 shiftval; + shiftval.r = step(offset.x, 0.0) * -offset.x; + shiftval.g = step(0.0, offset.x) * offset.x; + shiftval.b = step(offset.y, 0.0) * -offset.y; + shiftval.a = step(0.0, offset.y) * offset.y; - FragColor = col; + vec2 shift; + shift.x = -shiftval.x + shiftval.y; + shift.y = -shiftval.z + shiftval.w; + shift /= 50.; + + vec2 tc = gl_FragCoord.xy / screen; + float mask = texture(mask_tex, tc + shift).x; + tc += (mask < 1.) ? vec2(0.) : shift; + + FragColor = texture(color_tex, tc); } diff --git a/data/shaders/displace.vert b/data/shaders/displace.vert index 7c811d4aa..48b052077 100644 --- a/data/shaders/displace.vert +++ b/data/shaders/displace.vert @@ -1,13 +1,23 @@ -#version 330 uniform mat4 ModelViewProjectionMatrix; uniform mat4 ModelViewMatrix; +#if __VERSION__ >= 130 in vec3 Position; in vec2 Texcoord; in vec2 SecondTexcoord; out vec2 uv; out vec2 uv_bis; out float camdist; +#else +attribute vec3 Position; +attribute vec2 Texcoord; +attribute vec2 SecondTexcoord; +varying vec2 uv; +varying vec2 uv_bis; +varying float camdist; +#endif + + void main() { gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.); diff --git a/data/shaders/farplane.vert b/data/shaders/farplane.vert index eea0eeede..9d3a1b7db 100644 --- a/data/shaders/farplane.vert +++ b/data/shaders/farplane.vert @@ -1,4 +1,3 @@ -#version 330 compatibility uniform mat4 ModelViewProjectionMatrix; void main() { diff --git a/data/shaders/flipparticle.vert b/data/shaders/flipparticle.vert index 24ce2773a..7b479ec9f 100644 --- a/data/shaders/flipparticle.vert +++ b/data/shaders/flipparticle.vert @@ -1,4 +1,3 @@ -#version 330 uniform mat4 ProjectionMatrix; uniform mat4 ViewMatrix; diff --git a/data/shaders/fog.frag b/data/shaders/fog.frag index 60dd7dcf0..ce03d04af 100644 --- a/data/shaders/fog.frag +++ b/data/shaders/fog.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D tex; uniform float fogmax; @@ -9,8 +8,14 @@ uniform float end; uniform vec3 col; uniform mat4 ipvmat; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main() { diff --git a/data/shaders/gaussian3h.frag b/data/shaders/gaussian3h.frag index 07f4d4092..d444ba11d 100644 --- a/data/shaders/gaussian3h.frag +++ b/data/shaders/gaussian3h.frag @@ -1,11 +1,15 @@ -#version 330 uniform sampler2D tex; uniform vec2 pixel; // Gaussian separated blur with radius 3. +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif void main() { diff --git a/data/shaders/gaussian3v.frag b/data/shaders/gaussian3v.frag index 365e25678..16e21a1a5 100644 --- a/data/shaders/gaussian3v.frag +++ b/data/shaders/gaussian3v.frag @@ -1,11 +1,15 @@ -#version 330 uniform sampler2D tex; uniform vec2 pixel; // Gaussian separated blur with radius 3. +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif void main() { diff --git a/data/shaders/gaussian6h.frag b/data/shaders/gaussian6h.frag index a2ee0eb26..c17766c4b 100644 --- a/data/shaders/gaussian6h.frag +++ b/data/shaders/gaussian6h.frag @@ -1,11 +1,15 @@ -#version 330 uniform sampler2D tex; uniform vec2 pixel; // Gaussian separated blur with radius 6. +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif void main() { diff --git a/data/shaders/gaussian6v.frag b/data/shaders/gaussian6v.frag index 8150cbbf6..31d361e60 100644 --- a/data/shaders/gaussian6v.frag +++ b/data/shaders/gaussian6v.frag @@ -1,11 +1,15 @@ -#version 330 uniform sampler2D tex; uniform vec2 pixel; // Gaussian separated blur with radius 6. +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif void main() { diff --git a/data/shaders/glow.frag b/data/shaders/glow.frag index 0821b420a..7902bd93b 100644 --- a/data/shaders/glow.frag +++ b/data/shaders/glow.frag @@ -1,8 +1,12 @@ -#version 330 uniform sampler2D tex; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif void main() { diff --git a/data/shaders/godfade.frag b/data/shaders/godfade.frag index e44fdec04..fb60fe344 100644 --- a/data/shaders/godfade.frag +++ b/data/shaders/godfade.frag @@ -1,11 +1,17 @@ -#version 330 compatibility uniform sampler2D tex; uniform vec3 col; + +#if __VERSION__ >= 130 +in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif void main() { - vec4 res = texture(tex, gl_TexCoord[0].xy); + vec4 res = texture(tex, uv); // Keep the sun fully bright, but fade the sky float mul = distance(res.xyz, col); diff --git a/data/shaders/godray.frag b/data/shaders/godray.frag index 83422eb9c..8880d434d 100644 --- a/data/shaders/godray.frag +++ b/data/shaders/godray.frag @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D tex; uniform vec2 sunpos; @@ -6,14 +5,20 @@ uniform vec2 sunpos; const float decaystep = 0.88; +#if __VERSION__ >= 130 +in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif void main() { - vec2 texc = gl_TexCoord[0].xy; + vec2 texc = uv; vec2 tosun = sunpos - texc; - if (dot(tosun, tosun) > 0.49) discard; +// if (dot(tosun, tosun) > 0.49) discard; vec2 dist = tosun * 1.0/(float(SAMPLES) * 1.12); diff --git a/data/shaders/grass_pass1.vert b/data/shaders/grass_pass1.vert index 4d38b4f0a..647697da3 100644 --- a/data/shaders/grass_pass1.vert +++ b/data/shaders/grass_pass1.vert @@ -1,14 +1,24 @@ -#version 330 uniform vec3 windDir; uniform mat4 ModelViewProjectionMatrix; uniform mat4 TransposeInverseModelView; + +#if __VERSION__ >= 130 in vec3 Position; in vec3 Normal; in vec2 Texcoord; in vec4 Color; -noperspective out vec3 nor; +out vec3 nor; out vec2 uv; +#else +attribute vec3 Position; +attribute vec3 Normal; +attribute vec2 Texcoord; +attribute vec4 Color; +varying vec3 nor; +varying vec2 uv; +#endif + void main() { diff --git a/data/shaders/grass_pass2.vert b/data/shaders/grass_pass2.vert index 0d60826ea..34ee95fd9 100644 --- a/data/shaders/grass_pass2.vert +++ b/data/shaders/grass_pass2.vert @@ -1,11 +1,17 @@ -#version 330 uniform vec3 windDir; uniform mat4 ModelViewProjectionMatrix; +#if __VERSION__ >= 130 in vec3 Position; in vec2 Texcoord; in vec4 Color; out vec2 uv; +#else +attribute vec3 Position; +attribute vec2 Texcoord; +attribute vec4 Color; +varying vec2 uv; +#endif void main() { diff --git a/data/shaders/mipviz.frag b/data/shaders/mipviz.frag index e63ca8158..da795da40 100644 --- a/data/shaders/mipviz.frag +++ b/data/shaders/mipviz.frag @@ -1,5 +1,3 @@ -#version 330 compatibility - uniform sampler2D tex; uniform vec2 texsize; uniform int notex; diff --git a/data/shaders/motion_blur.frag b/data/shaders/motion_blur.frag index 3be7cc652..43eb263bc 100644 --- a/data/shaders/motion_blur.frag +++ b/data/shaders/motion_blur.frag @@ -17,7 +17,6 @@ // motion_blur.frag -#version 330 // The actual boost amount (which linearly scales the blur to be shown). // should be in the range [0.0, 1.0], though a larger value might make @@ -41,8 +40,13 @@ uniform float mask_radius; // Maximum height of texture used uniform float max_tex_height; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif // Number of samples used for blurring #define NB_SAMPLES 8 diff --git a/data/shaders/motion_blur.vert b/data/shaders/motion_blur.vert deleted file mode 100644 index 5c02f2bd3..000000000 --- a/data/shaders/motion_blur.vert +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - - -// motion_blur.vert -#version 330 compatibility - -void main() -{ - gl_TexCoord[0].st = vec2(gl_MultiTexCoord0.s, gl_MultiTexCoord0.t); - gl_Position = gl_Vertex; -} diff --git a/data/shaders/movingtexture.frag b/data/shaders/movingtexture.frag deleted file mode 100644 index 7d4d81c27..000000000 --- a/data/shaders/movingtexture.frag +++ /dev/null @@ -1,22 +0,0 @@ -#version 330 -uniform sampler2D Albedo; -uniform sampler2D DiffuseMap; -uniform sampler2D SpecularMap; -uniform sampler2D SSAO; -uniform vec2 screen; -uniform vec3 ambient; - -in vec2 uv; -out vec4 FragColor; - -void main(void) -{ - vec2 tc = gl_FragCoord.xy / screen; - vec4 color = texture(Albedo, uv); - vec3 DiffuseComponent = texture(DiffuseMap, tc).xyz; - vec3 SpecularComponent = texture(SpecularMap, tc).xyz; - float ao = texture(SSAO, tc).x; - vec3 LightFactor = ao * ambient + DiffuseComponent + SpecularComponent * (1. - color.a); - FragColor = vec4(color.xyz * LightFactor * (0.4 + ao*0.6), 1.); - //FragColor = vec4(color.xyz * LightFactor, 1.); -} diff --git a/data/shaders/movingtexture.vert b/data/shaders/movingtexture.vert deleted file mode 100644 index 87f40d795..000000000 --- a/data/shaders/movingtexture.vert +++ /dev/null @@ -1,16 +0,0 @@ -#version 330 -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 TextureMatrix; - -in vec3 Position; -in vec2 Texcoord; -in vec2 SecondTexcoord; -out vec2 uv; -out vec2 uv_bis; - -void main(void) -{ - uv = (TextureMatrix * vec4(Texcoord, 1., 1.)).xy; - uv_bis = SecondTexcoord; - gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.); -} diff --git a/data/shaders/multiply.frag b/data/shaders/multiply.frag index 1e9303bf1..d3d16cbdd 100644 --- a/data/shaders/multiply.frag +++ b/data/shaders/multiply.frag @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D tex1; uniform sampler2D tex2; diff --git a/data/shaders/normalmap.frag b/data/shaders/normalmap.frag index 00410d916..b07c307eb 100644 --- a/data/shaders/normalmap.frag +++ b/data/shaders/normalmap.frag @@ -1,10 +1,17 @@ -#version 330 uniform sampler2D normalMap; -noperspective in vec3 tangent; -noperspective in vec3 bitangent; +#if __VERSION__ >= 130 +in vec3 tangent; +in vec3 bitangent; in vec2 uv; out vec2 EncodedNormal; +#else +varying vec3 tangent; +varying vec3 bitangent; +varying vec2 uv; +#define EncodedNormal gl_FragColor.xy +#endif + // from Crytek "a bit more deferred CryEngine" vec2 EncodeNormal(vec3 n) diff --git a/data/shaders/normalmap.vert b/data/shaders/normalmap.vert index b7f74865d..5d5f79c21 100644 --- a/data/shaders/normalmap.vert +++ b/data/shaders/normalmap.vert @@ -1,14 +1,25 @@ -#version 330 uniform mat4 ModelViewProjectionMatrix; uniform mat4 TransposeInverseModelView; + +#if __VERSION__ >= 130 in vec3 Position; in vec2 Texcoord; in vec3 Tangent; in vec3 Bitangent; -noperspective out vec3 tangent; -noperspective out vec3 bitangent; +out vec3 tangent; +out vec3 bitangent; out vec2 uv; +#else +attribute vec3 Position; +attribute vec2 Texcoord; +attribute vec3 Tangent; +attribute vec3 Bitangent; +varying vec3 tangent; +varying vec3 bitangent; +varying vec2 uv; +#endif + void main() { diff --git a/data/shaders/object_pass1.frag b/data/shaders/object_pass1.frag index ff55a147d..e119e2e0a 100644 --- a/data/shaders/object_pass1.frag +++ b/data/shaders/object_pass1.frag @@ -1,6 +1,12 @@ -#version 330 -noperspective in vec3 nor; +#if __VERSION__ >= 130 +in vec3 nor; out vec2 EncodedNormal; +#else +varying vec3 nor; +#define EncodedNormal gl_FragColor.xy +#endif + + // from Crytek "a bit more deferred CryEngine" vec2 EncodeNormal(vec3 n) diff --git a/data/shaders/object_pass1.vert b/data/shaders/object_pass1.vert index edf27d885..12970e280 100644 --- a/data/shaders/object_pass1.vert +++ b/data/shaders/object_pass1.vert @@ -1,10 +1,16 @@ -#version 330 uniform mat4 ModelViewProjectionMatrix; uniform mat4 TransposeInverseModelView; +#if __VERSION__ >= 130 in vec3 Position; in vec3 Normal; -noperspective out vec3 nor; +out vec3 nor; +#else +attribute vec3 Position; +attribute vec3 Normal; +varying vec3 nor; +#endif + void main(void) { diff --git a/data/shaders/object_pass2.frag b/data/shaders/object_pass2.frag index 7d4d81c27..426a79ec4 100644 --- a/data/shaders/object_pass2.frag +++ b/data/shaders/object_pass2.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D Albedo; uniform sampler2D DiffuseMap; uniform sampler2D SpecularMap; @@ -6,8 +5,14 @@ uniform sampler2D SSAO; uniform vec2 screen; uniform vec3 ambient; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main(void) { diff --git a/data/shaders/object_pass2.vert b/data/shaders/object_pass2.vert index b20eeac18..c04d75dfd 100644 --- a/data/shaders/object_pass2.vert +++ b/data/shaders/object_pass2.vert @@ -1,15 +1,28 @@ -#version 330 uniform mat4 ModelViewProjectionMatrix; +uniform mat4 TextureMatrix = + mat4(1., 0., 0., 0., + 0., 1., 0., 0., + 0., 0., 1., 0., + 0., 0., 0., 1.); +#if __VERSION__ >= 130 in vec3 Position; in vec2 Texcoord; in vec2 SecondTexcoord; out vec2 uv; out vec2 uv_bis; +#else +attribute vec3 Position; +attribute vec2 Texcoord; +attribute vec2 SecondTexcoord; +varying vec2 uv; +varying vec2 uv_bis; +#endif + void main(void) { - uv = Texcoord; + uv = (TextureMatrix * vec4(Texcoord, 1., 1.)).xy; uv_bis = SecondTexcoord; gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.); } diff --git a/data/shaders/object_unlit.frag b/data/shaders/object_unlit.frag index 3677baae3..5c60f9f43 100644 --- a/data/shaders/object_unlit.frag +++ b/data/shaders/object_unlit.frag @@ -1,7 +1,13 @@ -#version 330 uniform sampler2D tex; + +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main(void) { diff --git a/data/shaders/objectpass_ref.frag b/data/shaders/objectpass_ref.frag deleted file mode 100644 index 38b42a644..000000000 --- a/data/shaders/objectpass_ref.frag +++ /dev/null @@ -1,29 +0,0 @@ -#version 330 -uniform sampler2D tex; -uniform int hastex; -uniform float objectid; - -noperspective in vec3 nor; -in vec2 uv0; -in vec2 uv1; -out vec4 Albedo; -out vec4 NormalDepth; -out vec4 Specular; - -void main() { - - //if (hastex != 0) { - vec4 col = texture(tex, uv0); - - if (col.a < 0.5) - discard; - - Albedo = vec4(col.xyz, 1.); - //} else { - // Albedo = gl_Color; - //} - - NormalDepth = vec4(0.5 * normalize(nor) + 0.5, gl_FragCoord.z); - Specular = vec4(1. - col.a); -} - diff --git a/data/shaders/objectpass_rimlit.frag b/data/shaders/objectpass_rimlit.frag index a17f533b9..907dd8e9f 100644 --- a/data/shaders/objectpass_rimlit.frag +++ b/data/shaders/objectpass_rimlit.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D Albedo; uniform sampler2D DiffuseMap; uniform sampler2D SpecularMap; @@ -6,10 +5,15 @@ uniform sampler2D SSAO; uniform vec2 screen; uniform vec3 ambient; -noperspective in vec3 normal; +#if __VERSION__ >= 130 +in vec3 normal; in vec2 uv; - out vec4 FragColor; +#else +varying vec3 normal; +varying vec2 uv; +#define FragColor gl_FragColor +#endif void main() { float rim = 1.0 - dot(normal, vec3(0., 0., -1)); diff --git a/data/shaders/objectpass_rimlit.vert b/data/shaders/objectpass_rimlit.vert index 7910ebb75..59f1feab3 100644 --- a/data/shaders/objectpass_rimlit.vert +++ b/data/shaders/objectpass_rimlit.vert @@ -1,16 +1,25 @@ -#version 330 uniform mat4 ModelViewProjectionMatrix; uniform mat4 TransposeInverseModelView; +uniform mat4 TextureMatrix; +#if __VERSION__ >= 130 in vec3 Position; in vec3 Normal; in vec2 Texcoord; in vec4 Color; out vec2 uv; -noperspective out vec3 normal; +out vec3 normal; +#else +attribute vec3 Position; +attribute vec3 Normal; +attribute vec2 Texcoord; +attribute vec4 Color; +varying vec2 uv; +varying vec3 normal; +#endif void main() { normal = (TransposeInverseModelView * vec4(Normal, 0)).xyz; - uv = Texcoord; + uv = (TextureMatrix * vec4(Texcoord, 1., 1.)).xy; gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.); } diff --git a/data/shaders/objectpass_spheremap.frag b/data/shaders/objectpass_spheremap.frag index 9d726b99a..13467bbad 100644 --- a/data/shaders/objectpass_spheremap.frag +++ b/data/shaders/objectpass_spheremap.frag @@ -1,22 +1,27 @@ -#version 330 -uniform sampler2D tex; +uniform samplerCube tex; +uniform mat4 invproj; +uniform vec2 screen; +uniform mat4 TransposeViewMatrix; -noperspective in vec3 nor; +#if __VERSION__ >= 130 +in vec3 nor; out vec4 FragColor; +#else +varying vec3 nor; +#define FragColor gl_FragColor +#endif + void main() { - // Calculate the spherical UV - const vec3 forward = vec3(0.0, 0.0, 1.0); + vec3 fpos = gl_FragCoord.xyz / vec3(screen, 1.); + vec4 xpos = 2.0 * vec4(fpos, 1.0) - 1.0; + xpos = invproj * xpos; - // get the angle between the forward vector and the horizontal portion of the normal - vec3 normal_x = normalize(vec3(nor.x, 0.0, nor.z)); - float sin_theta_x = length(cross( forward, normal_x )) * nor.x / abs(nor.x); + xpos.xyz /= xpos.w; + vec3 viewSampleDir = reflect(xpos.xyz, nor); + // Convert sampleDir in world space (where tex was generated) + vec4 sampleDir = TransposeViewMatrix * vec4(viewSampleDir, 0.); + vec4 detail0 = texture(tex, sampleDir.xyz); - // get the angle between the forward vector and the vertical portion of the normal - vec3 normal_y = normalize(vec3(0.0, nor.y, nor.z)); - float sin_theta_y = length(cross( forward, normal_y )) * nor.y / abs(nor.y); - - vec4 detail0 = texture(tex, 0.5 * vec2(sin_theta_x, sin_theta_y) + 0.5); - - FragColor = vec4(detail0.xyz, 1.); + FragColor = vec4(detail0.xyz, 1.); } diff --git a/data/shaders/objectref_pass1.frag b/data/shaders/objectref_pass1.frag index 06c8c413e..d322f9a5b 100644 --- a/data/shaders/objectref_pass1.frag +++ b/data/shaders/objectref_pass1.frag @@ -1,9 +1,15 @@ -#version 330 uniform sampler2D tex; -noperspective in vec3 nor; +#if __VERSION__ >= 130 +in vec3 nor; in vec2 uv; out vec2 EncodedNormal; +#else +varying vec3 nor; +varying vec2 uv; +#define EncodedNormal gl_FragColor.xy +#endif + // from Crytek "a bit more deferred CryEngine" vec2 EncodeNormal(vec3 n) diff --git a/data/shaders/objectref_pass1.vert b/data/shaders/objectref_pass1.vert index 462efa8ab..59fa0f3c5 100644 --- a/data/shaders/objectref_pass1.vert +++ b/data/shaders/objectref_pass1.vert @@ -1,16 +1,30 @@ -#version 330 uniform mat4 ModelViewProjectionMatrix; uniform mat4 TransposeInverseModelView; +uniform mat4 TextureMatrix = + mat4(1., 0., 0., 0., + 0., 1., 0., 0., + 0., 0., 1., 0., + 0., 0., 0., 1.); +#if __VERSION__ >= 130 in vec3 Position; in vec3 Normal; in vec2 Texcoord; -noperspective out vec3 nor; +out vec3 nor; out vec2 uv; +#else +attribute vec3 Position; +attribute vec3 Normal; +attribute vec2 Texcoord; +varying vec3 nor; +varying vec2 uv; +#endif + + void main(void) { - uv = Texcoord; + uv = (TextureMatrix * vec4(Texcoord, 1., 1.)).xy; gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.); nor = (TransposeInverseModelView * vec4(Normal, 0.)).xyz; } diff --git a/data/shaders/objectref_pass2.frag b/data/shaders/objectref_pass2.frag index e48755946..823d405d4 100644 --- a/data/shaders/objectref_pass2.frag +++ b/data/shaders/objectref_pass2.frag @@ -1,12 +1,18 @@ -#version 330 uniform sampler2D Albedo; uniform sampler2D DiffuseMap; uniform sampler2D SpecularMap; uniform sampler2D SSAO; uniform vec2 screen; uniform vec3 ambient; + +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main(void) { diff --git a/data/shaders/particle.frag b/data/shaders/particle.frag index 1b6c5f200..cf405c01d 100644 --- a/data/shaders/particle.frag +++ b/data/shaders/particle.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D tex; uniform sampler2D dtex; uniform mat4 invproj; diff --git a/data/shaders/particle.vert b/data/shaders/particle.vert index 73b0dd8de..2376b86bd 100644 --- a/data/shaders/particle.vert +++ b/data/shaders/particle.vert @@ -1,4 +1,3 @@ -#version 330 uniform mat4 ProjectionMatrix; uniform mat4 ViewMatrix; diff --git a/data/shaders/particlesimheightmap.vert b/data/shaders/particlesimheightmap.vert index 09fa55a98..b34fb360e 100644 --- a/data/shaders/particlesimheightmap.vert +++ b/data/shaders/particlesimheightmap.vert @@ -1,4 +1,3 @@ -#version 330 uniform int dt; uniform mat4 sourcematrix; uniform int level; diff --git a/data/shaders/pass.frag b/data/shaders/pass.frag index 327fcdffc..e5b1e7c69 100644 --- a/data/shaders/pass.frag +++ b/data/shaders/pass.frag @@ -1,9 +1,10 @@ -#version 330 compatibility +#version 330 uniform sampler2D tex; +in vec2 uv; out vec4 FragColor; void main() { - FragColor = texture(tex, gl_TexCoord[0].xy); + FragColor = texture(tex, uv); } diff --git a/data/shaders/pass.vert b/data/shaders/pass.vert index f2003abef..4c495e0a7 100644 --- a/data/shaders/pass.vert +++ b/data/shaders/pass.vert @@ -1,9 +1,11 @@ // Passthrough shader for drawQuad() -#version 330 compatibility +#version 330 +in vec3 Position; +in vec2 Texcoord; out vec2 uv; void main() { - uv = gl_MultiTexCoord0.xy; - gl_Position = gl_Vertex; + uv = Texcoord; + gl_Position = vec4(Position, 1.); } diff --git a/data/shaders/penumbrah.frag b/data/shaders/penumbrah.frag index 481db2dc8..2504d9752 100644 --- a/data/shaders/penumbrah.frag +++ b/data/shaders/penumbrah.frag @@ -1,9 +1,14 @@ -#version 330 uniform sampler2D tex; uniform vec2 pixel; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + // Separated penumbra, horizontal void main() diff --git a/data/shaders/penumbrav.frag b/data/shaders/penumbrav.frag index 7afc88173..715e07091 100644 --- a/data/shaders/penumbrav.frag +++ b/data/shaders/penumbrav.frag @@ -1,9 +1,14 @@ -#version 330 uniform sampler2D tex; uniform vec2 pixel; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + // Separated penumbra, vertical diff --git a/data/shaders/pointemitter.vert b/data/shaders/pointemitter.vert index 64a498dc7..333673f27 100644 --- a/data/shaders/pointemitter.vert +++ b/data/shaders/pointemitter.vert @@ -1,4 +1,3 @@ -#version 330 uniform int dt; uniform mat4 sourcematrix; uniform int level; diff --git a/data/shaders/pointlight.frag b/data/shaders/pointlight.frag index f21f49492..0c2c9a1cf 100644 --- a/data/shaders/pointlight.frag +++ b/data/shaders/pointlight.frag @@ -1,15 +1,14 @@ -#version 330 uniform sampler2D ntex; uniform sampler2D dtex; - -uniform vec4 center[16]; -uniform vec4 col[16]; -uniform float energy[16]; uniform float spec; uniform mat4 invproj; -uniform mat4 viewm; +uniform mat4 ViewMatrix; +uniform vec2 screen; + +flat in vec3 center; +flat in float energy; +flat in vec3 col; -in vec2 uv; out vec4 Diffuse; out vec4 Specular; @@ -21,7 +20,7 @@ vec3 DecodeNormal(vec2 n) } void main() { - vec2 texc = uv; + vec2 texc = gl_FragCoord.xy / screen; float z = texture(dtex, texc).x; vec3 norm = normalize(DecodeNormal(2. * texture(ntex, texc).xy - 1.)); @@ -32,26 +31,23 @@ void main() { vec3 diffuse = vec3(0.), specular = vec3(0.); - for (int i = 0; i < 16; ++i) { - vec4 pseudocenter = viewm * vec4(center[i].xyz, 1.0); - pseudocenter /= pseudocenter.w; - vec3 light_pos = pseudocenter.xyz; - vec3 light_col = col[i].xyz; - float d = distance(light_pos, xpos.xyz); - float att = energy[i] * 200. / (4. * 3.14 * d * d); - float spec_att = (energy[i] + 10.) * 200. / (4. * 3.14 * d * d); + vec4 pseudocenter = ViewMatrix * vec4(center.xyz, 1.0); + pseudocenter /= pseudocenter.w; + vec3 light_pos = pseudocenter.xyz; + vec3 light_col = col.xyz; + float d = distance(light_pos, xpos.xyz); + float att = energy * 200. / (4. * 3.14 * d * d); + float spec_att = (energy + 10.) * 200. / (4. * 3.14 * d * d); - // Light Direction - vec3 L = normalize(xpos.xyz - light_pos); + // Light Direction + vec3 L = normalize(xpos.xyz - light_pos); - float NdotL = max(0.0, dot(norm, -L)); - diffuse += NdotL * light_col * att; - // Reflected light dir - vec3 R = reflect(-L, norm); - float RdotE = max(0.0, dot(R, eyedir)); - float Specular = pow(RdotE, spec); - specular += Specular * light_col * spec_att; - } + float NdotL = max(0.0, dot(norm, -L)); + diffuse += NdotL * light_col * att; + // Reflected light dir + vec3 R = reflect(-L, norm); + float RdotE = max(0.0, dot(R, eyedir)); + specular += pow(RdotE, spec) * light_col * spec_att; Diffuse = vec4(diffuse, 1.); Specular = vec4(specular , 1.); diff --git a/data/shaders/pointlight.vert b/data/shaders/pointlight.vert new file mode 100644 index 000000000..540584c4c --- /dev/null +++ b/data/shaders/pointlight.vert @@ -0,0 +1,38 @@ +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; + +in vec3 Position; +in float Energy; +in vec3 Color; + +in vec2 Corner; + +flat out vec3 center; +flat out float energy; +flat out vec3 col; + +const float zNear = 1.; + +void main(void) +{ + // Beyond that value, light is too attenuated + float r = 40 * Energy; + center = Position; + energy = Energy; + vec4 Center = ViewMatrix * vec4(Position, 1.); + if (Center.z > zNear) // Light is in front of the cam + { + vec3 UnitCenter = normalize(-Center.xyz); + float clampedR = min(r, Center.z - 1.); + float cosTheta = dot(UnitCenter, vec3(0., 0., -1)); + float d = clampedR / cosTheta; + Center.xyz += d * UnitCenter; + } + else if (Center.z + r > zNear) // Light is behind the cam but in range + { + Center.z = zNear; + // TODO: Change r so that we make the screen aligned quad fits light range. + } + col = Color; + gl_Position = ProjectionMatrix * (Center + r * vec4(Corner, 0., 0.)); +} diff --git a/data/shaders/ppdisplace.frag b/data/shaders/ppdisplace.frag deleted file mode 100644 index 717f77881..000000000 --- a/data/shaders/ppdisplace.frag +++ /dev/null @@ -1,30 +0,0 @@ -#version 330 -uniform sampler2D tex; -uniform sampler2D dtex; - -uniform int viz; - -in vec2 uv; -out vec4 FragColor; - -void main() -{ - vec2 tc = uv; - - vec4 shiftval = texture(dtex, tc) / vec4(50.0); - vec2 shift; - shift.x = -shiftval.x + shiftval.y; - shift.y = -shiftval.z + shiftval.w; - - tc += shift; - - vec4 newcol = texture(tex, tc); - - if (viz < 1) - { - FragColor = newcol; - } else - { - FragColor = shiftval * vec4(50.0); - } -} diff --git a/data/shaders/rain.frag b/data/shaders/rain.frag index 66af66dd3..39c1cde03 100644 --- a/data/shaders/rain.frag +++ b/data/shaders/rain.frag @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D tex; uniform sampler2D normals_and_depth; uniform mat4 invproj; diff --git a/data/shaders/rain.vert b/data/shaders/rain.vert index e20bf80f3..6c999eb32 100644 --- a/data/shaders/rain.vert +++ b/data/shaders/rain.vert @@ -1,4 +1,3 @@ -#version 330 compatibility uniform float screenw; void main() diff --git a/data/shaders/rainsim.vert b/data/shaders/rainsim.vert index dca63e1bf..4a24d07e9 100644 --- a/data/shaders/rainsim.vert +++ b/data/shaders/rainsim.vert @@ -1,4 +1,3 @@ -#version 330 compatibility uniform float time; uniform vec3 campos; uniform mat4 viewm; diff --git a/data/shaders/screenquad.vert b/data/shaders/screenquad.vert index 1ba822b26..f13fbba0a 100644 --- a/data/shaders/screenquad.vert +++ b/data/shaders/screenquad.vert @@ -1,8 +1,12 @@ -#version 330 - in vec2 Position; in vec2 Texcoord; + +#if __VERSION__ >= 130 out vec2 uv; +#else +varying vec2 uv; +#endif + void main() { uv = Texcoord; diff --git a/data/shaders/shadow.geom b/data/shaders/shadow.geom index 17754b677..a538974fe 100644 --- a/data/shaders/shadow.geom +++ b/data/shaders/shadow.geom @@ -1,4 +1,3 @@ -#version 330 uniform mat4 ModelViewProjectionMatrix[4]; layout(triangles) in; diff --git a/data/shaders/shadow.vert b/data/shaders/shadow.vert index 0bff7c743..e58ec7c63 100644 --- a/data/shaders/shadow.vert +++ b/data/shaders/shadow.vert @@ -1,5 +1,3 @@ -#version 330 - in vec3 Position; in vec2 Texcoord; diff --git a/data/shaders/shadowgen.frag b/data/shaders/shadowgen.frag index 2a44707de..565e9345c 100644 --- a/data/shaders/shadowgen.frag +++ b/data/shaders/shadowgen.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D halft; // half is a reserved word uniform sampler2D quarter; uniform sampler2D eighth; diff --git a/data/shaders/shadowimportance.frag b/data/shaders/shadowimportance.frag index 1bcc21cd0..7796780f1 100644 --- a/data/shaders/shadowimportance.frag +++ b/data/shaders/shadowimportance.frag @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D ntex; uniform sampler2D ctex; uniform vec3 campos; diff --git a/data/shaders/shadowimportance.vert b/data/shaders/shadowimportance.vert index bb3a8b4b9..ddd0bad18 100644 --- a/data/shaders/shadowimportance.vert +++ b/data/shaders/shadowimportance.vert @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D dtex; uniform mat4 ipvmat; uniform mat4 shadowmat; diff --git a/data/shaders/shadowpass.frag b/data/shaders/shadowpass.frag index bcec0ee01..5de466456 100644 --- a/data/shaders/shadowpass.frag +++ b/data/shaders/shadowpass.frag @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D tex; uniform int hastex; uniform int viz; diff --git a/data/shaders/shadowpass.vert b/data/shaders/shadowpass.vert index 009f4b295..f6e1cf3fe 100644 --- a/data/shaders/shadowpass.vert +++ b/data/shaders/shadowpass.vert @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D warpx; uniform sampler2D warpy; diff --git a/data/shaders/shadowwarph.frag b/data/shaders/shadowwarph.frag index 38d46dd89..2c22c20ee 100644 --- a/data/shaders/shadowwarph.frag +++ b/data/shaders/shadowwarph.frag @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D tex; uniform int size; uniform vec2 pixel; diff --git a/data/shaders/shadowwarpv.frag b/data/shaders/shadowwarpv.frag index 5491d8f21..62bc6bf6c 100644 --- a/data/shaders/shadowwarpv.frag +++ b/data/shaders/shadowwarpv.frag @@ -1,4 +1,3 @@ -#version 330 compatibility uniform sampler2D tex; uniform int size; uniform vec2 pixel; diff --git a/data/shaders/sky.frag b/data/shaders/sky.frag new file mode 100644 index 000000000..d6e44b383 --- /dev/null +++ b/data/shaders/sky.frag @@ -0,0 +1,21 @@ +uniform samplerCube tex; +uniform mat4 InvProjView; +uniform vec2 screen; + + +#if __VERSION__ >= 130 +out vec4 FragColor; +#else +#define FragColor gl_FragColor +#endif + + +void main(void) +{ + vec3 eyedir = gl_FragCoord.xyz / vec3(screen, 1.); + eyedir = 2.0 * eyedir - 1.0; + vec4 tmp = (InvProjView * vec4(eyedir, 1.)); + eyedir = tmp.xyz / tmp.w; + vec4 color = texture(tex, eyedir); + FragColor = vec4(color.xyz, 1.); +} diff --git a/data/shaders/skybox.frag b/data/shaders/skybox.frag index 1d150e975..e9425c61b 100644 --- a/data/shaders/skybox.frag +++ b/data/shaders/skybox.frag @@ -14,7 +14,6 @@ // 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. -#version 330 compatibility uniform sampler2D tex; uniform sampler2D glow_tex; uniform float transparency; diff --git a/data/shaders/skybox.vert b/data/shaders/skybox.vert index 7d3097ca5..45ded6b85 100644 --- a/data/shaders/skybox.vert +++ b/data/shaders/skybox.vert @@ -17,7 +17,6 @@ // Creates a bubble (wave) effect by distorting the texture depending on time -#version 330 compatibility uniform mat4 ModelViewProjectionMatrix; uniform float time; diff --git a/data/shaders/splatting.frag b/data/shaders/splatting.frag index 38a8e9631..aada653ca 100644 --- a/data/shaders/splatting.frag +++ b/data/shaders/splatting.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D tex_layout; uniform sampler2D tex_detail0; uniform sampler2D tex_detail1; @@ -10,9 +9,16 @@ uniform sampler2D SSAO; uniform vec2 screen; uniform vec3 ambient; +#if __VERSION__ >= 130 in vec2 uv; in vec2 uv_bis; out vec4 FragColor; +#else +varying vec2 uv; +varying vec2 uv_bis; +#define FragColor gl_FragColor +#endif + void main() { // Splatting part diff --git a/data/shaders/splatting.vert b/data/shaders/splatting.vert index c1a779ef1..2e7743b19 100644 --- a/data/shaders/splatting.vert +++ b/data/shaders/splatting.vert @@ -15,15 +15,23 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#version 330 uniform mat4 ModelViewProjectionMatrix; uniform mat4 TransposeInverseModelView; +#if __VERSION__ >= 130 in vec3 Position; in vec2 Texcoord; in vec2 SecondTexcoord; out vec2 uv; out vec2 uv_bis; +#else +attribute vec3 Position; +attribute vec2 Texcoord; +attribute vec2 SecondTexcoord; +varying vec2 uv; +varying vec2 uv_bis; +#endif + void main() { diff --git a/data/shaders/ssao.frag b/data/shaders/ssao.frag index 1ae1cba7d..dacabddbc 100644 --- a/data/shaders/ssao.frag +++ b/data/shaders/ssao.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D ntex; uniform sampler2D dtex; uniform sampler2D noise_texture; @@ -6,8 +5,13 @@ uniform mat4 invprojm; uniform mat4 projm; uniform vec4 samplePoints[16]; +#if __VERSION__ >= 130 in vec2 uv; -out float ao; +out float AO; +#else +varying vec2 uv; +#define AO gl_FragColor.x +#endif const float strengh = 4.; const float radius = .4f; @@ -39,7 +43,7 @@ void main(void) vec3 norm = normalize(DecodeNormal(2. * texture(ntex, uv).xy - 1.)); // Workaround for nvidia and skyboxes float len = dot(vec3(1.0), abs(cur.xyz)); - if (len < 0.2 || curdepth > 0.999) discard; + if (len < 0.2 || curdepth > 0.9955) discard; // Make a tangent as random as possible vec3 randvect = rand(uv); vec3 tangent = normalize(cross(norm, randvect)); @@ -65,5 +69,5 @@ void main(void) bl += isOccluded ? smoothstep(radius, 0, distance(samplePos, FragPos)) : 0.; } - ao = 1.0 - bl * invSamples; + AO = 1.0 - bl * invSamples; } diff --git a/data/shaders/sunlight.frag b/data/shaders/sunlight.frag index 68c1049ed..fccf941d2 100644 --- a/data/shaders/sunlight.frag +++ b/data/shaders/sunlight.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D ntex; uniform sampler2D dtex; //uniform sampler2D cloudtex; @@ -9,9 +8,16 @@ uniform mat4 invproj; //uniform int hasclouds; //uniform vec2 wind; +#if __VERSION__ >= 130 in vec2 uv; out vec4 Diff; out vec4 Spec; +#else +varying vec2 uv; +#define Diff gl_FragData[0] +#define Spec gl_FragData[1] +#endif + vec3 DecodeNormal(vec2 n) { diff --git a/data/shaders/sunlightshadow.frag b/data/shaders/sunlightshadow.frag index 66c617afb..69ffafd41 100644 --- a/data/shaders/sunlightshadow.frag +++ b/data/shaders/sunlightshadow.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D ntex; uniform sampler2D dtex; uniform sampler2DArrayShadow shadowtex; @@ -13,9 +12,16 @@ uniform mat4 shadowmat[4]; //uniform vec2 wind; //uniform float shadowoffset; +#if __VERSION__ >= 130 in vec2 uv; out vec4 Diff; out vec4 Spec; +#else +varying vec2 uv; +#define Diff gl_FragData[0] +#define Spec gl_FragData[1] +#endif + vec3 DecodeNormal(vec2 n) { diff --git a/data/shaders/texturedquad.frag b/data/shaders/texturedquad.frag index 48f7335b7..995a3c572 100644 --- a/data/shaders/texturedquad.frag +++ b/data/shaders/texturedquad.frag @@ -1,8 +1,13 @@ -#version 330 uniform sampler2D tex; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main() { diff --git a/data/shaders/texturedquad.vert b/data/shaders/texturedquad.vert index e8a73d3b8..bc6f1b03d 100644 --- a/data/shaders/texturedquad.vert +++ b/data/shaders/texturedquad.vert @@ -1,12 +1,18 @@ -#version 330 uniform vec2 center; uniform vec2 size; uniform vec2 texcenter; uniform vec2 texsize; +#if __VERSION__ >= 130 in vec2 position; in vec2 texcoord; out vec2 uv; +#else +attribute vec2 position; +attribute vec2 texcoord; +varying vec2 uv; +#endif + void main() { diff --git a/data/shaders/transparent.frag b/data/shaders/transparent.frag index e5b1e7c69..4de578afd 100644 --- a/data/shaders/transparent.frag +++ b/data/shaders/transparent.frag @@ -1,8 +1,13 @@ -#version 330 uniform sampler2D tex; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main() { diff --git a/data/shaders/transparent.vert b/data/shaders/transparent.vert index b5451f0a5..9692fc549 100644 --- a/data/shaders/transparent.vert +++ b/data/shaders/transparent.vert @@ -1,10 +1,16 @@ -#version 330 uniform mat4 ModelViewProjectionMatrix; uniform mat4 TextureMatrix; +#if __VERSION__ >= 130 in vec3 Position; in vec2 Texcoord; out vec2 uv; +#else +attribute vec3 Position; +attribute vec2 Texcoord; +varying vec2 uv; +#endif + void main() { diff --git a/data/shaders/transparentfog.frag b/data/shaders/transparentfog.frag index 545587044..9e0e9ad0f 100644 --- a/data/shaders/transparentfog.frag +++ b/data/shaders/transparentfog.frag @@ -1,4 +1,3 @@ -#version 330 uniform sampler2D tex; uniform float fogmax; @@ -10,8 +9,14 @@ uniform vec3 col; uniform mat4 ipvmat; uniform vec2 screen; +#if __VERSION__ >= 130 in vec2 uv; out vec4 FragColor; +#else +varying vec2 uv; +#define FragColor gl_FragColor +#endif + void main() { diff --git a/data/shaders/untextured_object.frag b/data/shaders/untextured_object.frag index 24f4a54be..d4e7852ee 100644 --- a/data/shaders/untextured_object.frag +++ b/data/shaders/untextured_object.frag @@ -1,11 +1,17 @@ -#version 330 uniform sampler2D DiffuseMap; uniform sampler2D SpecularMap; uniform sampler2D SSAO; uniform vec2 screen; uniform vec3 ambient; + +#if __VERSION__ >= 130 in vec4 color; out vec4 FragColor; +#else +varying vec4 color; +#define FragColor gl_FragColor +#endif + void main(void) { diff --git a/data/shaders/untextured_object.vert b/data/shaders/untextured_object.vert index 5f0f91cf7..36020e0db 100644 --- a/data/shaders/untextured_object.vert +++ b/data/shaders/untextured_object.vert @@ -1,9 +1,15 @@ -#version 330 uniform mat4 ModelViewProjectionMatrix; +#if __VERSION__ >= 130 in vec3 Position; in vec4 Color; out vec4 color; +#else +attribute vec3 Position; +attribute vec4 Color; +varying vec4 color; +#endif + void main(void) { diff --git a/data/shaders/water.frag b/data/shaders/water.frag index 1e9d434b3..29bac3458 100644 --- a/data/shaders/water.frag +++ b/data/shaders/water.frag @@ -8,9 +8,9 @@ uniform sampler2D DecalTex; //The texture uniform vec2 delta1; uniform vec2 delta2; -noperspective in vec3 lightVec; -noperspective in vec3 halfVec; -noperspective in vec3 eyeVec; +in vec3 lightVec; +in vec3 halfVec; +in vec3 eyeVec; in vec2 uv; out vec4 FragColor; diff --git a/data/shaders/water.vert b/data/shaders/water.vert index 78a1fe5c5..cf44b8e8c 100644 --- a/data/shaders/water.vert +++ b/data/shaders/water.vert @@ -7,9 +7,9 @@ uniform float waveLength; uniform vec3 lightdir; -noperspective out vec3 lightVec; -noperspective out vec3 halfVec; -noperspective out vec3 eyeVec; +out vec3 lightVec; +out vec3 halfVec; +out vec3 eyeVec; out vec2 uv; void main() diff --git a/data/shaders/white.frag b/data/shaders/white.frag index 3017ace18..d48e4e724 100644 --- a/data/shaders/white.frag +++ b/data/shaders/white.frag @@ -1,5 +1,10 @@ -#version 330 +#if __VERSION__ >= 130 out vec4 FragColor; +#else +#define FragColor gl_FragColor +#endif + + void main() { FragColor = vec4(1.0); diff --git a/data/skins/Ocean.stkskin b/data/skins/Ocean.stkskin index 7f7c90768..031c1a9b6 100644 --- a/data/skins/Ocean.stkskin +++ b/data/skins/Ocean.stkskin @@ -105,7 +105,6 @@ when the border that intersect at this corner are enabled. left_border="75" right_border="75" top_border="0" bottom_border="15" hborder_out_portion="0.2" /> - + + + + + + + + + + + + - + lbound-fraction is the lower bound fraction of speed when lost will + detach parachute. E.g. at nearly 0 speed, only 5% of speed + need to be lost. + ubound-fraction is the upper bound fraction of speed when lost will + detach parachute. E.g. at max-speed 30% of speed must be lost. + max-speed is a factor that decides the impact of rate of speed + (distance between bounds) --> + diff --git a/lib/irrlicht/source/Irrlicht/COpenGLExtensionHandler.h b/lib/irrlicht/source/Irrlicht/COpenGLExtensionHandler.h index 822f114c6..757d416ee 100644 --- a/lib/irrlicht/source/Irrlicht/COpenGLExtensionHandler.h +++ b/lib/irrlicht/source/Irrlicht/COpenGLExtensionHandler.h @@ -49,6 +49,7 @@ #define NO_SDL_GLEXT #include #include + typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); #include "glext.h" #else #if defined(_IRR_OPENGL_USE_EXTPOINTER_) @@ -61,6 +62,7 @@ #include #include #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); #include #undef GLX_ARB_get_proc_address // avoid problems with local glxext.h #include diff --git a/sources.cmake b/sources.cmake index 7df0ad319..0a4f6f0ec 100644 --- a/sources.cmake +++ b/sources.cmake @@ -194,7 +194,7 @@ src/network/types.cpp src/online/current_user.cpp src/online/http_request.cpp src/online/messages.cpp -src/online/profile.cpp +src/online/online_profile.cpp src/online/profile_manager.cpp src/online/request.cpp src/online/request_manager.cpp @@ -527,7 +527,7 @@ src/network/types.hpp src/online/current_user.hpp src/online/http_request.hpp src/online/messages.hpp -src/online/profile.hpp +src/online/online_profile.hpp src/online/profile_manager.hpp src/online/request.hpp src/online/request_manager.hpp diff --git a/src/achievements/achievement.cpp b/src/achievements/achievement.cpp index 0804ac1f7..8e07dd60b 100644 --- a/src/achievements/achievement.cpp +++ b/src/achievements/achievement.cpp @@ -1,6 +1,7 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 Glenn De Jonghe +// Copyright (C) 2013-2014 Glenn De Jonghe +// 2014 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -26,17 +27,15 @@ #include "utils/log.hpp" #include "utils/translation.hpp" - -#include -#include -#include #include - +/** Constructur, initialises this object with the data from the + * corresponding AchievementInfo. + */ Achievement::Achievement(const AchievementInfo * info) - :m_achievement_info(info) + : m_achievement_info(info) { - m_id = info->getID(); + m_id = info->getID(); m_achieved = false; } // Achievement @@ -52,6 +51,15 @@ void Achievement::load(const XMLNode *node) { node->get("id", &m_id ); node->get("achieved", &m_achieved); + + for (unsigned int i = 0; i < node->getNumNodes(); i++) + { + const XMLNode *n = node->getNode(i); + std::string key = n->getName(); + int value = 0; + n->get("value", &value); + m_progress_map[key] = value; + } } // load // ---------------------------------------------------------------------------- @@ -62,16 +70,118 @@ void Achievement::save(UTFWriter &out) { out << L" \n"; + return; + } + + out << ">\n"; + std::map::iterator i; + for (i = m_progress_map.begin(); i != m_progress_map.end(); ++i) + { + out << " <" << i->first + << " value=\"" << i->second << "\"/>\n"; + } + out << " \n"; } // save // ---------------------------------------------------------------------------- +/** Returns the value for a key. + */ +int Achievement::getValue(const std::string & key) +{ + if (m_progress_map.find(key) != m_progress_map.end()) + return m_progress_map[key]; + return 0; +} +// ---------------------------------------------------------------------------- +/** Resets all currently key values to 0. Called if the reset-after-race flag + * is set for the corresponding AchievementInfo. + */ +void Achievement::reset() +{ + std::map::iterator iter; + for (iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter) + { + iter->second = 0; + } +} // reset + +// ---------------------------------------------------------------------------- +/** Returns how much of an achievement has been achieved in the form n/m. + * The AchievementInfo adds up all goal values to get 'm', and this + * this class end up all current key values for 'n'. + */ +irr::core::stringw Achievement::getProgressAsString() const +{ + int progress = 0; + std::map::const_iterator iter; + + // For now return N/N in case of an achieved achievement. + if (m_achieved) + return getInfo()->toString() +"/" + getInfo()->toString(); + + switch (m_achievement_info->getCheckType()) + { + case AchievementInfo::AC_ALL_AT_LEAST: + for (iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter) + { + progress += iter->second; + } + break; + case AchievementInfo::AC_ONE_AT_LEAST: + for (iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter) + { + if(iter->second>progress) progress = iter->second; + } + break; + default: + Log::fatal("Achievement", "Missing getProgressAsString for type %d.", + m_achievement_info->getCheckType()); + } + return StringUtils::toWString(progress) + "/" + getInfo()->toString(); +} // getProgressAsString + +// ---------------------------------------------------------------------------- +/** Increases the value of a key by a specified amount, but make sure to not + * increase the value above the goal (otherwise the achievement progress + * could be 12/10 (e.g. if one track is used 12 times for the Christoffel + * achievement), even though the achievement is not achieved. + * \param key The key whose value is increased. + * \param increase Amount to add to the value of this key. + */ +void Achievement::increase(const std::string & key, int increase) +{ + std::map::iterator it; + it = m_progress_map.find(key); + if (it != m_progress_map.end()) + { + it->second += increase; + if (it->second > m_achievement_info->getGoalValue(key)) + it->second = m_achievement_info->getGoalValue(key); + } + else + { + if (increase>m_achievement_info->getGoalValue(key)) + increase = m_achievement_info->getGoalValue(key); + m_progress_map[key] = increase; + } + check(); +} // increase + +// ---------------------------------------------------------------------------- +/** Called at the end of a race to potentially reset values. + */ void Achievement::onRaceEnd() { if(m_achievement_info->needsResetAfterRace()) - this->reset(); -} + reset(); +} // onRaceEnd // ---------------------------------------------------------------------------- +/** Checks if this achievement has been achieved. + */ void Achievement::check() { if(m_achieved) @@ -80,169 +190,14 @@ void Achievement::check() if(m_achievement_info->checkCompletion(this)) { //show achievement + core::stringw s = StringUtils::insertValues(_("Completed achievement \"%s\"."), + m_achievement_info->getTitle()); GUIEngine::DialogQueue::get()->pushDialog( - new NotificationDialog(NotificationDialog::T_Achievements, - irr::core::stringw(_("Completed achievement")) + irr::core::stringw(" \"") + m_achievement_info->getTitle() + irr::core::stringw("\".") - )); + new NotificationDialog(NotificationDialog::T_Achievements, s)); + //send to server Online::CurrentUser::get()->onAchieving(m_id); m_achieved = true; } -} - -// ---------------------------------------------------------------------------- -/** Constructor for a SingleAchievement. - */ -SingleAchievement::SingleAchievement(const AchievementInfo * info) - : Achievement(info) -{ - m_progress = 0; - m_achieved = false; -} // SingleAchievement - -// ---------------------------------------------------------------------------- -/** Loads the state from an xml node. - * \param node The XML data. - */ -void SingleAchievement::load(const XMLNode *node) -{ - Achievement::load(node); - if (!isAchieved()) - node->get("progress", &m_progress); -} // load - -// ---------------------------------------------------------------------------- -/** Save the state to a file. The progress is only saved if the achievement - * has not been achieved yet. - * \param out The output file. - */ -void SingleAchievement::save(UTFWriter &out) -{ - Achievement::save(out); - if (!m_achieved) - { - out << L" progress=\"" << m_progress << L"\""; - } - out << L"/>\n"; -} // save - -// ---------------------------------------------------------------------------- -/** Resets the challenge. Calls if necessary (i.e. if a challenge needs to - * be fulfilled in a single race). - */ -void SingleAchievement::reset() -{ - m_progress = 0; -} // reset - -// ---------------------------------------------------------------------------- -/** Adds a value to this counter. - * \param increase Value to add. - */ -void SingleAchievement::increase(int increase) -{ - m_progress += increase; - check(); -} // increase - -// ---------------------------------------------------------------------------- -/** Returns a "k/n" string indicating how much of an achievement was achieved. - */ -irr::core::stringw SingleAchievement::getProgressAsString() -{ - // The info class returns the goal value - return StringUtils::toWString(m_progress) + "/" - +getInfo()->toString(); -} // getProgressAsString - -// ============================================================================ - -/** Constructor for a MapAchievement. - */ -MapAchievement::MapAchievement(const AchievementInfo * info) - : Achievement(info) -{ -} // MapAchievement - -// ---------------------------------------------------------------------------- -/** Loads the status from an XML node. - * \param node The XML data to load the status from. - */ -void MapAchievement::load(const XMLNode *node) -{ - Achievement::load(node); - for (unsigned int i = 0; i < node->getNumNodes(); i++) - { - const XMLNode *n = node->getNode(i); - std::string key = n->getName(); - int value = 0; - n->get("value", &value); - m_progress_map[key] = value; - } -} // load - -// ---------------------------------------------------------------------------- -/** Saves the status of this achievement to a file. - * \param out The file to write the state to. - */ -void MapAchievement::save(UTFWriter &out) -{ - Achievement::save(out); - if (isAchieved()) - { - out << "/>\n"; - return; - } - out << ">\n"; - std::map::iterator i; - for (i = m_progress_map.begin(); i != m_progress_map.end(); ++i) - { - out << " <" << i->first - << " value=\"" << i->second << "\"/>\n"; - } - out << " \n"; -} // save - -// ---------------------------------------------------------------------------- - -int MapAchievement::getValue(const std::string & key) -{ - if ( m_progress_map.find(key) != m_progress_map.end()) - return m_progress_map[key]; - return 0; -} - -// ---------------------------------------------------------------------------- -void MapAchievement::reset() -{ - std::map::iterator iter; - for ( iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter ) - { - iter->second = 0; - } -} // reset - -// ---------------------------------------------------------------------------- -void MapAchievement::increase(const std::string & key, int increase) -{ - if (m_progress_map.find(key) != m_progress_map.end()) - { - m_progress_map[key] += increase; - check(); - } - else - m_progress_map[key] = increase; -} - -// ---------------------------------------------------------------------------- -irr::core::stringw MapAchievement::getProgressAsString() -{ - int progress = 0; - std::map::const_iterator iter; - for ( iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter) - { - progress += iter->second; - } - return StringUtils::toWString(progress) + "/" + getInfo()->toString(); -} +} // check diff --git a/src/achievements/achievement.hpp b/src/achievements/achievement.hpp index bca93442d..ec3790aad 100644 --- a/src/achievements/achievement.hpp +++ b/src/achievements/achievement.hpp @@ -30,40 +30,45 @@ class UTFWriter; class XMLNode; // ============================================================================ - /** This is the base class for any achievement. It allows achievement status - * to be saved, and detects when an achievement is fulfilled. + * to be saved, and detects when an achievement is fulfilled. It provides + * storage for state information by a generic key-value mapping. The values + * are stored as strings, but can be used to store numerical values. E.g. + * you can call increase("key", 10) for an achievement, which will convert + * the string to int, add 10, then convert the result back to string for + * storage. * \ingroup achievements */ class AchievementInfo; class Achievement { -protected: +private: /** The id of this achievement. */ uint32_t m_id; /** True if this achievement has been achieved. */ bool m_achieved; + /** The map of key-value pairs. */ + std::map m_progress_map; + /** A pointer to the corresponding AchievementInfo instance. */ const AchievementInfo *m_achievement_info; void check(); public: - enum AchievementType - { - AT_SINGLE, - AT_MAP - }; - Achievement(const AchievementInfo * info); - virtual ~Achievement (); - virtual void load (const XMLNode *node) ; - virtual void save (UTFWriter &out) ; - virtual void reset () = 0; - virtual irr::core::stringw getProgressAsString() = 0; + Achievement(const AchievementInfo * info); + virtual ~Achievement(); + virtual void load(const XMLNode *node); + virtual void save(UTFWriter &out); + virtual int getValue(const std::string & key); + void increase(const std::string & key, int increase = 1); + + virtual void reset(); + virtual irr::core::stringw getProgressAsString() const; void onRaceEnd(); // ------------------------------------------------------------------------ /** Returns the id of this achievement. */ @@ -77,56 +82,10 @@ public: // ------------------------------------------------------------------------ /** Returns if this achievement has been fulfilled. */ bool isAchieved() const { return m_achieved; } - + // ------------------------------------------------------------------------ + const std::map& getProgress() const + { + return m_progress_map; + } // getProgress }; // class Achievement - -// ============================================================================ -/** This is a base class for an achievement that counts how often an event - * happened, and triggers the achievement to be fulfilled when a certain - * goal value is reached. - * \ingroup achievements - */ -class SingleAchievement : public Achievement -{ -protected: - int m_progress; - -public: - SingleAchievement (const AchievementInfo * info); - virtual ~SingleAchievement () {}; - - void load (const XMLNode *node); - int getValue () const { return m_progress; } - void save (UTFWriter &out); - void increase (int increase = 1); - void reset (); - virtual irr::core::stringw getProgressAsString (); -}; // class SingleAchievement - -// ============================================================================ -/** This achievement can keep track of a set of key-value pairs. Fulfillment is - * triggered when all values defined in the data/achievements.xml file have - * been reached. -* \ingroup achievements -*/ -class MapAchievement : public Achievement -{ -protected: - /** The map of key-value pairs. */ - std::map m_progress_map; - -public: - MapAchievement (const AchievementInfo * info); - virtual ~MapAchievement () {}; - - void load (const XMLNode *node); - int getValue (const std::string & key); - void increase (const std::string & key, int increase = 1); - void save (UTFWriter &out); - void reset (); - virtual irr::core::stringw getProgressAsString (); -}; // class MapAchievement - -#endif - -/*EOF*/ +#endif \ No newline at end of file diff --git a/src/achievements/achievement_info.cpp b/src/achievements/achievement_info.cpp index eb09700ee..98602cd32 100644 --- a/src/achievements/achievement_info.cpp +++ b/src/achievements/achievement_info.cpp @@ -1,6 +1,7 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 Glenn De Jonghe +// Copyright (C) 2013-2014 Glenn De Jonghe +// 2014 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -25,7 +26,9 @@ #include #include - +/** The constructor reads the dat from the xml information. + * \param input XML node for this achievement info. + */ AchievementInfo::AchievementInfo(const XMLNode * input) { m_reset_after_race = false; @@ -45,68 +48,110 @@ AchievementInfo::AchievementInfo(const XMLNode * input) m_description.c_str()); } input->get("reset-after-race", &m_reset_after_race); -} // AchievementInfo -// ============================================================================ -SingleAchievementInfo::SingleAchievementInfo(const XMLNode * input) - : AchievementInfo(input) -{ - input->get("goal", &m_goal_value); -} // SingleAchievementInfo + m_check_type = AC_ALL_AT_LEAST; + std::string s; + input->get("check-type", &s); + if (s == "all-at-least") + m_check_type = AC_ALL_AT_LEAST; + else if (s == "one-at-least") + m_check_type = AC_ONE_AT_LEAST; + else + Log::warn("AchievementInfo", "Achievement check type '%s' unknown.", + s.c_str()); -// ---------------------------------------------------------------------------- -irr::core::stringw SingleAchievementInfo::toString() const -{ - return StringUtils::toWString(m_goal_value); -} // toString - -// ---------------------------------------------------------------------------- -bool SingleAchievementInfo::checkCompletion(Achievement * achievement) const -{ - SingleAchievement * single_achievement = (SingleAchievement *) achievement; - if(single_achievement->getValue() >= m_goal_value) - return true; - return false; -} - -// ============================================================================ -MapAchievementInfo::MapAchievementInfo(const XMLNode * input) - : AchievementInfo(input) -{ - std::vector xml_entries; - input->getNodes("entry", xml_entries); - for (unsigned int n=0; n < xml_entries.size(); n++) + // Now load the goal nodes + for (unsigned int n = 0; n < input->getNumNodes(); n++) { - std::string key(""); - xml_entries[n]->get("key", &key); - int goal(0); - xml_entries[n]->get("goal", &goal); + const XMLNode *node = input->getNode(n); + std::string key = node->getName(); + int goal = 0; + node->get("goal", &goal); m_goal_values[key] = goal; } - if(m_goal_values.size() != xml_entries.size()) - Log::error("MapAchievementInfo","Duplicate keys for the entries of a MapAchievement found."); -} + if (m_goal_values.size() != input->getNumNodes()) + Log::fatal("AchievementInfo", + "Duplicate keys for the entries of a MapAchievement found."); + + if (m_check_type == AC_ONE_AT_LEAST) + { + if (m_goal_values.size() != 1) + Log::fatal("AchievementInfo", + "A one-at-least achievement must have exactly one goal."); + } +} // AchievementInfo + // ---------------------------------------------------------------------------- -irr::core::stringw MapAchievementInfo::toString() const +/** Returns a string with a numerical value to display the progress of + * this achievement. It adds up all the goal values + */ +irr::core::stringw AchievementInfo::toString() const { int count = 0; std::map::const_iterator iter; - for (iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++) + switch (m_check_type) { - count += iter->second; + case AC_ALL_AT_LEAST: + // If all values need to be reached, add up all goal values + for (iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++) + { + count += iter->second; + } + break; + case AC_ONE_AT_LEAST: + // Only one goal is defined for a one-at-least + count = m_goal_values.begin()->second; + break; + default: + Log::fatal("AchievementInfo", "Missing toString for tpye %d.", + m_check_type); } return StringUtils::toWString(count); + } // toString // ---------------------------------------------------------------------------- -bool MapAchievementInfo::checkCompletion(Achievement * achievement) const +bool AchievementInfo::checkCompletion(Achievement * achievement) const { - MapAchievement * map_achievement = (MapAchievement *) achievement; std::map::const_iterator iter; - for ( iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++ ) + + switch (m_check_type) { - if(map_achievement->getValue(iter->first) < iter->second) - return false; + case AC_ALL_AT_LEAST: + for (iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++) + { + if (achievement->getValue(iter->first) < iter->second) + return false; + } + return true; + case AC_ONE_AT_LEAST: + { + // Test all progress values the kart has. + const std::map &progress = achievement->getProgress(); + for (iter = progress.begin(); iter != progress.end(); iter++) + { + // A one-at-least achievement has only one goal, so use it + if (iter->second >= m_goal_values.begin()->second) + return true; + } + return false; } - return true; + default: + Log::fatal("AchievementInfo", "Missing check for tpye %d.", + m_check_type); + } // switch + + // Avoid compiler warning + return false; } +// ---------------------------------------------------------------------------- +int AchievementInfo::getGoalValue(const std::string &key) const +{ + std::map::const_iterator it; + it = m_goal_values.find(key); + if (it != m_goal_values.end()) + return it->second; + else + return 0; +} // getGoalValue +// ---------------------------------------------------------------------------- diff --git a/src/achievements/achievement_info.hpp b/src/achievements/achievement_info.hpp index 78ae538d9..6b8bab458 100644 --- a/src/achievements/achievement_info.hpp +++ b/src/achievements/achievement_info.hpp @@ -1,6 +1,8 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 Glenn De Jonghe +// Copyright (C) 2013-2014 Glenn De Jonghe +// 2014 Joerg Henrichs + // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -38,7 +40,26 @@ class Achievement; */ class AchievementInfo { -protected: +public: + /** Some handy names for the various achievements. */ + enum { ACHIEVE_COLUMBUS = 1, + ACHIEVE_FIRST = ACHIEVE_COLUMBUS, + ACHIEVE_STRIKE = 2, + ACHIEVE_ARCH_ENEMY = 3, + ACHIEVE_MARATHONER = 4, + ACHIEVE_LAST = ACHIEVE_MARATHONER + }; + /** Achievement check type: + * ALL_AT_LEAST: All goal values must be reached (or exceeded). + * ONE_AT_LEAST: At least one current value reaches or exceedes the goal. + */ + enum AchievementCheckType + { + AC_ALL_AT_LEAST, + AC_ONE_AT_LEAST + }; + +private: /** The id of this Achievement. */ uint32_t m_id; @@ -48,15 +69,22 @@ protected: /** The description of this achievement. */ irr::core::stringw m_description; + /** Determines how this achievement is checked if it is successful. */ + AchievementCheckType m_check_type; + + /** The target values needed to be reached. */ + std::map m_goal_values; + /** True if the achievement needs to be reset after each race. */ bool m_reset_after_race; public: - AchievementInfo (const XMLNode * input); - virtual ~AchievementInfo () {}; - virtual Achievement::AchievementType getType() const = 0; - virtual irr::core::stringw toString() const = 0; - virtual bool checkCompletion(Achievement * achievement) const = 0; + AchievementInfo(const XMLNode * input); + virtual ~AchievementInfo() {}; + + virtual irr::core::stringw toString() const; + virtual bool checkCompletion(Achievement * achievement) const; + int getGoalValue(const std::string &key) const; // ------------------------------------------------------------------------ /** Returns the id of this achievement. */ @@ -69,64 +97,13 @@ public: irr::core::stringw getTitle() const { return m_title; } // ------------------------------------------------------------------------ bool needsResetAfterRace() const { return m_reset_after_race; } + // ------------------------------------------------------------------------ + /** Returns the check type for this achievement. */ + AchievementCheckType getCheckType() const { return m_check_type; } + // ------------------------------------------------------------------------ }; // class AchievementInfo -// ============================================================================ -/** This class stores the information about an achievement that count a - * single value. - */ -class SingleAchievementInfo : public AchievementInfo -{ -private: - /** Which value must be reached in order to achieve this achievement. */ - int m_goal_value; - -public: - SingleAchievementInfo(const XMLNode * input); - virtual ~SingleAchievementInfo() {}; - virtual irr::core::stringw toString() const; - virtual bool checkCompletion(Achievement * achievement) const; - // ------------------------------------------------------------------------ - int getGoalValue() const { return m_goal_value; } - // ------------------------------------------------------------------------ - virtual Achievement::AchievementType getType() const - { - return Achievement::AT_SINGLE; - } // getType -}; // class SingleAchievementInfo - - -// ============================================================================ -/** This class stores a set of key-value pairs. - */ -class MapAchievementInfo : public AchievementInfo -{ -protected: - - /** The target values needed to be reached. */ - std::map m_goal_values; - -public: - MapAchievementInfo(const XMLNode * input); - virtual ~MapAchievementInfo() {}; - virtual bool checkCompletion(Achievement * achievement) const; - virtual irr::core::stringw toString() const; - // ------------------------------------------------------------------------ - int getGoalValue(const std::string & key) { return m_goal_values[key]; } - // ------------------------------------------------------------------------ - const std::map & getGoalValues() const - { - return m_goal_values; - } // getGoalValues - // ------------------------------------------------------------------------ - virtual Achievement::AchievementType getType() const - { - return Achievement::AT_MAP; - } // getType - -}; // class MapAchievementInfo - #endif /*EOF*/ diff --git a/src/achievements/achievements_manager.cpp b/src/achievements/achievements_manager.cpp index c26b163d7..e13af174e 100644 --- a/src/achievements/achievements_manager.cpp +++ b/src/achievements/achievements_manager.cpp @@ -1,6 +1,7 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 Glenn De Jonghe +// Copyright (C) 2013-2014 Glenn De Jonghe +// 2014 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -35,11 +36,27 @@ AchievementsManager* AchievementsManager::m_achievements_manager = NULL; // ---------------------------------------------------------------------------- -/** Constructor, which reads data/achievements.xml. +/** Constructor, which reads data/achievements.xml and stores the information + * in AchievementInfo objects. */ AchievementsManager::AchievementsManager() { - parseAssetFile(); + const std::string file_name = file_manager->getAsset("achievements.xml"); + const XMLNode *root = file_manager->createXMLTree(file_name); + unsigned int num_nodes = root->getNumNodes(); + for (unsigned int i = 0; i < num_nodes; i++) + { + const XMLNode *node = root->getNode(i); + std::string type(""); + node->get("type", &type); + AchievementInfo * achievement_info = new AchievementInfo(node); + m_achievements_info[achievement_info->getID()] = achievement_info; + } + if (num_nodes != m_achievements_info.size()) + Log::error("AchievementsManager", + "Multiple achievements with the same id!"); + + delete root; } // AchievementsManager // ---------------------------------------------------------------------------- @@ -52,46 +69,6 @@ AchievementsManager::~AchievementsManager() m_achievements_info.clear(); } // ~AchievementsManager -// ---------------------------------------------------------------------------- -/** Parses the data/achievements.xml file and stores the information about - * all achievements in its internal map. - */ -void AchievementsManager::parseAssetFile() -{ - const std::string file_name = file_manager->getAsset("achievements.xml"); - const XMLNode *root = file_manager->createXMLTree(file_name); - unsigned int num_nodes = root->getNumNodes(); - for(unsigned int i = 0; i < num_nodes; i++) - { - const XMLNode *node = root->getNode(i); - std::string type(""); - node->get("type", &type); - AchievementInfo * achievement_info; - if(type == "single") - { - achievement_info = new SingleAchievementInfo(node); - } - else if(type == "map") - { - achievement_info = new MapAchievementInfo(node); - } - else - { - Log::error("AchievementsManager", - "Non-existent achievement type '%s'. Skipping - " - "definitely results in unwanted behaviour.", - type.c_str()); - continue; - } - m_achievements_info[achievement_info->getID()] = achievement_info; - } - if(num_nodes != m_achievements_info.size()) - Log::error("AchievementsManager::parseAchievements", - "Multiple achievements with the same id!"); - - delete root; -} // parseAssetFile - // ---------------------------------------------------------------------------- /** Create a new AchievementStatus object that stores all achievement status * information for a single player. @@ -107,16 +84,8 @@ AchievementsStatus* for (it = m_achievements_info.begin(); it != m_achievements_info.end(); ++it) { - Achievement::AchievementType achievement_type = it->second->getType(); Achievement * achievement; - if (achievement_type == Achievement::AT_SINGLE) - { - achievement = new SingleAchievement(it->second); - } - else if (achievement_type == Achievement::AT_MAP) - { - achievement = new MapAchievement(it->second); - } + achievement = new Achievement(it->second); status->add(achievement); } diff --git a/src/achievements/achievements_manager.hpp b/src/achievements/achievements_manager.hpp index ba024d611..67cebf888 100644 --- a/src/achievements/achievements_manager.hpp +++ b/src/achievements/achievements_manager.hpp @@ -31,8 +31,9 @@ class AchievementsStatus; #include -/** - * \brief Class that takes care of online profiles +/** This class manages the list of all achievements. It reads the + * data/achievements.xml file, which contains the conditions for + * each achievement. * \ingroup online */ class AchievementsManager @@ -46,7 +47,6 @@ private: AchievementsManager (); ~AchievementsManager (); AchievementsStatus * createNewSlot(unsigned int id, bool online); - void parseAssetFile(); public: /** Static function to create the instance of the achievement manager. */ diff --git a/src/achievements/achievements_status.cpp b/src/achievements/achievements_status.cpp index 236298247..40aa3d34d 100644 --- a/src/achievements/achievements_status.cpp +++ b/src/achievements/achievements_status.cpp @@ -1,6 +1,7 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 Glenn De Jonghe +// Copyright (C) 2013-2014 Glenn De Jonghe +// 2014 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -34,6 +35,8 @@ // ---------------------------------------------------------------------------- +/** Constructor for an Achievement. + */ AchievementsStatus::AchievementsStatus() { m_valid = true; @@ -41,9 +44,15 @@ AchievementsStatus::AchievementsStatus() } // AchievementsStatus // ---------------------------------------------------------------------------- +/** Removes all achievements. + */ AchievementsStatus::~AchievementsStatus() { - deleteAchievements(); + std::map::iterator it; + for (it = m_achievements.begin(); it != m_achievements.end(); ++it) { + delete it->second; + } + m_achievements.clear(); } // ~AchievementsStatus // ---------------------------------------------------------------------------- @@ -77,15 +86,6 @@ void AchievementsStatus::add(Achievement *achievement) m_achievements[achievement->getID()] = achievement; } // add -// ---------------------------------------------------------------------------- -void AchievementsStatus::deleteAchievements() -{ - std::map::iterator it; - for ( it = m_achievements.begin(); it != m_achievements.end(); ++it ) { - delete it->second; - } - m_achievements.clear(); -} // deleteAchievements // ---------------------------------------------------------------------------- /** Saves the achievement status to a file. Achievements are stored as part @@ -110,7 +110,7 @@ Achievement * AchievementsStatus::getAchievement(uint32_t id) if ( m_achievements.find(id) != m_achievements.end()) return m_achievements[id]; return NULL; -} +} // getAchievement // ---------------------------------------------------------------------------- void AchievementsStatus::sync(const std::vector & achieved_ids) @@ -121,7 +121,7 @@ void AchievementsStatus::sync(const std::vector & achieved_ids) if(achievement != NULL) achievement->setAchieved(); } -} +} // sync // ---------------------------------------------------------------------------- void AchievementsStatus::onRaceEnd() @@ -131,4 +131,4 @@ void AchievementsStatus::onRaceEnd() for ( iter = m_achievements.begin(); iter != m_achievements.end(); ++iter ) { iter->second->onRaceEnd(); } -} +} // onRaceEnd diff --git a/src/achievements/achievements_status.hpp b/src/achievements/achievements_status.hpp index c6ce0b5f8..e956dd99b 100644 --- a/src/achievements/achievements_status.hpp +++ b/src/achievements/achievements_status.hpp @@ -1,6 +1,7 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 Glenn De Jonghe +// Copyright (C) 2013-2014 Glenn De Jonghe +// 2014 Joerg Henrichs // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -30,6 +31,13 @@ class UTFWriter; class XMLNode; +/** This class keeps tracks of all achievements of one player. One instance + * of this class is stored in each PlayerProfile. It stores a map of + * achievements ids to instances of Achievement. Each achievement in + * turn stores either fulfilled achievements, or the current state of + * an achievement (e.g. an achievement to race every track in STK needs + * to keep information about which tracks have already been used.) +*/ class AchievementsStatus { private: @@ -37,8 +45,6 @@ private: bool m_online; bool m_valid; - void deleteAchievements(); - class SyncAchievementsRequest : public Online::XMLRequest { virtual void callback (); public: diff --git a/src/addons/addons_manager.cpp b/src/addons/addons_manager.cpp index 79f8af473..6f765aea9 100644 --- a/src/addons/addons_manager.cpp +++ b/src/addons/addons_manager.cpp @@ -22,6 +22,7 @@ #include "addons/news_manager.hpp" #include "addons/zip.hpp" +#include "config/user_config.hpp" #include "io/file_manager.hpp" #include "io/xml_node.hpp" #include "karts/kart_properties.hpp" diff --git a/src/animations/three_d_animation.cpp b/src/animations/three_d_animation.cpp index 5a64db219..793dc2fbb 100644 --- a/src/animations/three_d_animation.cpp +++ b/src/animations/three_d_animation.cpp @@ -47,7 +47,7 @@ ThreeDAnimation::ThreeDAnimation(const XMLNode &node, TrackObject* object) : Ani node.get("explode", &m_explode_kart); node.get("flatten", &m_flatten_kart); - m_important_animation = (World::getWorld()->getIdent() == IDENT_CUSTSCENE); + m_important_animation = (World::getWorld()->getIdent() == IDENT_CUTSCENE); node.get("important", &m_important_animation); /** Save the initial position and rotation in the base animation object. */ diff --git a/src/challenges/challenge_data.cpp b/src/challenges/challenge_data.cpp index 301140d51..63cffb694 100644 --- a/src/challenges/challenge_data.cpp +++ b/src/challenges/challenge_data.cpp @@ -33,9 +33,6 @@ #include "tracks/track_manager.hpp" ChallengeData::ChallengeData(const std::string& filename) -#ifndef WIN32 - throw(std::runtime_error) -#endif { m_filename = filename; m_mode = CM_SINGLE_RACE; diff --git a/src/challenges/challenge_data.hpp b/src/challenges/challenge_data.hpp index e55215b1c..c357141f1 100644 --- a/src/challenges/challenge_data.hpp +++ b/src/challenges/challenge_data.hpp @@ -111,11 +111,7 @@ private: irr::core::stringw m_challenge_description; public: -#ifdef WIN32 ChallengeData(const std::string& filename); -#else - ChallengeData(const std::string& filename) throw(std::runtime_error); -#endif virtual ~ChallengeData() {} diff --git a/src/challenges/challenge_status.hpp b/src/challenges/challenge_status.hpp index 04f966507..0026f7e76 100644 --- a/src/challenges/challenge_status.hpp +++ b/src/challenges/challenge_status.hpp @@ -44,9 +44,9 @@ class XMLNode; * the actual data about the challenge. The ChallengeStatus stores if the * challenge is not possible yet (inactive), active (i.e. user can try to * solve it), or solved. This status is stored for each difficulty level. - * This data is saved to and loaded from the player.xml file. - * A PlayerProfile will store an array of ChallengeStatuses, one for each - * Challenge in STK. + * This data is saved to and loaded from the players.xml file. + * A StoryModeStatus instance will store an array of ChallengeStatuses, + * one for each Challenge in STK. * * \ingroup challenges */ diff --git a/src/challenges/story_mode_status.hpp b/src/challenges/story_mode_status.hpp index 1a3fbc131..c123a68b6 100644 --- a/src/challenges/story_mode_status.hpp +++ b/src/challenges/story_mode_status.hpp @@ -35,9 +35,12 @@ class XMLNode; const int CHALLENGE_POINTS[] = { 8, 9, 10 }; -/** +/** This class contains the progression through challenges for the story mode. + * It maintains a list of all challenges in a mapping of challenge id to + * an instance of ChallengeStatus. Each ChallengeStatus stores at which level + * a challenge was solved. + * This object also keeps track of the overall points a player has. * \ingroup challenges - * This class contains the progression through challenges for the story mode. */ class StoryModeStatus diff --git a/src/challenges/unlock_manager.hpp b/src/challenges/unlock_manager.hpp index 093079389..d5834fbbd 100644 --- a/src/challenges/unlock_manager.hpp +++ b/src/challenges/unlock_manager.hpp @@ -21,8 +21,6 @@ #include -#include "config/user_config.hpp" - #include "challenges/challenge_data.hpp" #include "challenges/story_mode_status.hpp" diff --git a/src/config/player_manager.cpp b/src/config/player_manager.cpp index 005383928..dbec8dc99 100644 --- a/src/config/player_manager.cpp +++ b/src/config/player_manager.cpp @@ -63,7 +63,10 @@ PlayerManager::~PlayerManager() } // ~PlayerManager // ---------------------------------------------------------------------------- - +/** Manages the loading of saved player data from the players.xml file. + * This function create the XML tree from the file, and then creates the + * instances of PlayerProfile which read each node. + */ void PlayerManager::load() { std::string filename = file_manager->getUserConfigFile("players.xml"); @@ -91,26 +94,12 @@ void PlayerManager::load() } m_all_players.insertionSort(/*start*/0, /*desc*/true); - if(!m_current_player) - { - PlayerProfile *player; - for_in(player, m_all_players) - { - if(!player->isGuestAccount()) - { - m_current_player = player; - player->setDefault(true); - break; - } - } - } - if(!m_current_player) - Log::fatal("PlayerManager", "Can't find a default player."); - delete players; } // load // ---------------------------------------------------------------------------- +/** Saves all player profiles to players.xml. + */ void PlayerManager::save() { std::string filename = file_manager->getUserConfigFile("players.xml"); @@ -148,12 +137,60 @@ void PlayerManager::addNewPlayer(const core::stringw& name) } // addNewPlayer // ---------------------------------------------------------------------------- +/** Deletes a player profile from the list of all profiles. + */ void PlayerManager::deletePlayer(PlayerProfile *player) { m_all_players.erase(player); } // deletePlayer // ---------------------------------------------------------------------------- +/** This function makes sure that a current player is defined. This is called + * when a screen skipping command line option is given (-N, -R, ...), in + * which case there might not be a current player (if no default player is + * set in players.xml, i.e. the 'remember be' option was not picked ). Since + * a lot of code depends on having a local player, just set the most + * frequently used non-guest to be the current player. + */ +void PlayerManager::enforceCurrentPlayer() +{ + if (m_current_player) return; + + PlayerProfile *player; + for_in(player, m_all_players) + { + if (!player->isGuestAccount()) + { + Log::info("PlayerManager", "Enfocring current player '%ls'.", + player->getName().c_str() ); + m_current_player = player; + return; + } + } // for player in m_all_players + + // This shouldn't happen - but just in case: add the default players + // again, and search again for a non-guest player. + addDefaultPlayer(); + for_in(player, m_all_players) + { + if (!player->isGuestAccount()) + { + Log::info("PlayerManager", "Enfocring current player '%s'.", + player->getName().c_str()); + m_current_player = player; + return; + } + } // for player in m_all_players + + // Now this really really should not happen. + Log::fatal("PlayerManager", "Failed to find a non-guest player."); +} // enforceCurrentPlayer + +// ---------------------------------------------------------------------------- +/** Called when no player profiles exists. It creates two players: one + * guest player, and one non-guest player for whic hit tries to guess a + * mame based on environment variables. + */ void PlayerManager::addDefaultPlayer() { std::string username = "unnamed player"; @@ -175,7 +212,7 @@ void PlayerManager::addDefaultPlayer() } // addDefaultPlayer // ---------------------------------------------------------------------------- -/** This returns a unique id. This is 1 + larger id so far used. +/** This returns a unique id. This is 1 + largest id used so far. */ unsigned int PlayerManager::getUniqueId() const { @@ -190,6 +227,11 @@ unsigned int PlayerManager::getUniqueId() const } // getUniqueId // ---------------------------------------------------------------------------- +/** Returns a PlayerProfile with a given id. It searches linearly through + * the list of all players. + * \returns The profile, or NULL if no such profile exists. + * \param id The id of the player to look for. + */ const PlayerProfile *PlayerManager::getPlayerById(unsigned int id) { const PlayerProfile *player; @@ -202,6 +244,10 @@ const PlayerProfile *PlayerManager::getPlayerById(unsigned int id) } // getPlayerById // ---------------------------------------------------------------------------- +/** Returns a player with a given name. + * \return The player profile or NULL if the name was not found. + * \param name The name to search for. + */ PlayerProfile *PlayerManager::getPlayer(const irr::core::stringw &name) { PlayerProfile *player; @@ -213,14 +259,25 @@ PlayerProfile *PlayerManager::getPlayer(const irr::core::stringw &name) return NULL; } // getPlayer // ---------------------------------------------------------------------------- -void PlayerManager::setCurrentPlayer(PlayerProfile *player) +/** Sets the current player. This is the player that is used for story mode + * and achievements. If 'remember_me' is set, this information will be + * stored in the players.xml file, and automatically loaded next time + * STK is started. + * \param Player profile to be the current player. + * \param remember_me If this player should be marked as default + * player in players.xml + */ +void PlayerManager::setCurrentPlayer(PlayerProfile *player, bool remember_me) { // Reset current default player if(m_current_player) m_current_player->setDefault(false); m_current_player = player; - m_current_player->setDefault(true); - m_current_player->computeActive(); + if(m_current_player) + { + m_current_player->setDefault(remember_me); + m_current_player->computeActive(); + } } // setCurrentPlayer // ---------------------------------------------------------------------------- diff --git a/src/config/player_manager.hpp b/src/config/player_manager.hpp index fe07e6052..b167c70b5 100644 --- a/src/config/player_manager.hpp +++ b/src/config/player_manager.hpp @@ -19,6 +19,8 @@ #ifndef HEADER_PLAYER_MANAGER_HPP #define HEADER_PLAYER_MANAGER_HPP +#include "achievements/achievement.hpp" +#include "achievements/achievements_status.hpp" #include "config/player_profile.hpp" #include "utils/no_copy.hpp" #include "utils/ptr_vector.hpp" @@ -30,7 +32,11 @@ class AchievementsStatus; class PlayerProfile; -/** A special class that manages all local player accounts. +/** A special class that manages all local player accounts. It reads all player + * accounts from the players.xml file in the user config directory. It also + * keeps track of the currently logged in player. For each player an instance + * of PlayerProfile is created, which keeps track of story mode progress, + * achievements and other data. */ class PlayerManager : public NoCopy { @@ -70,8 +76,9 @@ public: void addDefaultPlayer(); void addNewPlayer(const irr::core::stringw& name); void deletePlayer(PlayerProfile *player); - void setCurrentPlayer(PlayerProfile *player); + void setCurrentPlayer(PlayerProfile *player, bool remember_me); const PlayerProfile *getPlayerById(unsigned int id); + void enforceCurrentPlayer(); // ------------------------------------------------------------------------ /** Returns the current player. */ PlayerProfile* getCurrentPlayer() { return m_current_player; } @@ -96,6 +103,19 @@ public: return get()->getCurrentPlayer()->getAchievementsStatus(); } // getCurrentAchievementsStatus // ------------------------------------------------------------------------ + /** A handy shortcut to increase points for an achievement key of the + * current player. */ + static void increaseAchievement(unsigned int index, const std::string &key, + int increase = 1) + { + Achievement *a = getCurrentAchievementsStatus()->getAchievement(index); + if (!a) + { + Log::fatal("PlayerManager", "Achievement '%d' not found.", index); + } + a->increase(key, increase); + } // increaseAchievement + // ------------------------------------------------------------------------ }; // PlayerManager diff --git a/src/config/player_profile.cpp b/src/config/player_profile.cpp index e809c28e6..c4f905266 100644 --- a/src/config/player_profile.cpp +++ b/src/config/player_profile.cpp @@ -38,11 +38,13 @@ PlayerProfile::PlayerProfile(const core::stringw& name, bool is_guest) #ifdef DEBUG m_magic_number = 0xABCD1234; #endif - m_name = name; + m_name = name; m_is_guest_account = is_guest; + m_is_default = false; m_use_frequency = is_guest ? -1 : 0; m_unique_id = PlayerManager::get()->getUniqueId(); m_story_mode_status = unlock_manager->createStoryModeStatus(); + m_is_default = false; m_achievements_status = AchievementsManager::get()->createAchievementsStatus(); } // PlayerProfile @@ -99,6 +101,15 @@ void PlayerProfile::incrementUseFrequency() else m_use_frequency++; } // incrementUseFrequency +// ------------------------------------------------------------------------ +/** Notification of a finished race, which can trigger fulfilling +* challenges. */ +void PlayerProfile::raceFinished() +{ + m_story_mode_status->raceFinished(); + m_achievements_status->onRaceEnd(); +} // raceFinished + //------------------------------------------------------------------------------ /** Comparison used to sort players. */ diff --git a/src/config/player_profile.hpp b/src/config/player_profile.hpp index bb20bcf56..fe7c57f13 100644 --- a/src/config/player_profile.hpp +++ b/src/config/player_profile.hpp @@ -20,7 +20,6 @@ #define HEADER_PLAYER_PROFILE_HPP #include "challenges/story_mode_status.hpp" -#include "config/user_config.hpp" #include "utils/no_copy.hpp" #include "utils/types.hpp" @@ -32,12 +31,13 @@ using namespace irr; class UTFWriter; class AchievementsStatus; -/** - * \brief Class for managing player profiles (name, control configuration, etc.) - * A list of all possible players is stored as PlayerProfiles in the user config. - * A list of currently playing players will be stored somewhere else (FIXME : complete comment) - * \ingroup config - */ +/** Class for managing player profiles (name, usage frequency, + * etc.). All PlayerProfiles are managed by the PlayerManager. + * A PlayerProfile keeps track of the story mode progress using an instance + * of StoryModeStatus, and achievements with AchievementsStatus. All data + * is saved in the players.xml file. + * \ingroup config + */ class PlayerProfile : public NoCopy { private: @@ -77,7 +77,7 @@ public: void incrementUseFrequency(); bool operator<(const PlayerProfile &other); bool operator>(const PlayerProfile &other); - + void raceFinished(); // ------------------------------------------------------------------------ ~PlayerProfile() @@ -148,10 +148,6 @@ public: m_story_mode_status->setCurrentChallenge(name); } // setCurrentChallenge // ------------------------------------------------------------------------ - /** Notification of a finished race, which can trigger fulfilling - * challenges. */ - void raceFinished() { m_story_mode_status->raceFinished(); } - // ------------------------------------------------------------------------ /** Callback when a GP is finished (to test if a challenge was * fulfilled). */ void grandPrixFinished() { m_story_mode_status->grandPrixFinished(); } diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index 1f302994c..6c9923410 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -109,7 +109,9 @@ void STKConfig::load(const std::string &filename) CHECK_NEG(m_max_karts, "getNode("parachute")) { - parachute_node->get("friction", &m_parachute_friction ); - parachute_node->get("time", &m_parachute_time ); - parachute_node->get("time-other", &m_parachute_time_other ); - parachute_node->get("done-fraction", &m_parachute_done_fraction); + parachute_node->get("friction", &m_parachute_friction ); + parachute_node->get("time", &m_parachute_time ); + parachute_node->get("time-other", &m_parachute_time_other ); + parachute_node->get("lbound-fraction", &m_parachute_lbound_fraction); + parachute_node->get("ubound-fraction", &m_parachute_ubound_fraction); + parachute_node->get("max-speed", &m_parachute_max_speed ); } if(const XMLNode *bomb_node= root->getNode("bomb")) diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp index 2fcdbeed5..d24a49ba6 100644 --- a/src/config/stk_config.hpp +++ b/src/config/stk_config.hpp @@ -60,37 +60,40 @@ public: m_same_powerup_mode; static float UNDEFINED; - float m_anvil_weight; /**m_comment.size() > 0) - stream << L"\n " << m_attributes[n]->m_param_name.c_str() - << L" : " << m_attributes[n]->m_comment.c_str(); + stream << "\n " << m_attributes[n]->m_param_name.c_str() + << " : " << m_attributes[n]->m_comment.c_str(); } - stream << L" -->\n <" << m_param_name.c_str() << "\n"; + stream << " -->\n <" << m_param_name.c_str() << "\n"; // actual values for (int n=0; nwriteInner(stream, 1); } - stream << L" >\n"; + stream << " >\n"; const int children_amount = m_children.size(); for (int n=0; nwriteInner(stream, 1); } - stream << L" \n\n"; + stream << " \n\n"; } // write // ---------------------------------------------------------------------------- -void GroupUserConfigParam::writeInner(UTFWriter& stream, int level) const +void GroupUserConfigParam::writeInner(std::ofstream& stream, int level) const { std::string tab(level * 4,' '); for(int i = 0; i < level; i++) tab =+ " "; const int children_amount = m_attributes.size(); - stream << L" " << tab.c_str() << "<" << m_param_name.c_str() << "\n"; + stream << " " << tab.c_str() << "<" << m_param_name.c_str() << "\n"; // actual values for (int n=0; nwriteInner(stream, level+1); } - stream << L" " << tab.c_str() << "/>\n"; + stream << " " << tab.c_str() << "/>\n"; } // writeInner // ---------------------------------------------------------------------------- @@ -160,7 +160,7 @@ void GroupUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node) } // findYourDataInAnAttributeOf // ---------------------------------------------------------------------------- -irr::core::stringw GroupUserConfigParam::toString() const +irr::core::stringc GroupUserConfigParam::toString() const { return ""; } // toString @@ -246,22 +246,22 @@ ListUserConfigParam::ListUserConfigParam(const char* param_name, // ---------------------------------------------------------------------------- template -void ListUserConfigParam::write(UTFWriter& stream) const +void ListUserConfigParam::write(std::ofstream& stream) const { const int elts_amount = m_elements.size(); // comment if(m_comment.size() > 0) stream << " \n <" << m_param_name.c_str() << "\n"; + stream << " -->\n <" << m_param_name.c_str() << "\n"; - stream << L" Size=\"" << elts_amount << "\"\n"; + stream << " Size=\"" << elts_amount << "\"\n"; // actual elements for (int n=0; n\n"; - stream << L" \n\n"; + stream << " >\n"; + stream << " \n\n"; } // write // ---------------------------------------------------------------------------- @@ -319,7 +319,7 @@ void ListUserConfigParam::addElement(T element) // ---------------------------------------------------------------------------- template -irr::core::stringw ListUserConfigParam::toString() const +core::stringc ListUserConfigParam::toString() const { return ""; } // toString @@ -352,19 +352,20 @@ IntUserConfigParam::IntUserConfigParam(int default_value, } // IntUserConfigParam // ---------------------------------------------------------------------------- -void IntUserConfigParam::write(UTFWriter& stream) const +void IntUserConfigParam::write(std::ofstream& stream) const { - if(m_comment.size() > 0) stream << L" \n"; - stream << L" <" << m_param_name.c_str() << L" value=\"" << m_value - << L"\" />\n\n"; + if(m_comment.size() > 0) stream << " \n"; + stream << " <" << m_param_name.c_str() << " value=\"" << m_value + << "\" />\n\n"; } // write // ---------------------------------------------------------------------------- -irr::core::stringw IntUserConfigParam::toString() const +irr::core::stringc IntUserConfigParam::toString() const { - irr::core::stringw tmp; + irr::core::stringc tmp; tmp += m_value; + return tmp; } // toString @@ -414,18 +415,18 @@ TimeUserConfigParam::TimeUserConfigParam(StkTime::TimeType default_value, } // TimeUserConfigParam // ---------------------------------------------------------------------------- -void TimeUserConfigParam::write(UTFWriter& stream) const +void TimeUserConfigParam::write(std::ofstream& stream) const { - if(m_comment.size() > 0) stream << L" \n"; + if(m_comment.size() > 0) stream << " \n"; std::ostringstream o; o<\n\n"; + stream << " <" << m_param_name.c_str() << " value=\"" + << o.str().c_str() << "\" />\n\n"; } // write // ---------------------------------------------------------------------------- -irr::core::stringw TimeUserConfigParam::toString() const +irr::core::stringc TimeUserConfigParam::toString() const { // irrString does not have a += with a 64-bit int type, so // we can't use an irrlicht's stringw directly. Since it's only a @@ -433,7 +434,7 @@ irr::core::stringw TimeUserConfigParam::toString() const std::ostringstream o; o< 0) stream << L" \n"; - stream << L" <" << m_param_name.c_str() << L" value=\"" - << m_value.c_str() << L"\" />\n\n"; + if(m_comment.size() > 0) stream << " \n"; + stream << " <" << m_param_name.c_str() << " value=\"" + << m_value.c_str() << "\" />\n\n"; } // write // ---------------------------------------------------------------------------- @@ -508,57 +509,6 @@ void StringUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node) node->get( m_param_name, &m_value ); } // findYourDataInAnAttributeOf -// ============================================================================ -WStringUserConfigParam::WStringUserConfigParam(const core::stringw& default_value, - const char* param_name, - const char* comment) -{ - - m_value = default_value; - m_default_value = default_value; - - m_param_name = param_name; - all_params.push_back(this); - if(comment != NULL) m_comment = comment; -} // WStringUserConfigParam - -// ---------------------------------------------------------------------------- -WStringUserConfigParam::WStringUserConfigParam(const core::stringw& default_value, - const char* param_name, - GroupUserConfigParam* group, - const char* comment) -{ - m_value = default_value; - m_default_value = default_value; - - m_param_name = param_name; - group->addChild(this); - if(comment != NULL) m_comment = comment; -} // WStringUserConfigParam - -// ---------------------------------------------------------------------------- -void WStringUserConfigParam::write(UTFWriter& stream) const -{ - if(m_comment.size() > 0) stream << L" \n"; - stream << L" <" << m_param_name.c_str() << L" value=\"" << m_value - << L"\" />\n\n"; -} // write -// ---------------------------------------------------------------------------- -void WStringUserConfigParam::findYourDataInAChildOf(const XMLNode* node) -{ - const XMLNode* child = node->getNode( m_param_name ); - if(child == NULL) return; - - child->get( "value", &m_value ); -} // findYourDataInAChildOf - -// ---------------------------------------------------------------------------- -void WStringUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node) -{ - node->get( m_param_name, &m_value ); -} // findYourDataInAnAttributeOf - // ============================================================================ BoolUserConfigParam::BoolUserConfigParam(bool default_value, const char* param_name, @@ -588,12 +538,12 @@ BoolUserConfigParam::BoolUserConfigParam(bool default_value, // ---------------------------------------------------------------------------- -void BoolUserConfigParam::write(UTFWriter& stream) const +void BoolUserConfigParam::write(std::ofstream& stream) const { - if(m_comment.size() > 0) stream << L" \n"; - stream << L" <" << m_param_name.c_str() << L" value=\"" - << (m_value ? L"true" : L"false" ) << L"\" />\n\n"; + if(m_comment.size() > 0) stream << " \n"; + stream << " <" << m_param_name.c_str() << " value=\"" + << (m_value ? "true" : "false" ) << "\" />\n\n"; } // write // ---------------------------------------------------------------------------- @@ -642,9 +592,9 @@ void BoolUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node) } // findYourDataInAnAttributeOf // ---------------------------------------------------------------------------- -irr::core::stringw BoolUserConfigParam::toString() const +irr::core::stringc BoolUserConfigParam::toString() const { - return (m_value ? L"true" : L"false" ); + return (m_value ? "true" : "false" ); } // toString // ============================================================================ @@ -675,12 +625,12 @@ FloatUserConfigParam::FloatUserConfigParam(float default_value, } // FloatUserConfigParam // ---------------------------------------------------------------------------- -void FloatUserConfigParam::write(UTFWriter& stream) const +void FloatUserConfigParam::write(std::ofstream& stream) const { - if(m_comment.size() > 0) stream << L" \n"; - stream << L" <" << m_param_name.c_str() << L" value=\"" << m_value - << L"\" />\n\n"; + if(m_comment.size() > 0) stream << " \n"; + stream << " <" << m_param_name.c_str() << " value=\"" << m_value + << "\" />\n\n"; } // write // ---------------------------------------------------------------------------- @@ -699,9 +649,9 @@ void FloatUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node) } // findYourDataInAnAttributeOf // ---------------------------------------------------------------------------- -irr::core::stringw FloatUserConfigParam::toString() const +core::stringc FloatUserConfigParam::toString() const { - irr::core::stringw tmp; + irr::core::stringc tmp; tmp += m_value; return tmp; } // toString @@ -738,8 +688,13 @@ bool UserConfig::loadConfig() XMLNode* root = file_manager->createXMLTree(filename); if(!root || root->getName() != "stkconfig") { - std::cerr << "Could not read user config file file " << filename << std::endl; + Log::error("UserConfig", + "Could not read user config file '%s'.", filename.c_str()); if(root) delete root; + // Create a default config file - just in case that stk crashes later + // there is a config file that can be modified (to e.g. disable + // shaders) + saveConfig(); return false; } @@ -797,11 +752,11 @@ void UserConfig::saveConfig() try { - UTFWriter configfile(filename.c_str()); + std::ofstream configfile (filename.c_str(), std::ofstream::out); - configfile << L"\n"; - configfile << L"\n\n"; + configfile << "\n"; + configfile << "\n\n"; const int paramAmount = all_params.size(); for(int i=0; i\n"; + configfile << "\n"; configfile.close(); } catch (std::runtime_error& e) diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 09bbbe14e..88c2e6562 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -68,11 +68,11 @@ protected: std::string m_comment; public: virtual ~UserConfigParam(); - virtual void write(UTFWriter& stream) const = 0; - virtual void writeInner(UTFWriter& stream, int level = 0) const; + virtual void write(std::ofstream & stream) const = 0; + virtual void writeInner(std::ofstream & stream, int level = 0) const; virtual void findYourDataInAChildOf(const XMLNode* node) = 0; virtual void findYourDataInAnAttributeOf(const XMLNode* node) = 0; - virtual irr::core::stringw toString() const = 0; + virtual irr::core::stringc toString() const = 0; }; // UserConfigParam // ============================================================================ @@ -85,8 +85,8 @@ public: GroupUserConfigParam(const char* param_name, GroupUserConfigParam* group, const char* comment = NULL); - void write(UTFWriter& stream) const; - void writeInner(UTFWriter& stream, int level = 0) const; + void write(std::ofstream& stream) const; + void writeInner(std::ofstream& stream, int level = 0) const; void findYourDataInAChildOf(const XMLNode* node); void findYourDataInAnAttributeOf(const XMLNode* node); @@ -94,7 +94,7 @@ public: void addChild(GroupUserConfigParam* child); void clearChildren(); - irr::core::stringw toString() const; + irr::core::stringc toString() const; }; // GroupUserConfigParam // ============================================================================ @@ -119,13 +119,13 @@ public: int nb_elts, ...); - void write(UTFWriter& stream) const; + void write(std::ofstream& stream) const; void findYourDataInAChildOf(const XMLNode* node); void findYourDataInAnAttributeOf(const XMLNode* node); void addElement(T element); - irr::core::stringw toString() const; + irr::core::stringc toString() const; operator std::vector() const { return m_elements; } @@ -150,11 +150,11 @@ public: GroupUserConfigParam* group, const char* comment = NULL); - void write(UTFWriter& stream) const; + void write(std::ofstream& stream) const; void findYourDataInAChildOf(const XMLNode* node); void findYourDataInAnAttributeOf(const XMLNode* node); - irr::core::stringw toString() const; + irr::core::stringc toString() const; void revertToDefaults() { m_value = m_default_value; } operator int() const { return m_value; } @@ -177,11 +177,11 @@ public: TimeUserConfigParam(StkTime::TimeType default_value, const char* param_name, GroupUserConfigParam* group, const char* comment=NULL); - void write(UTFWriter& stream) const; + void write(std::ofstream& stream) const; void findYourDataInAChildOf(const XMLNode* node); void findYourDataInAnAttributeOf(const XMLNode* node); - irr::core::stringw toString() const; + irr::core::stringc toString() const; void revertToDefaults() { m_value = m_default_value; } operator StkTime::TimeType() const { return m_value; } StkTime::TimeType& operator=(const StkTime::TimeType& v) @@ -204,7 +204,7 @@ public: GroupUserConfigParam* group, const char* comment = NULL); - void write(UTFWriter& stream) const; + void write(std::ofstream& stream) const; void findYourDataInAChildOf(const XMLNode* node); void findYourDataInAnAttributeOf(const XMLNode* node); @@ -212,7 +212,7 @@ public: std::string getDefaultValue() const { return m_default_value; } - irr::core::stringw toString() const { return m_value.c_str(); } + irr::core::stringc toString() const { return m_value.c_str(); } operator std::string() const { return m_value; } std::string& operator=(const std::string& v) @@ -223,37 +223,6 @@ public: const char* c_str() const { return m_value.c_str(); } }; // StringUserConfigParam -// ============================================================================ -class WStringUserConfigParam : public UserConfigParam -{ - stringw m_value; - stringw m_default_value; - -public: - - WStringUserConfigParam(const stringw& default_value, - const char* param_name, - const char* comment = NULL); - WStringUserConfigParam(const stringw& default_value, - const char* param_name, - GroupUserConfigParam* group, - const char* comment = NULL); - - void write(UTFWriter& stream) const; - void findYourDataInAChildOf(const XMLNode* node); - void findYourDataInAnAttributeOf(const XMLNode* node); - - void revertToDefaults() { m_value = m_default_value; } - - irr::core::stringw toString() const { return m_value; } - - operator stringw() const { return m_value; } - stringw& operator=(const stringw& v) { m_value = v; return m_value; } - stringw& operator=(const WStringUserConfigParam& v) - { m_value = (stringw)v; return m_value; } - const wchar_t* c_str() const { return m_value.c_str(); } -}; // WStringUserConfigParam - // ============================================================================ class BoolUserConfigParam : public UserConfigParam { @@ -266,11 +235,11 @@ public: BoolUserConfigParam(bool default_value, const char* param_name, GroupUserConfigParam* group, const char* comment = NULL); - void write(UTFWriter& stream) const; + void write(std::ofstream& stream) const; void findYourDataInAChildOf(const XMLNode* node); void findYourDataInAnAttributeOf(const XMLNode* node); - irr::core::stringw toString() const; + irr::core::stringc toString() const; void revertToDefaults() { m_value = m_default_value; } operator bool() const { return m_value; } @@ -292,11 +261,11 @@ public: GroupUserConfigParam* group, const char* comment = NULL); - void write(UTFWriter& stream) const; + void write(std::ofstream& stream) const; void findYourDataInAChildOf(const XMLNode* node); void findYourDataInAnAttributeOf(const XMLNode* node); - irr::core::stringw toString() const; + irr::core::stringc toString() const; void revertToDefaults() { m_value = m_default_value; } operator float() const { return m_value; } @@ -427,6 +396,9 @@ namespace UserConfigParams PARAM_DEFAULT( BoolUserConfigParam(false, "player_last", &m_gp_start_order, "Always put the player at the back or not (Bully mode).") ); + PARAM_PREFIX StringUserConfigParam m_additional_gp_directory + PARAM_DEFAULT( StringUserConfigParam("", "additional_gp_directory", + "Directory with additional GP's.")); // ---- Video PARAM_PREFIX GroupUserConfigParam m_video_group @@ -618,7 +590,7 @@ namespace UserConfigParams &m_graphics_quality, "Whether vertical sync is enabled") ); PARAM_PREFIX BoolUserConfigParam m_pixel_shaders - PARAM_DEFAULT( BoolUserConfigParam(true, "pixel_shaders", + PARAM_DEFAULT( BoolUserConfigParam(false, "pixel_shaders", &m_graphics_quality, "Whether to enable pixel shaders (splatting, normal maps, ...)") ); PARAM_PREFIX BoolUserConfigParam m_motionblur @@ -677,10 +649,6 @@ namespace UserConfigParams PARAM_DEFAULT( StringUserConfigParam("Peach.stkskin", "skin_file", "Name of the skin to use") ); - PARAM_PREFIX WStringUserConfigParam m_default_player - PARAM_DEFAULT( WStringUserConfigParam(L"", "default_player", - "Which player to use by default (if empty, will prompt)") ); - // ---- Internet related PARAM_PREFIX IntUserConfigParam m_internet_status diff --git a/src/graphics/callbacks.cpp b/src/graphics/callbacks.cpp index 1b61deba6..cadd5d332 100644 --- a/src/graphics/callbacks.cpp +++ b/src/graphics/callbacks.cpp @@ -422,13 +422,6 @@ void MLAANeigh3Provider::OnSetConstants(IMaterialRendererServices *srv, int) //------------------------------------- -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; @@ -548,43 +541,6 @@ void ShadowGenProvider::OnSetConstants(IMaterialRendererServices *srv, int) //------------------------------------- -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) { core::matrix4 ProjectionMatrix = srv->getVideoDriver()->getTransform(ETS_PROJECTION); diff --git a/src/graphics/callbacks.hpp b/src/graphics/callbacks.hpp index dcb6d3ec4..ab3b34503 100644 --- a/src/graphics/callbacks.hpp +++ b/src/graphics/callbacks.hpp @@ -450,20 +450,6 @@ public: // -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: @@ -556,19 +542,6 @@ public: // -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: diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp index 57e128ca3..6dd9b2192 100644 --- a/src/graphics/camera.cpp +++ b/src/graphics/camera.cpp @@ -28,6 +28,7 @@ #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" #include "karts/explosion_animation.hpp" +#include "karts/kart.hpp" #include "karts/kart_properties.hpp" #include "karts/skidding.hpp" #include "modes/world.hpp" @@ -54,12 +55,22 @@ Camera::Camera(int camera_index, AbstractKart* kart) : m_kart(NULL) m_camera = irr_driver->addCameraSceneNode(); #ifdef DEBUG - m_camera->setName(core::stringc("Camera for ") + kart->getKartProperties()->getName()); + if (kart != NULL) + m_camera->setName(core::stringc("Camera for ") + kart->getKartProperties()->getName()); + else + m_camera->setName("Camera"); #endif setupCamera(); - m_distance = kart->getKartProperties()->getCameraDistance(); - setKart(kart); + if (kart != NULL) + { + m_distance = kart->getKartProperties()->getCameraDistance(); + setKart(kart); + } + else + { + m_distance = 1000.0f; + } m_ambient_light = World::getWorld()->getTrack()->getDefaultAmbientColor(); // TODO: Put these values into a config file @@ -264,7 +275,9 @@ void Camera::reset() { m_kart = m_original_kart; setMode(CM_NORMAL); - setInitialTransform(); + + if (m_kart != NULL) + setInitialTransform(); } // reset //----------------------------------------------------------------------------- @@ -273,6 +286,8 @@ void Camera::reset() */ void Camera::setInitialTransform() { + if (m_kart == NULL) return; + Vec3 start_offset(0, 25, -50); Vec3 xx = m_kart->getTrans()(start_offset); m_camera->setPosition( xx.toIrrVector()); @@ -431,6 +446,8 @@ void Camera::getCameraSettings(float *above_kart, float *cam_angle, */ void Camera::update(float dt) { + if (m_kart == NULL) return; // cameras not attached to kart must be positioned manually + float above_kart, cam_angle, side_way, distance; bool smoothing; @@ -472,7 +489,6 @@ void Camera::update(float dt) m_camera->setTarget(current_target); } - else { getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing); @@ -533,12 +549,18 @@ void Camera::positionCamera(float dt, float above_kart, float cam_angle, wanted_target - m_camera->getPosition()); } } - - // Rotate the up vector (0,1,0) by the rotation ... which is just column 1 - Vec3 up = m_kart->getTrans().getBasis().getColumn(1); - float f = 0.04f; // weight for new up vector to reduce shaking - m_camera->setUpVector( f * up.toIrrVector() + - (1.0f-f) * m_camera->getUpVector() ); + + Kart *kart = dynamic_cast(m_kart); + if (kart && !kart->isFlying()) + { + // Rotate the up vector (0,1,0) by the rotation ... which is just column 1 + Vec3 up = m_kart->getTrans().getBasis().getColumn(1); + float f = 0.04f; // weight for new up vector to reduce shaking + m_camera->setUpVector(f * up.toIrrVector() + + (1.0f - f) * m_camera->getUpVector()); + } // kart && !flying + else + m_camera->setUpVector(core::vector3df(0, 1, 0)); } // positionCamera // ---------------------------------------------------------------------------- diff --git a/src/graphics/camera.hpp b/src/graphics/camera.hpp index 07ac34865..6b7e01fcf 100644 --- a/src/graphics/camera.hpp +++ b/src/graphics/camera.hpp @@ -86,7 +86,9 @@ private: float m_rotation_range; /** The kart that the camera follows. It can't be const, - * since in profile mode the camera might change its owner. */ + * since in profile mode the camera might change its owner. + * May be NULL (example: cutscene camera) + */ AbstractKart *m_kart; /** A pointer to the original kart the camera was pointing at when it diff --git a/src/graphics/glwrap.cpp b/src/graphics/glwrap.cpp index 466594ec0..bb94be63a 100644 --- a/src/graphics/glwrap.cpp +++ b/src/graphics/glwrap.cpp @@ -200,7 +200,7 @@ void initGL() static GLuint LoadShader(const char * file, unsigned type) { GLuint Id = glCreateShader(type); - std::string Code; + std::string Code = "#version 330\n"; std::ifstream Stream(file, std::ios::in); if (Stream.is_open()) { @@ -211,7 +211,7 @@ GLuint LoadShader(const char * file, unsigned type) { } GLint Result = GL_FALSE; int InfoLogLength; - printf("Compiling shader : %s\n", file); + Log::info("GLWrap", "Compiling shader : %s", file); char const * SourcePointer = Code.c_str(); int length = strlen(SourcePointer); glShaderSource(Id, 1, &SourcePointer, &length); diff --git a/src/graphics/gpuparticles.cpp b/src/graphics/gpuparticles.cpp index b67b2fa7e..dc5e33809 100644 --- a/src/graphics/gpuparticles.cpp +++ b/src/graphics/gpuparticles.cpp @@ -12,9 +12,8 @@ scene::IParticleSystemSceneNode *ParticleSystemProxy::addParticleNode( bool withDefaultEmitter, ISceneNode* parent, s32 id, const core::vector3df& position, const core::vector3df& rotation, - const core::vector3df& scale) { - if (!irr_driver->isGLSL()) - return irr_driver->addParticleNode(); + const core::vector3df& scale) +{ if (!parent) parent = irr_driver->getSceneManager()->getRootSceneNode(); @@ -31,7 +30,8 @@ ParticleSystemProxy::ParticleSystemProxy(bool createDefaultEmitter, ISceneNode* parent, scene::ISceneManager* mgr, s32 id, const core::vector3df& position, const core::vector3df& rotation, - const core::vector3df& scale) : CParticleSystemSceneNode(createDefaultEmitter, parent, mgr, id, position, rotation, scale), m_alpha_additive(false) { + const core::vector3df& scale) : CParticleSystemSceneNode(createDefaultEmitter, parent, mgr, id, position, rotation, scale), m_alpha_additive(false) +{ glGenBuffers(1, &initial_values_buffer); glGenBuffers(2, tfb_buffers); glGenBuffers(1, &quaternionsbuffer); diff --git a/src/graphics/gpuparticles.hpp b/src/graphics/gpuparticles.hpp index 7a79ebb46..598b303fd 100644 --- a/src/graphics/gpuparticles.hpp +++ b/src/graphics/gpuparticles.hpp @@ -9,7 +9,8 @@ namespace irr { namespace video{ class ITexture; } } -class ParticleSystemProxy : public scene::CParticleSystemSceneNode { +class ParticleSystemProxy : public scene::CParticleSystemSceneNode +{ protected: GLuint tfb_buffers[2], initial_values_buffer, heighmapbuffer, heightmaptexture, quaternionsbuffer; GLuint current_simulation_vao, non_current_simulation_vao; diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index b0d89c27a..97c104339 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -101,6 +101,7 @@ const int MIN_SUPPORTED_WIDTH = 800; IrrDriver::IrrDriver() { m_resolution_changing = RES_CHANGE_NONE; + m_phase = SOLID_NORMAL_AND_DEPTH_PASS; m_device = createDevice(video::EDT_NULL); m_request_screenshot = false; m_shaders = NULL; @@ -144,17 +145,17 @@ void IrrDriver::reset() void IrrDriver::setPhase(STKRenderingPass p) { - phase = p; + m_phase = p; } STKRenderingPass IrrDriver::getPhase() const { - return phase; + return m_phase; } void IrrDriver::IncreaseObjectCount() { - object_count[phase]++; + object_count[m_phase]++; } core::array &IrrDriver::getMainSetup() @@ -421,10 +422,11 @@ void IrrDriver::initDevice() m_gui_env = m_device->getGUIEnvironment(); m_video_driver = m_device->getVideoDriver(); - int GLMajorVersion; + int GLMajorVersion = 0, GLMinorVersion = 0; glGetIntegerv(GL_MAJOR_VERSION, &GLMajorVersion); - printf("OPENGL VERSION IS %d\n", GLMajorVersion); - m_glsl = (GLMajorVersion >= 3) && UserConfigParams::m_pixel_shaders; + glGetIntegerv(GL_MINOR_VERSION, &GLMinorVersion); + Log::info("IrrDriver", "OPENGL VERSION IS %d.%d", GLMajorVersion, GLMinorVersion); + m_glsl = (GLMajorVersion > 3 || (GLMajorVersion == 3 && GLMinorVersion == 3)) && UserConfigParams::m_pixel_shaders; // This remaps the window, so it has to be done before the clear to avoid flicker @@ -452,16 +454,16 @@ void IrrDriver::initDevice() m_shadow_importance = new ShadowImportance(); m_mrt.clear(); - m_mrt.reallocate(3); + m_mrt.reallocate(2); m_mrt.push_back(m_rtts->getRTT(RTT_COLOR)); m_mrt.push_back(m_rtts->getRTT(RTT_NORMAL_AND_DEPTH)); - m_mrt.push_back(m_rtts->getRTT(RTT_SPECULARMAP)); irr::video::COpenGLDriver* gl_driver = (irr::video::COpenGLDriver*)m_device->getVideoDriver(); gl_driver->extGlGenQueries(1, &m_lensflare_query); + m_query_issued = false; scene::IMesh * const sphere = m_scene_manager->getGeometryCreator()->createSphereMesh(1, 16, 16); - m_sun_interposer = m_scene_manager->addMeshSceneNode(sphere); + m_sun_interposer = new STKMeshSceneNode(sphere, m_scene_manager->getRootSceneNode(), NULL, -1); m_sun_interposer->grab(); m_sun_interposer->setParent(NULL); m_sun_interposer->setScale(core::vector3df(20)); @@ -469,7 +471,7 @@ void IrrDriver::initDevice() 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); + m_sun_interposer->getMaterial(0).MaterialType = m_shaders->getShader(ES_OBJECTPASS); sphere->drop(); @@ -1168,7 +1170,10 @@ scene::ISceneNode *IrrDriver::addSkyDome(video::ITexture *texture, scene::ISceneNode *IrrDriver::addSkyBox(const std::vector &texture) { + assert(texture.size() == 6); SkyboxTextures = texture; + SkyboxCubeMap = 0; + ConvolutedSkyboxCubeMap = 0; return m_scene_manager->addSkyBoxSceneNode(texture[0], texture[1], texture[2], texture[3], texture[4], texture[5]); @@ -1177,6 +1182,10 @@ scene::ISceneNode *IrrDriver::addSkyBox(const std::vector void IrrDriver::suppressSkyBox() { SkyboxTextures.clear(); + glDeleteTextures(1, &SkyboxCubeMap); + glDeleteTextures(1, &ConvolutedSkyboxCubeMap); + SkyboxCubeMap = 0; + ConvolutedSkyboxCubeMap = 0; } // ---------------------------------------------------------------------------- @@ -1797,18 +1806,7 @@ void IrrDriver::update(float dt) World *world = World::getWorld(); - // Handle cut scenes (which do not have any karts in it) - // ===================================================== - if (world && world->getNumKarts() == 0) - { - m_video_driver->beginScene(/*backBuffer clear*/true, /*zBuffer*/true, - world->getClearColor()); - m_scene_manager->drawAll(); - GUIEngine::render(dt); - m_video_driver->endScene(); - return; - } - else if (GUIEngine::getCurrentScreen() != NULL && + if (GUIEngine::getCurrentScreen() != NULL && GUIEngine::getCurrentScreen()->needs3D()) { //printf("Screen that needs 3D\n"); @@ -1821,10 +1819,10 @@ void IrrDriver::update(float dt) } else if (!world) { - m_video_driver->beginScene(/*backBuffer clear*/ true, /*zBuffer*/ true, + m_video_driver->beginScene(/*backBuffer clear*/ true, /*zBuffer*/ true, video::SColor(255,100,101,140)); - GUIEngine::render(dt); + GUIEngine::render(dt); m_video_driver->endScene(); return; diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index dba63df2c..9155451bf 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -116,6 +116,11 @@ private: std::vector SkyboxTextures; + float blueSHCoeff[9]; + float greenSHCoeff[9]; + float redSHCoeff[9]; + + /** 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. @@ -125,6 +130,7 @@ private: RES_CHANGE_CANCEL} m_resolution_changing; public: + GLuint SkyboxCubeMap, ConvolutedSkyboxCubeMap; /** A simple class to store video resolutions. */ class VideoMode { @@ -171,7 +177,8 @@ private: unsigned object_count[PASS_COUNT]; u32 m_renderpass; u32 m_lensflare_query; - scene::IMeshSceneNode *m_sun_interposer; + bool m_query_issued; + class STKMeshSceneNode *m_sun_interposer; scene::CLensFlareSceneNode *m_lensflare; scene::ICameraSceneNode *m_suncam; @@ -190,7 +197,7 @@ private: std::vector m_background; - STKRenderingPass phase; + STKRenderingPass m_phase; #ifdef DEBUG /** Used to visualise skeletons. */ @@ -212,7 +219,6 @@ private: std::vector& glows, const core::aabbox3df& cambox, int cam); - void renderSkybox(); void renderLights(const core::aabbox3df& cambox, scene::ICameraSceneNode * const camnode, video::SOverrideMaterial &overridemat, @@ -225,6 +231,8 @@ public: ~IrrDriver(); void initDevice(); void reset(); + void generateSkyboxCubemap(); + void renderSkybox(); void setPhase(STKRenderingPass); STKRenderingPass getPhase() const; const std::vector &getShadowViewProj() const @@ -495,7 +503,7 @@ public: // ------------------------------------------------------------------------ void clearLights(); // ------------------------------------------------------------------------ - scene::IMeshSceneNode *getSunInterposer() { return m_sun_interposer; } + class STKMeshSceneNode *getSunInterposer() { return m_sun_interposer; } // ------------------------------------------------------------------------ void setViewMatrix(core::matrix4 matrix) { m_ViewMatrix = matrix; matrix.getInverse(m_InvViewMatrix); } const core::matrix4 &getViewMatrix() const { return m_ViewMatrix; } diff --git a/src/graphics/particle_emitter.cpp b/src/graphics/particle_emitter.cpp index d96bb310b..c8c743602 100644 --- a/src/graphics/particle_emitter.cpp +++ b/src/graphics/particle_emitter.cpp @@ -218,6 +218,36 @@ public: }; // WindAffector +// ============================================================================ + +class ScaleAffector : public scene::IParticleAffector +{ +public: + ScaleAffector(const core::vector2df& scaleFactor = core::vector2df(1.0f, 1.0f)) : ScaleFactor(scaleFactor) + { + } + + virtual void affect(u32 now, scene::SParticle *particlearray, u32 count) + { + for (u32 i = 0; iisGLSL(); + setParticleType(type); assert(m_node != NULL); @@ -381,8 +413,12 @@ void ParticleEmitter::setParticleType(const ParticleKind* type) } else { - m_node = ParticleSystemProxy::addParticleNode(); - if (irr_driver->isGLSL()) + if (m_is_glsl) + m_node = ParticleSystemProxy::addParticleNode(m_is_glsl); + else + m_node = irr_driver->addParticleNode(); + + if (m_is_glsl) static_cast(m_node)->setAlphaAdditive(type->getMaterial()->isAlphaAdditive()); } @@ -550,14 +586,18 @@ void ParticleEmitter::setParticleType(const ParticleKind* type) if (type->hasScaleAffector()) { - core::dimension2df factor = core::dimension2df(type->getScaleAffectorFactorX(), - type->getScaleAffectorFactorY()); - scene::IParticleAffector* scale_affector = - m_node->createScaleParticleAffector(factor); - m_node->addAffector(scale_affector); - scale_affector->drop(); - if (irr_driver->isGLSL()) + if (m_is_glsl) + { static_cast(m_node)->setIncreaseFactor(type->getScaleAffectorFactorX()); + } + else + { + core::vector2df factor = core::vector2df(type->getScaleAffectorFactorX(), + type->getScaleAffectorFactorY()); + scene::IParticleAffector* scale_affector = new ScaleAffector(factor); + m_node->addAffector(scale_affector); + scale_affector->drop(); + } } const float windspeed = type->getWindSpeed(); @@ -566,14 +606,15 @@ void ParticleEmitter::setParticleType(const ParticleKind* type) WindAffector *waf = new WindAffector(windspeed); m_node->addAffector(waf); waf->drop(); - } + + // TODO: wind affector for GLSL particles + } const bool flips = type->getFlips(); if (flips) { - if (irr_driver->isGLSL()) + if (m_is_glsl) static_cast(m_node)->setFlip(); - //m_node->getMaterial(0).BlendOperation = video::EBO_ADD; } } } // setParticleType @@ -582,10 +623,9 @@ void ParticleEmitter::setParticleType(const ParticleKind* type) void ParticleEmitter::addHeightMapAffector(Track* t) { - HeightMapCollisionAffector* hmca = new HeightMapCollisionAffector(t); - m_node->addAffector(hmca); - hmca->drop(); - if (irr_driver->isGLSL()) { + + if (m_is_glsl) + { const Vec3* aabb_min; const Vec3* aabb_max; t->getAABB(&aabb_min, &aabb_max); @@ -596,6 +636,12 @@ void ParticleEmitter::addHeightMapAffector(Track* t) static_cast(m_node)->setHeightmap(t->buildHeightMap(), track_x, track_z, track_x_len, track_z_len); } + else + { + HeightMapCollisionAffector* hmca = new HeightMapCollisionAffector(t); + m_node->addAffector(hmca); + hmca->drop(); + } } //----------------------------------------------------------------------------- diff --git a/src/graphics/particle_emitter.hpp b/src/graphics/particle_emitter.hpp index 8c3dd941a..fe26dcf13 100644 --- a/src/graphics/particle_emitter.hpp +++ b/src/graphics/particle_emitter.hpp @@ -47,6 +47,8 @@ class ParticleEmitter : public NoCopy { private: + bool m_is_glsl; + /** Irrlicht's particle systems. */ scene::IParticleSystemSceneNode *m_node; diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index 6ba8a1a2c..b10dad033 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -24,6 +24,7 @@ #include "graphics/irr_driver.hpp" #include "graphics/mlaa_areamap.hpp" #include "graphics/shaders.hpp" +#include "graphics/stkmeshscenenode.hpp" #include "io/file_manager.hpp" #include "karts/abstract_kart.hpp" #include "karts/kart_model.hpp" @@ -248,37 +249,6 @@ void renderBloomBlend(ITexture *in) glDisable(GL_BLEND); } -static -void renderPPDisplace(ITexture *in) -{ - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_ONE, GL_ONE); - glDisable(GL_DEPTH_TEST); - - glUseProgram(FullScreenShader::PPDisplaceShader::Program); - glBindVertexArray(FullScreenShader::PPDisplaceShader::vao); - glUniform1i(FullScreenShader::PPDisplaceShader::uniform_viz, irr_driver->getDistortViz()); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, getTextureGLuint(in)); - glUniform1i(FullScreenShader::PPDisplaceShader::uniform_tex, 0); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, getTextureGLuint(irr_driver->getRTT(RTT_DISPLACE))); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glUniform1i(FullScreenShader::PPDisplaceShader::uniform_dtex, 1); - - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); -} - static void renderColorLevel(ITexture *in) { @@ -295,9 +265,13 @@ void renderColorLevel(ITexture *in) glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, getTextureGLuint(in)); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, getDepthTexture(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH))); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glUniform1i(FullScreenShader::ColorLevelShader::uniform_tex, 0); + glUniform1i(FullScreenShader::ColorLevelShader::uniform_dtex, 1); + glUniformMatrix4fv(FullScreenShader::ColorLevelShader::uniform_invprojm, 1, GL_FALSE, irr_driver->getInvProjMatrix().pointer()); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindVertexArray(0); @@ -306,26 +280,26 @@ void renderColorLevel(ITexture *in) glEnable(GL_DEPTH_TEST); } -void PostProcessing::renderPointlight(const std::vector &positions, const std::vector &colors, const std::vector &energy) +void PostProcessing::renderDiffuseEnvMap(const float *bSHCoeff, const float *gSHCoeff, const float *rSHCoeff) { - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_ONE, GL_ONE); - glDisable(GL_DEPTH_TEST); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE); - glUseProgram(FullScreenShader::PointLightShader::Program); - glBindVertexArray(FullScreenShader::PointLightShader::vao); + glUseProgram(FullScreenShader::DiffuseEnvMapShader::Program); + glBindVertexArray(FullScreenShader::DiffuseEnvMapShader::vao); setTexture(0, getTextureGLuint(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST); - setTexture(1, getDepthTexture(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST); - FullScreenShader::PointLightShader::setUniforms(irr_driver->getInvProjMatrix(), irr_driver->getViewMatrix(), positions, colors, energy, 200, 0, 1); + core::matrix4 TVM = irr_driver->getViewMatrix().getTransposed(); + FullScreenShader::DiffuseEnvMapShader::setUniforms(TVM, bSHCoeff, gSHCoeff, rSHCoeff, 0); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); } void PostProcessing::renderSunlight() @@ -603,6 +577,8 @@ void PostProcessing::renderMotionBlur(unsigned cam, ITexture *in, ITexture *out) glBindVertexArray(FullScreenShader::MotionBlurShader::vao); setTexture(0, getTextureGLuint(in), GL_NEAREST, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); FullScreenShader::MotionBlurShader::setUniforms(cb->getBoostTime(cam), cb->getCenter(cam), cb->getDirection(cam), 0.15, cb->getMaxHeight(cam) * 0.7, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -613,6 +589,40 @@ void PostProcessing::renderMotionBlur(unsigned cam, ITexture *in, ITexture *out) glDisable(GL_BLEND); } +static void renderGodFade(GLuint tex, const SColor &col) +{ + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + + glUseProgram(FullScreenShader::GodFadeShader::Program); + glBindVertexArray(FullScreenShader::GodFadeShader::vao); + setTexture(0, tex, GL_LINEAR, GL_LINEAR); + FullScreenShader::GodFadeShader::setUniforms(col, 0); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glEnable(GL_DEPTH_TEST); +} + +static void renderGodRay(GLuint tex, const core::vector2df &sunpos) +{ + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + + glUseProgram(FullScreenShader::GodRayShader::Program); + glBindVertexArray(FullScreenShader::GodRayShader::vao); + setTexture(0, tex, GL_LINEAR, GL_LINEAR); + FullScreenShader::GodRayShader::setUniforms(sunpos, 0); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glEnable(GL_DEPTH_TEST); +} + // ---------------------------------------------------------------------------- /** Render the post-processed scene */ void PostProcessing::render() @@ -688,9 +698,6 @@ void PostProcessing::render() // Additively blend on top of tmp1 drv->setRenderTarget(out, false, false); renderBloomBlend(irr_driver->getRTT(RTT_EIGHTH1)); - m_material.MaterialType = irr_driver->getShader(ES_RAIN); - drv->setMaterial(m_material); - static_cast(drv)->setRenderStates3DMode(); } // end if bloom in = irr_driver->getRTT(RTT_TMP1); @@ -699,33 +706,33 @@ void PostProcessing::render() PROFILER_POP_CPU_MARKER(); PROFILER_PUSH_CPU_MARKER("- Godrays", 0xFF, 0x00, 0x00); - if (World::getWorld()->getTrack()->hasGodRays() && m_sunpixels > 30) // god rays + if (m_sunpixels > 30)//World::getWorld()->getTrack()->hasGodRays() && ) // god rays { // Grab the sky drv->setRenderTarget(out, true, false); - irr_driver->getSceneManager()->drawAll(ESNRP_SKY_BOX); +// irr_driver->getSceneManager()->drawAll(ESNRP_SKY_BOX); + irr_driver->renderSkybox(); // 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); + ColorizeProvider * const colcb = (ColorizeProvider *) irr_driver->getCallback(ES_COLORIZE); + 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; + STKMeshSceneNode *sun = irr_driver->getSunInterposer(); +/* sun->getMaterial(0).ColorMask = ECP_ALL; + irr_driver->getSceneManager()->setCurrentRendertime(ESNRP_SOLID);*/ irr_driver->getSceneManager()->drawAll(ESNRP_CAMERA); - irr_driver->getSceneManager()->setCurrentRendertime(ESNRP_SOLID); - + irr_driver->setPhase(GLOW_PASS); sun->render(); - sun->getMaterial(0).ColorMask = ECP_NONE; + //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); + drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER1), false, false); + renderGodFade(getTextureGLuint(out), col); + // Blur renderGaussian3Blur(irr_driver->getRTT(RTT_QUARTER1), @@ -733,6 +740,8 @@ void PostProcessing::render() 4.f / UserConfigParams::m_width, 4.f / UserConfigParams::m_height); + + // Calculate the sun's position in texcoords const core::vector3df pos = sun->getPosition(); float ndc[4]; @@ -747,39 +756,26 @@ void PostProcessing::render() 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); +// ((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); + renderGodRay(getTextureGLuint(irr_driver->getRTT(RTT_QUARTER1)), core::vector2df(sunx, suny)); // 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); + renderGaussian3Blur(irr_driver->getRTT(RTT_QUARTER2), + irr_driver->getRTT(RTT_QUARTER1), + 4.f / UserConfigParams::m_width, + 4.f / UserConfigParams::m_height); - drawQuad(cam, m_material); + // Blend + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + glBlendEquation(GL_FUNC_ADD); - 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); + renderPassThrough(irr_driver->getRTT(RTT_QUARTER2)); } PROFILER_POP_CPU_MARKER(); @@ -793,17 +789,9 @@ void PostProcessing::render() PROFILER_POP_CPU_MARKER(); } - if (irr_driver->getDisplacingNodes().size()) // Displacement - { - PROFILER_PUSH_CPU_MARKER("- Displacement", 0xFF, 0x00, 0x00); - drv->setRenderTarget(out, true, false); - renderPPDisplace(in); - - ITexture *tmp = in; - in = out; - out = tmp; - PROFILER_POP_CPU_MARKER(); - } +/* m_material.MaterialType = irr_driver->getShader(ES_RAIN); + drv->setMaterial(m_material); + static_cast(drv)->setRenderStates3DMode();*/ if (UserConfigParams::m_mlaa) // MLAA. Must be the last pp filter. { diff --git a/src/graphics/post_processing.hpp b/src/graphics/post_processing.hpp index b1d29de03..bac7bdb5c 100644 --- a/src/graphics/post_processing.hpp +++ b/src/graphics/post_processing.hpp @@ -73,12 +73,12 @@ public: void update(float dt); /** Generate diffuse and specular map */ - void renderPointlight(const std::vector &positions, const std::vector &colors, const std::vector &energy); void renderSunlight(); void renderShadowedSunlight(const std::vector &sun_ortho_matrix, unsigned depthtex); void renderFog(const core::matrix4 &ipvmat); void renderSSAO(const core::matrix4 &invprojm, const core::matrix4 &projm); + void renderDiffuseEnvMap(const float *bSHCoeff, const float *gSHCoeff, const float *rSHCoeff); /** Blur the in texture */ void renderGaussian3Blur(video::ITexture *in, video::ITexture *temprtt, float inv_width, float inv_height); diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index cc472de0f..aba3241fa 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -35,6 +35,7 @@ #include "graphics/screenquad.hpp" #include "graphics/shaders.hpp" #include "graphics/shadow_importance.hpp" +#include "graphics/stkmeshscenenode.hpp" #include "graphics/wind.hpp" #include "io/file_manager.hpp" #include "items/item.hpp" @@ -142,8 +143,6 @@ void IrrDriver::renderGLSL(float dt) // Clear normal and depth to zero m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_NORMAL_AND_DEPTH), true, false, video::SColor(0,0,0,0)); - // Clear specular map to zero - m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_SPECULARMAP), true, false, video::SColor(0,0,0,0)); irr_driver->getVideoDriver()->enableMaterial2D(); RaceGUIBase *rg = world->getRaceGUI(); @@ -198,6 +197,7 @@ void IrrDriver::renderGLSL(float dt) glDisable(GL_ALPHA_TEST); glDepthMask(GL_TRUE); glDisable(GL_BLEND); + glEnable(GL_CULL_FACE); irr_driver->setPhase(SOLID_NORMAL_AND_DEPTH_PASS); m_scene_manager->drawAll(m_renderpass); irr_driver->setProjMatrix(irr_driver->getVideoDriver()->getTransform(video::ETS_PROJECTION)); @@ -236,6 +236,14 @@ void IrrDriver::renderGLSL(float dt) glDepthMask(GL_FALSE); glDisable(GL_BLEND); m_renderpass = scene::ESNRP_CAMERA | scene::ESNRP_SOLID; + setTexture(0, getTextureGLuint(irr_driver->getRTT(RTT_TMP1)), GL_NEAREST, GL_NEAREST); + setTexture(1, getTextureGLuint(irr_driver->getRTT(RTT_TMP2)), GL_NEAREST, GL_NEAREST); + setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_SSAO)), GL_NEAREST, GL_NEAREST); + if (!UserConfigParams::m_ssao) + { + GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ONE }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } m_scene_manager->drawAll(m_renderpass); PROFILER_POP_CPU_MARKER(); @@ -258,31 +266,32 @@ void IrrDriver::renderGLSL(float dt) PROFILER_POP_CPU_MARKER(); - if (!SkyboxTextures.empty()) - { - PROFILER_PUSH_CPU_MARKER("- Skybox", 0xFF, 0x00, 0xFF); - renderSkybox(); - PROFILER_POP_CPU_MARKER(); - } + PROFILER_PUSH_CPU_MARKER("- Skybox", 0xFF, 0x00, 0xFF); + renderSkybox(); + PROFILER_POP_CPU_MARKER(); PROFILER_PUSH_CPU_MARKER("- Lensflare/godray", 0x00, 0xFF, 0xFF); // 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) + if (true)//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); + GLuint res = 0; + if (m_query_issued) + gl_driver->extGlGetQueryObjectuiv(m_lensflare_query, GL_QUERY_RESULT, &res); m_post_processing->setSunPixels(res); // Prepare the query for the next frame. + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); gl_driver->extGlBeginQuery(GL_SAMPLES_PASSED_ARB, m_lensflare_query); m_scene_manager->setCurrentRendertime(scene::ESNRP_SOLID); m_scene_manager->drawAll(scene::ESNRP_CAMERA); + irr_driver->setPhase(GLOW_PASS); m_sun_interposer->render(); gl_driver->extGlEndQuery(GL_SAMPLES_PASSED_ARB); + m_query_issued = true; m_lensflare->setStrength(res / 4000.0f); @@ -735,11 +744,80 @@ void IrrDriver::renderGlow(video::SOverrideMaterial &overridemat, // ---------------------------------------------------------------------------- #define MAXLIGHT 16 // to be adjusted in pointlight.frag too + + +static GLuint pointlightvbo = 0; +static GLuint pointlightsvao = 0; + +struct PointLightInfo +{ + float posX; + float posY; + float posZ; + float energy; + float red; + float green; + float blue; + float padding; +}; + +void createPointLightVAO() +{ + glGenVertexArrays(1, &pointlightsvao); + glBindVertexArray(pointlightsvao); + + glBindBuffer(GL_ARRAY_BUFFER, SharedObject::billboardvbo); + glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Corner); + glVertexAttribPointer(MeshShader::PointLightShader::attrib_Corner, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); + + glGenBuffers(1, &pointlightvbo); + glBindBuffer(GL_ARRAY_BUFFER, pointlightvbo); + glBufferData(GL_ARRAY_BUFFER, MAXLIGHT * sizeof(PointLightInfo), 0, GL_DYNAMIC_DRAW); + + glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Position); + glVertexAttribPointer(MeshShader::PointLightShader::attrib_Position, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), 0); + glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Energy); + glVertexAttribPointer(MeshShader::PointLightShader::attrib_Energy, 1, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(3 * sizeof(float))); + glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Color); + glVertexAttribPointer(MeshShader::PointLightShader::attrib_Color, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(4 * sizeof(float))); + + glVertexAttribDivisor(MeshShader::PointLightShader::attrib_Position, 1); + glVertexAttribDivisor(MeshShader::PointLightShader::attrib_Energy, 1); + glVertexAttribDivisor(MeshShader::PointLightShader::attrib_Color, 1); +} + +static void renderPointLights() +{ + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glUseProgram(MeshShader::PointLightShader::Program); + glBindVertexArray(pointlightsvao); + + setTexture(0, getTextureGLuint(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST); + setTexture(1, getDepthTexture(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST); + MeshShader::PointLightShader::setUniforms(irr_driver->getViewMatrix(), irr_driver->getProjMatrix(), irr_driver->getInvProjMatrix(), core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height), 200, 0, 1); + + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, MAXLIGHT); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); +} + +PointLightInfo PointLightsInfo[MAXLIGHT]; + void IrrDriver::renderLights(const core::aabbox3df& cambox, scene::ICameraSceneNode * const camnode, video::SOverrideMaterial &overridemat, int cam, float dt) { + if (SkyboxCubeMap) + irr_driver->getSceneManager()->setAmbientLight(SColor(0, 0, 0, 0)); for (unsigned i = 0; i < sun_ortho_matrix.size(); i++) sun_ortho_matrix[i] *= getInvViewMatrix(); core::array rtts; @@ -754,9 +832,7 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, const u32 lightcount = m_lights.size(); const core::vector3df &campos = irr_driver->getSceneManager()->getActiveCamera()->getAbsolutePosition(); - std::vector accumulatedLightPos; - std::vector accumulatedLightColor; - std::vector accumulatedLightEnergy; + std::vector BucketedLN[15]; for (unsigned int i = 0; i < lightcount; i++) { @@ -782,7 +858,7 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, { for (unsigned j = 0; j < BucketedLN[i].size(); j++) { - if (++lightnum > MAXLIGHT) + if (++lightnum >= MAXLIGHT) { LightNode* light_node = BucketedLN[i].at(j); light_node->setEnergyMultiplier(0.0f); @@ -798,17 +874,16 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, } const core::vector3df &pos = light_node->getAbsolutePosition(); - accumulatedLightPos.push_back(pos.X); - accumulatedLightPos.push_back(pos.Y); - accumulatedLightPos.push_back(pos.Z); - accumulatedLightPos.push_back(0.); - const core::vector3df &col = light_node->getColor(); + PointLightsInfo[lightnum].posX = pos.X; + PointLightsInfo[lightnum].posY = pos.Y; + PointLightsInfo[lightnum].posZ = pos.Z; - accumulatedLightColor.push_back(col.X); - accumulatedLightColor.push_back(col.Y); - accumulatedLightColor.push_back(col.Z); - accumulatedLightColor.push_back(0.); - accumulatedLightEnergy.push_back(light_node->getEffectiveEnergy()); + PointLightsInfo[lightnum].energy = light_node->getEffectiveEnergy(); + + const core::vector3df &col = light_node->getColor(); + PointLightsInfo[lightnum].red = col.X; + PointLightsInfo[lightnum].green = col.Y; + PointLightsInfo[lightnum].blue = col.Z; } } if (lightnum > MAXLIGHT) @@ -817,19 +892,22 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, break; } } + + lightnum++; + // Fill lights for (; lightnum < MAXLIGHT; lightnum++) { - accumulatedLightPos.push_back(0.); - accumulatedLightPos.push_back(0.); - accumulatedLightPos.push_back(0.); - accumulatedLightPos.push_back(0.); - accumulatedLightColor.push_back(0.); - accumulatedLightColor.push_back(0.); - accumulatedLightColor.push_back(0.); - accumulatedLightColor.push_back(0.); - accumulatedLightEnergy.push_back(0.); + PointLightsInfo[lightnum].energy = 0; } - m_post_processing->renderPointlight(accumulatedLightPos, accumulatedLightColor, accumulatedLightEnergy); + + if (!pointlightsvao) + createPointLightVAO(); + glBindVertexArray(pointlightsvao); + glBindBuffer(GL_ARRAY_BUFFER, pointlightvbo); + glBufferSubData(GL_ARRAY_BUFFER, 0, MAXLIGHT * sizeof(PointLightInfo), PointLightsInfo); + renderPointLights(); + if (SkyboxCubeMap) + m_post_processing->renderDiffuseEnvMap(blueSHCoeff, greenSHCoeff, redSHCoeff); // Handle SSAO m_video_driver->setRenderTarget(irr_driver->getRTT(RTT_SSAO), true, false, SColor(255, 255, 255, 255)); @@ -853,44 +931,44 @@ static GLuint cubeidx; static void createcubevao() { - // From CSkyBoxSceneNode. Not optimal at all + // From CSkyBoxSceneNode float corners[] = { // top side - 1., 1., -1., 1., 1., - 1., 1., 1., 0., 1., - -1., 1., 1., 0., 0., - -1., 1., -1., 1., 0., + 1., 1., -1., + 1., 1., 1., + -1., 1., 1., + -1., 1., -1., // Bottom side - 1., -1., 1., 0., 0., - 1., -1., -1., 1., 0., - -1., -1., -1., 1., 1., - -1., -1., 1., 0., 1., + 1., -1., 1., + 1., -1., -1., + -1., -1., -1., + -1., -1., 1., // right side - 1., -1, -1, 1., 1., - 1., -1, 1, 0., 1., - 1., 1., 1., 0., 0., - 1., 1., -1., 1., 0., + 1., -1, -1, + 1., -1, 1, + 1., 1., 1., + 1., 1., -1., // left side - -1., -1., 1., 1., 1., - -1., -1., -1., 0., 1., - -1., 1., -1., 0., 0., - -1., 1., 1., 1., 0., + -1., -1., 1., + -1., -1., -1., + -1., 1., -1., + -1., 1., 1., // back side - -1., -1., -1., 1., 1., - 1., -1, -1., 0., 1., - 1, 1, -1., 0., 0., - -1, 1, -1., 1., 0., + -1., -1., -1., + 1., -1, -1., + 1, 1, -1., + -1, 1, -1., // front side - 1., -1., 1., 1., 1., - -1., -1., 1., 0., 1., - -1, 1., 1., 0., 0., - 1., 1., 1., 1., 0., + 1., -1., 1., + -1., -1., 1., + -1, 1., 1., + 1., 1., 1., }; int indices[] = { 0, 1, 2, 2, 3, 0, @@ -907,20 +985,412 @@ static void createcubevao() glBindVertexArray(cubevao); glBindBuffer(GL_ARRAY_BUFFER, cubevbo); - glBufferData(GL_ARRAY_BUFFER, 6 * 5 * 4 * sizeof(float), corners, GL_STATIC_DRAW); - glEnableVertexAttribArray(MeshShader::ObjectUnlitShader::attrib_position); - glEnableVertexAttribArray(MeshShader::ObjectUnlitShader::attrib_texcoord); - glVertexAttribPointer(MeshShader::ObjectUnlitShader::attrib_position, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0); - glVertexAttribPointer(MeshShader::ObjectUnlitShader::attrib_texcoord, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (GLvoid *)(3 * sizeof(float))); + glBufferData(GL_ARRAY_BUFFER, 6 * 4 * 3 * sizeof(float), corners, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeidx); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * 6 * sizeof(int), indices, GL_STATIC_DRAW); } +#define MAX2(a, b) ((a) > (b) ? (a) : (b)) +#define MIN2(a, b) ((a) > (b) ? (b) : (a)) + +static void getXYZ(GLenum face, float i, float j, float &x, float &y, float &z) +{ + switch (face) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + x = 1.; + y = -i; + z = -j; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + x = -1.; + y = -i; + z = j; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + x = j; + y = 1.; + z = i; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + x = j; + y = -1; + z = -i; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + x = j; + y = -i; + z = 1; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + x = -j; + y = -i; + z = -1; + break; + } + + float norm = sqrt(x * x + y * y + z * z); + x /= norm, y /= norm, z /= norm; + return; +} + +static void getYml(GLenum face, size_t width, size_t height, + float *Y00, + float *Y1minus1, float *Y10, float *Y11, + float *Y2minus2, float *Y2minus1, float *Y20, float *Y21, float *Y22) +{ + for (unsigned i = 0; i < width; i++) + { + for (unsigned j = 0; j < height; j++) + { + float x, y, z; + float fi = i, fj = j; + fi /= width, fj /= height; + fi = 2 * fi - 1, fj = 2 * fj - 1; + getXYZ(face, fi, fj, x, y, z); + + // constant part of Ylm + float c00 = 0.282095; + float c1minus1 = 0.488603; + float c10 = 0.488603; + float c11 = 0.488603; + float c2minus2 = 1.092548; + float c2minus1 = 1.092548; + float c21 = 1.092548; + float c20 = 0.315392; + float c22 = 0.546274; + + size_t idx = i * height + j; + + Y00[idx] = c00; + Y1minus1[idx] = c1minus1 * y; + Y10[idx] = c10 * z; + Y11[idx] = c11 * x; + Y2minus2[idx] = c2minus2 * x * y; + Y2minus1[idx] = c2minus1 * y * z; + Y21[idx] = c21 * x * z; + Y20[idx] = c20 * (3 * z * z - 1); + Y22[idx] = c22 * (x * x - y * y); + } + } +} + +static float getTexelValue(unsigned i, unsigned j, size_t width, size_t height, float *Coeff, float *Y00, float *Y1minus1, float *Y10, float *Y11, + float *Y2minus2, float * Y2minus1, float * Y20, float *Y21, float *Y22) +{ + float d = sqrt((float)(i * i + j * j + 1)); + float solidangle = 1.; + size_t idx = i * height + j; + float reconstructedVal = Y00[idx] * Coeff[0]; + reconstructedVal += Y1minus1[i * height + j] * Coeff[1] + Y10[i * height + j] * Coeff[2] + Y11[i * height + j] * Coeff[3]; + reconstructedVal += Y2minus2[idx] * Coeff[4] + Y2minus1[idx] * Coeff[5] + Y20[idx] * Coeff[6] + Y21[idx] * Coeff[7] + Y22[idx] * Coeff[8]; + reconstructedVal /= solidangle; + return MAX2(255 * reconstructedVal, 0.); +} + +static void unprojectSH(float *output[], size_t width, size_t height, + float *Y00[], + float *Y1minus1[], float *Y10[], float *Y11[], + float *Y2minus2[], float *Y2minus1[], float * Y20[],float *Y21[], float *Y22[], + float *blueSHCoeff, float *greenSHCoeff, float *redSHCoeff) +{ + for (unsigned face = 0; face < 6; face++) + { + for (unsigned i = 0; i < width; i++) + { + for (unsigned j = 0; j < height; j++) + { + float fi = i, fj = j; + fi /= width, fj /= height; + fi = 2 * fi - 1, fj = 2 * fj - 1; + + output[face][4 * height * i + 4 * j + 2] = getTexelValue(i, j, width, height, + redSHCoeff, + Y00[face], Y1minus1[face], Y10[face], Y11[face], Y2minus2[face], Y2minus1[face], Y20[face], Y21[face], Y22[face]); + output[face][4 * height * i + 4 * j + 1] = getTexelValue(i, j, width, height, + greenSHCoeff, + Y00[face], Y1minus1[face], Y10[face], Y11[face], Y2minus2[face], Y2minus1[face], Y20[face], Y21[face], Y22[face]); + output[face][4 * height * i + 4 * j] = getTexelValue(i, j, width, height, + blueSHCoeff, + Y00[face], Y1minus1[face], Y10[face], Y11[face], Y2minus2[face], Y2minus1[face], Y20[face], Y21[face], Y22[face]); + } + } + } +} + +static void projectSH(float *color[], size_t width, size_t height, + float *Y00[], + float *Y1minus1[], float *Y10[], float *Y11[], + float *Y2minus2[], float *Y2minus1[], float * Y20[], float *Y21[], float *Y22[], + float *blueSHCoeff, float *greenSHCoeff, float *redSHCoeff + ) +{ + for (unsigned i = 0; i < 9; i++) + { + blueSHCoeff[i] = 0; + greenSHCoeff[i] = 0; + redSHCoeff[i] = 0; + } + float wh = width * height; + for (unsigned face = 0; face < 6; face++) + { + for (unsigned i = 0; i < width; i++) + { + for (unsigned j = 0; j < height; j++) + { + size_t idx = i * height + j; + float fi = i, fj = j; + fi /= width, fj /= height; + fi = 2 * fi - 1, fj = 2 * fj - 1; + + + float d = sqrt(fi * fi + fj * fj + 1); + + // Constant obtained by projecting unprojected ref values + float solidangle = 2.75 / (wh * pow(d, 1.5f)); + float b = color[face][4 * height * i + 4 * j] / 255.; + float g = color[face][4 * height * i + 4 * j + 1] / 255.; + float r = color[face][4 * height * i + 4 * j + 2] / 255.; + + assert(b >= 0.); + + blueSHCoeff[0] += b * Y00[face][idx] * solidangle; + blueSHCoeff[1] += b * Y1minus1[face][idx] * solidangle; + blueSHCoeff[2] += b * Y10[face][idx] * solidangle; + blueSHCoeff[3] += b * Y11[face][idx] * solidangle; + blueSHCoeff[4] += b * Y2minus2[face][idx] * solidangle; + blueSHCoeff[5] += b * Y2minus1[face][idx] * solidangle; + blueSHCoeff[6] += b * Y20[face][idx] * solidangle; + blueSHCoeff[7] += b * Y21[face][idx] * solidangle; + blueSHCoeff[8] += b * Y22[face][idx] * solidangle; + + greenSHCoeff[0] += g * Y00[face][idx] * solidangle; + greenSHCoeff[1] += g * Y1minus1[face][idx] * solidangle; + greenSHCoeff[2] += g * Y10[face][idx] * solidangle; + greenSHCoeff[3] += g * Y11[face][idx] * solidangle; + greenSHCoeff[4] += g * Y2minus2[face][idx] * solidangle; + greenSHCoeff[5] += g * Y2minus1[face][idx] * solidangle; + greenSHCoeff[6] += g * Y20[face][idx] * solidangle; + greenSHCoeff[7] += g * Y21[face][idx] * solidangle; + greenSHCoeff[8] += g * Y22[face][idx] * solidangle; + + + redSHCoeff[0] += r * Y00[face][idx] * solidangle; + redSHCoeff[1] += r * Y1minus1[face][idx] * solidangle; + redSHCoeff[2] += r * Y10[face][idx] * solidangle; + redSHCoeff[3] += r * Y11[face][idx] * solidangle; + redSHCoeff[4] += r * Y2minus2[face][idx] * solidangle; + redSHCoeff[5] += r * Y2minus1[face][idx] * solidangle; + redSHCoeff[6] += r * Y20[face][idx] * solidangle; + redSHCoeff[7] += r * Y21[face][idx] * solidangle; + redSHCoeff[8] += r * Y22[face][idx] * solidangle; + } + } + } +} + +static void displayCoeff(float *SHCoeff) +{ + printf("L00:%f\n", SHCoeff[0]); + printf("L1-1:%f, L10:%f, L11:%f\n", SHCoeff[1], SHCoeff[2], SHCoeff[3]); + printf("L2-2:%f, L2-1:%f, L20:%f, L21:%f, L22:%f\n", SHCoeff[4], SHCoeff[5], SHCoeff[6], SHCoeff[7], SHCoeff[8]); +} + +// Only for 9 coefficients +static void testSH(char *color[6], size_t width, size_t height, + float *blueSHCoeff, float *greenSHCoeff, float *redSHCoeff) +{ + float *Y00[6]; + float *Y1minus1[6]; + float *Y10[6]; + float *Y11[6]; + float *Y2minus2[6]; + float *Y2minus1[6]; + float *Y20[6]; + float *Y21[6]; + float *Y22[6]; + + float *testoutput[6]; + for (unsigned i = 0; i < 6; i++) + { + testoutput[i] = new float[width * height * 4]; + for (unsigned j = 0; j < width * height; j++) + { + testoutput[i][4 * j] = 0xFF & color[i][4 * j]; + testoutput[i][4 * j + 1] = 0xFF & color[i][4 * j + 1]; + testoutput[i][4 * j + 2] = 0xFF & color[i][4 * j + 2]; + } + } + + for (unsigned face = 0; face < 6; face++) + { + Y00[face] = new float[width * height]; + Y1minus1[face] = new float[width * height]; + Y10[face] = new float[width * height]; + Y11[face] = new float[width * height]; + Y2minus2[face] = new float[width * height]; + Y2minus1[face] = new float[width * height]; + Y20[face] = new float[width * height]; + Y21[face] = new float[width * height]; + Y22[face] = new float[width * height]; + + getYml(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, width, height, Y00[face], Y1minus1[face], Y10[face], Y11[face], Y2minus2[face], Y2minus1[face], Y20[face], Y21[face], Y22[face]); + } + +/* blueSHCoeff[0] = 0.54, + blueSHCoeff[1] = .6, blueSHCoeff[2] = -.27, blueSHCoeff[3] = .01, + blueSHCoeff[4] = -.12, blueSHCoeff[5] = -.47, blueSHCoeff[6] = -.15, blueSHCoeff[7] = .14, blueSHCoeff[8] = -.3; + greenSHCoeff[0] = .44, + greenSHCoeff[1] = .35, greenSHCoeff[2] = -.18, greenSHCoeff[3] = -.06, + greenSHCoeff[4] = -.05, greenSHCoeff[5] = -.22, greenSHCoeff[6] = -.09, greenSHCoeff[7] = .21, greenSHCoeff[8] = -.05; + redSHCoeff[0] = .79, + redSHCoeff[1] = .39, redSHCoeff[2] = -.34, redSHCoeff[3] = -.29, + redSHCoeff[4] = -.11, redSHCoeff[5] = -.26, redSHCoeff[6] = -.16, redSHCoeff[7] = .56, redSHCoeff[8] = .21; + + printf("Blue:\n"); + displayCoeff(blueSHCoeff); + printf("Green:\n"); + displayCoeff(greenSHCoeff); + printf("Red:\n"); + displayCoeff(redSHCoeff);*/ + + projectSH(testoutput, width, height, + Y00, + Y1minus1, Y10, Y11, + Y2minus2, Y2minus1, Y20, Y21, Y22, + blueSHCoeff, greenSHCoeff, redSHCoeff + ); + + printf("Blue:\n"); + displayCoeff(blueSHCoeff); + printf("Green:\n"); + displayCoeff(greenSHCoeff); + printf("Red:\n"); + displayCoeff(redSHCoeff); + + + + // Convolute in frequency space +/* float A0 = 3.141593; + float A1 = 2.094395; + float A2 = 0.785398; + blueSHCoeff[0] *= A0; + greenSHCoeff[0] *= A0; + redSHCoeff[0] *= A0; + for (unsigned i = 0; i < 3; i++) + { + blueSHCoeff[1 + i] *= A1; + greenSHCoeff[1 + i] *= A1; + redSHCoeff[1 + i] *= A1; + } + for (unsigned i = 0; i < 5; i++) + { + blueSHCoeff[4 + i] *= A2; + greenSHCoeff[4 + i] *= A2; + redSHCoeff[4 + i] *= A2; + } + + + unprojectSH(testoutput, width, height, + Y00, + Y1minus1, Y10, Y11, + Y2minus2, Y2minus1, Y20, Y21, Y22, + blueSHCoeff, greenSHCoeff, redSHCoeff + );*/ + + +/* printf("Blue:\n"); + displayCoeff(blueSHCoeff); + printf("Green:\n"); + displayCoeff(greenSHCoeff); + printf("Red:\n"); + displayCoeff(redSHCoeff); + + printf("\nAfter projection\n\n");*/ + + + + for (unsigned i = 0; i < 6; i++) + { + for (unsigned j = 0; j < width * height; j++) + { + color[i][4 * j] = MIN2(testoutput[i][4 * j], 255); + color[i][4 * j + 1] = MIN2(testoutput[i][4 * j + 1], 255); + color[i][4 * j + 2] = MIN2(testoutput[i][4 * j + 2], 255); + } + } + + for (unsigned face = 0; face < 6; face++) + { + delete[] testoutput[face]; + delete[] Y00[face]; + delete[] Y1minus1[face]; + delete[] Y10[face]; + delete[] Y11[face]; + } +} + +void IrrDriver::generateSkyboxCubemap() +{ + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + + glGenTextures(1, &SkyboxCubeMap); + glGenTextures(1, &ConvolutedSkyboxCubeMap); + + GLint w = 0, h = 0; + for (unsigned i = 0; i < 6; i++) + { + w = MAX2(w, SkyboxTextures[i]->getOriginalSize().Width); + h = MAX2(h, SkyboxTextures[i]->getOriginalSize().Height); + } + + const unsigned texture_permutation[] = { 2, 3, 0, 1, 5, 4 }; + char *rgba[6]; + for (unsigned i = 0; i < 6; i++) + rgba[i] = new char[w * h * 4]; + for (unsigned i = 0; i < 6; i++) + { + unsigned idx = texture_permutation[i]; + + video::IImage* image = getVideoDriver()->createImageFromData( + SkyboxTextures[idx]->getColorFormat(), + SkyboxTextures[idx]->getSize(), + SkyboxTextures[idx]->lock(), + false + ); + SkyboxTextures[idx]->unlock(); + + image->copyToScaling(rgba[i], w, h); + image->drop(); + + glBindTexture(GL_TEXTURE_CUBE_MAP, SkyboxCubeMap); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]); + } + + testSH(rgba, w, h, blueSHCoeff, greenSHCoeff, redSHCoeff); + + for (unsigned i = 0; i < 6; i++) + { + glBindTexture(GL_TEXTURE_CUBE_MAP, ConvolutedSkyboxCubeMap); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]); + } + for (unsigned i = 0; i < 6; i++) + delete[] rgba[i]; + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +} + + void IrrDriver::renderSkybox() { + if (SkyboxTextures.empty()) return; + scene::ICameraSceneNode *camera = m_scene_manager->getActiveCamera(); if (!cubevao) createcubevao(); + if (!SkyboxCubeMap) + generateSkyboxCubemap(); glBindVertexArray(cubevao); glDisable(GL_CULL_FACE); assert(SkyboxTextures.size() == 6); @@ -933,16 +1403,17 @@ void IrrDriver::renderSkybox() core::matrix4 scale; scale.setScale(core::vector3df(viewDistance, viewDistance, viewDistance)); transform *= translate * scale; - - for (unsigned i = 0; i < 6; i++) - { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, static_cast(SkyboxTextures[i])->getOpenGLTextureName()); - glUseProgram(MeshShader::ObjectUnlitShader::Program); - MeshShader::ObjectUnlitShader::setUniforms(transform, 0); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (GLvoid*) (6 * i * sizeof(int))); - } - glBindVertexArray(0); + core::matrix4 invtransform; + transform.getInverse(invtransform); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, ConvolutedSkyboxCubeMap); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glUseProgram(MeshShader::SkyboxShader::Program); + MeshShader::SkyboxShader::setUniforms(transform, invtransform, core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height), 0); + glDrawElements(GL_TRIANGLES, 6 * 6, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); } // ---------------------------------------------------------------------------- @@ -950,9 +1421,8 @@ void IrrDriver::renderSkybox() void IrrDriver::renderDisplacement(video::SOverrideMaterial &overridemat, int cam) { - m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_DISPLACE), false, false); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); + irr_driver->getVideoDriver()->setRenderTarget(irr_driver->getRTT(RTT_TMP4), true, false); + irr_driver->getVideoDriver()->setRenderTarget(irr_driver->getRTT(RTT_DISPLACE), true, false); DisplaceProvider * const cb = (DisplaceProvider *)irr_driver->getCallback(ES_DISPLACE); cb->update(); @@ -963,6 +1433,10 @@ void IrrDriver::renderDisplacement(video::SOverrideMaterial &overridemat, glDisable(GL_ALPHA_TEST); glDepthMask(GL_FALSE); glDisable(GL_BLEND); + glClear(GL_STENCIL_BUFFER_BIT); + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 1, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); for (int i = 0; i < displacingcount; i++) { @@ -973,8 +1447,8 @@ void IrrDriver::renderDisplacement(video::SOverrideMaterial &overridemat, m_displacing[i]->render(); } - // Blur it - m_post_processing->renderGaussian3Blur(m_rtts->getRTT(RTT_DISPLACE), m_rtts->getRTT(RTT_TMP2), 1.f / UserConfigParams::m_width, 1.f / UserConfigParams::m_height); - m_video_driver->setRenderTarget(m_rtts->getRTT(RTT_COLOR), false, false); + glStencilFunc(GL_EQUAL, 1, 0xFF); + m_post_processing->renderPassThrough(m_rtts->getRTT(RTT_DISPLACE)); + glDisable(GL_STENCIL_TEST); } diff --git a/src/graphics/rtts.cpp b/src/graphics/rtts.cpp index 077dc6fdf..d5927c483 100644 --- a/src/graphics/rtts.cpp +++ b/src/graphics/rtts.cpp @@ -72,7 +72,6 @@ RTT::RTT() rtts[RTT_TMP4] = drv->addRenderTargetTexture(res, "rtt.tmp4", ECF_R8, stencil); rtts[RTT_NORMAL_AND_DEPTH] = drv->addRenderTargetTexture(res, "rtt.normal_and_depth", ECF_G16R16F, stencil); rtts[RTT_COLOR] = drv->addRenderTargetTexture(res, "rtt.color", ECF_A16B16G16R16F, stencil); - rtts[RTT_SPECULARMAP] = drv->addRenderTargetTexture(res, "rtt.specularmap", ECF_R8, stencil); rtts[RTT_HALF1] = drv->addRenderTargetTexture(half, "rtt.half1", ECF_A8R8G8B8, stencil); rtts[RTT_HALF2] = drv->addRenderTargetTexture(half, "rtt.half2", ECF_A8R8G8B8, stencil); diff --git a/src/graphics/rtts.hpp b/src/graphics/rtts.hpp index 9282f885e..74ad51c09 100644 --- a/src/graphics/rtts.hpp +++ b/src/graphics/rtts.hpp @@ -33,7 +33,6 @@ enum TypeRTT RTT_TMP4, RTT_NORMAL_AND_DEPTH, RTT_COLOR, - RTT_SPECULARMAP, RTT_HALF1, RTT_HALF2, diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index 853b6073b..405003ac4 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -44,13 +44,11 @@ Shaders::Shaders() m_callbacks[ES_MLAA_COLOR1] = new MLAAColor1Provider(); m_callbacks[ES_MLAA_BLEND2] = new MLAABlend2Provider(); m_callbacks[ES_MLAA_NEIGH3] = new MLAANeigh3Provider(); - 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_MULTIPLY_ADD] = new MultiplyProvider(); m_callbacks[ES_SHADOWGEN] = new ShadowGenProvider(); - m_callbacks[ES_CAUSTICS] = new CausticsProvider(); m_callbacks[ES_DISPLACE] = new DisplaceProvider(); for(s32 i=0 ; i < ES_COUNT ; i++) @@ -91,6 +89,21 @@ static void initQuadBuffer() glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), quad_vertex, GL_STATIC_DRAW); } +GLuint SharedObject::billboardvbo = 0; + +static void initBillboardVBO() +{ + float quad[] = { + -.5, -.5, 0., 1., + -.5, .5, 0., 0., + .5, -.5, 1., 1., + .5, .5, 1., 0., + }; + glGenBuffers(1, &(SharedObject::billboardvbo)); + glBindBuffer(GL_ARRAY_BUFFER, SharedObject::billboardvbo); + glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), quad, GL_STATIC_DRAW); +} + void Shaders::loadShaders() { const std::string &dir = file_manager->getAsset(FileManager::SHADER, ""); @@ -106,52 +119,52 @@ void Shaders::loadShaders() memcpy(saved_shaders, m_shaders, sizeof(m_shaders)); // Ok, go - m_shaders[ES_NORMAL_MAP] = glsl_noinput(dir + "normalmap.vert", dir + "normalmap.frag"); - m_shaders[ES_NORMAL_MAP_LIGHTMAP] = glsl_noinput(dir + "normalmap.vert", dir + "normalmap.frag"); + m_shaders[ES_NORMAL_MAP] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); + m_shaders[ES_NORMAL_MAP_LIGHTMAP] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); - m_shaders[ES_SKYBOX] = glslmat(dir + "skybox.vert", dir + "skybox.frag", + m_shaders[ES_SKYBOX] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_SKYBOX], EMT_TRANSPARENT_ALPHA_CHANNEL); - m_shaders[ES_SPLATTING] = glsl_noinput(dir + "splatting.vert", dir + "splatting.frag"); + m_shaders[ES_SPLATTING] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); - m_shaders[ES_WATER] = glslmat(dir + "water.vert", dir + "water.frag", + m_shaders[ES_WATER] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_WATER], EMT_TRANSPARENT_ALPHA_CHANNEL); - m_shaders[ES_WATER_SURFACE] = glsl(dir + "water.vert", dir + "pass.frag", + m_shaders[ES_WATER_SURFACE] = glsl(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_WATER]); - m_shaders[ES_SPHERE_MAP] = glsl_noinput(std::string(""), dir + "objectpass_spheremap.frag"); + m_shaders[ES_SPHERE_MAP] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); - m_shaders[ES_GRASS] = glslmat(std::string(""), dir + "pass.frag", + m_shaders[ES_GRASS] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_GRASS], EMT_TRANSPARENT_ALPHA_CHANNEL); - m_shaders[ES_GRASS_REF] = glslmat(std::string(""), dir + "pass.frag", + m_shaders[ES_GRASS_REF] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_GRASS], EMT_TRANSPARENT_ALPHA_CHANNEL_REF); - m_shaders[ES_BUBBLES] = glslmat(dir + "bubble.vert", dir + "bubble.frag", + m_shaders[ES_BUBBLES] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_BUBBLES], EMT_TRANSPARENT_ALPHA_CHANNEL); - m_shaders[ES_RAIN] = glslmat(dir + "rain.vert", dir + "rain.frag", + m_shaders[ES_RAIN] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_RAIN], EMT_TRANSPARENT_ALPHA_CHANNEL); - m_shaders[ES_MOTIONBLUR] = glsl(std::string(""), dir + "motion_blur.frag", + m_shaders[ES_MOTIONBLUR] = glsl(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_MOTIONBLUR]); - m_shaders[ES_GAUSSIAN3H] = glslmat(dir + "pass.vert", dir + "gaussian3h.frag", + m_shaders[ES_GAUSSIAN3H] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_GAUSSIAN3H], EMT_SOLID); - m_shaders[ES_GAUSSIAN3V] = glslmat(dir + "pass.vert", dir + "gaussian3v.frag", + m_shaders[ES_GAUSSIAN3V] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_GAUSSIAN3V], EMT_SOLID); - m_shaders[ES_MIPVIZ] = glslmat(std::string(""), dir + "mipviz.frag", + m_shaders[ES_MIPVIZ] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_MIPVIZ], EMT_SOLID); - m_shaders[ES_COLORIZE] = glslmat(std::string(""), dir + "colorize.frag", + m_shaders[ES_COLORIZE] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_COLORIZE], EMT_SOLID); - m_shaders[ES_OBJECTPASS] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); - m_shaders[ES_OBJECT_UNLIT] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); - m_shaders[ES_OBJECTPASS_REF] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); - m_shaders[ES_OBJECTPASS_RIMLIT] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); + m_shaders[ES_OBJECTPASS] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); + m_shaders[ES_OBJECT_UNLIT] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); + m_shaders[ES_OBJECTPASS_REF] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); + m_shaders[ES_OBJECTPASS_RIMLIT] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); - m_shaders[ES_SUNLIGHT] = glsl_noinput(std::string(""), dir + "sunlight.frag"); + m_shaders[ES_SUNLIGHT] = glsl_noinput(dir + "pass.vert", dir + "pass.frag"); m_shaders[ES_MLAA_COLOR1] = glsl(dir + "mlaa_offset.vert", dir + "mlaa_color1.frag", m_callbacks[ES_MLAA_COLOR1]); @@ -160,40 +173,36 @@ void Shaders::loadShaders() m_shaders[ES_MLAA_NEIGH3] = glsl(dir + "mlaa_offset.vert", dir + "mlaa_neigh3.frag", m_callbacks[ES_MLAA_NEIGH3]); - 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_shaders[ES_SHADOWPASS] = glsl(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_SHADOWPASS]); - m_shaders[ES_SHADOW_IMPORTANCE] = glsl(dir + "shadowimportance.vert", - dir + "shadowimportance.frag", + m_shaders[ES_SHADOW_IMPORTANCE] = glsl(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_SHADOW_IMPORTANCE]); - m_shaders[ES_COLLAPSE] = glsl(std::string(""), dir + "collapse.frag", + m_shaders[ES_COLLAPSE] = glsl(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_COLLAPSE]); - m_shaders[ES_SHADOW_WARPH] = glsl(std::string(""), dir + "shadowwarph.frag", + m_shaders[ES_SHADOW_WARPH] = glsl(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_COLLAPSE]); - m_shaders[ES_SHADOW_WARPV] = glsl(std::string(""), dir + "shadowwarpv.frag", + m_shaders[ES_SHADOW_WARPV] = glsl(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_COLLAPSE]); - m_shaders[ES_MULTIPLY_ADD] = glslmat(std::string(""), dir + "multiply.frag", + m_shaders[ES_MULTIPLY_ADD] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_MULTIPLY_ADD], EMT_ONETEXTURE_BLEND); - m_shaders[ES_PENUMBRAH] = glslmat(std::string(""), dir + "penumbrah.frag", + m_shaders[ES_PENUMBRAH] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_GAUSSIAN3H], EMT_SOLID); - m_shaders[ES_PENUMBRAV] = glslmat(std::string(""), dir + "penumbrav.frag", + m_shaders[ES_PENUMBRAV] = glslmat(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_GAUSSIAN3H], EMT_SOLID); - m_shaders[ES_SHADOWGEN] = glslmat(std::string(""), dir + "shadowgen.frag", + m_shaders[ES_SHADOWGEN] = glslmat(dir + "pass.vert", dir + "pass.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_CAUSTICS] = glslmat(dir + "pass.vert", dir + "pass.frag", + m_callbacks[ES_CAUSTICS], EMT_SOLID); - m_shaders[ES_DISPLACE] = glsl(dir + "displace.vert", dir + "displace.frag", + m_shaders[ES_DISPLACE] = glsl(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_DISPLACE]); - m_shaders[ES_PASSFAR] = glsl(dir + "farplane.vert", dir + "colorize.frag", + m_shaders[ES_PASSFAR] = glsl(dir + "pass.vert", dir + "pass.frag", m_callbacks[ES_COLORIZE]); // Check that all successfully loaded @@ -221,6 +230,7 @@ void Shaders::loadShaders() initGL(); initQuadVBO(); initQuadBuffer(); + initBillboardVBO(); FullScreenShader::BloomBlendShader::init(); FullScreenShader::BloomShader::init(); FullScreenShader::ColorLevelShader::init(); @@ -233,18 +243,18 @@ void Shaders::loadShaders() FullScreenShader::PenumbraVShader::init(); FullScreenShader::GlowShader::init(); FullScreenShader::PassThroughShader::init(); - FullScreenShader::PointLightShader::init(); - FullScreenShader::PPDisplaceShader::init(); FullScreenShader::SSAOShader::init(); FullScreenShader::SunLightShader::init(); + FullScreenShader::DiffuseEnvMapShader::init(); FullScreenShader::ShadowedSunLightShader::init(); FullScreenShader::MotionBlurShader::init(); + FullScreenShader::GodFadeShader::init(); + FullScreenShader::GodRayShader::init(); MeshShader::ColorizeShader::init(); MeshShader::NormalMapShader::init(); MeshShader::ObjectPass1Shader::init(); MeshShader::ObjectRefPass1Shader::init(); MeshShader::ObjectPass2Shader::init(); - MeshShader::MovingTextureShader::init(); MeshShader::DetailledObjectPass2Shader::init(); MeshShader::ObjectRimLimitShader::init(); MeshShader::UntexturedObjectShader::init(); @@ -254,14 +264,18 @@ void Shaders::loadShaders() MeshShader::SplattingShader::init(); MeshShader::GrassPass1Shader::init(); MeshShader::GrassPass2Shader::init(); + MeshShader::CausticsShader::init(); MeshShader::BubbleShader::init(); MeshShader::TransparentShader::init(); MeshShader::TransparentFogShader::init(); MeshShader::BillboardShader::init(); + MeshShader::PointLightShader::init(); MeshShader::DisplaceShader::init(); + MeshShader::DisplaceMaskShader::init(); MeshShader::ShadowShader::init(); MeshShader::RefShadowShader::init(); MeshShader::GrassShadowShader::init(); + MeshShader::SkyboxShader::init(); ParticleShader::FlipParticleRender::init(); ParticleShader::HeightmapSimulationShader::init(); ParticleShader::SimpleParticleRender::init(); @@ -292,13 +306,15 @@ 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 " + Log::error("shaders", "Shader %s failed to load. Update your drivers, if the issue " "persists, report a bug to us.", shader_names[num] + 3); } } namespace MeshShader { + + // Solid Normal and depth pass shaders GLuint ObjectPass1Shader::Program; GLuint ObjectPass1Shader::attrib_position; GLuint ObjectPass1Shader::attrib_normal; @@ -326,6 +342,7 @@ namespace MeshShader GLuint ObjectRefPass1Shader::attrib_texcoord; GLuint ObjectRefPass1Shader::uniform_MVP; GLuint ObjectRefPass1Shader::uniform_TIMV; + GLuint ObjectRefPass1Shader::uniform_TM; GLuint ObjectRefPass1Shader::uniform_tex; void ObjectRefPass1Shader::init() @@ -336,26 +353,87 @@ namespace MeshShader attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); uniform_TIMV = glGetUniformLocation(Program, "TransposeInverseModelView"); + uniform_TM = glGetUniformLocation(Program, "TextureMatrix"); uniform_tex = glGetUniformLocation(Program, "tex"); } - void ObjectRefPass1Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_tex) + void ObjectRefPass1Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &TextureMatrix, unsigned TU_tex) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); + glUniformMatrix4fv(uniform_TM, 1, GL_FALSE, TextureMatrix.pointer()); glUniformMatrix4fv(uniform_TIMV, 1, GL_FALSE, TransposeInverseModelView.pointer()); glUniform1i(uniform_tex, TU_tex); } + GLuint GrassPass1Shader::Program; + GLuint GrassPass1Shader::attrib_position; + GLuint GrassPass1Shader::attrib_texcoord; + GLuint GrassPass1Shader::attrib_normal; + GLuint GrassPass1Shader::attrib_color; + GLuint GrassPass1Shader::uniform_MVP; + GLuint GrassPass1Shader::uniform_TIMV; + GLuint GrassPass1Shader::uniform_tex; + GLuint GrassPass1Shader::uniform_windDir; + + void GrassPass1Shader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/grass_pass1.vert").c_str(), file_manager->getAsset("shaders/objectref_pass1.frag").c_str()); + attrib_position = glGetAttribLocation(Program, "Position"); + attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); + attrib_normal = glGetAttribLocation(Program, "Normal"); + attrib_color = glGetAttribLocation(Program, "Color"); + uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); + uniform_TIMV = glGetUniformLocation(Program, "TransposeInverseModelView"); + uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_windDir = glGetUniformLocation(Program, "windDir"); + } + + void GrassPass1Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::vector3df &windDirection, unsigned TU_tex) + { + glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); + glUniformMatrix4fv(uniform_TIMV, 1, GL_FALSE, TransposeInverseModelView.pointer()); + glUniform3f(uniform_windDir, windDirection.X, windDirection.Y, windDirection.Z); + glUniform1i(uniform_tex, TU_tex); + } + + GLuint NormalMapShader::Program; + GLuint NormalMapShader::attrib_position; + GLuint NormalMapShader::attrib_texcoord; + GLuint NormalMapShader::attrib_tangent; + GLuint NormalMapShader::attrib_bitangent; + GLuint NormalMapShader::uniform_MVP; + GLuint NormalMapShader::uniform_TIMV; + GLuint NormalMapShader::uniform_normalMap; + + void NormalMapShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/normalmap.vert").c_str(), file_manager->getAsset("shaders/normalmap.frag").c_str()); + attrib_position = glGetAttribLocation(Program, "Position"); + attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); + attrib_tangent = glGetAttribLocation(Program, "Tangent"); + attrib_bitangent = glGetAttribLocation(Program, "Bitangent"); + uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); + uniform_TIMV = glGetUniformLocation(Program, "TransposeInverseModelView"); + uniform_normalMap = glGetUniformLocation(Program, "normalMap"); + } + + void NormalMapShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_normalMap) + { + glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); + glUniformMatrix4fv(uniform_TIMV, 1, GL_FALSE, TransposeInverseModelView.pointer()); + glUniform1i(uniform_normalMap, TU_normalMap); + } + + // Solid Lit pass shaders + GLuint ObjectPass2Shader::Program; GLuint ObjectPass2Shader::attrib_position; GLuint ObjectPass2Shader::attrib_texcoord; GLuint ObjectPass2Shader::uniform_MVP; - GLuint ObjectPass2Shader::uniform_Albedo; - GLuint ObjectPass2Shader::uniform_DiffuseMap; - GLuint ObjectPass2Shader::uniform_SpecularMap; - GLuint ObjectPass2Shader::uniform_SSAO; + GLuint ObjectPass2Shader::uniform_TM; GLuint ObjectPass2Shader::uniform_screen; GLuint ObjectPass2Shader::uniform_ambient; + GLuint ObjectPass2Shader::TU_Albedo; void ObjectPass2Shader::init() { @@ -363,78 +441,41 @@ namespace MeshShader attrib_position = glGetAttribLocation(Program, "Position"); attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_Albedo = glGetUniformLocation(Program, "Albedo"); - uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); - uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); - uniform_SSAO = glGetUniformLocation(Program, "SSAO"); + uniform_TM = glGetUniformLocation(Program, "TextureMatrix"); + GLuint uniform_Albedo = glGetUniformLocation(Program, "Albedo"); + GLuint uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); + GLuint uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); + GLuint uniform_SSAO = glGetUniformLocation(Program, "SSAO"); uniform_screen = glGetUniformLocation(Program, "screen"); uniform_ambient = glGetUniformLocation(Program, "ambient"); + TU_Albedo = 3; + + glUseProgram(Program); + glUniform1i(uniform_DiffuseMap, 0); + glUniform1i(uniform_SpecularMap, 1); + glUniform1i(uniform_SSAO, 2); + glUniform1i(uniform_Albedo, TU_Albedo); + glUseProgram(0); } - void ObjectPass2Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO) + void ObjectPass2Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniform1i(uniform_Albedo, TU_Albedo); - glUniform1i(uniform_DiffuseMap, TU_DiffuseMap); - glUniform1i(uniform_SpecularMap, TU_SpecularMap); - glUniform1i(uniform_SSAO, TU_SSAO); + glUniformMatrix4fv(uniform_TM, 1, GL_FALSE, TextureMatrix.pointer()); glUniform2f(uniform_screen, UserConfigParams::m_width, UserConfigParams::m_height); const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); glUniform3f(uniform_ambient, s.r, s.g, s.b); } - GLuint MovingTextureShader::Program; - GLuint MovingTextureShader::attrib_position; - GLuint MovingTextureShader::attrib_texcoord; - GLuint MovingTextureShader::uniform_MVP; - GLuint MovingTextureShader::uniform_TM; - GLuint MovingTextureShader::uniform_Albedo; - GLuint MovingTextureShader::uniform_DiffuseMap; - GLuint MovingTextureShader::uniform_SpecularMap; - GLuint MovingTextureShader::uniform_SSAO; - GLuint MovingTextureShader::uniform_screen; - GLuint MovingTextureShader::uniform_ambient; - - void MovingTextureShader::init() - { - Program = LoadProgram(file_manager->getAsset("shaders/movingtexture.vert").c_str(), file_manager->getAsset("shaders/movingtexture.frag").c_str()); - attrib_position = glGetAttribLocation(Program, "Position"); - attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); - uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_TM = glGetUniformLocation(Program, "TextureMatrix"); - uniform_Albedo = glGetUniformLocation(Program, "Albedo"); - uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); - uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); - uniform_SSAO = glGetUniformLocation(Program, "SSAO"); - uniform_screen = glGetUniformLocation(Program, "screen"); - uniform_ambient = glGetUniformLocation(Program, "ambient"); - } - - void MovingTextureShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO) - { - glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniformMatrix4fv(uniform_TM, 1, GL_FALSE, TextureMatrix.pointer()); - glUniform1i(uniform_Albedo, TU_Albedo); - glUniform1i(uniform_DiffuseMap, TU_DiffuseMap); - glUniform1i(uniform_SpecularMap, TU_SpecularMap); - glUniform1i(uniform_SSAO, TU_SSAO); - glUniform2f(uniform_screen, UserConfigParams::m_width, UserConfigParams::m_height); - const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); - glUniform3f(uniform_ambient, s.r, s.g, s.b); - } - GLuint DetailledObjectPass2Shader::Program; GLuint DetailledObjectPass2Shader::attrib_position; GLuint DetailledObjectPass2Shader::attrib_texcoord; GLuint DetailledObjectPass2Shader::attrib_second_texcoord; GLuint DetailledObjectPass2Shader::uniform_MVP; - GLuint DetailledObjectPass2Shader::uniform_Albedo; - GLuint DetailledObjectPass2Shader::uniform_Detail; - GLuint DetailledObjectPass2Shader::uniform_DiffuseMap; - GLuint DetailledObjectPass2Shader::uniform_SpecularMap; - GLuint DetailledObjectPass2Shader::uniform_SSAO; GLuint DetailledObjectPass2Shader::uniform_screen; GLuint DetailledObjectPass2Shader::uniform_ambient; + GLuint DetailledObjectPass2Shader::TU_Albedo; + GLuint DetailledObjectPass2Shader::TU_detail; void DetailledObjectPass2Shader::init() { @@ -443,23 +484,28 @@ namespace MeshShader attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); attrib_second_texcoord = glGetAttribLocation(Program, "SecondTexcoord"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_Albedo = glGetUniformLocation(Program, "Albedo"); - uniform_Detail = glGetUniformLocation(Program, "Detail"); - uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); - uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); - uniform_SSAO = glGetUniformLocation(Program, "SSAO"); - uniform_screen = glGetUniformLocation(Program, "screen"); + GLuint uniform_Albedo = glGetUniformLocation(Program, "Albedo"); + GLuint uniform_Detail = glGetUniformLocation(Program, "Detail"); + GLuint uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); + GLuint uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); + GLuint uniform_SSAO = glGetUniformLocation(Program, "SSAO"); + uniform_screen = glGetUniformLocation(Program, "screen"); uniform_ambient = glGetUniformLocation(Program, "ambient"); + TU_Albedo = 3; + TU_detail = 4; + + glUseProgram(Program); + glUniform1i(uniform_DiffuseMap, 0); + glUniform1i(uniform_SpecularMap, 1); + glUniform1i(uniform_SSAO, 2); + glUniform1i(uniform_Albedo, TU_Albedo); + glUniform1i(uniform_Detail, TU_detail); + glUseProgram(0); } - void DetailledObjectPass2Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_Albedo, unsigned TU_detail, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO) + void DetailledObjectPass2Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniform1i(uniform_Albedo, TU_Albedo); - glUniform1i(uniform_Detail, TU_detail); - glUniform1i(uniform_DiffuseMap, TU_DiffuseMap); - glUniform1i(uniform_SpecularMap, TU_SpecularMap); - glUniform1i(uniform_SSAO, TU_SSAO); glUniform2f(uniform_screen, UserConfigParams::m_width, UserConfigParams::m_height); const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); glUniform3f(uniform_ambient, s.r, s.g, s.b); @@ -469,7 +515,7 @@ namespace MeshShader GLuint ObjectUnlitShader::attrib_position; GLuint ObjectUnlitShader::attrib_texcoord; GLuint ObjectUnlitShader::uniform_MVP; - GLuint ObjectUnlitShader::uniform_tex; + GLuint ObjectUnlitShader::TU_tex; void ObjectUnlitShader::init() { @@ -477,13 +523,17 @@ namespace MeshShader attrib_position = glGetAttribLocation(Program, "Position"); attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_tex = glGetUniformLocation(Program, "tex"); + GLuint uniform_tex = glGetUniformLocation(Program, "tex"); + TU_tex = 3; + + glUseProgram(Program); + glUniform1i(uniform_tex, TU_tex); + glUseProgram(0); } - void ObjectUnlitShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_tex) + void ObjectUnlitShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniform1i(uniform_tex, TU_tex); } GLuint ObjectRimLimitShader::Program; @@ -492,12 +542,10 @@ namespace MeshShader GLuint ObjectRimLimitShader::attrib_normal; GLuint ObjectRimLimitShader::uniform_MVP; GLuint ObjectRimLimitShader::uniform_TIMV; - GLuint ObjectRimLimitShader::uniform_Albedo; - GLuint ObjectRimLimitShader::uniform_DiffuseMap; - GLuint ObjectRimLimitShader::uniform_SpecularMap; - GLuint ObjectRimLimitShader::uniform_SSAO; + GLuint ObjectRimLimitShader::uniform_TM; GLuint ObjectRimLimitShader::uniform_screen; GLuint ObjectRimLimitShader::uniform_ambient; + GLuint ObjectRimLimitShader::TU_Albedo; void ObjectRimLimitShader::init() { @@ -507,22 +555,28 @@ namespace MeshShader attrib_normal = glGetAttribLocation(Program, "Normal"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); uniform_TIMV = glGetUniformLocation(Program, "TransposeInverseModelView"); - uniform_Albedo = glGetUniformLocation(Program, "Albedo"); - uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); - uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); - uniform_SSAO = glGetUniformLocation(Program, "SSAO"); + uniform_TM = glGetUniformLocation(Program, "TextureMatrix"); + GLuint uniform_Albedo = glGetUniformLocation(Program, "Albedo"); + GLuint uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); + GLuint uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); + GLuint uniform_SSAO = glGetUniformLocation(Program, "SSAO"); uniform_screen = glGetUniformLocation(Program, "screen"); uniform_ambient = glGetUniformLocation(Program, "ambient"); + TU_Albedo = 3; + + glUseProgram(Program); + glUniform1i(uniform_DiffuseMap, 0); + glUniform1i(uniform_SpecularMap, 1); + glUniform1i(uniform_SSAO, 2); + glUniform1i(uniform_Albedo, TU_Albedo); + glUseProgram(0); } - void ObjectRimLimitShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO) + void ObjectRimLimitShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &TextureMatrix) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); glUniformMatrix4fv(uniform_TIMV, 1, GL_FALSE, TransposeInverseModelView.pointer()); - glUniform1i(uniform_Albedo, TU_Albedo); - glUniform1i(uniform_DiffuseMap, TU_DiffuseMap); - glUniform1i(uniform_SpecularMap, TU_SpecularMap); - glUniform1i(uniform_SSAO, TU_SSAO); + glUniformMatrix4fv(uniform_TM, 1, GL_FALSE, TextureMatrix.pointer()); glUniform2f(uniform_screen, UserConfigParams::m_width, UserConfigParams::m_height); const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); glUniform3f(uniform_ambient, s.r, s.g, s.b); @@ -532,9 +586,6 @@ namespace MeshShader GLuint UntexturedObjectShader::attrib_position; GLuint UntexturedObjectShader::attrib_color; GLuint UntexturedObjectShader::uniform_MVP; - GLuint UntexturedObjectShader::uniform_DiffuseMap; - GLuint UntexturedObjectShader::uniform_SpecularMap; - GLuint UntexturedObjectShader::uniform_SSAO; GLuint UntexturedObjectShader::uniform_screen; GLuint UntexturedObjectShader::uniform_ambient; @@ -544,19 +595,22 @@ namespace MeshShader attrib_position = glGetAttribLocation(Program, "Position"); attrib_color = glGetAttribLocation(Program, "Color"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); - uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); - uniform_SSAO = glGetUniformLocation(Program, "SSAO"); + GLuint uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); + GLuint uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); + GLuint uniform_SSAO = glGetUniformLocation(Program, "SSAO"); uniform_screen = glGetUniformLocation(Program, "screen"); uniform_ambient = glGetUniformLocation(Program, "ambient"); + + glUseProgram(Program); + glUniform1i(uniform_DiffuseMap, 0); + glUniform1i(uniform_SpecularMap, 1); + glUniform1i(uniform_SSAO, 2); + glUseProgram(0); } - void UntexturedObjectShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO) + void UntexturedObjectShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniform1i(uniform_DiffuseMap, TU_DiffuseMap); - glUniform1i(uniform_SpecularMap, TU_SpecularMap); - glUniform1i(uniform_SSAO, TU_SSAO); glUniform2f(uniform_screen, UserConfigParams::m_width, UserConfigParams::m_height); const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); glUniform3f(uniform_ambient, s.r, s.g, s.b); @@ -567,12 +621,10 @@ namespace MeshShader GLuint ObjectRefPass2Shader::attrib_position; GLuint ObjectRefPass2Shader::attrib_texcoord; GLuint ObjectRefPass2Shader::uniform_MVP; - GLuint ObjectRefPass2Shader::uniform_Albedo; - GLuint ObjectRefPass2Shader::uniform_DiffuseMap; - GLuint ObjectRefPass2Shader::uniform_SpecularMap; - GLuint ObjectRefPass2Shader::uniform_SSAO; + GLuint ObjectRefPass2Shader::uniform_TM; GLuint ObjectRefPass2Shader::uniform_screen; GLuint ObjectRefPass2Shader::uniform_ambient; + GLuint ObjectRefPass2Shader::TU_Albedo; void ObjectRefPass2Shader::init() { @@ -581,69 +633,41 @@ namespace MeshShader attrib_position = glGetAttribLocation(Program, "Position"); attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_Albedo = glGetUniformLocation(Program, "Albedo"); - uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); - uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); - uniform_SSAO = glGetUniformLocation(Program, "SSAO"); + uniform_TM = glGetUniformLocation(Program, "TextureMatrix"); + GLuint uniform_Albedo = glGetUniformLocation(Program, "Albedo"); + GLuint uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); + GLuint uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); + GLuint uniform_SSAO = glGetUniformLocation(Program, "SSAO"); uniform_screen = glGetUniformLocation(Program, "screen"); uniform_ambient = glGetUniformLocation(Program, "ambient"); + TU_Albedo = 3; + + glUseProgram(Program); + glUniform1i(uniform_DiffuseMap, 0); + glUniform1i(uniform_SpecularMap, 1); + glUniform1i(uniform_SSAO, 2); + glUniform1i(uniform_Albedo, TU_Albedo); + glUseProgram(0); } - void ObjectRefPass2Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO) + void ObjectRefPass2Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniform1i(uniform_Albedo, TU_Albedo); - glUniform1i(uniform_DiffuseMap, TU_DiffuseMap); - glUniform1i(uniform_SpecularMap, TU_SpecularMap); - glUniform1i(uniform_SSAO, TU_SSAO); + glUniformMatrix4fv(uniform_TM, 1, GL_FALSE, TextureMatrix.pointer()); glUniform2f(uniform_screen, UserConfigParams::m_width, UserConfigParams::m_height); const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); glUniform3f(uniform_ambient, s.r, s.g, s.b); } - GLuint GrassPass1Shader::Program; - GLuint GrassPass1Shader::attrib_position; - GLuint GrassPass1Shader::attrib_texcoord; - GLuint GrassPass1Shader::attrib_normal; - GLuint GrassPass1Shader::attrib_color; - GLuint GrassPass1Shader::uniform_MVP; - GLuint GrassPass1Shader::uniform_TIMV; - GLuint GrassPass1Shader::uniform_tex; - GLuint GrassPass1Shader::uniform_windDir; - - void GrassPass1Shader::init() - { - Program = LoadProgram(file_manager->getAsset("shaders/grass_pass1.vert").c_str(), file_manager->getAsset("shaders/objectref_pass1.frag").c_str()); - attrib_position = glGetAttribLocation(Program, "Position"); - attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); - attrib_normal = glGetAttribLocation(Program, "Normal"); - attrib_color = glGetAttribLocation(Program, "Color"); - uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_TIMV = glGetUniformLocation(Program, "TransposeInverseModelView"); - uniform_tex = glGetUniformLocation(Program, "tex"); - uniform_windDir = glGetUniformLocation(Program, "windDir"); - } - - void GrassPass1Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::vector3df &windDirection, unsigned TU_tex) - { - glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniformMatrix4fv(uniform_TIMV, 1, GL_FALSE, TransposeInverseModelView.pointer()); - glUniform3f(uniform_windDir, windDirection.X, windDirection.Y, windDirection.Z); - glUniform1i(uniform_tex, TU_tex); - } - GLuint GrassPass2Shader::Program; GLuint GrassPass2Shader::attrib_position; GLuint GrassPass2Shader::attrib_texcoord; GLuint GrassPass2Shader::attrib_color; GLuint GrassPass2Shader::uniform_MVP; - GLuint GrassPass2Shader::uniform_Albedo; - GLuint GrassPass2Shader::uniform_DiffuseMap; - GLuint GrassPass2Shader::uniform_SpecularMap; - GLuint GrassPass2Shader::uniform_SSAO; GLuint GrassPass2Shader::uniform_screen; GLuint GrassPass2Shader::uniform_ambient; GLuint GrassPass2Shader::uniform_windDir; + GLuint GrassPass2Shader::TU_Albedo; void GrassPass2Shader::init() { @@ -652,62 +676,41 @@ namespace MeshShader attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); attrib_color = glGetAttribLocation(Program, "Color"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_Albedo = glGetUniformLocation(Program, "Albedo"); - uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); - uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); - uniform_SSAO = glGetUniformLocation(Program, "SSAO"); + GLuint uniform_Albedo = glGetUniformLocation(Program, "Albedo"); + GLuint uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); + GLuint uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); + GLuint uniform_SSAO = glGetUniformLocation(Program, "SSAO"); uniform_screen = glGetUniformLocation(Program, "screen"); uniform_ambient = glGetUniformLocation(Program, "ambient"); uniform_windDir = glGetUniformLocation(Program, "windDir"); + TU_Albedo = 3; + + glUseProgram(Program); + glUniform1i(uniform_DiffuseMap, 0); + glUniform1i(uniform_SpecularMap, 1); + glUniform1i(uniform_SSAO, 2); + glUniform1i(uniform_Albedo, TU_Albedo); + glUseProgram(0); } - void GrassPass2Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::vector3df &windDirection, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO) + void GrassPass2Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::vector3df &windDirection) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniform1i(uniform_Albedo, TU_Albedo); - glUniform1i(uniform_DiffuseMap, TU_DiffuseMap); - glUniform1i(uniform_SpecularMap, TU_SpecularMap); - glUniform1i(uniform_SSAO, TU_SSAO); glUniform2f(uniform_screen, UserConfigParams::m_width, UserConfigParams::m_height); const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); glUniform3f(uniform_ambient, s.r, s.g, s.b); glUniform3f(uniform_windDir, windDirection.X, windDirection.Y, windDirection.Z); } - GLuint NormalMapShader::Program; - GLuint NormalMapShader::attrib_position; - GLuint NormalMapShader::attrib_texcoord; - GLuint NormalMapShader::attrib_tangent; - GLuint NormalMapShader::attrib_bitangent; - GLuint NormalMapShader::uniform_MVP; - GLuint NormalMapShader::uniform_TIMV; - GLuint NormalMapShader::uniform_normalMap; - - void NormalMapShader::init() - { - Program = LoadProgram(file_manager->getAsset("shaders/normalmap.vert").c_str(), file_manager->getAsset("shaders/normalmap.frag").c_str()); - attrib_position = glGetAttribLocation(Program, "Position"); - attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); - attrib_tangent = glGetAttribLocation(Program, "Tangent"); - attrib_bitangent = glGetAttribLocation(Program, "Bitangent"); - uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_TIMV = glGetUniformLocation(Program, "TransposeInverseModelView"); - uniform_normalMap = glGetUniformLocation(Program, "normalMap"); - } - - void NormalMapShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_normalMap) - { - glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniformMatrix4fv(uniform_TIMV, 1, GL_FALSE, TransposeInverseModelView.pointer()); - glUniform1i(uniform_normalMap, TU_normalMap); - } - GLuint SphereMapShader::Program; GLuint SphereMapShader::attrib_position; GLuint SphereMapShader::attrib_normal; GLuint SphereMapShader::uniform_MVP; GLuint SphereMapShader::uniform_TIMV; - GLuint SphereMapShader::uniform_tex; + GLuint SphereMapShader::uniform_TVM; + GLuint SphereMapShader::uniform_invproj; + GLuint SphereMapShader::uniform_screen; + GLuint SphereMapShader::TU_tex; void SphereMapShader::init() { @@ -716,14 +719,24 @@ namespace MeshShader attrib_normal = glGetAttribLocation(Program, "Normal"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); uniform_TIMV = glGetUniformLocation(Program, "TransposeInverseModelView"); - uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_TVM = glGetUniformLocation(Program, "TransposeViewMatrix"); + GLuint uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_invproj = glGetUniformLocation(Program, "invproj"); + uniform_screen = glGetUniformLocation(Program, "screen"); + TU_tex = 3; + + glUseProgram(Program); + glUniform1i(uniform_tex, TU_tex); + glUseProgram(0); } - void SphereMapShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_tex) + void SphereMapShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeViewMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &InvProj, const core::vector2df& screen) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); glUniformMatrix4fv(uniform_TIMV, 1, GL_FALSE, TransposeInverseModelView.pointer()); - glUniform1i(uniform_tex, TU_tex); + glUniformMatrix4fv(uniform_TVM, 1, GL_FALSE, TransposeViewMatrix.pointer()); + glUniformMatrix4fv(uniform_invproj, 1, GL_FALSE, InvProj.pointer()); + glUniform2f(uniform_screen, screen.X, screen.Y); } GLuint SplattingShader::Program; @@ -731,16 +744,13 @@ namespace MeshShader GLuint SplattingShader::attrib_texcoord; GLuint SplattingShader::attrib_second_texcoord; GLuint SplattingShader::uniform_MVP; - GLuint SplattingShader::uniform_tex_layout; - GLuint SplattingShader::uniform_tex_detail0; - GLuint SplattingShader::uniform_tex_detail1; - GLuint SplattingShader::uniform_tex_detail2; - GLuint SplattingShader::uniform_tex_detail3; - GLuint SplattingShader::uniform_DiffuseMap; - GLuint SplattingShader::uniform_SpecularMap; - GLuint SplattingShader::uniform_SSAO; GLuint SplattingShader::uniform_screen; GLuint SplattingShader::uniform_ambient; + GLuint SplattingShader::TU_tex_layout; + GLuint SplattingShader::TU_tex_detail0; + GLuint SplattingShader::TU_tex_detail1; + GLuint SplattingShader::TU_tex_detail2; + GLuint SplattingShader::TU_tex_detail3; void SplattingShader::init() { @@ -749,34 +759,90 @@ namespace MeshShader attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); attrib_second_texcoord = glGetAttribLocation(Program, "SecondTexcoord"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); - uniform_tex_layout = glGetUniformLocation(Program, "tex_layout"); - uniform_tex_detail0 = glGetUniformLocation(Program, "tex_detail0"); - uniform_tex_detail1 = glGetUniformLocation(Program, "tex_detail1"); - uniform_tex_detail2 = glGetUniformLocation(Program, "tex_detail2"); - uniform_tex_detail3 = glGetUniformLocation(Program, "tex_detail3"); - uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); - uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); - uniform_SSAO = glGetUniformLocation(Program, "SSAO"); + GLuint uniform_tex_layout = glGetUniformLocation(Program, "tex_layout"); + GLuint uniform_tex_detail0 = glGetUniformLocation(Program, "tex_detail0"); + GLuint uniform_tex_detail1 = glGetUniformLocation(Program, "tex_detail1"); + GLuint uniform_tex_detail2 = glGetUniformLocation(Program, "tex_detail2"); + GLuint uniform_tex_detail3 = glGetUniformLocation(Program, "tex_detail3"); + GLuint uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); + GLuint uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); + GLuint uniform_SSAO = glGetUniformLocation(Program, "SSAO"); uniform_screen = glGetUniformLocation(Program, "screen"); uniform_ambient = glGetUniformLocation(Program, "ambient"); + TU_tex_layout = 3; + TU_tex_detail0 = 4; + TU_tex_detail1 = 5; + TU_tex_detail2 = 6; + TU_tex_detail3 = 7; + + glUseProgram(Program); + glUniform1i(uniform_DiffuseMap, 0); + glUniform1i(uniform_SpecularMap, 1); + glUniform1i(uniform_SSAO, 2); + glUniform1i(uniform_tex_layout, TU_tex_layout); + glUniform1i(uniform_tex_detail0, TU_tex_detail0); + glUniform1i(uniform_tex_detail1, TU_tex_detail1); + glUniform1i(uniform_tex_detail2, TU_tex_detail2); + glUniform1i(uniform_tex_detail3, TU_tex_detail3); + glUseProgram(0); } - void SplattingShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_tex_layout, unsigned TU_tex_detail0, unsigned TU_tex_detail1, unsigned TU_tex_detail2, unsigned TU_tex_detail3, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO) + void SplattingShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); - glUniform1i(uniform_tex_layout, TU_tex_layout); - glUniform1i(uniform_tex_detail0, TU_tex_detail0); - glUniform1i(uniform_tex_detail1, TU_tex_detail1); - glUniform1i(uniform_tex_detail2, TU_tex_detail2); - glUniform1i(uniform_tex_detail3, TU_tex_detail3); - glUniform1i(uniform_DiffuseMap, TU_DiffuseMap); - glUniform1i(uniform_SpecularMap, TU_SpecularMap); - glUniform1i(uniform_SSAO, TU_SSAO); glUniform2f(uniform_screen, UserConfigParams::m_width, UserConfigParams::m_height); const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); glUniform3f(uniform_ambient, s.r, s.g, s.b); } + GLuint CausticsShader::Program; + GLuint CausticsShader::attrib_position; + GLuint CausticsShader::attrib_texcoord; + GLuint CausticsShader::uniform_MVP; + GLuint CausticsShader::uniform_dir; + GLuint CausticsShader::uniform_dir2; + GLuint CausticsShader::uniform_screen; + GLuint CausticsShader::uniform_ambient; + GLuint CausticsShader::TU_Albedo; + GLuint CausticsShader::TU_caustictex; + + void CausticsShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/object_pass2.vert").c_str(), file_manager->getAsset("shaders/caustics.frag").c_str()); + attrib_position = glGetAttribLocation(Program, "Position"); + attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); + uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); + uniform_dir = glGetUniformLocation(Program, "dir"); + uniform_dir2 = glGetUniformLocation(Program, "dir2"); + GLuint uniform_Albedo = glGetUniformLocation(Program, "Albedo"); + GLuint uniform_caustictex = glGetUniformLocation(Program, "caustictex"); + GLuint uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); + GLuint uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); + GLuint uniform_SSAO = glGetUniformLocation(Program, "SSAO"); + uniform_screen = glGetUniformLocation(Program, "screen"); + uniform_ambient = glGetUniformLocation(Program, "ambient"); + TU_Albedo = 3; + TU_caustictex = 4; + + glUseProgram(Program); + glUniform1i(uniform_DiffuseMap, 0); + glUniform1i(uniform_SpecularMap, 1); + glUniform1i(uniform_SSAO, 2); + glUniform1i(uniform_Albedo, TU_Albedo); + glUniform1i(uniform_caustictex, TU_caustictex); + glUseProgram(0); + } + + void CausticsShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::vector2df &dir, const core::vector2df &dir2, const core::vector2df &screen) + { + glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); + glUniform2f(uniform_dir, dir.X, dir.Y); + glUniform2f(uniform_dir2, dir2.X, dir2.Y); + glUniform2f(uniform_screen, screen.X, screen.Y); + const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); + glUniform3f(uniform_ambient, s.r, s.g, s.b); + } + GLuint BubbleShader::Program; GLuint BubbleShader::attrib_position; GLuint BubbleShader::attrib_texcoord; @@ -874,6 +940,47 @@ namespace MeshShader glUniformMatrix4fv(uniform_ipvmat, 1, GL_FALSE, ipvmat.pointer()); glUniform1i(uniform_tex, TU_tex); } + + GLuint PointLightShader::Program; + GLuint PointLightShader::attrib_Position; + GLuint PointLightShader::attrib_Color; + GLuint PointLightShader::attrib_Energy; + GLuint PointLightShader::attrib_Corner; + GLuint PointLightShader::uniform_ntex; + GLuint PointLightShader::uniform_dtex; + GLuint PointLightShader::uniform_spec; + GLuint PointLightShader::uniform_screen; + GLuint PointLightShader::uniform_invproj; + GLuint PointLightShader::uniform_VM; + GLuint PointLightShader::uniform_PM; + + void PointLightShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/pointlight.vert").c_str(), file_manager->getAsset("shaders/pointlight.frag").c_str()); + attrib_Position = glGetAttribLocation(Program, "Position"); + attrib_Color = glGetAttribLocation(Program, "Color"); + attrib_Energy = glGetAttribLocation(Program, "Energy"); + attrib_Corner = glGetAttribLocation(Program, "Corner"); + uniform_ntex = glGetUniformLocation(Program, "ntex"); + uniform_dtex = glGetUniformLocation(Program, "dtex"); + uniform_spec = glGetUniformLocation(Program, "spec"); + uniform_invproj = glGetUniformLocation(Program, "invproj"); + uniform_screen = glGetUniformLocation(Program, "screen"); + uniform_VM = glGetUniformLocation(Program, "ViewMatrix"); + uniform_PM = glGetUniformLocation(Program, "ProjectionMatrix"); + } + + void PointLightShader::setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 &InvProjMatrix, const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex) + { + glUniform1f(uniform_spec, 200); + glUniform2f(uniform_screen, screen.X, screen.Y); + glUniformMatrix4fv(uniform_invproj, 1, GL_FALSE, InvProjMatrix.pointer()); + glUniformMatrix4fv(uniform_VM, 1, GL_FALSE, ViewMatrix.pointer()); + glUniformMatrix4fv(uniform_PM, 1, GL_FALSE, ProjMatrix.pointer()); + + glUniform1i(uniform_ntex, TU_ntex); + glUniform1i(uniform_dtex, TU_dtex); + } GLuint BillboardShader::Program; GLuint BillboardShader::attrib_corner; @@ -999,15 +1106,34 @@ namespace MeshShader glUniform3f(uniform_windDir, windDirection.X, windDirection.Y, windDirection.Z); } + GLuint DisplaceMaskShader::Program; + GLuint DisplaceMaskShader::attrib_position; + GLuint DisplaceMaskShader::uniform_MVP; + + void DisplaceMaskShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/displace.vert").c_str(), file_manager->getAsset("shaders/white.frag").c_str()); + attrib_position = glGetAttribLocation(Program, "Position"); + uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); + } + + void DisplaceMaskShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix) + { + glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); + } + GLuint DisplaceShader::Program; GLuint DisplaceShader::attrib_position; GLuint DisplaceShader::attrib_texcoord; GLuint DisplaceShader::attrib_second_texcoord; GLuint DisplaceShader::uniform_MVP; GLuint DisplaceShader::uniform_MV; - GLuint DisplaceShader::uniform_tex; + GLuint DisplaceShader::uniform_displacement_tex; + GLuint DisplaceShader::uniform_mask_tex; + GLuint DisplaceShader::uniform_color_tex; GLuint DisplaceShader::uniform_dir; GLuint DisplaceShader::uniform_dir2; + GLuint DisplaceShader::uniform_screen; void DisplaceShader::init() { @@ -1017,19 +1143,50 @@ namespace MeshShader attrib_second_texcoord = glGetAttribLocation(Program, "SecondTexcoord"); uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); uniform_MV = glGetUniformLocation(Program, "ModelViewMatrix"); - uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_displacement_tex = glGetUniformLocation(Program, "displacement_tex"); + uniform_color_tex = glGetUniformLocation(Program, "color_tex"); + uniform_mask_tex = glGetUniformLocation(Program, "mask_tex"); uniform_dir = glGetUniformLocation(Program, "dir"); uniform_dir2 = glGetUniformLocation(Program, "dir2"); + uniform_screen = glGetUniformLocation(Program, "screen"); } - void DisplaceShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &ModelViewMatrix, float dirX, float dirY, float dir2X, float dir2Y, unsigned TU_tex) + void DisplaceShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &ModelViewMatrix, const core::vector2df &dir, const core::vector2df &dir2, const core::vector2df &screen, unsigned TU_displacement_tex, unsigned TU_mask_tex, unsigned TU_color_tex) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); glUniformMatrix4fv(uniform_MV, 1, GL_FALSE, ModelViewMatrix.pointer()); - glUniform2f(uniform_dir, dirX, dirY); - glUniform2f(uniform_dir2, dir2X, dir2Y); - glUniform1i(uniform_tex, TU_tex); + glUniform2f(uniform_dir, dir.X, dir.Y); + glUniform2f(uniform_dir2, dir2.X, dir2.Y); + glUniform2f(uniform_screen, screen.X, screen.Y); + glUniform1i(uniform_displacement_tex, TU_displacement_tex); + glUniform1i(uniform_mask_tex, TU_mask_tex); + glUniform1i(uniform_color_tex, TU_color_tex); } + + GLuint SkyboxShader::Program; + GLuint SkyboxShader::attrib_position; + GLuint SkyboxShader::uniform_MVP; + GLuint SkyboxShader::uniform_tex; + GLuint SkyboxShader::uniform_screen; + GLuint SkyboxShader::uniform_InvProjView; + + void SkyboxShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/object_pass2.vert").c_str(), file_manager->getAsset("shaders/sky.frag").c_str()); + attrib_position = glGetAttribLocation(Program, "Position"); + uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); + uniform_InvProjView = glGetUniformLocation(Program, "InvProjView"); + uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_screen = glGetUniformLocation(Program, "screen"); + } + + void SkyboxShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &InvProjView, const core::vector2df &screen, unsigned TU_tex) + { + glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); + glUniformMatrix4fv(uniform_InvProjView, 1, GL_FALSE, InvProjView.pointer()); + glUniform1i(uniform_tex, TU_tex); + glUniform2f(uniform_screen, screen.X, screen.Y); + } } @@ -1251,72 +1408,24 @@ namespace FullScreenShader vao = createVAO(Program); } - GLuint PPDisplaceShader::Program; - GLuint PPDisplaceShader::uniform_tex; - GLuint PPDisplaceShader::uniform_dtex; - GLuint PPDisplaceShader::uniform_viz; - GLuint PPDisplaceShader::vao; - void PPDisplaceShader::init() - { - Program = LoadProgram(file_manager->getAsset("shaders/screenquad.vert").c_str(), file_manager->getAsset("shaders/ppdisplace.frag").c_str()); - uniform_tex = glGetUniformLocation(Program, "tex"); - uniform_dtex = glGetUniformLocation(Program, "dtex"); - uniform_viz = glGetUniformLocation(Program, "viz"); - vao = createVAO(Program); - } - GLuint ColorLevelShader::Program; GLuint ColorLevelShader::uniform_tex; GLuint ColorLevelShader::uniform_inlevel; GLuint ColorLevelShader::uniform_outlevel; GLuint ColorLevelShader::vao; + GLuint ColorLevelShader::uniform_invprojm; + GLuint ColorLevelShader::uniform_dtex; void ColorLevelShader::init() { Program = LoadProgram(file_manager->getAsset("shaders/screenquad.vert").c_str(), file_manager->getAsset("shaders/color_levels.frag").c_str()); uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_dtex = glGetUniformLocation(Program, "dtex"); uniform_inlevel = glGetUniformLocation(Program, "inlevel"); uniform_outlevel = glGetUniformLocation(Program, "outlevel"); + uniform_invprojm = glGetUniformLocation(Program, "invprojm"); vao = createVAO(Program); } - GLuint PointLightShader::Program; - GLuint PointLightShader::uniform_ntex; - GLuint PointLightShader::uniform_dtex; - GLuint PointLightShader::uniform_center; - GLuint PointLightShader::uniform_col; - GLuint PointLightShader::uniform_energy; - GLuint PointLightShader::uniform_spec; - GLuint PointLightShader::uniform_invproj; - GLuint PointLightShader::uniform_viewm; - GLuint PointLightShader::vao; - - void PointLightShader::init() - { - Program = LoadProgram(file_manager->getAsset("shaders/screenquad.vert").c_str(), file_manager->getAsset("shaders/pointlight.frag").c_str()); - uniform_ntex = glGetUniformLocation(Program, "ntex"); - uniform_dtex = glGetUniformLocation(Program, "dtex"); - uniform_center = glGetUniformLocation(Program, "center[0]"); - uniform_col = glGetUniformLocation(Program, "col[0]"); - uniform_energy = glGetUniformLocation(Program, "energy[0]"); - uniform_spec = glGetUniformLocation(Program, "spec"); - uniform_invproj = glGetUniformLocation(Program, "invproj"); - uniform_viewm = glGetUniformLocation(Program, "viewm"); - vao = createVAO(Program); - } - - void PointLightShader::setUniforms(const core::matrix4 &InvProjMatrix, const core::matrix4 &ViewMatrix, const std::vector &positions, const std::vector &colors, const std::vector &energy, unsigned spec, unsigned TU_ntex, unsigned TU_dtex) - { - glUniform4fv(FullScreenShader::PointLightShader::uniform_center, 16, positions.data()); - glUniform4fv(FullScreenShader::PointLightShader::uniform_col, 16, colors.data()); - glUniform1fv(FullScreenShader::PointLightShader::uniform_energy, 16, energy.data()); - glUniform1f(FullScreenShader::PointLightShader::uniform_spec, 200); - glUniformMatrix4fv(FullScreenShader::PointLightShader::uniform_invproj, 1, GL_FALSE, InvProjMatrix.pointer()); - glUniformMatrix4fv(FullScreenShader::PointLightShader::uniform_viewm, 1, GL_FALSE, ViewMatrix.pointer()); - - glUniform1i(FullScreenShader::PointLightShader::uniform_ntex, TU_ntex); - glUniform1i(FullScreenShader::PointLightShader::uniform_dtex, TU_dtex); - } - GLuint SunLightShader::Program; GLuint SunLightShader::uniform_ntex; GLuint SunLightShader::uniform_dtex; @@ -1345,6 +1454,34 @@ namespace FullScreenShader glUniform1i(uniform_dtex, TU_dtex); } + GLuint DiffuseEnvMapShader::Program; + GLuint DiffuseEnvMapShader::uniform_ntex; + GLuint DiffuseEnvMapShader::uniform_blueLmn; + GLuint DiffuseEnvMapShader::uniform_greenLmn; + GLuint DiffuseEnvMapShader::uniform_redLmn; + GLuint DiffuseEnvMapShader::uniform_TVM; + GLuint DiffuseEnvMapShader::vao; + + void DiffuseEnvMapShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/screenquad.vert").c_str(), file_manager->getAsset("shaders/diffuseenvmap.frag").c_str()); + uniform_ntex = glGetUniformLocation(Program, "ntex"); + uniform_blueLmn = glGetUniformLocation(Program, "blueLmn[0]"); + uniform_greenLmn = glGetUniformLocation(Program, "greenLmn[0]"); + uniform_redLmn = glGetUniformLocation(Program, "redLmn[0]"); + uniform_TVM = glGetUniformLocation(Program, "TransposeViewMatrix"); + vao = createVAO(Program); + } + + void DiffuseEnvMapShader::setUniforms(const core::matrix4 &TransposeViewMatrix, const float *blueSHCoeff, const float *greenSHCoeff, const float *redSHCoeff, unsigned TU_ntex) + { + glUniformMatrix4fv(uniform_TVM, 1, GL_FALSE, TransposeViewMatrix.pointer()); + glUniform1i(uniform_ntex, TU_ntex); + glUniform1fv(uniform_blueLmn, 9, blueSHCoeff); + glUniform1fv(uniform_greenLmn, 9, greenSHCoeff); + glUniform1fv(uniform_redLmn, 9, redSHCoeff); + } + GLuint ShadowedSunLightShader::Program; GLuint ShadowedSunLightShader::uniform_ntex; GLuint ShadowedSunLightShader::uniform_dtex; @@ -1724,6 +1861,44 @@ namespace FullScreenShader glUniform1f(uniform_max_tex_height, max_tex_height); glUniform1i(uniform_color_buffer, TU_cb); } + + GLuint GodFadeShader::Program; + GLuint GodFadeShader::uniform_tex; + GLuint GodFadeShader::uniform_col; + GLuint GodFadeShader::vao; + + void GodFadeShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/screenquad.vert").c_str(), file_manager->getAsset("shaders/godfade.frag").c_str()); + uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_col = glGetUniformLocation(Program, "col"); + vao = createVAO(Program); + } + + void GodFadeShader::setUniforms(const SColor &col, unsigned TU_tex) + { + glUniform3f(uniform_col, col.getRed() / 255., col.getGreen() / 255., col.getBlue() / 255.); + glUniform1i(uniform_tex, TU_tex); + } + + GLuint GodRayShader::Program; + GLuint GodRayShader::uniform_tex; + GLuint GodRayShader::uniform_sunpos; + GLuint GodRayShader::vao; + + void GodRayShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/screenquad.vert").c_str(), file_manager->getAsset("shaders/godray.frag").c_str()); + uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_sunpos = glGetUniformLocation(Program, "sunpos"); + vao = createVAO(Program); + } + + void GodRayShader::setUniforms(const core::vector2df &sunpos, unsigned TU_tex) + { + glUniform2f(uniform_sunpos, sunpos.X, sunpos.Y); + glUniform1i(uniform_tex, TU_tex); + } } namespace UIShader diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 5231010d6..e68fd7e40 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -24,6 +24,11 @@ typedef unsigned int GLuint; using namespace irr; +class SharedObject +{ +public: + static GLuint billboardvbo; +}; namespace MeshShader { class ObjectPass1Shader @@ -42,10 +47,32 @@ class ObjectRefPass1Shader public: static GLuint Program; static GLuint attrib_position, attrib_normal, attrib_texcoord; - static GLuint uniform_MVP, uniform_TIMV, uniform_tex; + static GLuint uniform_MVP, uniform_TM, uniform_TIMV, uniform_tex; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_texture); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &TextureMatrix, unsigned TU_texture); +}; + +class GrassPass1Shader +{ +public: + static GLuint Program; + static GLuint attrib_position, attrib_texcoord, attrib_normal, attrib_color; + static GLuint uniform_MVP, uniform_TIMV, uniform_tex, uniform_windDir; + + static void init(); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::vector3df &windDirection, unsigned TU_tex); +}; + +class NormalMapShader +{ +public: + static GLuint Program; + static GLuint attrib_position, attrib_texcoord, attrib_tangent, attrib_bitangent; + static GLuint uniform_MVP, uniform_TIMV, uniform_normalMap; + + static void init(); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_normalMap); }; class ObjectPass2Shader @@ -53,21 +80,11 @@ class ObjectPass2Shader public: static GLuint Program; static GLuint attrib_position, attrib_texcoord; - static GLuint uniform_MVP, uniform_Albedo, uniform_DiffuseMap, uniform_SpecularMap, uniform_SSAO, uniform_screen, uniform_ambient; + static GLuint uniform_MVP, uniform_TM, uniform_screen, uniform_ambient; + static GLuint TU_Albedo; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO); -}; - -class MovingTextureShader -{ -public: - static GLuint Program; - static GLuint attrib_position, attrib_texcoord; - static GLuint uniform_MVP, uniform_TM, uniform_Albedo, uniform_DiffuseMap, uniform_SpecularMap, uniform_SSAO, uniform_screen, uniform_ambient; - - static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix); }; class DetailledObjectPass2Shader @@ -75,10 +92,11 @@ class DetailledObjectPass2Shader public: static GLuint Program; static GLuint attrib_position, attrib_texcoord, attrib_second_texcoord; - static GLuint uniform_MVP, uniform_Albedo, uniform_Detail, uniform_DiffuseMap, uniform_SpecularMap, uniform_SSAO, uniform_screen, uniform_ambient; + static GLuint uniform_MVP, uniform_screen, uniform_ambient; + static GLuint TU_Albedo, TU_detail; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_Albedo, unsigned TU_detail, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix); }; class ObjectRimLimitShader @@ -86,10 +104,11 @@ class ObjectRimLimitShader public: static GLuint Program; static GLuint attrib_position, attrib_normal, attrib_texcoord; - static GLuint uniform_MVP, uniform_TIMV, uniform_Albedo, uniform_DiffuseMap, uniform_SpecularMap, uniform_SSAO, uniform_screen, uniform_ambient; + static GLuint uniform_MVP, uniform_TIMV, uniform_TM, uniform_screen, uniform_ambient; + static GLuint TU_Albedo; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &TextureMatrix); }; class UntexturedObjectShader @@ -97,10 +116,10 @@ class UntexturedObjectShader public: static GLuint Program; static GLuint attrib_position, attrib_color; - static GLuint uniform_MVP, uniform_DiffuseMap, uniform_SpecularMap, uniform_SSAO, uniform_screen, uniform_ambient; + static GLuint uniform_MVP, uniform_screen, uniform_ambient; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix); }; class ObjectUnlitShader @@ -108,10 +127,11 @@ class ObjectUnlitShader public: static GLuint Program; static GLuint attrib_position, attrib_texcoord; - static GLuint uniform_MVP, uniform_tex; + static GLuint uniform_MVP; + static GLuint TU_tex; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_tex); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix); }; class ObjectRefPass2Shader @@ -119,21 +139,11 @@ class ObjectRefPass2Shader public: static GLuint Program; static GLuint attrib_position, attrib_texcoord; - static GLuint uniform_MVP, uniform_Albedo, uniform_DiffuseMap, uniform_SpecularMap, uniform_SSAO, uniform_screen, uniform_ambient; + static GLuint uniform_MVP, uniform_TM, uniform_screen, uniform_ambient; + static GLuint TU_Albedo; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO); -}; - -class GrassPass1Shader -{ -public: - static GLuint Program; - static GLuint attrib_position, attrib_texcoord, attrib_normal, attrib_color; - static GLuint uniform_MVP, uniform_TIMV, uniform_tex, uniform_windDir; - - static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::vector3df &windDirection, unsigned TU_tex); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix); }; class GrassPass2Shader @@ -141,21 +151,11 @@ class GrassPass2Shader public: static GLuint Program; static GLuint attrib_position, attrib_texcoord, attrib_color; - static GLuint uniform_MVP, uniform_Albedo, uniform_DiffuseMap, uniform_SpecularMap, uniform_SSAO, uniform_screen, uniform_ambient, uniform_windDir; + static GLuint uniform_MVP, uniform_screen, uniform_ambient, uniform_windDir; + static GLuint TU_Albedo; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::vector3df &windDirection, unsigned TU_Albedo, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO); -}; - -class NormalMapShader -{ -public: - static GLuint Program; - static GLuint attrib_position, attrib_texcoord, attrib_tangent, attrib_bitangent; - static GLuint uniform_MVP, uniform_TIMV, uniform_normalMap; - - static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_normalMap); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::vector3df &windDirection); }; class SphereMapShader @@ -163,10 +163,11 @@ class SphereMapShader public: static GLuint Program; static GLuint attrib_position, attrib_normal; - static GLuint uniform_MVP, uniform_TIMV, uniform_tex; + static GLuint uniform_MVP, uniform_TIMV, uniform_TVM, uniform_invproj, uniform_screen; + static GLuint TU_tex; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_tex); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeViewMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &InvProj, const core::vector2df& screen); }; class SplattingShader @@ -174,10 +175,23 @@ class SplattingShader public: static GLuint Program; static GLuint attrib_position, attrib_texcoord, attrib_second_texcoord; - static GLuint uniform_MVP, uniform_tex_layout, uniform_tex_detail0, uniform_tex_detail1, uniform_tex_detail2, uniform_tex_detail3, uniform_DiffuseMap, uniform_SpecularMap, uniform_SSAO, uniform_screen, uniform_ambient; + static GLuint uniform_MVP, uniform_screen, uniform_ambient; + static GLuint TU_tex_layout, TU_tex_detail0, TU_tex_detail1, TU_tex_detail2, TU_tex_detail3; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, unsigned TU_tex_layout, unsigned TU_tex_detail0, unsigned TU_tex_detail1, unsigned TU_tex_detail2, unsigned TU_tex_detail3, unsigned TU_DiffuseMap, unsigned TU_SpecularMap, unsigned TU_SSAO); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix); +}; + +class CausticsShader +{ +public: + static GLuint Program; + static GLuint attrib_position, attrib_texcoord; + static GLuint uniform_MVP, uniform_dir, uniform_dir2, uniform_screen, uniform_ambient; + static GLuint TU_Albedo, TU_caustictex; + + static void init(); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::vector2df &dir, const core::vector2df &dir2, const core::vector2df &screen); }; class BubbleShader @@ -213,6 +227,18 @@ public: static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix, const core::matrix4 &ipvmat, float fogmax, float startH, float endH, float start, float end, const core::vector3df &col, const core::vector3df &campos, unsigned TU_tex); }; +class PointLightShader +{ +public: + static GLuint Program; + static GLuint attrib_Position, attrib_Energy, attrib_Color; + static GLuint attrib_Corner; + static GLuint uniform_ntex, uniform_dtex, uniform_spec, uniform_screen, uniform_invproj, uniform_VM, uniform_PM; + + static void init(); + static void setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 &InvProjMatrix, const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex); +}; + class BillboardShader { public: @@ -269,15 +295,37 @@ public: static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::vector3df &windDirection, unsigned TU_tex); }; +class DisplaceMaskShader +{ +public: + static GLuint Program; + static GLuint attrib_position; + static GLuint uniform_MVP; + + static void init(); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix); +}; + class DisplaceShader { public: static GLuint Program; static GLuint attrib_position, attrib_texcoord, attrib_second_texcoord; - static GLuint uniform_MVP, uniform_MV, uniform_tex, uniform_dir, uniform_dir2; + static GLuint uniform_MVP, uniform_MV, uniform_displacement_tex, uniform_mask_tex, uniform_color_tex, uniform_screen, uniform_dir, uniform_dir2; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &ModelViewMatrix, float dirX, float dirY, float dir2X, float dir2Y, unsigned TU_tex); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &ModelViewMatrix, const core::vector2df &dir, const core::vector2df &dir2, const core::vector2df &screen, unsigned TU_displacement_tex, unsigned TU_mask_tex, unsigned TU_color_tex); +}; + +class SkyboxShader +{ +public: + static GLuint Program; + static GLuint attrib_position; + static GLuint uniform_MVP, uniform_InvProjView, uniform_tex, uniform_screen; + + static void init(); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &InvProjView, const core::vector2df &screen, unsigned TU_tex); }; } @@ -354,37 +402,16 @@ public: static void init(); }; -class PPDisplaceShader -{ -public: - static GLuint Program; - static GLuint uniform_tex, uniform_dtex, uniform_viz; - static GLuint vao; - - static void init(); -}; - class ColorLevelShader { public: static GLuint Program; - static GLuint uniform_tex, uniform_inlevel, uniform_outlevel; + static GLuint uniform_tex, uniform_invprojm, uniform_dtex, uniform_inlevel, uniform_outlevel; static GLuint vao; static void init(); }; -class PointLightShader -{ -public: - static GLuint Program; - static GLuint uniform_ntex, uniform_dtex, uniform_center, uniform_col, uniform_energy, uniform_spec, uniform_invproj, uniform_viewm; - static GLuint vao; - - static void init(); - static void setUniforms(const core::matrix4 &InvProjMatrix, const core::matrix4 &ViewMatrix, const std::vector &positions, const std::vector &colors, const std::vector &energy, unsigned spec, unsigned TU_ntex, unsigned TU_dtex); -}; - class SunLightShader { public: @@ -396,6 +423,17 @@ public: static void setUniforms(const core::vector3df &direction, const core::matrix4 &InvProjMatrix, float r, float g, float b, unsigned TU_ntex, unsigned TU_dtex); }; +class DiffuseEnvMapShader +{ +public: + static GLuint Program; + static GLuint uniform_ntex, uniform_TVM, uniform_blueLmn, uniform_greenLmn, uniform_redLmn; + static GLuint vao; + + static void init(); + static void setUniforms(const core::matrix4 &TransposeViewMatrix, const float *blueSHCoeff, const float *greenSHCoeff, const float *redSHCoeff, unsigned TU_ntex); +}; + class ShadowedSunLightShader { public: @@ -534,6 +572,28 @@ public: static void setUniforms(float boost_amount, const core::vector2df ¢er, const core::vector2df &direction, float mask_radius, float max_tex_height, unsigned TU_cb); }; +class GodFadeShader +{ +public: + static GLuint Program; + static GLuint uniform_tex, uniform_col; + static GLuint vao; + + static void init(); + static void setUniforms(const video::SColor &col, unsigned TU_tex); +}; + +class GodRayShader +{ +public: + static GLuint Program; + static GLuint uniform_tex, uniform_sunpos; + static GLuint vao; + + static void init(); + static void setUniforms(const core::vector2df &sunpos, unsigned TU_tex); +}; + } namespace UIShader @@ -601,8 +661,6 @@ public: ACT(ES_MLAA_COLOR1) \ ACT(ES_MLAA_BLEND2) \ ACT(ES_MLAA_NEIGH3) \ - ACT(ES_GODFADE) \ - ACT(ES_GODRAY) \ ACT(ES_SHADOWPASS) \ ACT(ES_SHADOW_IMPORTANCE) \ ACT(ES_COLLAPSE) \ diff --git a/src/graphics/slip_stream.cpp b/src/graphics/slip_stream.cpp index e2cccdc4f..b662e8d92 100644 --- a/src/graphics/slip_stream.cpp +++ b/src/graphics/slip_stream.cpp @@ -18,6 +18,7 @@ #include "graphics/slip_stream.hpp" +#include "config/user_config.hpp" #include "graphics/material.hpp" #include "graphics/material_manager.hpp" #include "graphics/irr_driver.hpp" diff --git a/src/graphics/stkanimatedmesh.cpp b/src/graphics/stkanimatedmesh.cpp index ab1248359..8bb937dd1 100644 --- a/src/graphics/stkanimatedmesh.cpp +++ b/src/graphics/stkanimatedmesh.cpp @@ -23,72 +23,52 @@ void STKAnimatedMesh::setMesh(scene::IAnimatedMesh* mesh) { firstTime = true; GLmeshes.clear(); + for (unsigned i = 0; i < FPSM_COUNT; i++) + GeometricMesh[i].clear(); + for (unsigned i = 0; i < SM_COUNT; i++) + ShadedMesh[i].clear(); CAnimatedMeshSceneNode::setMesh(mesh); } -void STKAnimatedMesh::drawTransparent(const GLMesh &mesh, video::E_MATERIAL_TYPE type) +void STKAnimatedMesh::drawSolidPass1(const GLMesh &mesh, GeometricMaterial type) { - assert(irr_driver->getPhase() == TRANSPARENT_PASS); - - computeMVP(ModelViewProjectionMatrix); - - if (World::getWorld()->getTrack()->isFogEnabled()) - drawTransparentFogObject(mesh, ModelViewProjectionMatrix, core::matrix4::EM4CONST_IDENTITY); - else - drawTransparentObject(mesh, ModelViewProjectionMatrix, core::matrix4::EM4CONST_IDENTITY); - - return; + switch (type) + { + case FPSM_ALPHA_REF_TEXTURE: + drawObjectRefPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView, mesh.TextureMatrix); + break; + case FPSM_DEFAULT: + drawObjectPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); + break; + default: + assert(0 && "Wrong geometric material"); + break; + } } -void STKAnimatedMesh::drawSolid(const GLMesh &mesh, video::E_MATERIAL_TYPE type) +void STKAnimatedMesh::drawSolidPass2(const GLMesh &mesh, ShadedMaterial type) { - switch (irr_driver->getPhase()) - { - case SOLID_NORMAL_AND_DEPTH_PASS: - { - computeMVP(ModelViewProjectionMatrix); - computeTIMV(TransposeInverseModelView); - - if (type == irr_driver->getShader(ES_OBJECTPASS_REF)) - drawObjectRefPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); - else - drawObjectPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); - break; - } - case SOLID_LIT_PASS: - { - if (type == irr_driver->getShader(ES_OBJECTPASS_REF)) - drawObjectRefPass2(mesh, ModelViewProjectionMatrix); - else if (type == irr_driver->getShader(ES_OBJECTPASS_RIMLIT)) - drawObjectRimLimit(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); - else if (type == irr_driver->getShader(ES_OBJECT_UNLIT)) - drawObjectUnlit(mesh, ModelViewProjectionMatrix); - else if (mesh.textures[1]) - drawDetailledObjectPass2(mesh, ModelViewProjectionMatrix); - else - drawObjectPass2(mesh, ModelViewProjectionMatrix); - break; - } - default: - { - assert(0 && "wrong pass"); - } - } -} - -void STKAnimatedMesh::drawShadow(const GLMesh &mesh) -{ - GLenum ptype = mesh.PrimitiveType; - GLenum itype = mesh.IndexType; - size_t count = mesh.IndexCount; - assert(irr_driver->getPhase() == SHADOW_PASS); - std::vector ShadowMVP(irr_driver->getShadowViewProj()); - for (unsigned i = 0; i < ShadowMVP.size(); i++) - ShadowMVP[i] *= irr_driver->getVideoDriver()->getTransform(video::ETS_WORLD); - glUseProgram(MeshShader::ShadowShader::Program); - MeshShader::ShadowShader::setUniforms(ShadowMVP); - glBindVertexArray(mesh.vao_shadow_pass); - glDrawElements(ptype, count, itype, 0); + switch (type) + { + case SM_ALPHA_REF_TEXTURE: + drawObjectRefPass2(mesh, ModelViewProjectionMatrix, mesh.TextureMatrix); + break; + case SM_RIMLIT: + drawObjectRimLimit(mesh, ModelViewProjectionMatrix, TransposeInverseModelView, mesh.TextureMatrix); + break; + case SM_UNLIT: + drawObjectUnlit(mesh, ModelViewProjectionMatrix); + break; + case SM_DETAILS: + drawDetailledObjectPass2(mesh, ModelViewProjectionMatrix); + break; + case SM_DEFAULT: + drawObjectPass2(mesh, ModelViewProjectionMatrix, mesh.TextureMatrix); + break; + default: + assert(0 && "Wrong shaded material"); + break; + } } void STKAnimatedMesh::render() @@ -114,53 +94,142 @@ void STKAnimatedMesh::render() driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); - if (firstTime) - for (u32 i = 0; igetMeshBufferCount(); ++i) - { - scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); - GLmeshes.push_back(allocateMeshBuffer(mb)); - } + if (firstTime) + { + for (u32 i = 0; i < m->getMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); + GLmeshes.push_back(allocateMeshBuffer(mb)); + } + + for (u32 i = 0; i < m->getMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); + if (!mb) + continue; + video::E_MATERIAL_TYPE type = mb->getMaterial().MaterialType; + video::IMaterialRenderer* rnd = driver->getMaterialRenderer(type); + if (!isObject(type)) + { +#ifdef DEBUG + Log::warn("material", "Unhandled (animated) material type : %d", type); +#endif + continue; + } + GLMesh &mesh = GLmeshes[i]; + if (rnd->isTransparent()) + { + TransparentMaterial TranspMat = MaterialTypeToTransparentMaterial(type); + initvaostate(mesh, TranspMat); + TransparentMesh[TranspMat].push_back(&mesh); + } + else + { + GeometricMaterial GeometricType = MaterialTypeToGeometricMaterial(type); + ShadedMaterial ShadedType = MaterialTypeToShadedMaterial(type, mesh.textures); + initvaostate(mesh, GeometricType, ShadedType); + GeometricMesh[GeometricType].push_back(&mesh); + ShadedMesh[ShadedType].push_back(&mesh); + } + } + } firstTime = false; - // render original meshes - for (u32 i = 0; igetMeshBufferCount(); ++i) - { - video::IMaterialRenderer* rnd = driver->getMaterialRenderer(Materials[i].MaterialType); - bool transparent = (rnd && rnd->isTransparent()); - - // only render transparent buffer if this is the transparent render pass - // and solid only in solid pass - if (transparent != isTransparentPass) - continue; - scene::IMeshBuffer* mb = m->getMeshBuffer(i); - const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i]; - if (RenderFromIdentity) - driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); - else if (Mesh->getMeshType() == scene::EAMT_SKINNED) - driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((scene::SSkinMeshBuffer*)mb)->Transformation); + for (u32 i = 0; igetMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = m->getMeshBuffer(i); + const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i]; if (isObject(material.MaterialType)) - { - irr_driver->IncreaseObjectCount(); - initvaostate(GLmeshes[i], material.MaterialType, false); - if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS) - { - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, GLmeshes[i].vertex_buffer); - glBufferSubData(GL_ARRAY_BUFFER, 0, mb->getVertexCount() * GLmeshes[i].Stride, mb->getVertices()); - } - if (irr_driver->getPhase() == SHADOW_PASS) - drawShadow(GLmeshes[i]); - else if (isTransparentPass) - drawTransparent(GLmeshes[i], material.MaterialType); - else - drawSolid(GLmeshes[i], material.MaterialType); - } - else - { -#ifdef DEBUG - Log::warn("material", "Unhandled (animated) material type : %d", material.MaterialType); -#endif - continue; - } - } + { + if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS) + { + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, GLmeshes[i].vertex_buffer); + glBufferSubData(GL_ARRAY_BUFFER, 0, mb->getVertexCount() * GLmeshes[i].Stride, mb->getVertices()); + } + } + if (mb) + GLmeshes[i].TextureMatrix = getMaterial(i).getTextureMatrix(0); + + video::IMaterialRenderer* rnd = driver->getMaterialRenderer(Materials[i].MaterialType); + bool transparent = (rnd && rnd->isTransparent()); + + // only render transparent buffer if this is the transparent render pass + // and solid only in solid pass + if (transparent != isTransparentPass) + continue; + + if (RenderFromIdentity) + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + else if (Mesh->getMeshType() == scene::EAMT_SKINNED) + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((scene::SSkinMeshBuffer*)mb)->Transformation); + + } + + if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS) + { + computeMVP(ModelViewProjectionMatrix); + computeTIMV(TransposeInverseModelView); + + glUseProgram(MeshShader::ObjectPass1Shader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++) + drawSolidPass1(*GeometricMesh[FPSM_DEFAULT][i], FPSM_DEFAULT); + + glUseProgram(MeshShader::ObjectRefPass1Shader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_ALPHA_REF_TEXTURE].size(); i++) + drawSolidPass1(*GeometricMesh[FPSM_ALPHA_REF_TEXTURE][i], FPSM_ALPHA_REF_TEXTURE); + + return; + } + + if (irr_driver->getPhase() == SOLID_LIT_PASS) + { + glUseProgram(MeshShader::ObjectPass2Shader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_DEFAULT].size(); i++) + drawSolidPass2(*ShadedMesh[SM_DEFAULT][i], SM_DEFAULT); + + glUseProgram(MeshShader::ObjectRefPass2Shader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_ALPHA_REF_TEXTURE].size(); i++) + drawSolidPass2(*ShadedMesh[SM_ALPHA_REF_TEXTURE][i], SM_ALPHA_REF_TEXTURE); + + glUseProgram(MeshShader::ObjectRimLimitShader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_RIMLIT].size(); i++) + drawSolidPass2(*ShadedMesh[SM_RIMLIT][i], SM_RIMLIT); + + glUseProgram(MeshShader::ObjectUnlitShader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_UNLIT].size(); i++) + drawSolidPass2(*ShadedMesh[SM_UNLIT][i], SM_UNLIT); + + glUseProgram(MeshShader::DetailledObjectPass2Shader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_DETAILS].size(); i++) + drawSolidPass2(*ShadedMesh[SM_DETAILS][i], SM_DETAILS); + + return; + } + + if (irr_driver->getPhase() == SHADOW_PASS) + { + glUseProgram(MeshShader::ShadowShader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++) + drawShadow(*GeometricMesh[FPSM_DEFAULT][i]); + + glUseProgram(MeshShader::RefShadowShader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_ALPHA_REF_TEXTURE].size(); i++) + drawShadowRef(*GeometricMesh[FPSM_ALPHA_REF_TEXTURE][i]); + return; + } + + if (irr_driver->getPhase() == TRANSPARENT_PASS) + { + computeMVP(ModelViewProjectionMatrix); + + glUseProgram(MeshShader::BubbleShader::Program); + for (unsigned i = 0; i < TransparentMesh[TM_BUBBLE].size(); i++) + drawBubble(*TransparentMesh[TM_BUBBLE][i], ModelViewProjectionMatrix); + + glUseProgram(MeshShader::TransparentShader::Program); + for (unsigned i = 0; i < TransparentMesh[TM_DEFAULT].size(); i++) + drawTransparentObject(*TransparentMesh[TM_DEFAULT][i], ModelViewProjectionMatrix, (*TransparentMesh[TM_DEFAULT][i]).TextureMatrix); + return; + } } diff --git a/src/graphics/stkanimatedmesh.hpp b/src/graphics/stkanimatedmesh.hpp index 1df7fc005..20521b2d3 100644 --- a/src/graphics/stkanimatedmesh.hpp +++ b/src/graphics/stkanimatedmesh.hpp @@ -11,11 +11,13 @@ class STKAnimatedMesh : public irr::scene::CAnimatedMeshSceneNode { protected: bool firstTime; + std::vector GeometricMesh[FPSM_COUNT]; + std::vector ShadedMesh[SM_COUNT]; + std::vector TransparentMesh[TM_COUNT]; std::vector GLmeshes; - core::matrix4 ModelViewProjectionMatrix, TransposeInverseModelView; - void drawSolid(const GLMesh &mesh, video::E_MATERIAL_TYPE type); - void drawTransparent(const GLMesh &mesh, video::E_MATERIAL_TYPE type); - void drawShadow(const GLMesh &mesh); + core::matrix4 ModelViewProjectionMatrix, TransposeInverseModelView; + void drawSolidPass1(const GLMesh &mesh, GeometricMaterial type); + void drawSolidPass2(const GLMesh &mesh, ShadedMaterial type); public: STKAnimatedMesh(irr::scene::IAnimatedMesh* mesh, irr::scene::ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id, diff --git a/src/graphics/stkbillboard.cpp b/src/graphics/stkbillboard.cpp index ee24b1270..2f4d5f578 100644 --- a/src/graphics/stkbillboard.cpp +++ b/src/graphics/stkbillboard.cpp @@ -5,23 +5,13 @@ using namespace irr; -static GLuint billboardvbo; static GLuint billboardvao = 0; static void createbillboardvao() { - float quad[] = { - -.5, -.5, 0., 1., - -.5, .5, 0., 0., - .5, -.5, 1., 1., - .5, .5, 1., 0., - }; - - glGenBuffers(1, &billboardvbo); glGenVertexArrays(1, &billboardvao); glBindVertexArray(billboardvao); - glBindBuffer(GL_ARRAY_BUFFER, billboardvbo); - glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), quad, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, SharedObject::billboardvbo); glEnableVertexAttribArray(MeshShader::BillboardShader::attrib_corner); glEnableVertexAttribArray(MeshShader::BillboardShader::attrib_texcoord); glVertexAttribPointer(MeshShader::BillboardShader::attrib_corner, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); diff --git a/src/graphics/stkmesh.cpp b/src/graphics/stkmesh.cpp index 90ff143d7..98ac9d682 100644 --- a/src/graphics/stkmesh.cpp +++ b/src/graphics/stkmesh.cpp @@ -9,6 +9,49 @@ #include "graphics/camera.hpp" #include "modes/world.hpp" +GeometricMaterial MaterialTypeToGeometricMaterial(video::E_MATERIAL_TYPE MaterialType) +{ + if (MaterialType == irr_driver->getShader(ES_NORMAL_MAP)) + return FPSM_NORMAL_MAP; + else if (MaterialType == irr_driver->getShader(ES_OBJECTPASS_REF) || MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF) + return FPSM_ALPHA_REF_TEXTURE; + else if (MaterialType == irr_driver->getShader(ES_GRASS) || MaterialType == irr_driver->getShader(ES_GRASS_REF)) + return FPSM_GRASS; + else + return FPSM_DEFAULT; +} + +ShadedMaterial MaterialTypeToShadedMaterial(video::E_MATERIAL_TYPE type, GLuint *textures) +{ + if (type == irr_driver->getShader(ES_SPHERE_MAP)) + return SM_SPHEREMAP; + else if (type == irr_driver->getShader(ES_SPLATTING)) + return SM_SPLATTING; + else if (type == irr_driver->getShader(ES_OBJECTPASS_REF) || type == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF) + return SM_ALPHA_REF_TEXTURE; + else if (type == irr_driver->getShader(ES_OBJECTPASS_RIMLIT)) + return SM_RIMLIT; + else if (type == irr_driver->getShader(ES_GRASS) || type == irr_driver->getShader(ES_GRASS_REF)) + return SM_GRASS; + else if (type == irr_driver->getShader(ES_OBJECT_UNLIT)) + return SM_UNLIT; + else if (type == irr_driver->getShader(ES_CAUSTICS)) + return SM_CAUSTICS; + else if (textures[1] && type != irr_driver->getShader(ES_NORMAL_MAP)) + return SM_DETAILS; + else if (!textures[0]) + return SM_UNTEXTURED; + else + return SM_DEFAULT; +} + +TransparentMaterial MaterialTypeToTransparentMaterial(video::E_MATERIAL_TYPE type) +{ + if (type == irr_driver->getShader(ES_BUBBLES)) + return TM_BUBBLE; + else + return TM_DEFAULT; +} GLuint createVAO(GLuint vbo, GLuint idx, GLuint attrib_position, GLuint attrib_texcoord, GLuint attrib_second_texcoord, GLuint attrib_normal, GLuint attrib_tangent, GLuint attrib_bitangent, GLuint attrib_color, size_t stride) { @@ -141,6 +184,7 @@ GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb) else result.textures[i] = 0; } + result.TextureMatrix = 0; return result; } @@ -162,20 +206,20 @@ void computeTIMV(core::matrix4 &TransposeInverseModelView) void drawObjectPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView) { + irr_driver->IncreaseObjectCount(); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; - glUseProgram(MeshShader::ObjectPass1Shader::Program); MeshShader::ObjectPass1Shader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView); glBindVertexArray(mesh.vao_first_pass); glDrawElements(ptype, count, itype, 0); } -void drawObjectRefPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView) +void drawObjectRefPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &TextureMatrix) { - glDisable(GL_CULL_FACE); + irr_driver->IncreaseObjectCount(); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; @@ -183,23 +227,21 @@ void drawObjectRefPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProje setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - glUseProgram(MeshShader::ObjectRefPass1Shader::Program); - MeshShader::ObjectRefPass1Shader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView, 0); + MeshShader::ObjectRefPass1Shader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView, TextureMatrix, 0); glBindVertexArray(mesh.vao_first_pass); glDrawElements(ptype, count, itype, 0); - glEnable(GL_CULL_FACE); } void drawGrassPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, core::vector3df windDir) { + irr_driver->IncreaseObjectCount(); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - glUseProgram(MeshShader::GrassPass1Shader::Program); MeshShader::GrassPass1Shader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView, windDir, 0); glBindVertexArray(mesh.vao_first_pass); @@ -208,6 +250,7 @@ void drawGrassPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectio void drawNormalPass(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView) { + irr_driver->IncreaseObjectCount(); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; @@ -215,7 +258,6 @@ void drawNormalPass(const GLMesh &mesh, const core::matrix4 & ModelViewProjectio assert(mesh.textures[1]); setTexture(0, mesh.textures[1], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - glUseProgram(MeshShader::NormalMapShader::Program); MeshShader::NormalMapShader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView, 0); glBindVertexArray(mesh.vao_first_pass); @@ -224,27 +266,44 @@ void drawNormalPass(const GLMesh &mesh, const core::matrix4 & ModelViewProjectio void drawSphereMap(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView) { + irr_driver->IncreaseObjectCount(); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + glActiveTexture(GL_TEXTURE0 + MeshShader::SphereMapShader::TU_tex); + if (!irr_driver->SkyboxCubeMap) + { + GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ONE }; + glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else + { + glBindTexture(GL_TEXTURE_CUBE_MAP, irr_driver->SkyboxCubeMap); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } - glUseProgram(MeshShader::SphereMapShader::Program); - MeshShader::SphereMapShader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView, 0); + MeshShader::SphereMapShader::setUniforms(ModelViewProjectionMatrix, irr_driver->getViewMatrix().getTransposed(), TransposeInverseModelView, irr_driver->getInvProjMatrix(), core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height)); glBindVertexArray(mesh.vao_second_pass); glDrawElements(ptype, count, itype, 0); + if (!irr_driver->SkyboxCubeMap) + { + GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } } void drawSplatting(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) { + irr_driver->IncreaseObjectCount(); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; // Texlayout - setTexture(0, mesh.textures[1], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + setTexture(MeshShader::SplattingShader::TU_tex_layout, mesh.textures[1], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); if (irr_driver->getLightViz()) { GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; @@ -256,7 +315,7 @@ void drawSplatting(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionM glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } //Tex detail0 - setTexture(1, mesh.textures[2], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + setTexture(MeshShader::SplattingShader::TU_tex_detail0, mesh.textures[2], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); if (irr_driver->getLightViz()) { GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; @@ -268,7 +327,7 @@ void drawSplatting(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionM glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } //Tex detail1 - setTexture(2, mesh.textures[3], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + setTexture(MeshShader::SplattingShader::TU_tex_detail1, mesh.textures[3], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); if (irr_driver->getLightViz()) { GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; @@ -280,7 +339,7 @@ void drawSplatting(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionM glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } //Tex detail2 - setTexture(3, mesh.textures[4], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + setTexture(MeshShader::SplattingShader::TU_tex_detail2, mesh.textures[4], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); if (irr_driver->getLightViz()) { GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; @@ -292,196 +351,7 @@ void drawSplatting(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionM glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } //Tex detail3 - setTexture(4, mesh.textures[5], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - if (irr_driver->getLightViz()) - { - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - else - { - GLint swizzleMask[] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - // Diffuse - setTexture(5, getTextureGLuint(irr_driver->getRTT(RTT_TMP1)), GL_NEAREST, GL_NEAREST); - - // Specular - setTexture(6, getTextureGLuint(irr_driver->getRTT(RTT_TMP2)), GL_NEAREST, GL_NEAREST); - - // SSAO - setTexture(7, getTextureGLuint(irr_driver->getRTT(RTT_SSAO)), GL_NEAREST, GL_NEAREST); - if (!UserConfigParams::m_ssao) - { - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ONE}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - - glUseProgram(MeshShader::SplattingShader::Program); - MeshShader::SplattingShader::setUniforms(ModelViewProjectionMatrix, 0, 1, 2, 3, 4, 5, 6, 7); - - glBindVertexArray(mesh.vao_second_pass); - glDrawElements(ptype, count, itype, 0); -} - -void drawObjectRefPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) -{ - glDisable(GL_CULL_FACE); - GLenum ptype = mesh.PrimitiveType; - GLenum itype = mesh.IndexType; - size_t count = mesh.IndexCount; - - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - if (irr_driver->getLightViz()) - { - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - else - { - GLint swizzleMask[] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - setTexture(1, getTextureGLuint(irr_driver->getRTT(RTT_TMP1)), GL_NEAREST, GL_NEAREST); - setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_TMP2)), GL_NEAREST, GL_NEAREST); - setTexture(3, getTextureGLuint(irr_driver->getRTT(RTT_SSAO)), GL_NEAREST, GL_NEAREST); - if (!UserConfigParams::m_ssao) - { - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ONE}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - - glUseProgram(MeshShader::ObjectRefPass2Shader::Program); - MeshShader::ObjectRefPass2Shader::setUniforms(ModelViewProjectionMatrix, 0, 1, 2, 3); - - glBindVertexArray(mesh.vao_second_pass); - glDrawElements(ptype, count, itype, 0); - glEnable(GL_CULL_FACE); -} - -void drawGrassPass2(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, core::vector3df windDir) -{ - GLenum ptype = mesh.PrimitiveType; - GLenum itype = mesh.IndexType; - size_t count = mesh.IndexCount; - - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - if (irr_driver->getLightViz()) - { - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - else - { - GLint swizzleMask[] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - setTexture(1, getTextureGLuint(irr_driver->getRTT(RTT_TMP1)), GL_NEAREST, GL_NEAREST); - setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_TMP2)), GL_NEAREST, GL_NEAREST); - setTexture(3, getTextureGLuint(irr_driver->getRTT(RTT_SSAO)), GL_NEAREST, GL_NEAREST); - if (!UserConfigParams::m_ssao) - { - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ONE}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - - glUseProgram(MeshShader::GrassPass2Shader::Program); - MeshShader::GrassPass2Shader::setUniforms(ModelViewProjectionMatrix, windDir, 0, 1, 2, 3); - - glBindVertexArray(mesh.vao_second_pass); - glDrawElements(ptype, count, itype, 0); -} - -void drawUntexturedObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) -{ - GLenum ptype = mesh.PrimitiveType; - GLenum itype = mesh.IndexType; - size_t count = mesh.IndexCount; - - setTexture(0, getTextureGLuint(irr_driver->getRTT(RTT_TMP1)), GL_NEAREST, GL_NEAREST); - setTexture(1, getTextureGLuint(irr_driver->getRTT(RTT_TMP2)), GL_NEAREST, GL_NEAREST); - setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_SSAO)), GL_NEAREST, GL_NEAREST); - if (!UserConfigParams::m_ssao) - { - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ONE}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - - - glUseProgram(MeshShader::UntexturedObjectShader::Program); - MeshShader::UntexturedObjectShader::setUniforms(ModelViewProjectionMatrix, 0, 1, 2); - - glBindVertexArray(mesh.vao_second_pass); - glDrawElements(ptype, count, itype, 0); -} - -void drawObjectRimLimit(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView) -{ - GLenum ptype = mesh.PrimitiveType; - GLenum itype = mesh.IndexType; - size_t count = mesh.IndexCount; - - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - if (irr_driver->getLightViz()) - { - GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - else - { - GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - - setTexture(1, getTextureGLuint(irr_driver->getRTT(RTT_TMP1)), GL_NEAREST, GL_NEAREST); - setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_TMP2)), GL_NEAREST, GL_NEAREST); - setTexture(3, getTextureGLuint(irr_driver->getRTT(RTT_SSAO)), GL_NEAREST, GL_NEAREST); - if (!UserConfigParams::m_ssao) - { - GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ONE }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - - glUseProgram(MeshShader::ObjectRimLimitShader::Program); - MeshShader::ObjectRimLimitShader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView, 0, 1, 2, 3); - - glBindVertexArray(mesh.vao_second_pass); - glDrawElements(ptype, count, itype, 0); -} - -void drawObjectUnlit(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) -{ - GLenum ptype = mesh.PrimitiveType; - GLenum itype = mesh.IndexType; - size_t count = mesh.IndexCount; - - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - if (irr_driver->getLightViz()) - { - GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - else - { - GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - - - glUseProgram(MeshShader::ObjectUnlitShader::Program); - MeshShader::ObjectUnlitShader::setUniforms(ModelViewProjectionMatrix, 0); - - glBindVertexArray(mesh.vao_second_pass); - glDrawElements(ptype, count, itype, 0); -} - -void drawDetailledObjectPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) -{ - GLenum ptype = mesh.PrimitiveType; - GLenum itype = mesh.IndexType; - size_t count = mesh.IndexCount; - - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + setTexture(MeshShader::SplattingShader::TU_tex_detail3, mesh.textures[5], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); if (irr_driver->getLightViz()) { GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; @@ -493,65 +363,45 @@ void drawDetailledObjectPass2(const GLMesh &mesh, const core::matrix4 &ModelView glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } - setTexture(1, mesh.textures[1], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - - setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_TMP1)), GL_NEAREST, GL_NEAREST); - setTexture(3, getTextureGLuint(irr_driver->getRTT(RTT_TMP2)), GL_NEAREST, GL_NEAREST); - setTexture(4, getTextureGLuint(irr_driver->getRTT(RTT_SSAO)), GL_NEAREST, GL_NEAREST); - if (!UserConfigParams::m_ssao) - { - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ONE}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - - glUseProgram(MeshShader::DetailledObjectPass2Shader::Program); - MeshShader::DetailledObjectPass2Shader::setUniforms(ModelViewProjectionMatrix, 0, 1, 2, 3, 4); + MeshShader::SplattingShader::setUniforms(ModelViewProjectionMatrix); glBindVertexArray(mesh.vao_second_pass); glDrawElements(ptype, count, itype, 0); } -void drawObjectPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) +void drawObjectRefPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix) { - GLenum ptype = mesh.PrimitiveType; - GLenum itype = mesh.IndexType; - size_t count = mesh.IndexCount; + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - if (irr_driver->getLightViz()) - { - GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - else - { - GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } + setTexture(MeshShader::ObjectRefPass2Shader::TU_Albedo, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + if (irr_driver->getLightViz()) + { + GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else + { + GLint swizzleMask[] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } - setTexture(1, getTextureGLuint(irr_driver->getRTT(RTT_TMP1)), GL_NEAREST, GL_NEAREST); - setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_TMP2)), GL_NEAREST, GL_NEAREST); - setTexture(3, getTextureGLuint(irr_driver->getRTT(RTT_SSAO)), GL_NEAREST, GL_NEAREST); - if (!UserConfigParams::m_ssao) - { - GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ONE }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } + MeshShader::ObjectRefPass2Shader::setUniforms(ModelViewProjectionMatrix, TextureMatrix); - glUseProgram(MeshShader::ObjectPass2Shader::Program); - MeshShader::ObjectPass2Shader::setUniforms(ModelViewProjectionMatrix, 0, 1, 2, 3); - - glBindVertexArray(mesh.vao_second_pass); - glDrawElements(ptype, count, itype, 0); + glBindVertexArray(mesh.vao_second_pass); + glDrawElements(ptype, count, itype, 0); } -void drawMovingTexture(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix) +void drawCaustics(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, core::vector2df dir, core::vector2df dir2) { + irr_driver->IncreaseObjectCount(); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + setTexture(MeshShader::CausticsShader::TU_Albedo, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); if (irr_driver->getLightViz()) { GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA }; @@ -562,32 +412,163 @@ void drawMovingTexture(const GLMesh &mesh, const core::matrix4 &ModelViewProject GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } + setTexture(MeshShader::CausticsShader::TU_caustictex, getTextureGLuint(irr_driver->getTexture(file_manager->getAsset("textures/caustics.png").c_str())), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - setTexture(1, getTextureGLuint(irr_driver->getRTT(RTT_TMP1)), GL_NEAREST, GL_NEAREST); - setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_TMP2)), GL_NEAREST, GL_NEAREST); - setTexture(3, getTextureGLuint(irr_driver->getRTT(RTT_SSAO)), GL_NEAREST, GL_NEAREST); - if (!UserConfigParams::m_ssao) - { - GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ONE }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - - glUseProgram(MeshShader::MovingTextureShader::Program); - MeshShader::MovingTextureShader::setUniforms(ModelViewProjectionMatrix, TextureMatrix, 0, 1, 2, 3); + MeshShader::CausticsShader::setUniforms(ModelViewProjectionMatrix, dir, dir2, core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height)); glBindVertexArray(mesh.vao_second_pass); glDrawElements(ptype, count, itype, 0); } +void drawGrassPass2(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, core::vector3df windDir) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + setTexture(MeshShader::GrassPass2Shader::TU_Albedo, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + if (irr_driver->getLightViz()) + { + GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else + { + GLint swizzleMask[] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + + MeshShader::GrassPass2Shader::setUniforms(ModelViewProjectionMatrix, windDir); + + glBindVertexArray(mesh.vao_second_pass); + glDrawElements(ptype, count, itype, 0); +} + +void drawUntexturedObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + MeshShader::UntexturedObjectShader::setUniforms(ModelViewProjectionMatrix); + + glBindVertexArray(mesh.vao_second_pass); + glDrawElements(ptype, count, itype, 0); +} + +void drawObjectRimLimit(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &TextureMatrix) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + setTexture(MeshShader::ObjectRimLimitShader::TU_Albedo, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + if (irr_driver->getLightViz()) + { + GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else + { + GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + + MeshShader::ObjectRimLimitShader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView, TextureMatrix); + + glBindVertexArray(mesh.vao_second_pass); + glDrawElements(ptype, count, itype, 0); +} + +void drawObjectUnlit(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + setTexture(MeshShader::ObjectUnlitShader::TU_tex, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + if (irr_driver->getLightViz()) + { + GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else + { + GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + + MeshShader::ObjectUnlitShader::setUniforms(ModelViewProjectionMatrix); + + glBindVertexArray(mesh.vao_second_pass); + glDrawElements(ptype, count, itype, 0); +} + +void drawDetailledObjectPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + setTexture(MeshShader::DetailledObjectPass2Shader::TU_Albedo, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + if (irr_driver->getLightViz()) + { + GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else + { + GLint swizzleMask[] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + + setTexture(MeshShader::DetailledObjectPass2Shader::TU_detail, mesh.textures[1], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + + MeshShader::DetailledObjectPass2Shader::setUniforms(ModelViewProjectionMatrix); + + glBindVertexArray(mesh.vao_second_pass); + glDrawElements(ptype, count, itype, 0); +} + +void drawObjectPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + setTexture(MeshShader::ObjectPass2Shader::TU_Albedo, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + if (irr_driver->getLightViz()) + { + GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ALPHA }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else + { + GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + + MeshShader::ObjectPass2Shader::setUniforms(ModelViewProjectionMatrix, TextureMatrix); + + glBindVertexArray(mesh.vao_second_pass); + glDrawElements(ptype, count, itype, 0); +} + void drawTransparentObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix) { + irr_driver->IncreaseObjectCount(); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - glUseProgram(MeshShader::TransparentShader::Program); MeshShader::TransparentShader::setUniforms(ModelViewProjectionMatrix, TextureMatrix, 0); glBindVertexArray(mesh.vao_first_pass); @@ -596,6 +577,7 @@ void drawTransparentObject(const GLMesh &mesh, const core::matrix4 &ModelViewPro void drawTransparentFogObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix) { + irr_driver->IncreaseObjectCount(); GLenum ptype = mesh.PrimitiveType; GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; @@ -625,6 +607,7 @@ void drawTransparentFogObject(const GLMesh &mesh, const core::matrix4 &ModelView void drawBubble(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix) { + irr_driver->IncreaseObjectCount(); const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; float transparency = 1.; @@ -634,13 +617,54 @@ void drawBubble(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatr setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - glUseProgram(MeshShader::BubbleShader::Program); MeshShader::BubbleShader::setUniforms(ModelViewProjectionMatrix, 0, time, transparency); glBindVertexArray(mesh.vao_first_pass); glDrawElements(ptype, count, itype, 0); } +void drawShadowRef(const GLMesh &mesh) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + std::vector ShadowMVP(irr_driver->getShadowViewProj()); + for (unsigned i = 0; i < ShadowMVP.size(); i++) + ShadowMVP[i] *= irr_driver->getVideoDriver()->getTransform(video::ETS_WORLD); + + setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + MeshShader::RefShadowShader::setUniforms(ShadowMVP, 0); + + glBindVertexArray(mesh.vao_shadow_pass); + glDrawElements(ptype, count, itype, 0); +} + +void drawShadow(const GLMesh &mesh) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + std::vector ShadowMVP(irr_driver->getShadowViewProj()); + for (unsigned i = 0; i < ShadowMVP.size(); i++) + ShadowMVP[i] *= irr_driver->getVideoDriver()->getTransform(video::ETS_WORLD); + + /* if (type == irr_driver->getShader(ES_GRASS) || type == irr_driver->getShader(ES_GRASS_REF)) + { + setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + glUseProgram(MeshShader::GrassShadowShader::Program); + MeshShader::GrassShadowShader::setUniforms(ShadowMVP, windDir, 0); + }*/ + + MeshShader::ShadowShader::setUniforms(ShadowMVP); + + glBindVertexArray(mesh.vao_shadow_pass); + glDrawElements(ptype, count, itype, 0); +} + bool isObject(video::E_MATERIAL_TYPE type) { if (type == irr_driver->getShader(ES_OBJECTPASS)) @@ -663,142 +687,127 @@ bool isObject(video::E_MATERIAL_TYPE type) return true; if (type == irr_driver->getShader(ES_OBJECT_UNLIT)) return true; + if (type == irr_driver->getShader(ES_CAUSTICS)) + return true; if (type == video::EMT_TRANSPARENT_ALPHA_CHANNEL) return true; if (type == video::EMT_ONETEXTURE_BLEND) return true; if (type == video::EMT_TRANSPARENT_ADD_COLOR) return true; + if (type == video::EMT_SOLID) + return true; + if (type == video::EMT_LIGHTMAP_LIGHTING) + return true; + if (type == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF) + return true; return false; } -void initvaostate(GLMesh &mesh, video::E_MATERIAL_TYPE type, bool MovingTexture) +void initvaostate(GLMesh &mesh, GeometricMaterial GeoMat, ShadedMaterial ShadedMat) { - switch (irr_driver->getPhase()) - { - case SOLID_NORMAL_AND_DEPTH_PASS: - if (mesh.vao_first_pass) - return; - if (type == irr_driver->getShader(ES_NORMAL_MAP)) - { - mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::NormalMapShader::attrib_position, MeshShader::NormalMapShader::attrib_texcoord, -1, -1, MeshShader::NormalMapShader::attrib_tangent, MeshShader::NormalMapShader::attrib_bitangent, -1, mesh.Stride); - } - else if (type == irr_driver->getShader(ES_OBJECTPASS_REF)) - { - mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::ObjectPass1Shader::attrib_position, MeshShader::ObjectRefPass1Shader::attrib_texcoord, -1, MeshShader::ObjectPass1Shader::attrib_normal, -1, -1, -1, mesh.Stride); - } - else if (type == irr_driver->getShader(ES_GRASS) || type == irr_driver->getShader(ES_GRASS_REF)) - { - mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::GrassPass1Shader::attrib_position, MeshShader::GrassPass1Shader::attrib_texcoord, -1, MeshShader::GrassPass1Shader::attrib_normal, -1, -1, MeshShader::GrassPass1Shader::attrib_color, mesh.Stride); - } - else - { - mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::ObjectPass1Shader::attrib_position, -1, -1, MeshShader::ObjectPass1Shader::attrib_normal, -1, -1, -1, mesh.Stride); - } - return; - case SOLID_LIT_PASS: - if (mesh.vao_second_pass) - return; - if (type == irr_driver->getShader(ES_SPHERE_MAP)) - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::SphereMapShader::attrib_position, -1, -1, MeshShader::SphereMapShader::attrib_normal, -1, -1, -1, mesh.Stride); - } - else if (type == irr_driver->getShader(ES_SPLATTING)) - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::SplattingShader::attrib_position, MeshShader::SplattingShader::attrib_texcoord, MeshShader::SplattingShader::attrib_second_texcoord, -1, -1, -1, -1, mesh.Stride); - } - else if (type == irr_driver->getShader(ES_OBJECTPASS_REF)) - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::ObjectRefPass2Shader::attrib_position, MeshShader::ObjectRefPass2Shader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); - } - else if (type == irr_driver->getShader(ES_OBJECTPASS_RIMLIT)) - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::ObjectRimLimitShader::attrib_position, MeshShader::ObjectRimLimitShader::attrib_texcoord, -1, MeshShader::ObjectRimLimitShader::attrib_normal, -1, -1, -1, mesh.Stride); - } - else if (type == irr_driver->getShader(ES_GRASS) || type == irr_driver->getShader(ES_GRASS_REF)) - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::GrassPass2Shader::attrib_position, MeshShader::GrassPass2Shader::attrib_texcoord, -1, -1, -1, -1, MeshShader::GrassPass2Shader::attrib_color, mesh.Stride); - } - else if (type == irr_driver->getShader(ES_OBJECT_UNLIT)) - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::ObjectUnlitShader::attrib_position, MeshShader::ObjectUnlitShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); - } - else if (mesh.textures[1]) - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::DetailledObjectPass2Shader::attrib_position, MeshShader::DetailledObjectPass2Shader::attrib_texcoord, MeshShader::DetailledObjectPass2Shader::attrib_second_texcoord, -1, -1, -1, -1, mesh.Stride); - } - else if (!mesh.textures[0]) - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::UntexturedObjectShader::attrib_position, -1, -1, -1, -1, -1, MeshShader::UntexturedObjectShader::attrib_color, mesh.Stride); - } - else if (MovingTexture) - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::MovingTextureShader::attrib_position, MeshShader::MovingTextureShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); - } - else - { - mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::ObjectPass2Shader::attrib_position, MeshShader::ObjectPass2Shader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); - } - return; - case GLOW_PASS: - if (mesh.vao_glow_pass) - return; - mesh.vao_glow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::ColorizeShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride); - return; - case TRANSPARENT_PASS: - if (mesh.vao_first_pass) - return; - if (type == irr_driver->getShader(ES_BUBBLES)) - { - mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::BubbleShader::attrib_position, MeshShader::BubbleShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); - } - else if (World::getWorld()->getTrack()->isFogEnabled()) - { - mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::TransparentFogShader::attrib_position, MeshShader::TransparentFogShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); - } - else - { - mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, - MeshShader::TransparentShader::attrib_position, MeshShader::TransparentShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); - } - return; - case DISPLACEMENT_PASS: - if (mesh.vao_displace_pass) - return; - mesh.vao_displace_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::DisplaceShader::attrib_position, MeshShader::DisplaceShader::attrib_texcoord, MeshShader::DisplaceShader::attrib_second_texcoord, -1, -1, -1, -1, mesh.Stride); - return; - case SHADOW_PASS: - if (mesh.vao_shadow_pass) - return; - if (type == irr_driver->getShader(ES_OBJECTPASS_REF)) - { - mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::RefShadowShader::attrib_position, MeshShader::RefShadowShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); - } - /*else if (type == irr_driver->getShader(ES_GRASS) || type == irr_driver->getShader(ES_GRASS_REF)) - { - mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::GrassShadowShader::attrib_position, MeshShader::GrassShadowShader::attrib_texcoord, -1, -1, -1, -1, MeshShader::GrassShadowShader::attrib_color, mesh.Stride); - }*/ - else - { - mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::ShadowShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride); - } - return; - } + switch (GeoMat) + { + case FPSM_DEFAULT: + mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::ObjectPass1Shader::attrib_position, -1, -1, MeshShader::ObjectPass1Shader::attrib_normal, -1, -1, -1, mesh.Stride); + mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::ShadowShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride); + break; + case FPSM_ALPHA_REF_TEXTURE: + mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::ObjectRefPass1Shader::attrib_position, MeshShader::ObjectRefPass1Shader::attrib_texcoord, -1, MeshShader::ObjectRefPass1Shader::attrib_normal, -1, -1, -1, mesh.Stride); + mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::RefShadowShader::attrib_position, MeshShader::RefShadowShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); + break; + case FPSM_NORMAL_MAP: + mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::NormalMapShader::attrib_position, MeshShader::NormalMapShader::attrib_texcoord, -1, -1, MeshShader::NormalMapShader::attrib_tangent, MeshShader::NormalMapShader::attrib_bitangent, -1, mesh.Stride); + mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::ShadowShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride); + break; + case FPSM_GRASS: + mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::GrassPass1Shader::attrib_position, MeshShader::GrassPass1Shader::attrib_texcoord, -1, MeshShader::GrassPass1Shader::attrib_normal, -1, -1, MeshShader::GrassPass1Shader::attrib_color, mesh.Stride); + mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::GrassShadowShader::attrib_position, MeshShader::GrassShadowShader::attrib_texcoord, -1, -1, -1, -1, MeshShader::GrassShadowShader::attrib_color, mesh.Stride); + break; + default: + assert(0 && "Unknow material"); + break; + } + + switch (ShadedMat) + { + case SM_SPHEREMAP: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::SphereMapShader::attrib_position, -1, -1, MeshShader::SphereMapShader::attrib_normal, -1, -1, -1, mesh.Stride); + break; + case SM_SPLATTING: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::SplattingShader::attrib_position, MeshShader::SplattingShader::attrib_texcoord, MeshShader::SplattingShader::attrib_second_texcoord, -1, -1, -1, -1, mesh.Stride); + break; + case SM_ALPHA_REF_TEXTURE: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::ObjectRefPass2Shader::attrib_position, MeshShader::ObjectRefPass2Shader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); + break; + case SM_RIMLIT: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::ObjectRimLimitShader::attrib_position, MeshShader::ObjectRimLimitShader::attrib_texcoord, -1, MeshShader::ObjectRimLimitShader::attrib_normal, -1, -1, -1, mesh.Stride); + break; + case SM_GRASS: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::GrassPass2Shader::attrib_position, MeshShader::GrassPass2Shader::attrib_texcoord, -1, -1, -1, -1, MeshShader::GrassPass2Shader::attrib_color, mesh.Stride); + break; + case SM_UNLIT: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::ObjectUnlitShader::attrib_position, MeshShader::ObjectUnlitShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); + break; + case SM_CAUSTICS: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::CausticsShader::attrib_position, MeshShader::CausticsShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); + break; + case SM_DETAILS: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::DetailledObjectPass2Shader::attrib_position, MeshShader::DetailledObjectPass2Shader::attrib_texcoord, MeshShader::DetailledObjectPass2Shader::attrib_second_texcoord, -1, -1, -1, -1, mesh.Stride); + break; + case SM_UNTEXTURED: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::UntexturedObjectShader::attrib_position, -1, -1, -1, -1, -1, MeshShader::UntexturedObjectShader::attrib_color, mesh.Stride); + break; + case SM_DEFAULT: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::ObjectPass2Shader::attrib_position, MeshShader::ObjectPass2Shader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); + break; + default: + assert(0 && "unknow shaded material"); + break; + } + + mesh.vao_glow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::ColorizeShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride); + mesh.vao_displace_mask_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::DisplaceShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride); + if (mesh.Stride >= 44) + mesh.vao_displace_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::DisplaceShader::attrib_position, MeshShader::DisplaceShader::attrib_texcoord, MeshShader::DisplaceShader::attrib_second_texcoord, -1, -1, -1, -1, mesh.Stride); +} + +void initvaostate(GLMesh &mesh, TransparentMaterial TranspMat) +{ + switch (TranspMat) + { + case TM_BUBBLE: + mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::BubbleShader::attrib_position, MeshShader::BubbleShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); + break; + case TM_DEFAULT: + mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::TransparentShader::attrib_position, MeshShader::TransparentShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); + break; + } + mesh.vao_displace_mask_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::DisplaceShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride); + if (mesh.Stride >= 44) + mesh.vao_displace_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::DisplaceShader::attrib_position, MeshShader::DisplaceShader::attrib_texcoord, MeshShader::DisplaceShader::attrib_second_texcoord, -1, -1, -1, -1, mesh.Stride); + +/* +else if (World::getWorld()->getTrack()->isFogEnabled()) +{ +mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, +MeshShader::TransparentFogShader::attrib_position, MeshShader::TransparentFogShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); +}*/ } diff --git a/src/graphics/stkmesh.hpp b/src/graphics/stkmesh.hpp index 9fcb7f9db..d24834ed7 100644 --- a/src/graphics/stkmesh.hpp +++ b/src/graphics/stkmesh.hpp @@ -8,11 +8,43 @@ #include "glwrap.hpp" #include +enum GeometricMaterial +{ + FPSM_DEFAULT, + FPSM_ALPHA_REF_TEXTURE, + FPSM_NORMAL_MAP, + FPSM_GRASS, + FPSM_COUNT +}; + +enum ShadedMaterial +{ + SM_DEFAULT, + SM_ALPHA_REF_TEXTURE, + SM_RIMLIT, + SM_SPHEREMAP, + SM_SPLATTING, + SM_GRASS, + SM_UNLIT, + SM_CAUSTICS, + SM_DETAILS, + SM_UNTEXTURED, + SM_COUNT +}; + +enum TransparentMaterial +{ + TM_DEFAULT, + TM_BUBBLE, + TM_COUNT +}; + struct GLMesh { GLuint vao_first_pass; GLuint vao_second_pass; GLuint vao_glow_pass; GLuint vao_displace_pass; + GLuint vao_displace_mask_pass; GLuint vao_shadow_pass; GLuint vertex_buffer; GLuint index_buffer; @@ -21,11 +53,13 @@ struct GLMesh { GLenum IndexType; size_t IndexCount; size_t Stride; + core::matrix4 TextureMatrix; }; GLuint createVAO(GLuint vbo, GLuint idx, GLuint attrib_position, GLuint attrib_texcoord, GLuint attrib_second_texcoord, GLuint attrib_normal, GLuint attrib_tangent, GLuint attrib_bitangent, GLuint attrib_color, size_t stride); GLMesh allocateMeshBuffer(scene::IMeshBuffer* mb); -void initvaostate(GLMesh &mesh, video::E_MATERIAL_TYPE type, bool moving_texture); +void initvaostate(GLMesh &mesh, GeometricMaterial GeoMat, ShadedMaterial ShadedMat); +void initvaostate(GLMesh &mesh, TransparentMaterial TranspMat); void computeMVP(core::matrix4 &ModelViewProjectionMatrix); void computeTIMV(core::matrix4 &TransposeInverseModelView); bool isObject(video::E_MATERIAL_TYPE type); @@ -33,24 +67,32 @@ bool isObject(video::E_MATERIAL_TYPE type); // Pass 1 shader (ie shaders that outputs normals and depth) void drawObjectPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView); void drawNormalPass(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView); -void drawObjectRefPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView); +void drawObjectRefPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &TextureMatrix); void drawGrassPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, core::vector3df windDir); // Pass 2 shader (ie shaders that outputs final color) void drawDetailledObjectPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix); -void drawObjectPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix); -void drawMovingTexture(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix); +void drawObjectPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix); void drawUntexturedObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix); -void drawObjectRefPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix); +void drawObjectRefPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix); void drawSphereMap(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView); void drawSplatting(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix); +void drawCaustics(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, core::vector2df dir, core::vector2df dir2); void drawGrassPass2(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, core::vector3df windDir); -void drawObjectRimLimit(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView); +void drawObjectRimLimit(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &TextureMatrix); void drawObjectUnlit(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix); +// Shadow pass +void drawShadowRef(const GLMesh &mesh); +void drawShadow(const GLMesh &mesh); + // Forward pass (for transparents meshes) void drawTransparentObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix); void drawTransparentFogObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix); void drawBubble(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix); -#endif // STKMESH_H \ No newline at end of file +GeometricMaterial MaterialTypeToGeometricMaterial(video::E_MATERIAL_TYPE); +ShadedMaterial MaterialTypeToShadedMaterial(video::E_MATERIAL_TYPE, GLuint *textures); +TransparentMaterial MaterialTypeToTransparentMaterial(video::E_MATERIAL_TYPE); + +#endif // STKMESH_H diff --git a/src/graphics/stkmeshscenenode.cpp b/src/graphics/stkmeshscenenode.cpp index c0112297e..045fef6c6 100644 --- a/src/graphics/stkmeshscenenode.cpp +++ b/src/graphics/stkmeshscenenode.cpp @@ -42,6 +42,46 @@ void STKMeshSceneNode::createGLMeshes() scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); GLmeshes.push_back(allocateMeshBuffer(mb)); } + isMaterialInitialized = false; +} + +void STKMeshSceneNode::setFirstTimeMaterial() +{ + if (isMaterialInitialized) + return; + irr::video::IVideoDriver* driver = irr_driver->getVideoDriver(); + for (u32 i = 0; igetMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); + if (!mb) + continue; + video::E_MATERIAL_TYPE type = mb->getMaterial().MaterialType; + video::IMaterialRenderer* rnd = driver->getMaterialRenderer(type); + if (!isObject(type)) + { +#ifdef DEBUG + Log::warn("material", "Unhandled (static) material type : %d", type); +#endif + continue; + } + + GLMesh &mesh = GLmeshes[i]; + if (rnd->isTransparent()) + { + TransparentMaterial TranspMat = MaterialTypeToTransparentMaterial(type); + initvaostate(mesh, TranspMat); + TransparentMesh[TranspMat].push_back(&mesh); + } + else + { + GeometricMaterial GeometricType = MaterialTypeToGeometricMaterial(type); + ShadedMaterial ShadedType = MaterialTypeToShadedMaterial(type, mesh.textures); + initvaostate(mesh, GeometricType, ShadedType); + GeometricMesh[GeometricType].push_back(&mesh); + ShadedMesh[ShadedType].push_back(&mesh); + } + } + isMaterialInitialized = true; } void STKMeshSceneNode::cleanGLMeshes() @@ -63,6 +103,10 @@ void STKMeshSceneNode::cleanGLMeshes() glDeleteBuffers(1, &(mesh.index_buffer)); } GLmeshes.clear(); + for (unsigned i = 0; i < FPSM_COUNT; i++) + GeometricMesh[i].clear(); + for (unsigned i = 0; i < SM_COUNT; i++) + ShadedMesh[i].clear(); } void STKMeshSceneNode::setMesh(irr::scene::IMesh* mesh) @@ -86,7 +130,6 @@ void STKMeshSceneNode::drawGlow(const GLMesh &mesh) size_t count = mesh.IndexCount; computeMVP(ModelViewProjectionMatrix); - glUseProgram(MeshShader::ColorizeShader::Program); MeshShader::ColorizeShader::setUniforms(ModelViewProjectionMatrix, cb->getRed(), cb->getGreen(), cb->getBlue()); glBindVertexArray(mesh.vao_glow_pass); @@ -104,9 +147,24 @@ void STKMeshSceneNode::drawDisplace(const GLMesh &mesh) computeMVP(ModelViewProjectionMatrix); core::matrix4 ModelViewMatrix = irr_driver->getVideoDriver()->getTransform(video::ETS_VIEW); ModelViewMatrix *= irr_driver->getVideoDriver()->getTransform(video::ETS_WORLD); + + // Generate displace mask + // Use RTT_TMP4 as displace mask + irr_driver->getVideoDriver()->setRenderTarget(irr_driver->getRTT(RTT_TMP4), false, false); + + glUseProgram(MeshShader::DisplaceMaskShader::Program); + MeshShader::DisplaceMaskShader::setUniforms(ModelViewProjectionMatrix); + + glBindVertexArray(mesh.vao_displace_mask_pass); + glDrawElements(ptype, count, itype, 0); + + // Render the effect + irr_driver->getVideoDriver()->setRenderTarget(irr_driver->getRTT(RTT_DISPLACE), false, false); setTexture(0, getTextureGLuint(irr_driver->getTexture(FileManager::TEXTURE, "displace.png")), GL_LINEAR, GL_LINEAR, true); + setTexture(1, getTextureGLuint(irr_driver->getRTT(RTT_TMP4)), GL_LINEAR, GL_LINEAR, true); + setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_COLOR)), GL_LINEAR, GL_LINEAR, true); glUseProgram(MeshShader::DisplaceShader::Program); - MeshShader::DisplaceShader::setUniforms(ModelViewProjectionMatrix, ModelViewMatrix, cb->getDirX(), cb->getDirY(), cb->getDir2X(), cb->getDir2Y(), 0); + MeshShader::DisplaceShader::setUniforms(ModelViewProjectionMatrix, ModelViewMatrix, core::vector2df(cb->getDirX(), cb->getDirY()), core::vector2df(cb->getDir2X(), cb->getDir2Y()), core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height), 0, 1, 2); glBindVertexArray(mesh.vao_displace_pass); glDrawElements(ptype, count, itype, 0); @@ -120,95 +178,92 @@ void STKMeshSceneNode::drawTransparent(const GLMesh &mesh, video::E_MATERIAL_TYP if (type == irr_driver->getShader(ES_BUBBLES)) drawBubble(mesh, ModelViewProjectionMatrix); - else if (World::getWorld()->getTrack()->isFogEnabled()) - drawTransparentFogObject(mesh, ModelViewProjectionMatrix, TextureMatrix); +// else if (World::getWorld()->getTrack()->isFogEnabled()) +// drawTransparentFogObject(mesh, ModelViewProjectionMatrix, TextureMatrix); else - drawTransparentObject(mesh, ModelViewProjectionMatrix, TextureMatrix); + drawTransparentObject(mesh, ModelViewProjectionMatrix, mesh.TextureMatrix); return; } -void STKMeshSceneNode::drawShadow(const GLMesh &mesh, video::E_MATERIAL_TYPE type) +void STKMeshSceneNode::drawSolidPass1(const GLMesh &mesh, GeometricMaterial type) { - - GLenum ptype = mesh.PrimitiveType; - GLenum itype = mesh.IndexType; - size_t count = mesh.IndexCount; - - - std::vector ShadowMVP(irr_driver->getShadowViewProj()); - for (unsigned i = 0; i < ShadowMVP.size(); i++) - ShadowMVP[i] *= irr_driver->getVideoDriver()->getTransform(video::ETS_WORLD); - - if (type == irr_driver->getShader(ES_OBJECTPASS_REF)) + irr_driver->IncreaseObjectCount(); + windDir = getWind(); + switch (type) { - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - glUseProgram(MeshShader::RefShadowShader::Program); - MeshShader::RefShadowShader::setUniforms(ShadowMVP, 0); + case FPSM_NORMAL_MAP: + drawNormalPass(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); + break; + case FPSM_ALPHA_REF_TEXTURE: + drawObjectRefPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView, mesh.TextureMatrix); + break; + case FPSM_GRASS: + drawGrassPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView, windDir); + break; + case FPSM_DEFAULT: + drawObjectPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); + break; + default: + assert(0 && "wrong geometric material"); } - /* else if (type == irr_driver->getShader(ES_GRASS) || type == irr_driver->getShader(ES_GRASS_REF)) - { - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); - glUseProgram(MeshShader::GrassShadowShader::Program); - MeshShader::GrassShadowShader::setUniforms(ShadowMVP, windDir, 0); - }*/ - else - { - glUseProgram(MeshShader::ShadowShader::Program); - MeshShader::ShadowShader::setUniforms(ShadowMVP); - } - glBindVertexArray(mesh.vao_shadow_pass); - glDrawElements(ptype, count, itype, 0); } -void STKMeshSceneNode::drawSolid(const GLMesh &mesh, video::E_MATERIAL_TYPE type) +void STKMeshSceneNode::drawSolidPass2(const GLMesh &mesh, ShadedMaterial type) { - switch (irr_driver->getPhase()) + switch (type) { - case SOLID_NORMAL_AND_DEPTH_PASS: + case SM_SPHEREMAP: + drawSphereMap(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); + break; + case SM_SPLATTING: + drawSplatting(mesh, ModelViewProjectionMatrix); + break; + case SM_ALPHA_REF_TEXTURE: + drawObjectRefPass2(mesh, ModelViewProjectionMatrix, mesh.TextureMatrix); + break; + case SM_GRASS: + drawGrassPass2(mesh, ModelViewProjectionMatrix, windDir); + break; + case SM_RIMLIT: + drawObjectRimLimit(mesh, ModelViewProjectionMatrix, TransposeInverseModelView, core::matrix4::EM4CONST_IDENTITY); + break; + case SM_UNLIT: + drawObjectUnlit(mesh, ModelViewProjectionMatrix); + break; + case SM_CAUSTICS: { - windDir = getWind(); + const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + const float speed = World::getWorld()->getTrack()->getCausticsSpeed(); - computeMVP(ModelViewProjectionMatrix); - computeTIMV(TransposeInverseModelView); + float strength = time; + strength = fabsf(noise2d(strength / 10.0f)) * 0.006f + 0.001f; - if (type == irr_driver->getShader(ES_NORMAL_MAP)) - drawNormalPass(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); - else if (type == irr_driver->getShader(ES_OBJECTPASS_REF)) - drawObjectRefPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); - else if (type == irr_driver->getShader(ES_GRASS) || type == irr_driver->getShader(ES_GRASS_REF)) - drawGrassPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView, windDir); - else - drawObjectPass1(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); + vector3df wind = irr_driver->getWind() * strength * speed; + caustic_dir.X += wind.X; + caustic_dir.Y += 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)); + caustic_dir2.X += wind.X; + caustic_dir2.Y += wind.Z; + drawCaustics(mesh, ModelViewProjectionMatrix, caustic_dir, caustic_dir2); break; } - case SOLID_LIT_PASS: - { - if (type == irr_driver->getShader(ES_SPHERE_MAP)) - drawSphereMap(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); - else if (type == irr_driver->getShader(ES_SPLATTING)) - drawSplatting(mesh, ModelViewProjectionMatrix); - else if (type == irr_driver->getShader(ES_OBJECTPASS_REF)) - drawObjectRefPass2(mesh, ModelViewProjectionMatrix); - else if (type == irr_driver->getShader(ES_GRASS) || type == irr_driver->getShader(ES_GRASS_REF)) - drawGrassPass2(mesh, ModelViewProjectionMatrix, windDir); - else if (type == irr_driver->getShader(ES_OBJECTPASS_RIMLIT)) - drawObjectRimLimit(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); - else if (type == irr_driver->getShader(ES_OBJECT_UNLIT)) - drawObjectUnlit(mesh, ModelViewProjectionMatrix); - else if (mesh.textures[1] && type != irr_driver->getShader(ES_NORMAL_MAP)) - drawDetailledObjectPass2(mesh, ModelViewProjectionMatrix); - else if (!mesh.textures[0]) - drawUntexturedObject(mesh, ModelViewProjectionMatrix); - else if (!TextureMatrix.isIdentity()) - drawMovingTexture(mesh, ModelViewProjectionMatrix, TextureMatrix); - else - drawObjectPass2(mesh, ModelViewProjectionMatrix); + case SM_DETAILS: + drawDetailledObjectPass2(mesh, ModelViewProjectionMatrix); + break; + case SM_UNTEXTURED: + drawUntexturedObject(mesh, ModelViewProjectionMatrix); + break; + case SM_DEFAULT: + drawObjectPass2(mesh, ModelViewProjectionMatrix, mesh.TextureMatrix); break; - } default: - { - assert(0 && "wrong pass"); - } + assert(0 && "Wrong shaded material"); + break; } } @@ -227,54 +282,131 @@ void STKMeshSceneNode::render() driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); Box = Mesh->getBoundingBox(); - for (u32 i = 0; igetMeshBufferCount(); ++i) + setFirstTimeMaterial(); + + for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i) { scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); - if (mb) + if (!mb) + continue; + GLmeshes[i].TextureMatrix = getMaterial(i).getTextureMatrix(0); + } + + if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS) + { + computeMVP(ModelViewProjectionMatrix); + computeTIMV(TransposeInverseModelView); + + glUseProgram(MeshShader::ObjectPass1Shader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++) + drawSolidPass1(*GeometricMesh[FPSM_DEFAULT][i], FPSM_DEFAULT); + + glUseProgram(MeshShader::ObjectRefPass1Shader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_ALPHA_REF_TEXTURE].size(); i++) + drawSolidPass1(*GeometricMesh[FPSM_ALPHA_REF_TEXTURE][i], FPSM_ALPHA_REF_TEXTURE); + + glUseProgram(MeshShader::NormalMapShader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_NORMAL_MAP].size(); i++) + drawSolidPass1(*GeometricMesh[FPSM_NORMAL_MAP][i], FPSM_NORMAL_MAP); + + glUseProgram(MeshShader::GrassPass1Shader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_GRASS].size(); i++) + drawSolidPass1(*GeometricMesh[FPSM_GRASS][i], FPSM_GRASS); + + return; + } + + if (irr_driver->getPhase() == SOLID_LIT_PASS) + { + glUseProgram(MeshShader::ObjectPass2Shader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_DEFAULT].size(); i++) + drawSolidPass2(*ShadedMesh[SM_DEFAULT][i], SM_DEFAULT); + + glUseProgram(MeshShader::ObjectRefPass2Shader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_ALPHA_REF_TEXTURE].size(); i++) + drawSolidPass2(*ShadedMesh[SM_ALPHA_REF_TEXTURE][i], SM_ALPHA_REF_TEXTURE); + + glUseProgram(MeshShader::ObjectRimLimitShader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_RIMLIT].size(); i++) + drawSolidPass2(*ShadedMesh[SM_RIMLIT][i], SM_RIMLIT); + + glUseProgram(MeshShader::SphereMapShader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_SPHEREMAP].size(); i++) + drawSolidPass2(*ShadedMesh[SM_SPHEREMAP][i], SM_SPHEREMAP); + + glUseProgram(MeshShader::SplattingShader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_SPLATTING].size(); i++) + drawSolidPass2(*ShadedMesh[SM_SPLATTING][i], SM_SPLATTING); + + glUseProgram(MeshShader::GrassPass2Shader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_GRASS].size(); i++) + drawSolidPass2(*ShadedMesh[SM_GRASS][i], SM_GRASS); + + glUseProgram(MeshShader::ObjectUnlitShader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_UNLIT].size(); i++) + drawSolidPass2(*ShadedMesh[SM_UNLIT][i], SM_UNLIT); + + glUseProgram(MeshShader::CausticsShader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_CAUSTICS].size(); i++) + drawSolidPass2(*ShadedMesh[SM_CAUSTICS][i], SM_CAUSTICS); + + glUseProgram(MeshShader::DetailledObjectPass2Shader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_DETAILS].size(); i++) + drawSolidPass2(*ShadedMesh[SM_DETAILS][i], SM_DETAILS); + + glUseProgram(MeshShader::UntexturedObjectShader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_UNTEXTURED].size(); i++) + drawSolidPass2(*ShadedMesh[SM_UNTEXTURED][i], SM_UNTEXTURED); + + return; + } + + if (irr_driver->getPhase() == SHADOW_PASS) + { + glUseProgram(MeshShader::ShadowShader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++) + drawShadow(*GeometricMesh[FPSM_DEFAULT][i]); + + glUseProgram(MeshShader::RefShadowShader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_ALPHA_REF_TEXTURE].size(); i++) + drawShadowRef(*GeometricMesh[FPSM_ALPHA_REF_TEXTURE][i]); + return; + } + + if (irr_driver->getPhase() == GLOW_PASS) + { + glUseProgram(MeshShader::ColorizeShader::Program); + for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i) { - TextureMatrix = getMaterial(i).getTextureMatrix(0); - const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i]; - - video::IMaterialRenderer* rnd = driver->getMaterialRenderer(material.MaterialType); - bool transparent = (rnd && rnd->isTransparent()); - - if (isTransparentPass != transparent) + scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); + if (!mb) continue; - if (irr_driver->getPhase() == DISPLACEMENT_PASS) - { - initvaostate(GLmeshes[i], material.MaterialType, false); - drawDisplace(GLmeshes[i]); - continue; - } - if (!isObject(material.MaterialType)) - { -#ifdef DEBUG - Log::warn("material", "Unhandled (static) material type : %d", material.MaterialType); -#endif - continue; - } + drawGlow(GLmeshes[i]); + } + } - // only render transparent buffer if this is the transparent render pass - // and solid only in solid pass - if (irr_driver->getPhase() == GLOW_PASS) - { - initvaostate(GLmeshes[i], material.MaterialType, TextureMatrix.isIdentity()); - drawGlow(GLmeshes[i]); - } - else if (irr_driver->getPhase() == SHADOW_PASS) - { - initvaostate(GLmeshes[i], material.MaterialType, TextureMatrix.isIdentity()); - drawShadow(GLmeshes[i], material.MaterialType); - } - else - { - irr_driver->IncreaseObjectCount(); - initvaostate(GLmeshes[i], material.MaterialType, TextureMatrix.isIdentity()); - if (transparent) - drawTransparent(GLmeshes[i], material.MaterialType); - else - drawSolid(GLmeshes[i], material.MaterialType); - } + if (irr_driver->getPhase() == TRANSPARENT_PASS) + { + computeMVP(ModelViewProjectionMatrix); + + glUseProgram(MeshShader::BubbleShader::Program); + for (unsigned i = 0; i < TransparentMesh[TM_BUBBLE].size(); i++) + drawBubble(*TransparentMesh[TM_BUBBLE][i], ModelViewProjectionMatrix); + + glUseProgram(MeshShader::TransparentShader::Program); + for (unsigned i = 0; i < TransparentMesh[TM_DEFAULT].size(); i++) + drawTransparentObject(*TransparentMesh[TM_DEFAULT][i], ModelViewProjectionMatrix, (*TransparentMesh[TM_DEFAULT][i]).TextureMatrix); + return; + } + + if (irr_driver->getPhase() == DISPLACEMENT_PASS) + { + for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); + if (!mb) + continue; + drawDisplace(GLmeshes[i]); } } } diff --git a/src/graphics/stkmeshscenenode.hpp b/src/graphics/stkmeshscenenode.hpp index eca1979d9..afc628335 100644 --- a/src/graphics/stkmeshscenenode.hpp +++ b/src/graphics/stkmeshscenenode.hpp @@ -6,18 +6,24 @@ class STKMeshSceneNode : public irr::scene::CMeshSceneNode { protected: + std::vector GeometricMesh[FPSM_COUNT]; + std::vector ShadedMesh[SM_COUNT]; + std::vector TransparentMesh[TM_COUNT]; std::vector GLmeshes; - core::matrix4 ModelViewProjectionMatrix, TransposeInverseModelView, TextureMatrix; + core::matrix4 ModelViewProjectionMatrix, TransposeInverseModelView; core::vector3df windDir; - void drawSolid(const GLMesh &mesh, video::E_MATERIAL_TYPE type); + core::vector2df caustic_dir, caustic_dir2; + void drawSolidPass1(const GLMesh &mesh, GeometricMaterial type); + void drawSolidPass2(const GLMesh &mesh, ShadedMaterial type); void drawTransparent(const GLMesh &mesh, video::E_MATERIAL_TYPE type); // Misc passes shaders (glow, displace...) void drawGlow(const GLMesh &mesh); void drawDisplace(const GLMesh &mesh); - void drawShadow(const GLMesh &mesh, video::E_MATERIAL_TYPE type); void createGLMeshes(); void cleanGLMeshes(); + void setFirstTimeMaterial(); + bool isMaterialInitialized; public: STKMeshSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id, const irr::core::vector3df& position = irr::core::vector3df(0, 0, 0), @@ -29,4 +35,4 @@ public: ~STKMeshSceneNode(); }; -#endif \ No newline at end of file +#endif diff --git a/src/guiengine/abstract_state_manager.cpp b/src/guiengine/abstract_state_manager.cpp index 7bc01fdb0..f3fd29fe6 100644 --- a/src/guiengine/abstract_state_manager.cpp +++ b/src/guiengine/abstract_state_manager.cpp @@ -18,14 +18,16 @@ #include "guiengine/abstract_state_manager.hpp" -#include -#include - +#include "config/user_config.hpp" #include "guiengine/engine.hpp" #include "guiengine/modaldialog.hpp" #include "guiengine/screen.hpp" #include "input/device_manager.hpp" +#include +#include + + using namespace GUIEngine; diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index e47059035..69ce7b712 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -648,9 +648,10 @@ namespace GUIEngine #include "guiengine/engine.hpp" -#include "io/file_manager.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "input/input_manager.hpp" +#include "io/file_manager.hpp" #include "guiengine/event_handler.hpp" #include "guiengine/modaldialog.hpp" #include "guiengine/scalable_font.hpp" diff --git a/src/guiengine/event_handler.cpp b/src/guiengine/event_handler.cpp index 27a82609a..acce1b1d9 100644 --- a/src/guiengine/event_handler.cpp +++ b/src/guiengine/event_handler.cpp @@ -17,11 +17,7 @@ #include "guiengine/event_handler.hpp" -#include - -#include -#include - +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/abstract_state_manager.hpp" #include "guiengine/engine.hpp" @@ -37,6 +33,12 @@ #include "utils/debug.hpp" #include "utils/profiler.hpp" + +#include +#include + +#include + using GUIEngine::EventHandler; using GUIEngine::EventPropagation; diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 49d6ce6aa..c2a01af7d 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -1222,11 +1222,41 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget, } } - BoxRenderParams& params = (focused || pressed) - ? SkinConfig::m_render_params["spinner::focused"] - : SkinConfig::m_render_params["spinner::neutral"]; + BoxRenderParams* params; + SpinnerWidget* q = dynamic_cast(widget); + if(q->getUseBackgroundColor()) + { + int player_id=q->getSpinnerWidgetPlayerID(); + if(player_id==0) + params=&SkinConfig::m_render_params["spinner1::neutral"]; + else if(player_id==1) + params=&SkinConfig::m_render_params["spinner2::neutral"]; + else if(player_id==2) + params=&SkinConfig::m_render_params["spinner3::neutral"]; + else if(player_id==3) + params=&SkinConfig::m_render_params["spinner4::neutral"]; + } + else if (focused|| pressed) + { + params=&SkinConfig::m_render_params["spinner::focused"]; + } + else + { + params=&SkinConfig::m_render_params["spinner::neutral"]; + } + if (widget->isFocusedForPlayer(0)) + { + core::recti rect2 = rect; + rect2.UpperLeftCorner.X += 2; + rect2.UpperLeftCorner.Y -= 3; + rect2.LowerRightCorner.X -= 2; + rect2.LowerRightCorner.Y += 5; + drawBoxFromStretchableTexture(widget, rect2, + SkinConfig::m_render_params["squareFocusHalo::neutral"]); + - if (widget->isFocusedForPlayer(1)) + } + else if (widget->isFocusedForPlayer(1)) { core::recti rect2 = rect; rect2.UpperLeftCorner.X += 2; @@ -1278,16 +1308,17 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget, - (int)center.Y)*texture_size); } - drawBoxFromStretchableTexture(widget, sized_rect, params, + drawBoxFromStretchableTexture(widget, sized_rect, *params, widget->m_deactivated); // ---- If this spinner is of "gauge" type, draw filling const SpinnerWidget* w = dynamic_cast(widget); + if (w->isGauge() && !w->m_deactivated) { - const int handle_size = (int)( widget->m_h*params.m_left_border - /(float)params.getImage()->getSize().Height ); + const int handle_size = (int)( widget->m_h*params->m_left_border + /(float)params->getImage()->getSize().Height ); const float value = (float)(w->getValue() - w->getMin()) / (w->getMax() - w->getMin()); diff --git a/src/guiengine/skin.hpp b/src/guiengine/skin.hpp index 9d4bebc04..3c8eac393 100644 --- a/src/guiengine/skin.hpp +++ b/src/guiengine/skin.hpp @@ -132,7 +132,6 @@ using namespace irr; */ namespace GUIEngine { - /** * In order to avoid calculating render information every frame, it's * stored in a SkinWidgetContainer for each widget (or each widget part @@ -269,11 +268,8 @@ namespace GUIEngine video::ITexture* bg_image; - - std::vector m_tooltips; std::vector m_tooltip_at_mouse; - #ifdef USE_PER_LINE_BACKGROUND public: #endif @@ -323,12 +319,12 @@ namespace GUIEngine void drawTooltip(Widget* widget, bool atMouse); + public: // dirty way to have dialogs that zoom in bool m_dialog; float m_dialog_size; - /** * \brief load a skin from the file specified in the user configuration file * \throw std::runtime_error if file cannot be read diff --git a/src/guiengine/widgets/spinner_widget.cpp b/src/guiengine/widgets/spinner_widget.cpp index 3787388b0..86c3b7dbf 100644 --- a/src/guiengine/widgets/spinner_widget.cpp +++ b/src/guiengine/widgets/spinner_widget.cpp @@ -39,13 +39,13 @@ using namespace irr::video; SpinnerWidget::SpinnerWidget(const bool gauge) : Widget(WTYPE_SPINNER) { m_gauge = gauge; - m_listener = NULL; m_graphical = false; m_check_inside_me = true; //FIXME: not sure this is necessary m_supports_multiplayer = true; m_value = -1; - + m_use_background_color=false; + m_spinner_widget_player_id=-1; m_min = 0; m_max = 999; } @@ -160,6 +160,7 @@ void SpinnerWidget::add() { label->setText(m_labels[m_value].c_str() ); } + } @@ -173,9 +174,10 @@ void SpinnerWidget::add() m_children[2].m_id = m_children[2].m_element->getID(); // refresh display + + setValue(m_value); } - // ----------------------------------------------------------------------------- ITexture* SpinnerWidget::getTexture() diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index 364dad936..f4fceab52 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -57,6 +57,9 @@ namespace GUIEngine int m_value, m_min, m_max; + int m_spinner_widget_player_id; + bool m_use_background_color; + /** If each value the spinner can take has an associated text, this vector will be non-empty */ std::vector m_labels; @@ -68,7 +71,8 @@ namespace GUIEngine * it displays how close the value is to the maximum by filling a line */ bool m_gauge; - + + /** \brief Whether to wrap back to the first value when going "beyond" the last value */ bool m_wrap_around; @@ -93,9 +97,9 @@ namespace GUIEngine /** Call only if this spinner is graphical. Returns the current texture to display */ irr::video::ITexture* getTexture(); - + public: - + LEAK_CHECK() SpinnerWidget(const bool gauge=false); @@ -104,7 +108,16 @@ namespace GUIEngine void addLabel(irr::core::stringw label); void clearLabels(); - + + // next four functions are for background colour behind playername in multikart screen selection + void setUseBackgroundColor() {m_use_background_color=true; } + bool getUseBackgroundColor() {return m_use_background_color; } + void setSpinnerWidgetPlayerID(int playerID) {m_spinner_widget_player_id=playerID;} + int getSpinnerWidgetPlayerID() {return m_spinner_widget_player_id; } + void unsetUseBackgroundColor() {m_use_background_color=false; } + + + void setListener(ISpinnerConfirmListener* listener) { m_listener = listener; } /** \brief implement method from base class Widget */ @@ -166,7 +179,7 @@ namespace GUIEngine /** Display custom text in spinner */ void setCustomText(const core::stringw& text); }; - + } #endif diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index a068bfe44..0c63f5bab 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -17,13 +17,14 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "input/input_manager.hpp" -#include "main_loop.hpp" + +#include "config/user_config.hpp" #include "graphics/camera.hpp" +#include "graphics/irr_driver.hpp" #include "guiengine/engine.hpp" #include "guiengine/event_handler.hpp" #include "guiengine/modaldialog.hpp" #include "guiengine/screen.hpp" -#include "graphics/irr_driver.hpp" #include "input/device_manager.hpp" #include "input/input.hpp" #include "karts/controller/controller.hpp" diff --git a/src/input/wiimote.cpp b/src/input/wiimote.cpp index d27c6b38c..d3ccd34e8 100644 --- a/src/input/wiimote.cpp +++ b/src/input/wiimote.cpp @@ -20,6 +20,7 @@ #include "input/wiimote.hpp" +#include "config/user_config.hpp" #include "input/device_manager.hpp" #include "utils/string_utils.hpp" diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index 37bf5c1e1..2ff762ba2 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -160,12 +160,16 @@ FileManager::FileManager() root_dir = "../data/" ; else if(m_file_system->existFile("../../data")) root_dir = "../../data/" ; + // Test for old style build environment, with executable in root of stk else if(m_file_system->existFile(exe_path+"data")) root_dir = (exe_path+"data/").c_str(); - else if(m_file_system->existFile(exe_path+"/../data")) + // Check for windows cmake style: bld/Debug/bin/supertuxkart.exe + else if (m_file_system->existFile(exe_path + "../../../data")) + root_dir = (exe_path + "../../../data/").c_str(); + else if (m_file_system->existFile(exe_path + "../data")) { root_dir = exe_path.c_str(); - root_dir += "/../data/"; + root_dir += "../data/"; } else { @@ -351,7 +355,7 @@ FileManager::~FileManager() */ void FileManager::addRootDirs(const std::string &roots) { - std::vector all = StringUtils::split(roots, ':'); + std::vector all = StringUtils::splitPath(roots); for(unsigned int i=0; igetSpeed() <= - m_initial_speed*stk_config->m_parachute_done_fraction) + // This percentage is based on the ratio of + // initial_speed / initial_max_speed + + float f = m_initial_speed / stk_config->m_parachute_max_speed; + if (f > 1.0f) f = 1.0f; // cap fraction + if (m_kart->getSpeed() <= m_initial_speed * + (stk_config->m_parachute_lbound_fraction + + f * ( stk_config->m_parachute_ubound_fraction + - stk_config->m_parachute_lbound_fraction))) { m_time_left = -1; } + } break; case ATTACH_ANVIL: // handled in Kart::updatePhysics case ATTACH_NOTHING: // Nothing to do, but complete all cases for switch diff --git a/src/items/rubber_ball.cpp b/src/items/rubber_ball.cpp index 36a252636..cc6f268e8 100644 --- a/src/items/rubber_ball.cpp +++ b/src/items/rubber_ball.cpp @@ -21,6 +21,7 @@ #include "audio/sfx_base.hpp" #include "audio/sfx_manager.hpp" #include "config/stk_config.hpp" +#include "config/user_config.hpp" #include "io/xml_node.hpp" #include "items/attachment.hpp" #include "items/projectile_manager.hpp" diff --git a/src/karts/controller/ai_base_controller.cpp b/src/karts/controller/ai_base_controller.cpp index 2580b5fa1..a192eb5ba 100644 --- a/src/karts/controller/ai_base_controller.cpp +++ b/src/karts/controller/ai_base_controller.cpp @@ -19,8 +19,7 @@ #include "karts/controller/ai_base_controller.hpp" -#include - +#include "config/user_config.hpp" #include "karts/abstract_kart.hpp" #include "karts/kart_properties.hpp" #include "karts/skidding_properties.hpp" @@ -29,6 +28,8 @@ #include "tracks/track.hpp" #include "utils/constants.hpp" +#include + bool AIBaseController::m_ai_debug = false; /** diff --git a/src/karts/controller/network_player_controller.cpp b/src/karts/controller/network_player_controller.cpp index c82e59d08..b7616c5c3 100644 --- a/src/karts/controller/network_player_controller.cpp +++ b/src/karts/controller/network_player_controller.cpp @@ -1,5 +1,6 @@ #include "karts/controller/network_player_controller.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "graphics/post_processing.hpp" #include "input/input_manager.hpp" diff --git a/src/karts/controller/player_controller.cpp b/src/karts/controller/player_controller.cpp index 74e9c88aa..68927a30d 100644 --- a/src/karts/controller/player_controller.cpp +++ b/src/karts/controller/player_controller.cpp @@ -22,6 +22,7 @@ #include "audio/sfx_base.hpp" #include "audio/sfx_manager.hpp" #include "config/stk_config.hpp" +#include "config/user_config.hpp" #include "graphics/camera.hpp" #include "graphics/irr_driver.hpp" #include "graphics/post_processing.hpp" diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 2edf614ff..f3f6aaba9 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -355,8 +355,9 @@ void Kart::reset() // In case that the kart was in the air, in which case its // linear damping is 0 - m_body->setDamping(m_kart_properties->getChassisLinearDamping(), - m_kart_properties->getChassisAngularDamping() ); + if(m_body) + m_body->setDamping(m_kart_properties->getChassisLinearDamping(), + m_kart_properties->getChassisAngularDamping() ); if(m_terrain_sound) { diff --git a/src/karts/kart.hpp b/src/karts/kart.hpp index 5dd049226..eaf7e835c 100644 --- a/src/karts/kart.hpp +++ b/src/karts/kart.hpp @@ -424,6 +424,9 @@ public: TerrainInfo *getTerrainInfo() { return m_terrain_info; } // ------------------------------------------------------------------------ virtual void setOnScreenText(const wchar_t *text); + // ------------------------------------------------------------------------ + /** For debugging only: check if a kart is flying. */ + bool isFlying() const { return m_flying; } }; // Kart diff --git a/src/karts/moveable.cpp b/src/karts/moveable.cpp index afeb56e4c..84f5d17e0 100644 --- a/src/karts/moveable.cpp +++ b/src/karts/moveable.cpp @@ -105,17 +105,19 @@ void Moveable::flyUp() { m_body->setGravity(btVector3(0.0, 8.0, 0.0)); m_body->applyCentralImpulse(btVector3(0.0, 100.0, 0.0)); -} +} // flyUp +// ---------------------------------------------------------------------------- void Moveable::flyDown() { m_body->applyCentralImpulse(btVector3(0.0, -100.0, 0.0)); -} +} // flyDown +// ---------------------------------------------------------------------------- void Moveable::stopFlying() { m_body->setGravity(btVector3(0.0, -World::getWorld()->getTrack()->getGravity(), 0.0)); -} +} // stopFlying //----------------------------------------------------------------------------- /** Updates the current position and rotation from the corresponding physics diff --git a/src/main.cpp b/src/main.cpp index 14544bc47..8a3a4db32 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -158,8 +158,8 @@ #include "guiengine/engine.hpp" #include "guiengine/event_handler.hpp" #include "guiengine/dialog_queue.hpp" -#include "input/input_manager.hpp" #include "input/device_manager.hpp" +#include "input/input_manager.hpp" #include "input/wiimote_manager.hpp" #include "io/file_manager.hpp" #include "items/attachment_manager.hpp" @@ -170,20 +170,17 @@ #include "karts/kart_properties_manager.hpp" #include "modes/demo_world.hpp" #include "modes/profile_world.hpp" +#include "network/client_network_manager.hpp" #include "network/network_manager.hpp" +#include "network/protocol_manager.hpp" +#include "network/protocols/server_lobby_room_protocol.hpp" #include "network/client_network_manager.hpp" #include "network/server_network_manager.hpp" #include "network/protocol_manager.hpp" #include "network/protocols/server_lobby_room_protocol.hpp" #include "online/current_user.hpp" -#include "online/request_manager.hpp" -#include "network/client_network_manager.hpp" -#include "network/server_network_manager.hpp" -#include "network/protocol_manager.hpp" -#include "network/protocols/server_lobby_room_protocol.hpp" -#include "online/current_user.hpp" -#include "online/request_manager.hpp" #include "online/profile_manager.hpp" +#include "online/request_manager.hpp" #include "online/servers_manager.hpp" #include "race/grand_prix_manager.hpp" #include "race/highscore_manager.hpp" @@ -403,6 +400,9 @@ void cmdLineHelp() " and the music.\n" " -t, --track=NAME Start at track NAME.\n" " --gp=NAME Start the specified Grand Prix.\n" + " --add-gp-dir=DIR Load Grand Prix in DIR. Setting will be saved " + "inconfig.xml under additional_gp_directory. Use " + "--add-gp-dir=\"\" to unset.\n" " --stk-config=FILE use ./data/FILE instead of " "./data/stk_config.xml\n" " -k, --numkarts=NUM Number of karts on the racetrack.\n" @@ -584,6 +584,19 @@ int handleCmdLinePreliminary() IRRLICHT_VERSION_REVISION, IRRLICHT_SDK_VERSION ); Log::info("main", "=============================="); } // --verbose or -v + + // Enable loading GP's from local directory + if(CommandLine::has("--add-gp-dir", &s)) + { + // Ensure that the path ends with a / + if (s[s.size()] == '/') + UserConfigParams::m_additional_gp_directory = s; + else + UserConfigParams::m_additional_gp_directory = s + "/"; + + Log::info("main", "Additional Grand Prix's will be loaded from %s", + UserConfigParams::m_additional_gp_directory.c_str()); + } int n; if(CommandLine::has("--xmas", &n)) @@ -683,7 +696,7 @@ int handleCmdLine() { const PlayerProfile *player = PlayerManager::get()->getCurrentPlayer(); - if(!player->isLocked(s)) + if(player && !player->isLocked(s)) { const KartProperties *prop = kart_properties_manager->getKart(s); @@ -709,9 +722,12 @@ int handleCmdLine() } else // kart locked { - Log::warn("main", "Kart '%s' has not been unlocked yet.", - s.c_str()); - return 0; + if (player) + Log::warn("main", "Kart '%s' has not been unlocked yet.", + s.c_str()); + else + Log::warn("main", + "A default player must exist in order to use --kart."); } // if kart locked } // if --kart @@ -751,7 +767,7 @@ int handleCmdLine() if(CommandLine::has("--track", &s) || CommandLine::has("-t", &s)) { const PlayerProfile *player = PlayerManager::get()->getCurrentPlayer(); - if (!player->isLocked(s)) + if (player && !player->isLocked(s)) { race_manager->setTrack(s); Log::verbose("main", "You choose to start in track '%s'.", @@ -783,9 +799,12 @@ int handleCmdLine() } else { - Log::warn("main", "Track '%s' has not been unlocked yet.", - s.c_str()); - return 0; + if (player) + Log::warn("main", "Track '%s' has not been unlocked yet.", + s.c_str()); + else + Log::warn("main", + "A default player must exist in order to use --track."); } } // --track @@ -1009,6 +1028,7 @@ void initRest() // online section of the addons manager will be initialised from a // separate thread running in network http. addons_manager = new AddonsManager(); + Online::ProfileManager::create(); Online::RequestManager::get()->startNetworkThread(); NewsManager::get(); // this will create the news manager @@ -1056,18 +1076,43 @@ void initRest() } // initRest //============================================================================= -#ifdef BREAKPAD -bool ShowDumpResults(const wchar_t* dump_path, - const wchar_t* minidump_id, - void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - bool succeeded) +void askForInternetPermission() { - wprintf(L"Path: %s id %s.\n", dump_path, minidump_id); - return succeeded; -} -#endif + if (UserConfigParams::m_internet_status == + Online::RequestManager::IPERM_NOT_ASKED) + { + class ConfirmServer : + public MessageDialog::IConfirmDialogListener + { + public: + virtual void onConfirm() + { + UserConfigParams::m_internet_status = + Online::RequestManager::IPERM_ALLOWED; + GUIEngine::ModalDialog::dismiss(); + } // onConfirm + // -------------------------------------------------------- + virtual void onCancel() + { + UserConfigParams::m_internet_status = + Online::RequestManager::IPERM_NOT_ALLOWED; + GUIEngine::ModalDialog::dismiss(); + } // onCancel + }; // ConfirmServer + + new MessageDialog(_("SuperTuxKart may connect to a server " + "to download add-ons and notify you of updates. Would you " + "like this feature to be enabled? (To change this setting " + "at a later time, go to options, select tab " + "'User Interface', and edit \"Allow STK to connect to the " + "Internet\")."), + MessageDialog::MESSAGE_DIALOG_CONFIRM, + new ConfirmServer(), true); + } + +} // askForInternetPermission + +//============================================================================= #if defined(DEBUG) && defined(WIN32) && !defined(__CYGWIN__) #pragma comment(linker, "/SUBSYSTEM:console") @@ -1076,10 +1121,6 @@ bool ShowDumpResults(const wchar_t* dump_path, // ---------------------------------------------------------------------------- int main(int argc, char *argv[] ) { -#ifdef BREAKPAD - google_breakpad::ExceptionHandler eh(L"C:\\Temp", NULL, ShowDumpResults, - NULL, google_breakpad::ExceptionHandler::HANDLER_ALL); -#endif CommandLine::init(argc, argv); CrashReporting::installHandlers(); @@ -1204,40 +1245,15 @@ int main(int argc, char *argv[] ) wiimote_manager->askUserToConnectWiimotes(); } #endif - if(UserConfigParams::m_internet_status == - Online::RequestManager::IPERM_NOT_ASKED) - { - class ConfirmServer : - public MessageDialog::IConfirmDialogListener - { - public: - virtual void onConfirm() - { - UserConfigParams::m_internet_status = - Online::RequestManager::IPERM_ALLOWED; - GUIEngine::ModalDialog::dismiss(); - } // onConfirm - // -------------------------------------------------------- - virtual void onCancel() - { - UserConfigParams::m_internet_status = - Online::RequestManager::IPERM_NOT_ALLOWED; - GUIEngine::ModalDialog::dismiss(); - } // onCancel - }; // ConfirmServer - - new MessageDialog(_("SuperTuxKart may connect to a server " - "to download add-ons and notify you of updates. Would you " - "like this feature to be enabled? (To change this setting " - "at a later time, go to options, select tab " - "'User Interface', and edit \"Allow STK to connect to the " - "Internet\")."), - MessageDialog::MESSAGE_DIALOG_CONFIRM, - new ConfirmServer(), true); - } + askForInternetPermission(); } else { + // Skip the start screen. This esp. means that no login screen is + // displayed (if necessary), so we have to make sure there is + // a current player + PlayerManager::get()->enforceCurrentPlayer(); + InputDevice *device; // Use keyboard 0 by default in --no-start-screen @@ -1393,7 +1409,7 @@ static void cleanSuperTuxKart() //see InitTuxkart() Online::RequestManager::deallocate(); Online::ServersManager::deallocate(); - Online::ProfileManager::deallocate(); + Online::ProfileManager::destroy(); Online::CurrentUser::deallocate(); GUIEngine::DialogQueue::deallocate(); diff --git a/src/modes/cutscene_world.cpp b/src/modes/cutscene_world.cpp index e394f0670..b95ed070b 100644 --- a/src/modes/cutscene_world.cpp +++ b/src/modes/cutscene_world.cpp @@ -22,6 +22,7 @@ #include "audio/music_manager.hpp" #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "graphics/camera.hpp" #include "graphics/irr_driver.hpp" #include "io/file_manager.hpp" #include "karts/abstract_kart.hpp" @@ -73,9 +74,11 @@ void CutsceneWorld::init() //const btTransform &s = getTrack()->getStartTransform(0); //const Vec3 &v = s.getOrigin(); - m_camera = irr_driver->getSceneManager() - ->addCameraSceneNode(NULL, core::vector3df(0.0f, 0.0f, 0.0f), - core::vector3df(0.0f, 0.0f, 0.0f)); + Camera* stk_cam = Camera::createCamera(NULL); + m_camera = stk_cam->getCameraSceneNode(); + //m_camera = irr_driver->getSceneManager() + // ->addCameraSceneNode(NULL, core::vector3df(0.0f, 0.0f, 0.0f), + // core::vector3df(0.0f, 0.0f, 0.0f)); m_camera->setFOV(0.61f); m_camera->bindTargetAndRotation(true); // no "look-at" @@ -168,7 +171,7 @@ CutsceneWorld::~CutsceneWorld() */ const std::string& CutsceneWorld::getIdent() const { - return IDENT_CUSTSCENE; + return IDENT_CUTSCENE; } // getIdent //----------------------------------------------------------------------------- diff --git a/src/modes/demo_world.cpp b/src/modes/demo_world.cpp index c6dad061c..0c8c86dcb 100644 --- a/src/modes/demo_world.cpp +++ b/src/modes/demo_world.cpp @@ -19,6 +19,7 @@ #include "modes/demo_world.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "guiengine/modaldialog.hpp" #include "input/device_manager.hpp" #include "input/input_manager.hpp" diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index d4d7b09a8..865e995be 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -17,11 +17,10 @@ #include "modes/linear_world.hpp" -#include - #include "audio/music_manager.hpp" #include "audio/sfx_base.hpp" #include "audio/sfx_manager.hpp" +#include "config/user_config.hpp" #include "karts/abstract_kart.hpp" #include "karts/controller/controller.hpp" #include "karts/kart_properties.hpp" @@ -34,6 +33,8 @@ #include "utils/string_utils.hpp" #include "utils/translation.hpp" +#include + //----------------------------------------------------------------------------- /** Constructs the linear world. Note that here no functions can be called * that use World::getWorld(), since it is not yet defined. diff --git a/src/modes/overworld.cpp b/src/modes/overworld.cpp index 078e5255b..1d72f2d47 100644 --- a/src/modes/overworld.cpp +++ b/src/modes/overworld.cpp @@ -15,9 +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. +#include "modes/overworld.hpp" + #include "audio/music_manager.hpp" #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "input/device_manager.hpp" #include "input/input.hpp" @@ -26,7 +29,6 @@ #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "karts/rescue_animation.hpp" -#include "modes/overworld.hpp" #include "physics/physics.hpp" #include "states_screens/dialogs/select_challenge.hpp" #include "states_screens/offline_kart_selection.hpp" diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 5a0b2d953..e90b89dbb 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -18,7 +18,7 @@ #include "modes/world.hpp" -#include "achievements/achievements_manager.hpp" +#include "achievements/achievement_info.hpp" #include "audio/music_manager.hpp" #include "audio/sfx_base.hpp" #include "audio/sfx_manager.hpp" @@ -443,13 +443,16 @@ void World::terminateRace() { updateHighscores(&best_highscore_rank, &best_finish_time, &highscore_who, &best_player); - PlayerManager::get()->getCurrentPlayer()->raceFinished(); } + PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_COLUMBUS, + getTrack()->getIdent(), 1); + if (raceHasLaps()) + { + PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_MARATHONER, + "laps", race_manager->getNumLaps()); + } PlayerManager::get()->getCurrentPlayer()->raceFinished(); - AchievementsStatus* status = PlayerManager::getCurrentAchievementsStatus(); - dynamic_cast(status->getAchievement(1))->increase(getTrack()->getIdent(), 1); - AchievementsManager::get()->onRaceEnd(); if (m_race_gui) m_race_gui->clearAllMessages(); // we can't delete the race gui here, since it is needed in case of diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index 440903230..f15c69a85 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -21,6 +21,7 @@ #include "audio/sfx_manager.hpp" #include "audio/sfx_base.hpp" #include "config/stk_config.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/modaldialog.hpp" #include "karts/abstract_kart.hpp" diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index 58bb978da..1cbdbc0b4 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -20,6 +20,7 @@ #include "karts/abstract_kart.hpp" #include "modes/world.hpp" +#include "online/online_profile.hpp" #include "race/race_manager.hpp" #include "utils/log.hpp" @@ -49,7 +50,7 @@ void GameSetup::addPlayer(NetworkPlayerProfile* profile) { m_players.push_back(profile); Log::info("GameSetup", "New player in the game setup. Global id : %u, " - "Race id : %d.", profile->user_profile->getID(), profile->race_id); + "Race id : %d.", profile->user_profile->getID(), profile->race_id); } //----------------------------------------------------------------------------- diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index b928e6ba3..171160278 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -22,12 +22,14 @@ #ifndef GAME_SETUP_HPP #define GAME_SETUP_HPP -#include "online/profile.hpp" #include "network/race_config.hpp" #include #include +namespace Online { class OnlineProfile; } + + /*! \class PlayerProfile * \brief Contains the profile of a player. */ @@ -39,7 +41,7 @@ class NetworkPlayerProfile uint8_t race_id; //!< The id of the player for the race std::string kart_name; //!< The selected kart. - Online::Profile* user_profile; //!< Pointer to the lobby profile + Online::OnlineProfile* user_profile; //!< Pointer to the lobby profile uint8_t world_kart_id; //!< the kart id in the World class (pointer to AbstractKart) }; diff --git a/src/network/protocols/client_lobby_room_protocol.cpp b/src/network/protocols/client_lobby_room_protocol.cpp index a6abcb51a..af7800547 100644 --- a/src/network/protocols/client_lobby_room_protocol.cpp +++ b/src/network/protocols/client_lobby_room_protocol.cpp @@ -18,14 +18,14 @@ #include "network/protocols/client_lobby_room_protocol.hpp" -#include "network/network_manager.hpp" -#include "network/protocols/start_game_protocol.hpp" -#include "network/network_world.hpp" - #include "modes/world_with_rank.hpp" +#include "network/network_manager.hpp" +#include "network/network_world.hpp" +#include "network/protocols/start_game_protocol.hpp" #include "online/current_user.hpp" -#include "states_screens/state_manager.hpp" +#include "online/online_profile.hpp" #include "states_screens/network_kart_selection.hpp" +#include "states_screens/state_manager.hpp" #include "utils/log.hpp" ClientLobbyRoomProtocol::ClientLobbyRoomProtocol(const TransportAddress& server_address) @@ -305,7 +305,7 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event) NetworkPlayerProfile* profile = new NetworkPlayerProfile(); profile->kart_name = ""; profile->race_id = race_id; - profile->user_profile = new Online::Profile(global_id, ""); + profile->user_profile = new Online::OnlineProfile(global_id, ""); m_setup->addPlayer(profile); } else @@ -396,7 +396,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) uint8_t race_id = data[1]; uint32_t global_id = data.gui32(3); - Online::Profile* new_user = new Online::Profile(global_id, ""); + Online::OnlineProfile* new_user = new Online::OnlineProfile(global_id, ""); NetworkPlayerProfile* profile2 = new NetworkPlayerProfile(); profile2->race_id = race_id; diff --git a/src/network/protocols/get_peer_address.hpp b/src/network/protocols/get_peer_address.hpp index 771825d97..6dac695a1 100644 --- a/src/network/protocols/get_peer_address.hpp +++ b/src/network/protocols/get_peer_address.hpp @@ -20,7 +20,8 @@ #define GET_PEER_ADDRESS_HPP #include "network/protocol.hpp" -#include "online/request.hpp" + +namespace Online { class XMLRequest; } class GetPeerAddress : public Protocol { diff --git a/src/network/protocols/hide_public_address.hpp b/src/network/protocols/hide_public_address.hpp index e91ac3db7..e1c5c800a 100644 --- a/src/network/protocols/hide_public_address.hpp +++ b/src/network/protocols/hide_public_address.hpp @@ -20,9 +20,11 @@ #define HIDE_PUBLIC_ADDRESS_HPP #include "network/protocol.hpp" -#include "online/request.hpp" + #include +namespace Online { class XMLRequest; } + class HidePublicAddress : public Protocol { public: diff --git a/src/network/protocols/kart_update_protocol.cpp b/src/network/protocols/kart_update_protocol.cpp index 67d351cd4..c97101ef5 100644 --- a/src/network/protocols/kart_update_protocol.cpp +++ b/src/network/protocols/kart_update_protocol.cpp @@ -4,6 +4,7 @@ #include "modes/world.hpp" #include "network/protocol_manager.hpp" #include "network/network_world.hpp" +#include "utils/time.hpp" KartUpdateProtocol::KartUpdateProtocol() : Protocol(NULL, PROTOCOL_KART_UPDATE) diff --git a/src/network/protocols/quick_join_protocol.hpp b/src/network/protocols/quick_join_protocol.hpp index 144e49d20..f7f374d97 100644 --- a/src/network/protocols/quick_join_protocol.hpp +++ b/src/network/protocols/quick_join_protocol.hpp @@ -2,7 +2,8 @@ #define QUICK_JOIN_PROTOCOL_HPP #include "network/protocol.hpp" -#include "online/request.hpp" + +namespace Online { class XMLRequest; } class QuickJoinProtocol : public Protocol { diff --git a/src/network/protocols/server_lobby_room_protocol.cpp b/src/network/protocols/server_lobby_room_protocol.cpp index 0c5d28088..578068357 100644 --- a/src/network/protocols/server_lobby_room_protocol.cpp +++ b/src/network/protocols/server_lobby_room_protocol.cpp @@ -18,21 +18,21 @@ #include "network/protocols/server_lobby_room_protocol.hpp" -#include "network/server_network_manager.hpp" +#include "config/user_config.hpp" +#include "modes/world.hpp" #include "network/network_world.hpp" #include "network/protocols/get_public_address.hpp" #include "network/protocols/show_public_address.hpp" #include "network/protocols/connect_to_peer.hpp" #include "network/protocols/start_server.hpp" #include "network/protocols/start_game_protocol.hpp" - +#include "network/server_network_manager.hpp" #include "online/current_user.hpp" +#include "online/online_profile.hpp" #include "online/request_manager.hpp" -#include "config/user_config.hpp" -#include "modes/world.hpp" #include "utils/log.hpp" -#include "utils/time.hpp" #include "utils/random_generator.hpp" +#include "utils/time.hpp" ServerLobbyRoomProtocol::ServerLobbyRoomProtocol() : LobbyRoomProtocol(NULL) @@ -386,7 +386,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) NetworkPlayerProfile* profile = new NetworkPlayerProfile(); profile->race_id = m_next_id; profile->kart_name = ""; - profile->user_profile = new Online::Profile(player_id, ""); + profile->user_profile = new Online::OnlineProfile(player_id, ""); m_setup->addPlayer(profile); peer->setPlayerProfile(profile); Log::verbose("ServerLobbyRoomProtocol", "New player."); diff --git a/src/network/protocols/show_public_address.hpp b/src/network/protocols/show_public_address.hpp index fb84f8477..e1dae5387 100644 --- a/src/network/protocols/show_public_address.hpp +++ b/src/network/protocols/show_public_address.hpp @@ -20,9 +20,11 @@ #define SHOW_PUBLIC_ADDRESS_HPP #include "network/protocol.hpp" -#include "online/request.hpp" + #include +namespace Online { class XMLRequest; } + class ShowPublicAddress : public Protocol { public: diff --git a/src/network/protocols/start_game_protocol.cpp b/src/network/protocols/start_game_protocol.cpp index 1700f18e6..a9b1513e1 100644 --- a/src/network/protocols/start_game_protocol.cpp +++ b/src/network/protocols/start_game_protocol.cpp @@ -11,6 +11,7 @@ #include "network/network_world.hpp" #include "network/protocols/synchronization_protocol.hpp" #include "online/current_user.hpp" +#include "online/online_profile.hpp" #include "race/race_manager.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/kart_selection.hpp" diff --git a/src/network/protocols/start_server.hpp b/src/network/protocols/start_server.hpp index 5fce8a458..b375ff8d3 100644 --- a/src/network/protocols/start_server.hpp +++ b/src/network/protocols/start_server.hpp @@ -2,7 +2,8 @@ #define START_SERVER_HPP #include "network/protocol.hpp" -#include "online/request.hpp" + +namespace Online { class XMLRequest; } /*! * This protocol tells to the database that the server is up and running, diff --git a/src/network/protocols/stop_server.hpp b/src/network/protocols/stop_server.hpp index 5b5c7a553..feba521b1 100644 --- a/src/network/protocols/stop_server.hpp +++ b/src/network/protocols/stop_server.hpp @@ -2,7 +2,8 @@ #define STOP_SERVER_HPP #include "network/protocol.hpp" -#include "online/request.hpp" + +namespace Online { class XMLRequest; } /*! \brief Removes the server info from the database */ diff --git a/src/network/server_network_manager.cpp b/src/network/server_network_manager.cpp index c6d33aaf0..f433b43ef 100644 --- a/src/network/server_network_manager.cpp +++ b/src/network/server_network_manager.cpp @@ -18,16 +18,16 @@ #include "network/server_network_manager.hpp" +#include "main_loop.hpp" +#include "network/protocols/connect_to_server.hpp" +#include "network/protocols/get_peer_address.hpp" #include "network/protocols/get_public_address.hpp" #include "network/protocols/hide_public_address.hpp" -#include "network/protocols/show_public_address.hpp" -#include "network/protocols/get_peer_address.hpp" -#include "network/protocols/connect_to_server.hpp" -#include "network/protocols/stop_server.hpp" #include "network/protocols/server_lobby_room_protocol.hpp" - -#include "main_loop.hpp" +#include "network/protocols/show_public_address.hpp" +#include "network/protocols/stop_server.hpp" #include "utils/log.hpp" +#include "utils/time.hpp" #include #include diff --git a/src/online/current_user.cpp b/src/online/current_user.cpp index 6927b658f..60913d930 100644 --- a/src/online/current_user.cpp +++ b/src/online/current_user.cpp @@ -26,8 +26,9 @@ #include "config/user_config.hpp" #include "guiengine/dialog_queue.hpp" #include "guiengine/screen.hpp" -#include "online/servers_manager.hpp" +#include "online/online_profile.hpp" #include "online/profile_manager.hpp" +#include "online/servers_manager.hpp" #include "states_screens/login_screen.hpp" #include "states_screens/dialogs/change_password_dialog.hpp" #include "states_screens/dialogs/user_info_dialog.hpp" @@ -62,6 +63,21 @@ namespace Online delete current_user_singleton; current_user_singleton = NULL; } // deallocate + // ------------------------------------------------------------------------ + /** Adds the login credential to a http request. A handy static function + * to allow for shorter request creation code. It sets the name of + * the script to invokce, token, and user id. + * \param request The http request. + */ + void CurrentUser::setUserDetails(HTTPRequest *request) + { + CurrentUser *cu = CurrentUser::get(); + assert(cu && cu->m_state == US_SIGNED_IN); + assert(cu->m_profile); + request->setServerURL("client-user.php"); + request->addParameter("token", cu->m_token); + request->addParameter("userid", cu->m_profile->getID()); + } // setUserDetails // ======================================================================== CurrentUser::CurrentUser() @@ -188,7 +204,7 @@ namespace Online int username_fetched = input->get("username", &username); uint32_t userid(0); int userid_fetched = input->get("userid", &userid); - m_profile = new Profile(userid, username, true); + m_profile = new OnlineProfile(userid, username, true); assert(token_fetched && username_fetched && userid_fetched); m_state = US_SIGNED_IN; if(saveSession()) @@ -366,7 +382,7 @@ namespace Online * search term. * \param search_string the string to search for. */ - const XMLRequest* + XMLRequest* CurrentUser::requestUserSearch(const core::stringw &search_string) const { assert(m_state == US_SIGNED_IN); @@ -409,8 +425,8 @@ namespace Online if(isSuccess()) { CurrentUser::get()->getProfile()->addFriend(id); - Profile::RelationInfo *info = - new Profile::RelationInfo(_("Today"), false, true, false); + OnlineProfile::RelationInfo *info = + new OnlineProfile::RelationInfo(_("Today"), false, true, false); ProfileManager::get()->getProfileByID(id)->setRelationInfo(info); OnlineProfileFriends::getInstance()->refreshFriendsList(); info_text = _("Friend request send!"); @@ -452,10 +468,10 @@ namespace Online core::stringw info_text(""); if(isSuccess()) { - Profile * profile = ProfileManager::get()->getProfileByID(id); + OnlineProfile * profile = ProfileManager::get()->getProfileByID(id); profile->setFriend(); - Profile::RelationInfo *info = - new Profile::RelationInfo(_("Today"), false, false, true); + OnlineProfile::RelationInfo *info = + new OnlineProfile::RelationInfo(_("Today"), false, false, true); profile->setRelationInfo(info); OnlineProfileFriends::getInstance()->refreshFriendsList(); info_text = _("Friend request accepted!"); @@ -683,9 +699,9 @@ namespace Online now_online = true; online_friends.erase(iter); } - Profile * profile = + OnlineProfile * profile = ProfileManager::get()->getProfileByID(friends[i]); - Profile::RelationInfo * relation_info = + OnlineProfile::RelationInfo * relation_info = profile->getRelationInfo(); if( relation_info->isOnline() ) { @@ -755,9 +771,9 @@ namespace Online const XMLNode * node = getXMLData()->getNode(i); if(node->getName() == "new_friend_request") { - Profile::RelationInfo * ri = - new Profile::RelationInfo("New", false, true, true); - Profile * p = new Profile(node); + OnlineProfile::RelationInfo * ri = + new OnlineProfile::RelationInfo("New", false, true, true); + OnlineProfile * p = new OnlineProfile(node); p->setRelationInfo(ri); ProfileManager::get()->addPersistent(p); friend_request_count++; diff --git a/src/online/current_user.hpp b/src/online/current_user.hpp index f5b00e03c..9cd57c607 100644 --- a/src/online/current_user.hpp +++ b/src/online/current_user.hpp @@ -19,9 +19,10 @@ #ifndef HEADER_CURRENT_ONLINE_USER_HPP #define HEADER_CURRENT_ONLINE_USER_HPP +#include "online/http_request.hpp" +#include "online/online_profile.hpp" #include "online/request_manager.hpp" #include "online/server.hpp" -#include "online/profile.hpp" #include "online/xml_request.hpp" #include "utils/types.hpp" #include "utils/synchronised.hpp" @@ -34,6 +35,8 @@ namespace Online { + class OnlineProfile; + // ============================================================================ /** @@ -152,7 +155,7 @@ namespace Online std::string m_token; bool m_save_session; UserState m_state; - Profile * m_profile; + OnlineProfile *m_profile; bool saveSession() const { return m_save_session; } @@ -165,6 +168,7 @@ namespace Online /**Singleton */ static CurrentUser * get(); static void deallocate(); + static void setUserDetails(HTTPRequest *html); void requestSavedSession(); SignInRequest * requestSignIn( const irr::core::stringw &username, @@ -196,7 +200,7 @@ namespace Online const irr::core::stringw &new_password, const irr::core::stringw &new_password_ver) const; - const XMLRequest * requestUserSearch(const irr::core::stringw & search_string) const; + XMLRequest * requestUserSearch(const irr::core::stringw & search_string) const; void onSTKQuit() const; void onAchieving(uint32_t achievement_id) const; @@ -204,14 +208,20 @@ namespace Online irr::core::stringw getUserName() const; uint32_t getID() const; + // ---------------------------------------------------------------- /** Returns the user state. */ - const UserState getUserState() const { return m_state; } + const UserState getUserState() const { return m_state; } + // ---------------------------------------------------------------- /** Returns whether a user is signed in or not. */ - bool isRegisteredUser() const { return m_state == US_SIGNED_IN; } + bool isRegisteredUser() const { return m_state == US_SIGNED_IN; } + // ---------------------------------------------------------------- /** Returns the session token of the signed in user. */ - const std::string & getToken() const { return m_token; } - /** Returns a pointer to the profile associated with the current user. */ - Profile * getProfile() const { return m_profile; } + const std::string& getToken() const { return m_token; } + // ---------------------------------------------------------------- + /** Returns a pointer to the profile associated with the current + * user. */ + OnlineProfile* getProfile() const { return m_profile; } + // ---------------------------------------------------------------- }; // class CurrentUser diff --git a/src/online/http_request.cpp b/src/online/http_request.cpp index f5970edae..2e52075c1 100644 --- a/src/online/http_request.cpp +++ b/src/online/http_request.cpp @@ -197,9 +197,28 @@ namespace Online if(m_parameters.size()==0) Log::info("HTTPRequest", "Downloading %s", m_url.c_str()); - else + else if (Log::getLogLevel()<=Log::LL_INFO) + { + // Avoid printing the password or token, just replace them with *s + std::string param = m_parameters; + for (unsigned int j = 0; j < 2; j++) + { + // Get the string that should be replaced. + std::string s = (j == 0 ? "&password=" : "&token="); + std::size_t pos = param.find(s); + if (pos != std::string::npos) + { + pos += s.size(); + while (pos < param.size() && param[pos] != '&') + { + param[pos] = '*'; + pos++; + } // while not end + } // if string found + } // for j < 2 Log::info("HTTPRequest", "Sending %s to %s", - m_parameters.c_str(), m_url.c_str()); + param.c_str(), m_url.c_str()); + } curl_easy_setopt(m_curl_session, CURLOPT_POSTFIELDS, m_parameters.c_str()); std::string uagent( std::string("SuperTuxKart/") + STK_VERSION ); diff --git a/src/online/online_profile.cpp b/src/online/online_profile.cpp new file mode 100644 index 000000000..8405c3e59 --- /dev/null +++ b/src/online/online_profile.cpp @@ -0,0 +1,329 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Glenn De Jonghe +// +// 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 "online/online_profile.hpp" + +#include "online/profile_manager.hpp" +#include "online/request_manager.hpp" +#include "config/user_config.hpp" +#include "online/current_user.hpp" +#include "utils/log.hpp" +#include "utils/translation.hpp" + +#include +#include +#include + +using namespace Online; + +namespace Online +{ + +OnlineProfile::RelationInfo::RelationInfo(const irr::core::stringw & date, + bool is_online, bool is_pending, + bool is_asker) +{ + m_date = date; + m_is_online = is_online; + m_is_pending = is_pending; + m_is_asker = is_asker; +} // RelationInfo::RelationInfo + +// ---------------------------------------------------------------------------- +void OnlineProfile::RelationInfo::setOnline(bool online) +{ + m_is_online = online; + if (m_is_online) + m_is_pending = false; +} + +// ============================================================================ +/** Constructor for a new profile. It does only store the ID, a name, and + * if it is the current user. + */ +OnlineProfile::OnlineProfile(const uint32_t & userid, + const irr::core::stringw & username, + bool is_current_user) +{ + m_state = S_READY; + m_cache_bit = true; + m_id = userid; + m_is_current_user = is_current_user; + m_username = username; + m_has_fetched_friends = false; + m_has_fetched_achievements = false; + m_relation_info = NULL; + m_is_friend = false; +} // Profile + +// ---------------------------------------------------------------------------- +/** Creates a new profile from an XML Node. Two different profiles can be + * created: either a simple one with no relation, or a profile with + * relation information, i.e. it contains how this profile is related + * to the current profile. + * \param xml The XML node with the data to use. + * \param type Either C_DEFAULT (no relation), or C_RELATION_INFO + * if the XML node contains relation information. + */ +OnlineProfile::OnlineProfile(const XMLNode * xml, ConstructorType type) +{ + m_relation_info = NULL; + m_is_friend = false; + m_cache_bit = true; + m_has_fetched_friends = false; + m_has_fetched_achievements = false; + if (type == C_RELATION_INFO) + { + irr::core::stringw date(""); + xml->get("date", &date); + std::string is_pending_string(""); + bool is_pending = false; + xml->get("is_pending", &is_pending); + bool is_asker = false; + bool is_online = false; + if (is_pending) + { + xml->get("is_asker", &is_asker); + } + else + { + xml->get("online", &is_online); + m_is_friend = true; + } + m_relation_info = new RelationInfo(date, is_online, is_pending, + is_asker); + xml = xml->getNode("user"); + } + + xml->get("id", &m_id ); + xml->get("user_name", &m_username); + m_is_current_user = (m_id == CurrentUser::get()->getID()); + m_state = S_READY; +} // OnlineProfile(XMLNode) + +// ---------------------------------------------------------------------------- +OnlineProfile::~OnlineProfile() +{ + delete m_relation_info; +} // ~OnlineProfile + +// ---------------------------------------------------------------------------- +/** Triggers an asynchronous request to get the achievements for this user + * from the server. The state of this profile is changed to be fetching, + * and will be reset to ready when the server request returns. + */ +void OnlineProfile::fetchAchievements() +{ + assert(CurrentUser::get()->isRegisteredUser()); + if (m_has_fetched_achievements || m_is_current_user) + return; + m_state = S_FETCHING; + + // ------------------------------------------------------------------------ + /** A simple class that receives the achievements, and calls the right + * Profile instance to store them. */ + class AchievementsRequest : public XMLRequest + { + public: + AchievementsRequest() : XMLRequest(0, true) {} + virtual void callback() + { + uint32_t user_id = 0; + getXMLData()->get("visitingid", &user_id); + OnlineProfile *profile = ProfileManager::get()->getProfileByID(user_id); + if (profile) + profile->storeAchievements(getXMLData()); + } // AchievementsRequest::callback + }; // class AchievementsRequest + // ------------------------------------------------------------------------ + + AchievementsRequest * request = new AchievementsRequest(); + CurrentUser::setUserDetails(request); + request->addParameter("action", "get-achievements"); + request->addParameter("visitingid", m_id); + RequestManager::get()->addRequest(request); +} // fetchAchievements + +// ---------------------------------------------------------------------------- +/** Stores the achievement ids from an XML node into this profile. It also + * sets that achievements have been fetched, and changes the state to be + * READY again. + * \param input XML node with the achievements data. + */ +void OnlineProfile::storeAchievements(const XMLNode * input) +{ + m_achievements.clear(); + std::string achieved_string(""); + if (input->get("achieved", &achieved_string) == 1) + { + m_achievements = StringUtils::splitToUInt(achieved_string, ' '); + } + m_has_fetched_achievements = true; + m_state = S_READY; +} // storeAchievements + +// ---------------------------------------------------------------------------- +/** Triggers an asynchronous request to download the friends for this user. + * The state of this profile is changed to be fetching, + * and will be reset to ready when the server request returns. + */ +void OnlineProfile::fetchFriends() +{ + assert(CurrentUser::get()->isRegisteredUser()); + if (m_has_fetched_friends) + return; + m_state = S_FETCHING; + + // ------------------------------------------------------------------------ + class FriendsListRequest : public XMLRequest + { + public: + FriendsListRequest() : XMLRequest(0, true) {} + virtual void callback() + { + uint32_t user_id = 0; + getXMLData()->get("visitingid", &user_id); + OnlineProfile *profile = ProfileManager::get()->getProfileByID(user_id); + if (profile) + profile->storeFriends(getXMLData()); + } // callback + }; // class FriendsListRequest + // ------------------------------------------------------------------------ + + FriendsListRequest * request = new FriendsListRequest(); + CurrentUser::setUserDetails(request); + request->addParameter("action", "get-friends-list"); + request->addParameter("visitingid", m_id); + RequestManager::get()->addRequest(request); +} // fetchFriends + +// ---------------------------------------------------------------------------- +/** Stores the friends from an XML node into this profile. It also + * sets that friends have been fetched, and changes the state of the profile + * to be READY again. + * \param input XML node with the friends data. + */ +void OnlineProfile::storeFriends(const XMLNode * input) +{ + const XMLNode * friends_xml = input->getNode("friends"); + m_friends.clear(); + for (unsigned int i = 0; i < friends_xml->getNumNodes(); i++) + { + OnlineProfile * profile; + if (m_is_current_user) + { + profile = new OnlineProfile(friends_xml->getNode(i), C_RELATION_INFO); + m_friends.push_back(profile->getID()); + ProfileManager::get()->addPersistent(profile); + } + else + { + profile = new OnlineProfile(friends_xml->getNode(i)->getNode("user"), + C_DEFAULT); + m_friends.push_back(profile->getID()); + ProfileManager::get()->addToCache(profile); + } + } // for i in nodes + m_has_fetched_friends = true; + m_state = S_READY; +} // storeFriends + +// ---------------------------------------------------------------------------- +/** Removed a friend with a given id. + * \param id Friend id to remove. + */ +void OnlineProfile::removeFriend(const uint32_t id) +{ + assert(m_has_fetched_friends); + IDList::iterator iter; + for (iter = m_friends.begin(); iter != m_friends.end();) + { + if (*iter == id) + { + m_friends.erase(iter++); + break; + } + else + ++iter; + } +} // removeFriend + +// ---------------------------------------------------------------------------- +/** Adds a friend to the friend list. + * \param id The id of the profile to add. + */ +void OnlineProfile::addFriend(const uint32_t id) +{ + assert(m_has_fetched_friends); + for (unsigned int i = 0; i < m_friends.size(); i++) + if (m_friends[i] == id) + return; + m_friends.push_back(id); +} // addFriend + +// ---------------------------------------------------------------------------- +/** Deletes the relational info for this profile. + */ +void OnlineProfile::deleteRelationalInfo() +{ + delete m_relation_info; + m_relation_info = NULL; +} // deleteRelationalInfo + +// ---------------------------------------------------------------------------- +/** Returns the list of all friend ids. + */ +const OnlineProfile::IDList& OnlineProfile::getFriends() +{ + assert(m_has_fetched_friends && m_state == S_READY); + return m_friends; +} // getFriends + +// ---------------------------------------------------------------------------- +/** Returns the list of all achievement ids. + */ +const OnlineProfile::IDList& OnlineProfile::getAchievements() +{ + assert(m_has_fetched_achievements && m_state == S_READY && !m_is_current_user); + return m_achievements; +} // getAchievements + +// ---------------------------------------------------------------------------- +/** Merges the information from a given profile with this profile. Any data + * that is in the given profile that's not available in this profile will + * be copied over, then the given profile will be deleted. + */ +void OnlineProfile::merge(OnlineProfile *profile) +{ + assert(profile != NULL); + if (!this->m_has_fetched_friends && profile->m_has_fetched_friends) + this->m_friends = profile->m_friends; + if (!this->m_has_fetched_achievements && profile->m_has_fetched_achievements) + this->m_achievements = profile->m_achievements; + if (this->m_relation_info == NULL && profile->m_relation_info != NULL) + { + this->m_relation_info = profile->m_relation_info; + // We don't want the destructor of the profile instance to destroy + // the relation info + profile->m_relation_info = NULL; + } + delete profile; +} // merge + +} // namespace Online diff --git a/src/online/online_profile.hpp b/src/online/online_profile.hpp new file mode 100644 index 000000000..f36ee8d62 --- /dev/null +++ b/src/online/online_profile.hpp @@ -0,0 +1,166 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013 Glenn De Jonghe +// +// 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_ONLINE_PROFILE_HPP +#define HEADER_ONLINE_PROFILE_HPP + +#include "online/request_manager.hpp" +#include "online/xml_request.hpp" +#include "utils/types.hpp" +#include "utils/ptr_vector.hpp" + + +#include + +#include + +namespace Online +{ +/** Class that represents an online profile. It manages the online profile + * for any user on this system, but also for users for which information + * is requested (e.g. to see the achievements of friends). All those profiles + * are managed by the ProfileManager. + * \ingroup online + */ +class OnlineProfile +{ +public: + enum ConstructorType + { + C_DEFAULT = 1, + C_RELATION_INFO + }; + + // ======================================================================== + class RelationInfo + { + private: + bool m_is_online; + bool m_is_pending; + bool m_is_asker; + irr::core::stringw m_date; + public: + RelationInfo(const irr::core::stringw & date, bool is_online, + bool is_pending, bool is_asker = false); + void setOnline(bool online); + // -------------------------------------------------------------------- + bool isPending() const { return m_is_pending; } + // -------------------------------------------------------------------- + bool isAsker() const { return m_is_asker; } + // -------------------------------------------------------------------- + const irr::core::stringw & getDate() const { return m_date; } + // -------------------------------------------------------------------- + bool isOnline() const { return m_is_online; } + }; // class RelationInfo + // ======================================================================== + + typedef std::vector IDList; +private: + + /** The profile can either be fetching data, or be ready. */ + enum State + { + S_FETCHING = 1, + S_READY + }; + + State m_state; + bool m_is_current_user; + uint32_t m_id; + irr::core::stringw m_username; + /** information about the relation with the current user */ + RelationInfo * m_relation_info; + /** Whether or not the user of this profile, is a friend of the current user */ + bool m_is_friend; + + bool m_has_fetched_friends; + + /** List of user id's that are friends with the user of this profile. + * In case this profile is of the current user, this list also contains + * any id's of users that still have a friend request pending. */ + std::vector m_friends; + + bool m_has_fetched_achievements; + std::vector m_achievements; + + bool m_cache_bit; + + void storeFriends(const XMLNode * input); + void storeAchievements(const XMLNode * input); + +public: + OnlineProfile(const uint32_t & userid, + const irr::core::stringw & username, + bool is_current_user = false ); + OnlineProfile(const XMLNode * xml, + ConstructorType type = C_DEFAULT); + ~OnlineProfile(); + void fetchFriends(); + const IDList& getFriends(); + void fetchAchievements(); + void removeFriend(const uint32_t id); + void addFriend(const uint32_t id); + void deleteRelationalInfo(); + const IDList& getAchievements(); + void merge(OnlineProfile * profile); + // ------------------------------------------------------------------------ + /** Returns true if the achievements for this profile have been fetched. */ + bool hasFetchedAchievements() const { return m_has_fetched_achievements; } + // ------------------------------------------------------------------------ + /** Returns true if the friend list for this profile has been fetched. */ + bool hasFetchedFriends() const { return m_has_fetched_friends; } + // ------------------------------------------------------------------------ + /** True if the profile is not fetching data atm. */ + bool isReady() const { return m_state == S_READY; } + // ------------------------------------------------------------------------ + /** Returns true if this item is the current user. */ + bool isCurrentUser() const { return m_is_current_user; } + // ------------------------------------------------------------------------ + bool isFriend() const { return m_is_friend; } + // ------------------------------------------------------------------------ + void setFriend() { m_is_friend = true; } + // ------------------------------------------------------------------------ + RelationInfo* getRelationInfo() { return m_relation_info; } + // ------------------------------------------------------------------------ + void setRelationInfo(RelationInfo * r) + { + delete m_relation_info; m_relation_info = r; + } // setRelationInfo + // ------------------------------------------------------------------------ + /** Sets the cache bit of this profile. Used by the cache eviction + * algorithm. */ + void setCacheBit(bool cache_bit) { m_cache_bit = cache_bit; } + // ------------------------------------------------------------------------ + /** Returns the cache bit for this profile. Used by the cache eviction + * algorithm. */ + bool getCacheBit() const { return m_cache_bit; } + // ------------------------------------------------------------------------ + /** Returns the online id of this profile. */ + uint32_t getID() const { return m_id; } + // ------------------------------------------------------------------------ + /** Returns the user name of this profile. */ + const irr::core::stringw& getUserName() const { return m_username; } + // ------------------------------------------------------------------------ + +}; // class OnlineProfile + +} // namespace Online + +#endif + +/*EOF*/ diff --git a/src/online/profile.cpp b/src/online/profile.cpp deleted file mode 100644 index c4dad781e..000000000 --- a/src/online/profile.cpp +++ /dev/null @@ -1,283 +0,0 @@ -// -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 Glenn De Jonghe -// -// 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 "online/profile.hpp" - -#include "online/profile_manager.hpp" -#include "online/request_manager.hpp" -#include "config/user_config.hpp" -#include "online/current_user.hpp" -#include "utils/log.hpp" -#include "utils/translation.hpp" - -#include -#include -#include - -using namespace Online; - -namespace Online{ - - - - Profile::RelationInfo::RelationInfo(const irr::core::stringw & date, bool is_online, bool is_pending, bool is_asker) - { - m_date = date; - m_is_online = is_online; - m_is_pending = is_pending; - m_is_asker = is_asker; - } - - // ============================================================================ - void Profile::RelationInfo::setOnline(bool online) - { - m_is_online = online; - if(m_is_online) - m_is_pending = false; - } - - // ============================================================================ - Profile::Profile( const uint32_t & userid, - const irr::core::stringw & username, - bool is_current_user) - { - m_state = S_READY; - m_cache_bit = true; - m_id = userid; - m_is_current_user = is_current_user; - m_username = username; - m_has_fetched_friends = false; - m_has_fetched_achievements = false; - m_relation_info = NULL; - m_is_friend = false; - } - - Profile::Profile(const XMLNode * xml, ConstructorType type) - { - m_relation_info = NULL; - m_is_friend = false; - if(type == C_RELATION_INFO){ - irr::core::stringw date(""); - xml->get("date", &date); - std::string is_pending_string(""); - xml->get("is_pending", &is_pending_string); - bool is_pending = is_pending_string == "yes"; - bool is_asker(false); - bool is_online(false); - if(is_pending) - { - std::string is_asker_string(""); - xml->get("is_asker", &is_asker_string); - is_asker = is_asker_string == "yes"; - } - else - { - std::string is_online_string(""); - xml->get("online", &is_online_string); - is_online = is_online_string == "yes"; - m_is_friend = true; - } - m_relation_info = new RelationInfo(date, is_online, is_pending, is_asker); - xml = xml->getNode("user"); - } - - xml->get("id", &m_id); - xml->get("user_name", &m_username); - m_cache_bit = true; - m_has_fetched_friends = false; - m_has_fetched_achievements = false; - m_is_current_user = (m_id == CurrentUser::get()->getID()); - m_state = S_READY; - } - // ============================================================================ - Profile::~Profile() - { - delete m_relation_info; - } - - // ============================================================================ - void Profile::fetchAchievements() - { - assert(CurrentUser::get()->isRegisteredUser()); - if(m_has_fetched_achievements || m_is_current_user) - return; - m_state = S_FETCHING; - requestAchievements(); - } - - // ============================================================================ - void Profile::achievementsCallback(const XMLNode * input) - { - m_achievements.clear(); - std::string achieved_string(""); - if(input->get("achieved", &achieved_string) == 1) - { - m_achievements = StringUtils::splitToUInt(achieved_string, ' '); - } - m_has_fetched_achievements = true; - m_state = S_READY; - Log::info("test","tit"); - } - - // ============================================================================ - - void Profile::requestAchievements() - { - assert(CurrentUser::get()->isRegisteredUser() && !m_is_current_user); - AchievementsRequest * request = new AchievementsRequest(); - request->setServerURL("client-user.php"); - request->addParameter("action","get-achievements"); - request->addParameter("token", CurrentUser::get()->getToken()); - request->addParameter("userid", CurrentUser::get()->getID()); - request->addParameter("visitingid", m_id); - RequestManager::get()->addRequest(request); - } - - void Profile::AchievementsRequest::callback() - { - uint32_t user_id(0); - getXMLData()->get("visitingid", &user_id); - if( ProfileManager::get()->getProfileByID(user_id) != NULL ) - ProfileManager::get()->getProfileByID(user_id) - ->achievementsCallback(getXMLData()); - } - - // ============================================================================ - void Profile::fetchFriends() - { - assert(CurrentUser::get()->isRegisteredUser()); - if(m_has_fetched_friends) - return; - m_state = S_FETCHING; - requestFriendsList(); - } - // ============================================================================ - void Profile::friendsListCallback(const XMLNode * input) - { - const XMLNode * friends_xml = input->getNode("friends"); - m_friends.clear(); - for (unsigned int i = 0; i < friends_xml->getNumNodes(); i++) - { - Profile * profile; - if(m_is_current_user) - { - profile = new Profile(friends_xml->getNode(i) , C_RELATION_INFO); - ProfileManager::get()->addPersistent(profile); - } - else - { - profile = new Profile(friends_xml->getNode(i)->getNode("user"), C_DEFAULT); - ProfileManager::get()->addToCache(profile); - } - m_friends.push_back(profile->getID()); - } - m_has_fetched_friends = true; - m_state = S_READY; - } - - // ============================================================================ - - void Profile::requestFriendsList() - { - assert(CurrentUser::get()->isRegisteredUser()); - FriendsListRequest * request = new FriendsListRequest(); - request->setServerURL("client-user.php"); - request->addParameter("action","get-friends-list"); - request->addParameter("token", CurrentUser::get()->getToken()); - request->addParameter("userid", CurrentUser::get()->getID()); - request->addParameter("visitingid", m_id); - RequestManager::get()->addRequest(request); - } - - void Profile::FriendsListRequest::callback() - { - uint32_t user_id(0); - getXMLData()->get("visitingid", &user_id); - if( ProfileManager::get()->getProfileByID(user_id) != NULL ) - ProfileManager::get()->getProfileByID(user_id) - ->friendsListCallback(getXMLData()); - } - - // ============================================================================ - - void Profile::removeFriend( const uint32_t id) - { - assert (m_has_fetched_friends); - std::vector::iterator iter; - for (iter = m_friends.begin(); iter != m_friends.end();) - { - if (*iter == id) - { - m_friends.erase(iter++); - break; - } - else - ++iter; - } - } - // ============================================================================ - - void Profile::addFriend( const uint32_t id) - { - assert (m_has_fetched_friends); - for(unsigned int i=0; i< m_friends.size(); i++) - if(m_friends[i] == id) - return; - m_friends.push_back(id); - } - - // ============================================================================ - - void Profile::deleteRelationalInfo() - { - delete m_relation_info; - m_relation_info = NULL; - } - - // ============================================================================ - const std::vector & Profile::getFriends() - { - assert (m_has_fetched_friends && m_state == S_READY); - return m_friends; - } - - // ============================================================================ - const std::vector & Profile::getAchievements() - { - assert (m_has_fetched_achievements && m_state == S_READY && !m_is_current_user); - return m_achievements; - } - - //============================================================================= - void Profile::merge(Profile * profile) - { - assert (profile != NULL); - if(!this->m_has_fetched_friends && profile->m_has_fetched_friends) - this->m_friends = profile->m_friends; - if(!this->m_has_fetched_achievements && profile->m_has_fetched_achievements) - this->m_achievements = profile->m_achievements; - if(this->m_relation_info == NULL && profile->m_relation_info != NULL) - { - this->m_relation_info = profile->m_relation_info; - profile->m_relation_info = NULL; //We don't want the destructor of the profile instance to destroy the relation info - } - delete profile; - } - -} // namespace Online diff --git a/src/online/profile.hpp b/src/online/profile.hpp deleted file mode 100644 index 1095d474d..000000000 --- a/src/online/profile.hpp +++ /dev/null @@ -1,154 +0,0 @@ -// -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013 Glenn De Jonghe -// -// 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_ONLINE_PROFILE_HPP -#define HEADER_ONLINE_PROFILE_HPP - -#include "online/request_manager.hpp" -#include "online/xml_request.hpp" -#include "utils/types.hpp" -#include "utils/ptr_vector.hpp" - - -#include - -#include - -namespace Online{ - - // ============================================================================ - - /** - * \brief Class that represents an online profile - * \ingroup online - */ - class Profile - { - public : - enum ConstructorType - { - C_DEFAULT = 1, - C_RELATION_INFO - }; - class RelationInfo - { - private: - bool m_is_online; - bool m_is_pending; - bool m_is_asker; - irr::core::stringw m_date; - public: - RelationInfo(const irr::core::stringw & date, bool is_online, bool is_pending, bool is_asker = false); - bool isPending(){return m_is_pending;} - bool isAsker(){return m_is_asker;} - const irr::core::stringw & getDate() { return m_date; } - bool isOnline() const { return m_is_online; } - void setOnline(bool online); - }; - class FriendsListRequest : public XMLRequest - { - virtual void callback (); - public: - FriendsListRequest() : XMLRequest(0, true) {} - }; - class AchievementsRequest : public XMLRequest - { - virtual void callback (); - public: - AchievementsRequest() : XMLRequest(0, true) {} - }; - - typedef std::vector IDList; - private: - - enum State - { - S_FETCHING = 1, - S_READY - }; - - State m_state; - bool m_is_current_user; - uint32_t m_id; - irr::core::stringw m_username; - /** information about the relation with the current user */ - RelationInfo * m_relation_info; - /** Whether or not the user of this profile, is a friend of the current user */ - bool m_is_friend; - - bool m_has_fetched_friends; - /** - * List of user id's that are friends with the user of this profile. - * In case this profile is of the current user, this list also contains any id's of users that still have a friend request pending. - * */ - std::vector m_friends; - - bool m_has_fetched_achievements; - std::vector m_achievements; - - bool m_cache_bit; - - void requestFriendsList(); - void friendsListCallback(const XMLNode * input); - - void requestAchievements(); - void achievementsCallback(const XMLNode * input); - - public: - Profile( const uint32_t & userid, - const irr::core::stringw & username, - bool is_current_user = false); - Profile( const XMLNode * xml, - ConstructorType type = C_DEFAULT); - ~Profile(); - void fetchFriends(); - const std::vector & getFriends(); - bool hasFetchedFriends() { return m_has_fetched_friends;} - - void fetchAchievements(); - const std::vector & getAchievements(); - bool hasFetchedAchievements() { return m_has_fetched_achievements;} - - bool isFetching() const { return m_state == S_FETCHING; } - bool isReady() const { return m_state == S_READY; } - - bool isCurrentUser() const { return m_is_current_user; } - bool isFriend() const { return m_is_friend; } - void setFriend() { m_is_friend = true; } - void removeFriend(const uint32_t id); - void addFriend(const uint32_t id); - void deleteRelationalInfo(); - RelationInfo * getRelationInfo() { return m_relation_info; } - void setRelationInfo(RelationInfo * r){ delete m_relation_info; m_relation_info = r;} - - void setCacheBit(bool cache_bit) { m_cache_bit = cache_bit; } - bool getCacheBit() const { return m_cache_bit; } - - uint32_t getID() const { return m_id; } - const irr::core::stringw & getUserName() const { return m_username; } - - void merge(Profile * profile); - - - }; // class Profile - -} // namespace Online - -#endif - -/*EOF*/ diff --git a/src/online/profile_manager.cpp b/src/online/profile_manager.cpp index 142ae2d5e..b4850b43c 100644 --- a/src/online/profile_manager.cpp +++ b/src/online/profile_manager.cpp @@ -20,6 +20,7 @@ #include "online/profile_manager.hpp" #include "online/current_user.hpp" +#include "online/online_profile.hpp" #include "utils/log.hpp" #include "utils/translation.hpp" @@ -29,202 +30,246 @@ using namespace Online; -namespace Online{ - static ProfileManager* profile_manager_singleton(NULL); +namespace Online +{ - ProfileManager* ProfileManager::get() - { - if (profile_manager_singleton == NULL) - profile_manager_singleton = new ProfileManager(); - return profile_manager_singleton; +ProfileManager* ProfileManager::m_profile_manager = NULL; + +// ------------------------------------------------------------------------ +/** Private constructor, used by static create() function. + */ +ProfileManager::ProfileManager() +{ + m_max_cache_size = 2; + m_currently_visiting = NULL; +} // ProfileManager + +// ------------------------------------------------------------------------ +/** Destructor, which frees the persistent and cached data. + */ +ProfileManager::~ProfileManager() +{ + clearPersistent(); + ProfilesMap::iterator it; + for (it = m_profiles_cache.begin(); it != m_profiles_cache.end(); ++it) { + delete it->second; } +} // ~ProfileManager - void ProfileManager::deallocate() +// ------------------------------------------------------------------------ +/** Makes sure that the cache can store at least max_num entries. This is + * used by the online search screen to make sure all results found can + * be cached at the same time. + * \param min_num Minimum number of entries the chache should be able to + * store. + */ +int ProfileManager::guaranteeCacheSize(unsigned int min_num) +{ + if (m_max_cache_size < min_num) { - delete profile_manager_singleton; - profile_manager_singleton = NULL; - } // deallocate - - // ============================================================================ - ProfileManager::ProfileManager() - { - assert(m_max_cache_size > 1); - m_currently_visiting = NULL; + // Avoid that the cache can grow too big by setting an + // upper limit. + if (min_num > 100) + min_num = 100; + m_max_cache_size = min_num; } + return m_max_cache_size; - // ============================================================================ - ProfileManager::~ProfileManager() +} // guaranteeCacheSize + +// ------------------------------------------------------------------------ +/** Search for a given profile in the set of persistent and cached + * entries. If the profile does not exist, a NULL is returned. + * FIXME: This should be improved to download the profile is necessary. + * \param id The id of the profile to find. + */ +OnlineProfile* ProfileManager::getProfileByID(const uint32_t id) +{ + if (inPersistent(id)) + return m_profiles_persistent[id]; + if (isInCache(id)) + return m_profiles_cache[id]; + //FIXME not able to get! Now this should actually fetch the info from the + // server, but I haven't come up with a good asynchronous idea yet. + return NULL; +} // getProfileByID + +// ------------------------------------------------------------------------ +/** Adds profile to the cache. If the profile is already persistent, then +* it merges any new information from this profile to the persistent one. +* If the entry is already in the cache, the cached entry will be updated +* with any new information from the given profile. Otherwise, the profile +* is just added to the cache. +*/ +void ProfileManager::addToCache(OnlineProfile * profile) +{ + if (inPersistent(profile->getID())) + m_profiles_persistent[profile->getID()]->merge(profile); + else if (isInCache(profile->getID())) + m_profiles_cache[profile->getID()]->merge(profile); + else + addDirectToCache(profile); +} // addToCache + +// ------------------------------------------------------------------------ +/** Initialisation before the object is displayed. If necessary this function + * will pause the race if it is running (i.e. world exists). While only some + * of the screen can be shown during the race (via the in-game menu you + * can get the options screen and the help screens only). This is used by + * the RaceResultGUI to leave the race running (for the end animation) while + * the results are being shown. + */ +void ProfileManager::addDirectToCache(OnlineProfile* profile) +{ + assert(profile != NULL); + if (m_profiles_cache.size() == m_max_cache_size) { - clearPersistent(); - ProfilesMap::iterator it; - for ( it = m_profiles_cache.begin(); it != m_profiles_cache.end(); ++it ) { - delete it->second; - } - } - - // ============================================================================ - - void ProfileManager::iterateCache(Profile * profile) - { - if(m_profiles_cache.size() == m_max_cache_size) + // We have to replace a cached entry, find one entry that + // doesn't have its used bit set + ProfilesMap::iterator iter; + for (iter = m_profiles_cache.begin(); iter != m_profiles_cache.end();) { - profile->setCacheBit(true); - ProfilesMap::iterator iter; - for (iter = m_profiles_cache.begin(); iter != m_profiles_cache.end(); ++iter) + if (!iter->second->getCacheBit()) { - if (!iter->second->getCacheBit()) - return; + delete iter->second; + m_profiles_cache.erase(iter); + break; } - //All cache bits are one! Set them all to zero except the one currently being visited - for (iter = m_profiles_cache.begin(); iter != m_profiles_cache.end(); ++iter) - { - iter->second->setCacheBit(false); - } - profile->setCacheBit(true); + else + ++iter; } - } + m_profiles_cache[profile->getID()] = profile; + assert(m_profiles_cache.size() <= m_max_cache_size); - // ============================================================================ - /** Initialisation before the object is displayed. If necessary this function - * will pause the race if it is running (i.e. world exists). While only some - * of the screen can be shown during the race (via the in-game menu you - * can get the options screen and the help screens only). This is used by - * the RaceResultGUI to leave the race running (for the end animation) while - * the results are being shown. - */ - void ProfileManager::directToCache(Profile * profile) +} // addDirectToCache + +// ------------------------------------------------------------------------ +/** Checks if a profile is in cache. If so, it updates its usage bit. +* \param id Identifier for the profile to check. +*/ +bool ProfileManager::isInCache(const uint32_t id) +{ + ProfilesMap::const_iterator i = m_profiles_cache.find(id); + if (i != m_profiles_cache.end()) { - assert(profile != NULL); - if(m_profiles_cache.size() == m_max_cache_size) + updateCacheBits(i->second); + return true; + } + return false; +} // isInCache + +// ------------------------------------------------------------------------ +/** This function updates the cache bits of all cached entries. It will +* set the cache bit of the given profile. Then, if the cachen is full +* it will check if there are any entries that don't have the cache bit +* set (i.e. entries that can be discarded because they were not used). +* If no such entry is found, all usage flags will be reset, and only +* the one for the given entry will remain set. This results with high +* probability that most often used entries will remain in the cache, +* without adding much overhead. +*/ +void ProfileManager::updateCacheBits(OnlineProfile * profile) +{ + profile->setCacheBit(true); + if (m_profiles_cache.size() == m_max_cache_size) + { + ProfilesMap::iterator iter; + for (iter = m_profiles_cache.begin(); + iter != m_profiles_cache.end(); ++iter) { - ProfilesMap::iterator iter; - for (iter = m_profiles_cache.begin(); iter != m_profiles_cache.end();) - { - if (!iter->second->getCacheBit()) - { - delete iter->second; - m_profiles_cache.erase(iter); - break; - } - else - ++iter; - } + if (!iter->second->getCacheBit()) + return; } - m_profiles_cache[profile->getID()] = profile; - assert(m_profiles_cache.size() <= m_max_cache_size); - - } - - // ============================================================================ - /** - * Adds a profile to the persistent map. - * If a profile with the same id is already in there, the profiles are "merged" with as goal saving as much information. - * (i.e. one profile instance could have already fetched the friends, while the other could have fetched the achievements.) - */ - void ProfileManager::addPersistent(Profile * profile) - { - if(inPersistent(profile->getID())) + // All cache bits are set! Set them all to zero except the one + // currently being visited + for (iter = m_profiles_cache.begin(); + iter != m_profiles_cache.end(); ++iter) { - m_profiles_persistent[profile->getID()]->merge(profile); - } - else - { - m_profiles_persistent[profile->getID()] = profile; + iter->second->setCacheBit(false); } + profile->setCacheBit(true); } - // ============================================================================ - /** - * Removes and deletes an entry from the persistent map. - */ - void ProfileManager::deleteFromPersistent(const uint32_t id) + +} // updateCacheBits + +// ------------------------------------------------------------------------ +/** True if the profile with the given id is persistent. +* \param id The id of the profile to test. +*/ +bool ProfileManager::inPersistent(const uint32_t id) +{ + return m_profiles_persistent.find(id) != m_profiles_persistent.end(); +} // inPersistent + +// ------------------------------------------------------------------------ +/** Adds a profile to the persistent map. If a profile with the same id + * is already in there, the profiles are "merged" with the goal to save as + * much information (i.e. one profile instance could have already fetched + * the friends, while the other could have fetched the achievements.) + * \param profile The profile to make persistent. + */ +void ProfileManager::addPersistent(OnlineProfile * profile) +{ + if (inPersistent(profile->getID())) { - if (inPersistent(id)) - { - delete m_profiles_persistent[id]; - m_profiles_persistent.erase(id); - } - else - Log::warn("ProfileManager::removePersistent", "Tried to remove profile with id %d from persistent while not present", id); + m_profiles_persistent[profile->getID()]->merge(profile); } - - // ============================================================================ - - void ProfileManager::clearPersistent() + else { - ProfilesMap::iterator it; - for ( it = m_profiles_persistent.begin(); it != m_profiles_persistent.end(); ++it ) { - delete it->second; - } - m_profiles_persistent.clear(); + m_profiles_persistent[profile->getID()] = profile; } +} // addPersistent - // ============================================================================ - - void ProfileManager::moveToCache(const uint32_t id) +// ------------------------------------------------------------------------ +/** Removes and deletes an entry from the persistent map. + * \param id the id of the profile to be removed. + */ +void ProfileManager::deleteFromPersistent(const uint32_t id) +{ + if (inPersistent(id)) { - if (inPersistent(id)) - { - Profile * profile = getProfileByID(id); - m_profiles_persistent.erase(id); - addToCache(profile); - } - else - Log::warn("ProfileManager::moveToCache", "Tried to move profile with id %d from persistent to cache while not present", id); + delete m_profiles_persistent[id]; + m_profiles_persistent.erase(id); } + else + Log::warn("ProfileManager", + "Tried to remove profile with id %d from persistent while " + "not present", id); +} // deleteFromPersistent - // ============================================================================ - - void ProfileManager::addToCache(Profile * profile) +// ------------------------------------------------------------------------ +/** Deletes all persistent profiles. + */ +void ProfileManager::clearPersistent() +{ + ProfilesMap::iterator it; + for (it = m_profiles_persistent.begin(); + it != m_profiles_persistent.end(); ++it) { - if(inPersistent(profile->getID())) - m_profiles_persistent[profile->getID()]->merge(profile); - else if(cacheHit(profile->getID())) - m_profiles_cache[profile->getID()]->merge(profile); - else - directToCache(profile); + delete it->second; } + m_profiles_persistent.clear(); +} // clearPersistent - // ============================================================================ - - bool ProfileManager::inPersistent(const uint32_t id) +// ------------------------------------------------------------------------ +/** Removes a currently persistent profile to the cache (where it can + * be deleted later). + * \param id The the id of the profile to be moved. + */ +void ProfileManager::moveToCache(const uint32_t id) +{ + if (inPersistent(id)) { - if (m_profiles_persistent.find(id) != m_profiles_persistent.end()) - return true; - return false; + OnlineProfile * profile = getProfileByID(id); + m_profiles_persistent.erase(id); + addToCache(profile); } - - // ============================================================================ - - bool ProfileManager::cacheHit(const uint32_t id) - { - if (m_profiles_cache.find(id) != m_profiles_cache.end()) - { - iterateCache(m_profiles_cache[id]); - return true; - } - return false; - } - - // ============================================================================ - void ProfileManager::setVisiting(const uint32_t id) - { - m_currently_visiting = getProfileByID(id); - } - - // ============================================================================ - - Profile * ProfileManager::getProfileByID(const uint32_t id) - { - - if(inPersistent(id)) - return m_profiles_persistent[id]; - if(cacheHit(id)) - return m_profiles_cache[id]; - //FIXME not able to get! Now this should actually fetch the info from the server, but I haven't come up with a good asynchronous idea yet. - return NULL; - } - + else + Log::warn("ProfileManager", + "Tried to move profile with id %d from persistent to " + "cache while not present", id); +} // moveToCache } // namespace Online diff --git a/src/online/profile_manager.hpp b/src/online/profile_manager.hpp index 3f2e6a6f0..1a461c074 100644 --- a/src/online/profile_manager.hpp +++ b/src/online/profile_manager.hpp @@ -20,59 +20,109 @@ #define HEADER_ONLINE_PROFILE_MANAGER_HPP #include "utils/types.hpp" -#include "online/profile.hpp" - #include +#include +#include #include -namespace Online{ - /** - * \brief Class that takes care of online profiles - * \ingroup online - */ - class ProfileManager +namespace Online +{ + + class OnlineProfile; + +/** Class that manages all online profiles. Profiles are used for storing + * online information from local users, but also to store information about + * remote users (e.g. if you want to see the achievements of another user + * a Profile for this user is created, the server is then queried for + * the information and the result is stored in that profile). + * The profile manager has two + * \ingroup online. + */ +class ProfileManager +{ +private: + /** Singleton pointer. */ + static ProfileManager* m_profile_manager; + + ProfileManager(); + ~ProfileManager(); + + /** The mapping of ids to profile. */ + typedef std::map ProfilesMap; + + /** A map of profiles that is persistent. (i.e. no automatic + * removing happens) Normally used for the current user's profile + * and friends. */ + ProfilesMap m_profiles_persistent; + + /** Any profiles that don't go into the persistent map, go here. This + * uses a pseudo-LRU algorithm with age bits to remove entries when + * the max size is reached. */ + ProfilesMap m_profiles_cache; + + /** A temporary profile that is currently being 'visited', + * e.g. its data is shown in a gui. */ + OnlineProfile* m_currently_visiting; + + /** The max size of the m_profiles cache. Its default size can be + * inrceased when necessary (e.g. when too many search results are + * loaded, to make sure they can be all stored). */ + unsigned int m_max_cache_size; + + void updateCacheBits(OnlineProfile * profile); + void addDirectToCache(OnlineProfile * profile); + +public: + /** Create the singleton instance. */ + static void create() { + assert(!m_profile_manager); + m_profile_manager = new ProfileManager(); + } // create + // ---------------------------------------------------------------- + /** Returns the singleton. + * \pre create has been called to create the singleton. + */ + static ProfileManager* get() + { + assert(m_profile_manager); + return m_profile_manager; + } // get + // ---------------------------------------------------------------- + /** Destroys the singleton. */ + static void destroy() + { + assert(m_profile_manager); + delete m_profile_manager; + m_profile_manager = NULL; + } // destroy + // ---------------------------------------------------------------- - private: - ProfileManager (); - ~ProfileManager (); + void addToCache(OnlineProfile *profile); + void addPersistent(OnlineProfile *profile); + void deleteFromPersistent(const uint32_t id); + void clearPersistent(); + void moveToCache(const uint32_t id); + int guaranteeCacheSize(unsigned int max_num); + bool isInCache(const uint32_t id); + bool inPersistent(const uint32_t id); + OnlineProfile* getProfileByID(const uint32_t id); + // ---------------------------------------------------------------- + /** Marks a given profile to be the currently visited one. This + * is used to mark the profiles that ave its data display (e.g. + * to see achievements either of a local or a remote player). */ + void setVisiting(const uint32_t id) + { + m_currently_visiting = getProfileByID(id); + } // setVisiting + // ---------------------------------------------------------------- + /** \return the instance of the profile that's currently being + * visited */ + OnlineProfile* getVisitingProfile() { return m_currently_visiting; } - typedef std::map ProfilesMap; - - /** A map of profiles that is persistent. (i.e. no automatic removing happens) Normally used for the current user's profile and friends. */ - ProfilesMap m_profiles_persistent; - /** - * Any profiles that don't go into the persistent map, go here. - * Using a Least Recent Used caching algorithm with age bits to remove entries when the max size is reached. - **/ - ProfilesMap m_profiles_cache; - Profile * m_currently_visiting; - /** The max size of the m_profiles cache. */ - static const unsigned int m_max_cache_size = 20; - - void iterateCache(Profile * profile); - void directToCache(Profile * profile); - - public: - /**Singleton */ - static ProfileManager * get(); - static void deallocate(); - - void addToCache(Profile * profile); - void addPersistent(Profile * profile); - void deleteFromPersistent(const uint32_t id); - void clearPersistent(); - void moveToCache(const uint32_t id); - void setVisiting(const uint32_t id); - bool cacheHit(const uint32_t id); - bool inPersistent(const uint32_t id); - /** \return the instance of the profile that's currently being visited */ - Profile * getVisitingProfile() {return m_currently_visiting;} - Profile * getProfileByID(const uint32_t id); - - }; // class CurrentUser +}; // class CurrentUser } // namespace Online diff --git a/src/online/request.hpp b/src/online/request.hpp index a3572e644..4ddec7387 100644 --- a/src/online/request.hpp +++ b/src/online/request.hpp @@ -66,15 +66,17 @@ namespace Online LEAK_CHECK() /** Type of the request. Has 0 as default value. */ - const int m_type; + const int m_type; + /** True if the memory for this Request should be managed by * http connector (i.e. this object is freed once the request * is handled). Otherwise the memory is not freed, so it must * be freed by the calling function. */ - const bool m_manage_memory; + bool m_manage_memory; + /** The priority of this request. The higher the value the more important this request is. */ - const int m_priority; + const int m_priority; /** The different state of the requst: * - S_PREPARING:\n The request is created and can be configured, it @@ -140,6 +142,11 @@ namespace Online * by network_http (i.e. freed once the request is handled). */ bool manageMemory() const { return m_manage_memory; } // -------------------------------------------------------------------- + /** Sets the memory management flag of this request. This function + * must only be called by the main thread, since it is only tested by + * the main thread. */ + void setManageMemory(bool m) { m_manage_memory = m; } + // -------------------------------------------------------------------- /** Returns the priority of this request. */ int getPriority() const { return m_priority; } // -------------------------------------------------------------------- diff --git a/src/online/request_manager.cpp b/src/online/request_manager.cpp index b717c4d46..14be63b88 100644 --- a/src/online/request_manager.cpp +++ b/src/online/request_manager.cpp @@ -263,7 +263,7 @@ namespace Online else request->setDone(); } - } + } // handleResultQueue // ------------------------------------------------------------------------ /** Should be called every frame and takes care of processing the result diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 18f2a965a..dbbedd1ca 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -18,7 +18,7 @@ #include "physics/physics.hpp" -#include "achievements/achievements_manager.hpp" +#include "achievements/achievement_info.hpp" #include "animations/three_d_animation.hpp" #include "config/player_manager.hpp" #include "config/player_profile.hpp" @@ -28,6 +28,7 @@ #include "items/flyable.hpp" #include "karts/kart_properties.hpp" #include "karts/rescue_animation.hpp" +#include "karts/controller/player_controller.hpp" #include "modes/soccer_world.hpp" #include "modes/world.hpp" #include "karts/explosion_animation.hpp" @@ -258,13 +259,28 @@ void Physics::update(float dt) PowerupManager::PowerupType type = p->getUserPointer(0)->getPointerFlyable()->getType(); if(type != PowerupManager::POWERUP_BOWLING || !target_kart->isInvulnerable()) { - p->getUserPointer(0)->getPointerFlyable()->hit(target_kart); - if (type == PowerupManager::POWERUP_BOWLING) + Flyable *f = p->getUserPointer(0)->getPointerFlyable(); + f->hit(target_kart); + + // Check for achievements + AbstractKart * kart = World::getWorld()->getKart(f->getOwnerId()); + PlayerController *c = dynamic_cast(kart->getController()); + + // Check that it's not a kart hitting itself (this can + // happen at the time a flyable is shot - release too close + // to the kart, and it's the current player. At this stage + // only the current player can get achievements. + if (target_kart != kart && c && + c->getPlayer()->getConstProfile() == PlayerManager::get()->getCurrentPlayer()) { - AchievementsStatus* status = - PlayerManager::getCurrentAchievementsStatus(); - ((SingleAchievement *) status->getAchievement(2))->increase(1); - } + PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_ARCH_ENEMY, + target_kart->getIdent(), 1); + if (type == PowerupManager::POWERUP_BOWLING) + { + PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_STRIKE, + "ball", 1); + } // is bowling ball + } // if target_kart != kart && is a player kart and is current player } } diff --git a/src/race/grand_prix_data.cpp b/src/race/grand_prix_data.cpp index def7b336d..2a62811eb 100644 --- a/src/race/grand_prix_data.cpp +++ b/src/race/grand_prix_data.cpp @@ -31,16 +31,29 @@ #include #include -GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) +GrandPrixData::GrandPrixData(const std::string filename) +{ + load_from_file(file_manager->getAsset(FileManager::GRANDPRIX, filename), + filename); +} +// ---------------------------------------------------------------------------- +GrandPrixData::GrandPrixData(const std::string dir, const std::string filename) +{ + assert(dir[dir.size() - 1] == '/'); + load_from_file(dir + filename, filename); +} +// ---------------------------------------------------------------------------- +void GrandPrixData::load_from_file(const std::string fullpath, + const std::string filename) { m_filename = filename; m_id = StringUtils::getBasename(StringUtils::removeExtension(filename)); - XMLNode* root = file_manager->createXMLTree(file_manager->getAsset(FileManager::GRANDPRIX,filename)); + XMLNode * root = file_manager->createXMLTree(fullpath); if (!root) { - Log::error("GrandPrixData","Error while trying to read grandprix file '%s'", - filename.c_str()); + Log::error("GrandPrixData","Error while trying to read grandprix file " + "'%s'", fullpath.c_str()); throw std::logic_error("File not found"); } @@ -51,8 +64,9 @@ GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) std::string temp_name; if (root->get("name", &temp_name) == 0) { - Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : " - "missing 'name' attribute\n", filename.c_str()); + Log::error("GrandPrixData", "Error while trying to read grandprix " + "file '%s' : missing 'name' attribute\n", + fullpath.c_str()); delete root; throw std::logic_error("File contents are incomplete or corrupt"); } @@ -61,8 +75,9 @@ GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) } else { - Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : " - "Root node has an unexpected name\n", filename.c_str()); + Log::error("GrandPrixData", "Error while trying to read grandprix file " + "'%s' : Root node has an unexpected name\n", + fullpath.c_str()); delete root; throw std::logic_error("File contents are incomplete or corrupt"); } @@ -80,18 +95,20 @@ GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) int numLaps; bool reversed = false; - const int idFound = node->get("id", &trackID ); - const int lapFound = node->get("laps", &numLaps ); + const int idFound = node->get("id", &trackID); + const int lapFound = node->get("laps", &numLaps); // Will stay false if not found node->get("reverse", &reversed ); if (!idFound || !lapFound) { - Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : " - " tag does not have idi and laps reverse attributes. \n", - filename.c_str()); + Log::error("GrandPrixData", "Error while trying to read " + "grandprix file '%s' : tag does not have " + "idi and laps reverse attributes. \n", + fullpath.c_str()); delete root; - throw std::logic_error("File contents are incomplete or corrupt"); + throw std::logic_error("File contents are incomplete or " + "corrupt"); } // Make sure the track really is reversible @@ -110,22 +127,22 @@ GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) } else { - std::cerr << "Unknown node in Grand Prix XML file : " << node->getName().c_str() << std::endl; + Log::error("Unknown node in Grand Prix XML file: %s/n", + node->getName().c_str()); delete root; throw std::runtime_error("Unknown node in sfx XML file"); } - }// nend for + }// end for delete root; // sanity checks if (!foundName) { - Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : " - "missing 'name' attribute\n", filename.c_str()); + Log::error("GrandPrixData", "Error while trying to read grandprix file " + "'%s' : missing 'name' attribute\n", fullpath.c_str()); throw std::logic_error("File contents are incomplete or corrupt"); } - } // ---------------------------------------------------------------------------- bool GrandPrixData::checkConsistency(bool chatty) const @@ -149,7 +166,6 @@ bool GrandPrixData::checkConsistency(bool chatty) const return true; } // checkConsistency - // ---------------------------------------------------------------------------- /** Returns true if the track is available. This is used to test if Fort Magma * is available (this way FortMagma is not used in the last Grand Prix in diff --git a/src/race/grand_prix_data.hpp b/src/race/grand_prix_data.hpp index 074b6534f..8061d88c9 100644 --- a/src/race/grand_prix_data.hpp +++ b/src/race/grand_prix_data.hpp @@ -27,6 +27,7 @@ #include #include "utils/translation.hpp" +#include "io/file_manager.hpp" /** Simple class that hold the data relevant to a 'grand_prix', aka. a number * of races that has to be completed one after the other @@ -34,6 +35,7 @@ */ class GrandPrixData { +private: /** The name of the grand prix. */ irr::core::stringw m_name; @@ -63,6 +65,7 @@ class GrandPrixData /** Whether the track in question should be done in reverse mode */ std::vector m_reversed; + void load_from_file(const std::string fullpath, const std::string filename); bool isTrackAvailable(const std::string &id) const; public: @@ -70,8 +73,10 @@ public: #if (defined(WIN32) || defined(_WIN32)) && !defined(__MINGW32__) #pragma warning(disable:4290) #endif - GrandPrixData (const std::string filename) throw(std::logic_error); - GrandPrixData () {}; // empty for initialising + GrandPrixData () {}; // empty for initialising + GrandPrixData(const std::string filename); + GrandPrixData (const std::string dir, const std::string filename); + bool checkConsistency(bool chatty=true) const; const std::vector& getTrackNames() const; diff --git a/src/race/grand_prix_manager.cpp b/src/race/grand_prix_manager.cpp index 504d73797..508c35eae 100644 --- a/src/race/grand_prix_manager.cpp +++ b/src/race/grand_prix_manager.cpp @@ -21,22 +21,63 @@ #include #include "io/file_manager.hpp" #include "utils/string_utils.hpp" +#include "config/user_config.hpp" GrandPrixManager *grand_prix_manager = NULL; GrandPrixManager::GrandPrixManager() { // Findout which grand prixs are available and load them + // Grand Prix in the standart directory std::set result; - std::string gp_dir = file_manager->getAsset(FileManager::GRANDPRIX,""); + std::string gp_dir = file_manager->getAsset(FileManager::GRANDPRIX, ""); file_manager->listFiles(result, gp_dir); for(std::set::iterator i = result.begin(); i != result.end() ; i++) { - if (StringUtils::hasSuffix(*i, ".grandprix")) load(*i); - } // for i -} // GrandPrixManager + if (StringUtils::hasSuffix(*i, ".grandprix")) + { + try + { + m_gp_data.push_back(new GrandPrixData(*i)); + Log::debug("GrandPrixManager", "Grand Prix %s loaded.", + i->c_str()); + } + catch (std::logic_error& e) + { + Log::error("GrandPrixManager", "Ignoring GP %s ( %s ) \n", + i->c_str(), e.what()); + } + } + } + // Load additional Grand Prix + const std::string dir = UserConfigParams::m_additional_gp_directory; + if(dir != "") { + Log::info("GrandPrixManager", "Loading additional Grand Prix from " + "%s ...", dir.c_str()); + file_manager->listFiles(result, dir); + for(std::set::iterator i = result.begin(); + i != result.end() ; i++) + { + if (StringUtils::hasSuffix(*i, ".grandprix")) + { + try + { + m_gp_data.push_back(new GrandPrixData(dir, *i)); + Log::debug("GrandPrixManager", "Grand Prix %s loaded from " + "%s", i->c_str(), + dir.c_str()); + } + catch (std::logic_error& e) + { + Log::error("GrandPrixManager", "Ignoring GP %s ( %s ) \n", + i->c_str(), e.what()); + } + } + } // end for + } // end if +} // GrandPrixManager // ---------------------------------------------------------------------------- GrandPrixManager::~GrandPrixManager() { @@ -50,22 +91,11 @@ GrandPrixManager::~GrandPrixManager() const GrandPrixData* GrandPrixManager::getGrandPrix(const std::string& s) const { for(unsigned int i=0; igetId()==s) return m_gp_data[i]; + if(m_gp_data[i]->getId() == s) + return m_gp_data[i]; + return NULL; } // getGrandPrix -// ---------------------------------------------------------------------------- -void GrandPrixManager::load(const std::string& filename) -{ - try - { - m_gp_data.push_back(new GrandPrixData(filename)); - } - catch (std::logic_error& er) - { - Log::error("GrandPrixManager", "Ignoring GP %s ( %s ) \n", filename.c_str(), er.what()); - } -} // load - // ---------------------------------------------------------------------------- void GrandPrixManager::checkConsistency() { diff --git a/src/race/highscore_manager.cpp b/src/race/highscore_manager.cpp index 2af1a2582..b652f60ce 100644 --- a/src/race/highscore_manager.cpp +++ b/src/race/highscore_manager.cpp @@ -76,7 +76,7 @@ void HighscoreManager::loadHighscores() saveHighscores(); if(m_can_write) { - Log::error("Highscore Manager", "New highscore file '%s' created.\n", + Log::info("Highscore Manager", "New highscore file '%s' created.\n", m_filename.c_str()); } delete root; diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 29c36eeb2..3b29c01db 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -340,7 +340,8 @@ void RaceManager::startNew(bool from_overworld) } m_track_number = 0; - if(m_major_mode==MAJOR_MODE_GRAND_PRIX && !NetworkWorld::getInstance()->isRunning()) // offline mode only + if(m_major_mode==MAJOR_MODE_GRAND_PRIX && + !NetworkWorld::getInstance()->isRunning()) // offline mode only { //We look if Player 1 has a saved version of this GP. // ================================================= diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 35c07b26e..20a2a2b90 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -42,10 +42,10 @@ static const std::string IDENT_STD ("STANDARD" ); static const std::string IDENT_TTRIAL ("STD_TIMETRIAL" ); static const std::string IDENT_FTL ("FOLLOW_LEADER" ); static const std::string IDENT_STRIKES ("BATTLE_3_STRIKES"); -static const std::string IDENT_EASTER ("EASTER_EGG_HUNT"); +static const std::string IDENT_EASTER ("EASTER_EGG_HUNT" ); static const std::string IDENT_SOCCER ("SOCCER" ); -static const std::string IDENT_OVERWORLD("OVERWORLD" ); -static const std::string IDENT_CUSTSCENE("CUTSCENE" ); +static const std::string IDENT_OVERWORLD("OVERWORLD" ); +static const std::string IDENT_CUTSCENE ("CUTSCENE" ); /** * The race manager has two functions: diff --git a/src/states_screens/addons_screen.cpp b/src/states_screens/addons_screen.cpp index 757731251..ccd131d58 100644 --- a/src/states_screens/addons_screen.cpp +++ b/src/states_screens/addons_screen.cpp @@ -17,10 +17,9 @@ #include "states_screens/addons_screen.hpp" -#include - #include "addons/addons_manager.hpp" #include "addons/news_manager.hpp" +#include "config/user_config.hpp" #include "guiengine/CGUISpriteBank.h" #include "guiengine/modaldialog.hpp" #include "guiengine/scalable_font.hpp" @@ -34,6 +33,8 @@ #include "utils/translation.hpp" #include "utils/ptr_vector.hpp" +#include + DEFINE_SCREEN_SINGLETON( AddonsScreen ); using namespace Online; diff --git a/src/states_screens/arenas_screen.cpp b/src/states_screens/arenas_screen.cpp index 0523c1b8a..fd94d20cd 100644 --- a/src/states_screens/arenas_screen.cpp +++ b/src/states_screens/arenas_screen.cpp @@ -17,6 +17,7 @@ #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/widget.hpp" #include "guiengine/widgets/dynamic_ribbon_widget.hpp" diff --git a/src/states_screens/create_server_screen.cpp b/src/states_screens/create_server_screen.cpp index 64952f816..080eab702 100644 --- a/src/states_screens/create_server_screen.cpp +++ b/src/states_screens/create_server_screen.cpp @@ -19,20 +19,22 @@ #include "states_screens/create_server_screen.hpp" -#include -#include - -#include "challenges/unlock_manager.hpp" #include "audio/sfx_manager.hpp" +#include "challenges/unlock_manager.hpp" +#include "modes/demo_world.hpp" +#include "online/servers_manager.hpp" +#include "online/messages.hpp" #include "states_screens/online_screen.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/dialogs/message_dialog.hpp" -#include "modes/demo_world.hpp" -#include "utils/translation.hpp" #include "states_screens/networking_lobby.hpp" #include "states_screens/dialogs/server_info_dialog.hpp" -#include "online/servers_manager.hpp" -#include "online/messages.hpp" +#include "utils/translation.hpp" + +#include + +#include +#include using namespace GUIEngine; @@ -121,7 +123,7 @@ void CreateServerScreen::onUpdate(float delta) // ---------------------------------------------------------------------------- void CreateServerScreen::serverCreationRequest() { - const stringw name = m_name_widget->getText().trim(); + const irr::core::stringw name = m_name_widget->getText().trim(); const int max_players = m_max_players_widget->getValue(); m_info_widget->setErrorColor(); if (name.size() < 4 || name.size() > 30) diff --git a/src/states_screens/dialogs/change_password_dialog.cpp b/src/states_screens/dialogs/change_password_dialog.cpp index cdaceb40f..29791dc03 100644 --- a/src/states_screens/dialogs/change_password_dialog.cpp +++ b/src/states_screens/dialogs/change_password_dialog.cpp @@ -17,8 +17,6 @@ #include "states_screens/dialogs/change_password_dialog.hpp" -#include - #include "audio/sfx_manager.hpp" #include "guiengine/engine.hpp" #include "states_screens/state_manager.hpp" @@ -26,9 +24,12 @@ #include "utils/string_utils.hpp" #include "online/messages.hpp" +#include +#include using namespace GUIEngine; using namespace irr; +using namespace irr::core; using namespace irr::gui; using namespace Online; diff --git a/src/states_screens/dialogs/gp_info_dialog.cpp b/src/states_screens/dialogs/gp_info_dialog.cpp index 73b0f8475..ecc7568f4 100644 --- a/src/states_screens/dialogs/gp_info_dialog.cpp +++ b/src/states_screens/dialogs/gp_info_dialog.cpp @@ -48,6 +48,7 @@ using namespace GUIEngine; GPInfoDialog::GPInfoDialog(const std::string& gpIdent, const float w, const float h) : ModalDialog(w, h) { + doInit(); m_curr_time = 0.0f; const int y1 = m_area.getHeight()/7; diff --git a/src/states_screens/dialogs/notification_dialog.cpp b/src/states_screens/dialogs/notification_dialog.cpp index 298e89cda..4483b5925 100644 --- a/src/states_screens/dialogs/notification_dialog.cpp +++ b/src/states_screens/dialogs/notification_dialog.cpp @@ -22,6 +22,7 @@ #include "audio/sfx_manager.hpp" #include "guiengine/engine.hpp" #include "states_screens/state_manager.hpp" +#include "states_screens/online_profile_achievements.hpp" #include "states_screens/online_profile_friends.hpp" #include "utils/translation.hpp" @@ -129,17 +130,22 @@ void NotificationDialog::onUpdate(float dt) // It's unsafe to delete from inside the event handler so we do it here if (m_self_destroy) { + // Since dismiss deletes this object, store the instance values which + // we still need + bool view = m_view; + NotificationDialog::Type type = m_type; ModalDialog::dismiss(); - if (m_view) + if (view) { - if(m_type == T_Friends) + if(type == T_Friends) { ProfileManager::get()->setVisiting(CurrentUser::get()->getID()); StateManager::get()->pushScreen(OnlineProfileFriends::getInstance()); } - else if (m_type == T_Achievements) + else if (type == T_Achievements) { - //FIXME + ProfileManager::get()->setVisiting(CurrentUser::get()->getID()); + StateManager::get()->pushScreen(OnlineProfileAchievements::getInstance()); } } return; diff --git a/src/states_screens/dialogs/player_info_dialog.cpp b/src/states_screens/dialogs/player_info_dialog.cpp index b8f5b991a..5e0718e8c 100644 --- a/src/states_screens/dialogs/player_info_dialog.cpp +++ b/src/states_screens/dialogs/player_info_dialog.cpp @@ -43,6 +43,7 @@ using namespace irr::core; PlayerInfoDialog::PlayerInfoDialog(PlayerProfile* player, const float w, const float h) : ModalDialog(w, h) { m_player = player; + doInit(); showRegularDialog(); } @@ -146,7 +147,6 @@ void PlayerInfoDialog::showConfirmDialog() { clearWindow(); - IGUIFont* font = GUIEngine::getFont(); const int textHeight = GUIEngine::getFontHeight(); const int buttonHeight = textHeight + 10; diff --git a/src/states_screens/dialogs/recovery_dialog.cpp b/src/states_screens/dialogs/recovery_dialog.cpp index f0275f779..fc7b69a7e 100644 --- a/src/states_screens/dialogs/recovery_dialog.cpp +++ b/src/states_screens/dialogs/recovery_dialog.cpp @@ -17,8 +17,6 @@ #include "states_screens/dialogs/recovery_dialog.hpp" -#include - #include "audio/sfx_manager.hpp" #include "guiengine/engine.hpp" #include "states_screens/state_manager.hpp" @@ -26,6 +24,7 @@ #include "utils/string_utils.hpp" #include "online/messages.hpp" +#include using namespace GUIEngine; using namespace irr; @@ -103,8 +102,8 @@ bool RecoveryDialog::onEscapePressed() void RecoveryDialog::processInput() { - const stringw username = m_username_widget->getText().trim(); - const stringw email = m_email_widget->getText().trim(); + const core::stringw username = m_username_widget->getText().trim(); + const core::stringw email = m_email_widget->getText().trim(); if (username.size() < 4 || username.size() > 30 || email.size() < 4 || email.size() > 50) { sfx_manager->quickSound("anvil"); diff --git a/src/states_screens/dialogs/track_info_dialog.cpp b/src/states_screens/dialogs/track_info_dialog.cpp index a74f1cb23..d3023dc3f 100644 --- a/src/states_screens/dialogs/track_info_dialog.cpp +++ b/src/states_screens/dialogs/track_info_dialog.cpp @@ -19,6 +19,7 @@ #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/engine.hpp" #include "guiengine/screen.hpp" diff --git a/src/states_screens/dialogs/user_info_dialog.cpp b/src/states_screens/dialogs/user_info_dialog.cpp index 3c42aa80a..696738509 100644 --- a/src/states_screens/dialogs/user_info_dialog.cpp +++ b/src/states_screens/dialogs/user_info_dialog.cpp @@ -17,15 +17,15 @@ #include "states_screens/dialogs/user_info_dialog.hpp" -#include - #include "audio/sfx_manager.hpp" #include "guiengine/engine.hpp" -#include "states_screens/state_manager.hpp" -#include "states_screens/online_profile_overview.hpp" -#include "utils/translation.hpp" +#include "online/online_profile.hpp" #include "online/messages.hpp" +#include "states_screens/online_profile_overview.hpp" +#include "states_screens/state_manager.hpp" +#include "utils/translation.hpp" +#include using namespace GUIEngine; using namespace irr; @@ -93,7 +93,7 @@ void UserInfoDialog::beforeAddingWidgets() m_remove_widget->setVisible(true); } - Profile::RelationInfo * relation_info = m_profile->getRelationInfo(); + OnlineProfile::RelationInfo * relation_info = m_profile->getRelationInfo(); if(relation_info != NULL) { if(relation_info->isPending()) diff --git a/src/states_screens/dialogs/user_info_dialog.hpp b/src/states_screens/dialogs/user_info_dialog.hpp index c9f16eec3..d231b2157 100644 --- a/src/states_screens/dialogs/user_info_dialog.hpp +++ b/src/states_screens/dialogs/user_info_dialog.hpp @@ -19,14 +19,13 @@ #ifndef HEADER_USER_INFO_DIALOG_HPP #define HEADER_USER_INFO_DIALOG_HPP -#include - #include "guiengine/modaldialog.hpp" #include "guiengine/widgets.hpp" -#include "online/profile_manager.hpp" #include "online/current_user.hpp" +#include "online/profile_manager.hpp" #include "utils/types.hpp" +#include /** * \brief Dialog that allows a user to sign in @@ -45,7 +44,7 @@ private: irr::core::stringw m_info; const uint32_t m_showing_id; - Online::Profile * m_profile; + Online::OnlineProfile * m_profile; GUIEngine::LabelWidget * m_name_widget; GUIEngine::LabelWidget * m_info_widget; diff --git a/src/states_screens/easter_egg_screen.cpp b/src/states_screens/easter_egg_screen.cpp index 18ade0b41..cc78d4b2a 100644 --- a/src/states_screens/easter_egg_screen.cpp +++ b/src/states_screens/easter_egg_screen.cpp @@ -19,6 +19,7 @@ #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/widget.hpp" #include "guiengine/widgets/dynamic_ribbon_widget.hpp" diff --git a/src/states_screens/help_screen_1.cpp b/src/states_screens/help_screen_1.cpp index d8ca787b7..3dda36791 100644 --- a/src/states_screens/help_screen_1.cpp +++ b/src/states_screens/help_screen_1.cpp @@ -19,6 +19,7 @@ #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "guiengine/widget.hpp" #include "guiengine/widgets/list_widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp" diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index d777f3ede..1091a4e40 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -40,7 +40,7 @@ #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "modes/overworld.hpp" -#include "online/profile.hpp" +#include "online/online_profile.hpp" #include "states_screens/race_setup_screen.hpp" #include "states_screens/state_manager.hpp" #include "utils/log.hpp" @@ -134,12 +134,15 @@ PlayerNameSpinner::PlayerNameSpinner(KartSelectionScreen* parent, m_incorrect = false; m_red_mark_widget = NULL; m_parent = parent; + setUseBackgroundColor();//except for multiplayer kart selection, this is false + setSpinnerWidgetPlayerID(m_player_id); } // PlayerNameSpinner // ------------------------------------------------------------------------ void PlayerNameSpinner::setID(const int m_player_id) { PlayerNameSpinner::m_player_id = m_player_id; -} // setID + setSpinnerWidgetPlayerID(m_player_id); +} // setID // ------------------------------------------------------------------------ /** Add a red mark on the spinner to mean "invalid choice" */ void PlayerNameSpinner::markAsIncorrect() @@ -174,7 +177,6 @@ void PlayerNameSpinner::markAsCorrect() m_incorrect = false; } } // markAsCorrect - // ============================================================================ #if 0 @@ -187,7 +189,7 @@ void PlayerNameSpinner::markAsCorrect() PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, StateManager::ActivePlayer* associated_player, - Online::Profile* associated_user, + Online::OnlineProfile* associated_user, core::recti area, const int player_id, std::string kart_group, const int irrlicht_widget_id) : Widget(WTYPE_DIV) @@ -270,6 +272,7 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, //m_player_ident_spinner->m_event_handler = this; m_children.push_back(m_player_ident_spinner); + // ----- Kart model view @@ -377,7 +380,6 @@ PlayerKartWidget::~PlayerKartWidget() if (m_kart_name->getIrrlichtElement() != NULL) m_kart_name->getIrrlichtElement()->remove(); - getCurrentScreen()->manualRemoveWidget(this); #ifdef DEBUG @@ -410,12 +412,14 @@ void PlayerKartWidget::setPlayerID(const int newPlayerID) // Change the player ID m_player_id = newPlayerID; - + m_player_ident_spinner->setID(m_player_id); // restore previous focus, but with new player ID if (focus != NULL) focus->setFocusForPlayer(m_player_id); if (m_player_ident_spinner != NULL) + { m_player_ident_spinner->setID(m_player_id); + } } // setPlayerID // ------------------------------------------------------------------------ @@ -481,7 +485,7 @@ void PlayerKartWidget::add() const int player_amount = PlayerManager::get()->getNumPlayers(); for (int n=0; ngetPlayer(n)->getName(); + core::stringw name = PlayerManager::get()->getPlayer(n)->getName(); m_player_ident_spinner->addLabel( translations->fribidize(name) ); } diff --git a/src/states_screens/kart_selection.hpp b/src/states_screens/kart_selection.hpp index 13f0be8f7..229826fa0 100644 --- a/src/states_screens/kart_selection.hpp +++ b/src/states_screens/kart_selection.hpp @@ -19,25 +19,30 @@ #ifndef KART_SELECTION_INCLUDED #define KART_SELECTION_INCLUDED -#include #include "guiengine/screen.hpp" #include "guiengine/widgets/dynamic_ribbon_widget.hpp" #include "guiengine/widgets/label_widget.hpp" #include "guiengine/widgets/model_view_widget.hpp" #include "guiengine/widgets/spinner_widget.hpp" #include "states_screens/state_manager.hpp" + #include +#include + namespace GUIEngine { class Widget; class BubbleWidget; enum EventPropagation; + } namespace Online { class User; + class OnlineProfile; } + class InputDevice; class PlayerKartWidget; class KartHoverListener; @@ -203,7 +208,6 @@ class PlayerNameSpinner : public GUIEngine::SpinnerWidget bool m_incorrect; irr::gui::IGUIImage* m_red_mark_widget; KartSelectionScreen* m_parent; - //virtual EventPropagation focused(const int m_playerID) ; public: @@ -216,7 +220,7 @@ public: // ------------------------------------------------------------------------ /** Remove any red mark set with 'markAsIncorrect' */ - void markAsCorrect(); + void markAsCorrect(); }; /** A widget representing the kart selection for a player (i.e. the player's @@ -247,7 +251,7 @@ class PlayerKartWidget : public GUIEngine::Widget, int m_player_id; /** Network info about the user. */ - Online::Profile* m_associated_user; + Online::OnlineProfile* m_associated_user; /** Internal name of the spinner; useful to interpret spinner events, * which contain the name of the activated object */ @@ -278,7 +282,7 @@ public: PlayerKartWidget(KartSelectionScreen* parent, StateManager::ActivePlayer* associated_player, - Online::Profile* associated_user, + Online::OnlineProfile* associated_user, core::recti area, const int player_id, std::string kart_group, const int irrlicht_idget_id=-1); diff --git a/src/states_screens/login_screen.cpp b/src/states_screens/login_screen.cpp index 3e145c858..5f7610360 100644 --- a/src/states_screens/login_screen.cpp +++ b/src/states_screens/login_screen.cpp @@ -32,7 +32,10 @@ #include "utils/log.hpp" #include "utils/translation.hpp" +#include + using namespace GUIEngine; +using namespace irr; DEFINE_SCREEN_SINGLETON( LoginScreen ); @@ -76,9 +79,9 @@ void LoginScreen::login() info_widget->setDefaultColor(); info_widget->setText("", false); - const stringw username = getWidget("username") + const core::stringw username = getWidget("username") ->getText().trim(); - const stringw password = getWidget("password") + const core::stringw password = getWidget("password") ->getText().trim(); if (username.size() < 4 || username.size() > 30 || diff --git a/src/states_screens/main_menu_screen.cpp b/src/states_screens/main_menu_screen.cpp index c2ed26403..bbe0a215c 100644 --- a/src/states_screens/main_menu_screen.cpp +++ b/src/states_screens/main_menu_screen.cpp @@ -22,6 +22,7 @@ #include "addons/news_manager.hpp" #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/widgets/label_widget.hpp" diff --git a/src/states_screens/network_kart_selection.cpp b/src/states_screens/network_kart_selection.cpp index 1c419eb7a..6b31323a3 100644 --- a/src/states_screens/network_kart_selection.cpp +++ b/src/states_screens/network_kart_selection.cpp @@ -2,6 +2,7 @@ #include "audio/sfx_manager.hpp" #include "challenges/unlock_manager.hpp" +#include "config/user_config.hpp" #include "items/item_manager.hpp" #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" diff --git a/src/states_screens/online_profile_achievements.cpp b/src/states_screens/online_profile_achievements.cpp index 9784c4fb8..9651fdca4 100644 --- a/src/states_screens/online_profile_achievements.cpp +++ b/src/states_screens/online_profile_achievements.cpp @@ -24,11 +24,12 @@ #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/widget.hpp" +#include "online/messages.hpp" +#include "online/online_profile.hpp" #include "states_screens/dialogs/message_dialog.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/dialogs/user_info_dialog.hpp" #include "utils/translation.hpp" -#include "online/messages.hpp" #include @@ -43,99 +44,138 @@ using namespace Online; DEFINE_SCREEN_SINGLETON( OnlineProfileAchievements ); // ----------------------------------------------------------------------------- - -OnlineProfileAchievements::OnlineProfileAchievements() : OnlineProfileBase("online/profile_achievements.stkgui") +/** Constructor. + */ +OnlineProfileAchievements::OnlineProfileAchievements() + : OnlineProfileBase("online/profile_achievements.stkgui") { m_selected_achievement_index = -1; } // OnlineProfileAchievements // ----------------------------------------------------------------------------- - +/** Callback when the xml file was loaded. + */ void OnlineProfileAchievements::loadedFromFile() { OnlineProfileBase::loadedFromFile(); - m_achievements_list_widget = getWidget("achievements_list"); + m_achievements_list_widget = getWidget("achievements_list"); assert(m_achievements_list_widget != NULL); } // loadedFromFile // ---------------------------------------------------------------------------- - +/** Callback before widgets are added. Clears all widgets. + */ void OnlineProfileAchievements::beforeAddingWidget() { OnlineProfileBase::beforeAddingWidget(); m_achievements_list_widget->clearColumns(); m_achievements_list_widget->addColumn( _("Name"), 2 ); - if(m_visiting_profile->isCurrentUser()) + + // For the current player (even if not logged in, i.e. m_visiting_profile + // = NULL) user achievement progress will also be displayed + if(!m_visiting_profile || m_visiting_profile->isCurrentUser()) { m_achievements_list_widget->addColumn( _("Progress"), 1 ); } -} +} // beforeAddingWidget // ----------------------------------------------------------------------------- - +/** Called when entering this menu (after widgets have been added). +*/ void OnlineProfileAchievements::init() { OnlineProfileBase::init(); - m_profile_tabs->select( m_achievements_tab->m_properties[PROP_ID], PLAYER_ID_GAME_MASTER ); - assert(m_visiting_profile != NULL); - if(m_visiting_profile->isCurrentUser()) + m_profile_tabs->select( m_achievements_tab->m_properties[PROP_ID], + PLAYER_ID_GAME_MASTER ); + + // For current user add the progrss information. + // m_visiting_profile is NULL if the user is not logged in. + if(!m_visiting_profile || m_visiting_profile->isCurrentUser()) { + // No need to wait for results, since they are local anyway m_waiting_for_achievements = false; m_achievements_list_widget->clear(); const std::map & all_achievements = PlayerManager::get()->getCurrentPlayer()->getAchievementsStatus() ->getAllAchievements(); std::map::const_iterator it; - for (it = all_achievements.begin(); it != all_achievements.end(); ++it ) + for (it = all_achievements.begin(); it != all_achievements.end(); ++it) { - std::vector row; - row.push_back(GUIEngine::ListWidget::ListCell(it->second->getInfo()->getTitle(),-1,2)); - row.push_back(GUIEngine::ListWidget::ListCell(it->second->getProgressAsString(),-1,1, true)); - m_achievements_list_widget->addItem(StringUtils::toString(it->second->getInfo()->getID()), row); + std::vector row; + const Achievement *a = it->second; + ListWidget::ListCell title(a->getInfo()->getTitle(), -1, 2); + ListWidget::ListCell progress(a->getProgressAsString(), -1, 1); + row.push_back(title); + row.push_back(progress); + const std::string id = StringUtils::toString(a->getInfo()->getID()); + m_achievements_list_widget->addItem(id, row); + if (a->isAchieved()) + m_achievements_list_widget->markItemBlue(id); } } else { + // Show achievements of a remote user. Set the waiting flag + // and submit a request to get the achievement data. m_waiting_for_achievements = true; m_visiting_profile->fetchAchievements(); m_achievements_list_widget->clear(); - m_achievements_list_widget->addItem("loading", Messages::fetchingAchievements()); + m_achievements_list_widget->addItem("loading", + Messages::fetchingAchievements()); } } // init + // ----------------------------------------------------------------------------- -void OnlineProfileAchievements::eventCallback(Widget* widget, const std::string& name, const int playerID) +void OnlineProfileAchievements::eventCallback(Widget* widget, + const std::string& name, + const int playerID) { OnlineProfileBase::eventCallback( widget, name, playerID); if (name == m_achievements_list_widget->m_properties[GUIEngine::PROP_ID]) { - m_selected_achievement_index = m_achievements_list_widget->getSelectionID(); + m_selected_achievement_index = + m_achievements_list_widget->getSelectionID(); int id; - StringUtils::fromString(m_achievements_list_widget->getSelectionInternalName(), id); - new MessageDialog(AchievementsManager::get()->getAchievementInfo(id)->getDescription()); + std::string achievement = + m_achievements_list_widget->getSelectionInternalName(); + // Convert the achievement number into an integer, and if there + // is no error, show the achievement (it can happen that the + // string is "" if no achievement exists) + if(StringUtils::fromString(achievement, id)) + new MessageDialog(AchievementsManager::get() + ->getAchievementInfo(id)->getDescription()); } } // eventCallback // ---------------------------------------------------------------------------- +/** Called every frame. It will check if results from an achievement request + * have been received, and if so, display them. + */ void OnlineProfileAchievements::onUpdate(float delta) { - if(m_waiting_for_achievements) + if (!m_waiting_for_achievements) return; + + if (!m_visiting_profile->isReady()) { - if(m_visiting_profile->isReady()) - { - m_achievements_list_widget->clear(); - for(unsigned int i = 0; i < m_visiting_profile->getAchievements().size(); i++) - { - AchievementInfo * info = AchievementsManager::get()->getAchievementInfo(m_visiting_profile->getAchievements()[i]); - m_achievements_list_widget->addItem(StringUtils::toString(info->getID()), info->getTitle()); - } - m_waiting_for_achievements = false; - } - else - { - m_achievements_list_widget->renameItem("loading", Messages::fetchingFriends()); - } + // This will display an increasing number of dots while waiting. + m_achievements_list_widget->renameItem("loading", + Messages::fetchingAchievements()); + return; } -} + + // Now reesults are available, display them. + m_achievements_list_widget->clear(); + const OnlineProfile::IDList &a = m_visiting_profile->getAchievements(); + for (unsigned int i = 0; i < a.size(); i++) + { + AchievementInfo *info = + AchievementsManager::get()->getAchievementInfo(a[i]); + m_achievements_list_widget->addItem(StringUtils::toString(info->getID()), + info->getTitle() ); + } + m_waiting_for_achievements = false; + +} // onUpdate diff --git a/src/states_screens/online_profile_base.cpp b/src/states_screens/online_profile_base.cpp index 091bf0db4..38937648e 100644 --- a/src/states_screens/online_profile_base.cpp +++ b/src/states_screens/online_profile_base.cpp @@ -21,6 +21,7 @@ #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/widget.hpp" +#include "online/online_profile.hpp" #include "states_screens/state_manager.hpp" #include "utils/translation.hpp" #include "states_screens/online_profile_overview.hpp" @@ -42,34 +43,50 @@ OnlineProfileBase::OnlineProfileBase(const char* filename) : Screen(filename) } // OnlineProfileBase // ----------------------------------------------------------------------------- - +/** Callback when the xml file was loaded. + */ void OnlineProfileBase::loadedFromFile() { - m_profile_tabs = this->getWidget("profile_tabs"); + m_profile_tabs = getWidget("profile_tabs"); assert(m_profile_tabs != NULL); - m_header = this->getWidget("title"); + m_header = getWidget("title"); assert(m_header != NULL); - m_overview_tab = (IconButtonWidget *) m_profile_tabs->findWidgetNamed("tab_overview"); + m_overview_tab = + (IconButtonWidget *)m_profile_tabs->findWidgetNamed("tab_overview"); assert(m_overview_tab != NULL); - m_friends_tab = (IconButtonWidget *) m_profile_tabs->findWidgetNamed("tab_friends"); + m_friends_tab = + (IconButtonWidget *) m_profile_tabs->findWidgetNamed("tab_friends"); assert(m_friends_tab != NULL); - m_achievements_tab = (IconButtonWidget *) m_profile_tabs->findWidgetNamed("tab_achievements"); + m_achievements_tab = + (IconButtonWidget*)m_profile_tabs->findWidgetNamed("tab_achievements"); assert(m_achievements_tab != NULL); - m_settings_tab = (IconButtonWidget *) m_profile_tabs->findWidgetNamed("tab_settings"); + m_settings_tab = + (IconButtonWidget *) m_profile_tabs->findWidgetNamed("tab_settings"); assert(m_settings_tab != NULL); - } // loadedFromFile // ----------------------------------------------------------------------------- +/** Callback before widgets are added. Clears all widgets and saves the + * current profile. + */ void OnlineProfileBase::beforeAddingWidget() { m_visiting_profile = ProfileManager::get()->getVisitingProfile(); - if (!m_visiting_profile->isCurrentUser()) + if (!m_visiting_profile || !m_visiting_profile->isCurrentUser()) m_settings_tab->setVisible(false); -} + + // If not logged in, don't show profile or friends + if (!m_visiting_profile) + { + m_friends_tab->setVisible(false); + m_profile_tabs->setVisible(false); + } +} // beforeAddingWidget // ----------------------------------------------------------------------------- +/** Called when entering this menu (before widgets are added). + */ void OnlineProfileBase::init() { Screen::init(); @@ -79,27 +96,37 @@ void OnlineProfileBase::init() m_achievements_tab->setTooltip( _("Achievements") ); m_settings_tab->setTooltip( _("Account Settings") ); - if (m_visiting_profile->isCurrentUser()) + // If no visiting_profile is defined, use the data of the current player. + if (!m_visiting_profile || m_visiting_profile->isCurrentUser()) m_header->setText(_("Your profile"), false); - else + else if (m_visiting_profile) { - m_header->setText( m_visiting_profile->getUserName() + _("'s profile"), false); + m_header->setText(m_visiting_profile->getUserName() + _("'s profile"), false); } + else + Log::error("OnlineProfileBase", "No visting profile"); } // init // ----------------------------------------------------------------------------- - -void OnlineProfileBase::eventCallback(Widget* widget, const std::string& name, const int playerID) +/** Called when an event occurs (i.e. user clicks on something). +*/ +void OnlineProfileBase::eventCallback(Widget* widget, const std::string& name, + const int playerID) { if (name == m_profile_tabs->m_properties[PROP_ID]) { - std::string selection = ((RibbonWidget*)widget)->getSelectionIDString(PLAYER_ID_GAME_MASTER).c_str(); - - if (selection == m_overview_tab->m_properties[PROP_ID]) StateManager::get()->replaceTopMostScreen(OnlineProfileOverview::getInstance()); - else if (selection == m_friends_tab->m_properties[PROP_ID]) StateManager::get()->replaceTopMostScreen(OnlineProfileFriends::getInstance()); - else if (selection == m_achievements_tab->m_properties[PROP_ID]) StateManager::get()->replaceTopMostScreen(OnlineProfileAchievements::getInstance()); - else if (selection == m_settings_tab->m_properties[PROP_ID]) StateManager::get()->replaceTopMostScreen(OnlineProfileSettings::getInstance()); + std::string selection = + ((RibbonWidget*)widget)->getSelectionIDString(PLAYER_ID_GAME_MASTER); + StateManager *sm = StateManager::get(); + if (selection == m_overview_tab->m_properties[PROP_ID]) + sm->replaceTopMostScreen(OnlineProfileOverview::getInstance()); + else if (selection == m_friends_tab->m_properties[PROP_ID]) + sm->replaceTopMostScreen(OnlineProfileFriends::getInstance()); + else if (selection == m_achievements_tab->m_properties[PROP_ID]) + sm->replaceTopMostScreen(OnlineProfileAchievements::getInstance()); + else if (selection == m_settings_tab->m_properties[PROP_ID]) + sm->replaceTopMostScreen(OnlineProfileSettings::getInstance()); } else if (name == "back") { diff --git a/src/states_screens/online_profile_base.hpp b/src/states_screens/online_profile_base.hpp index 6b5ceba7a..034ce2ccb 100644 --- a/src/states_screens/online_profile_base.hpp +++ b/src/states_screens/online_profile_base.hpp @@ -29,14 +29,17 @@ namespace GUIEngine { class Widget; } -/** - * \brief Online profile base screen - * \ingroup states_screens - */ +/** Online profile base screen. Used for displaying friends, achievements, + * overview, and settings. It handles the tabs which are common to each + * of those screens, and keeps track of the profile to display. + * \ingroup states_screens + */ class OnlineProfileBase : public GUIEngine::Screen { protected: OnlineProfileBase(const char* filename); + + /** Pointer to the various widgets on the screen. */ GUIEngine::LabelWidget * m_header; GUIEngine::RibbonWidget* m_profile_tabs; GUIEngine::IconButtonWidget * m_overview_tab; @@ -44,7 +47,8 @@ protected: GUIEngine::IconButtonWidget * m_achievements_tab; GUIEngine::IconButtonWidget * m_settings_tab; - Online::Profile * m_visiting_profile; + /** The profile that should be shown. */ + Online::OnlineProfile *m_visiting_profile; public: @@ -52,7 +56,9 @@ public: virtual void loadedFromFile() OVERRIDE; /** \brief implement callback from parent class GUIEngine::Screen */ - virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name, const int playerID) OVERRIDE; + virtual void eventCallback(GUIEngine::Widget* widget, + const std::string& name, + const int playerID) OVERRIDE; /** \brief implement callback from parent class GUIEngine::Screen */ virtual void init() OVERRIDE; diff --git a/src/states_screens/online_profile_friends.cpp b/src/states_screens/online_profile_friends.cpp index 9335a9f1e..1c6c70021 100644 --- a/src/states_screens/online_profile_friends.cpp +++ b/src/states_screens/online_profile_friends.cpp @@ -21,17 +21,14 @@ #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/widget.hpp" -#include "states_screens/state_manager.hpp" -#include "states_screens/online_user_search.hpp" -#include "states_screens/dialogs/user_info_dialog.hpp" -#include "utils/translation.hpp" #include "online/messages.hpp" +#include "states_screens/dialogs/user_info_dialog.hpp" +#include "states_screens/online_user_search.hpp" +#include "states_screens/state_manager.hpp" +#include "utils/translation.hpp" #include -#include -#include - using namespace GUIEngine; using namespace irr::core; using namespace irr::gui; @@ -40,28 +37,30 @@ using namespace Online; DEFINE_SCREEN_SINGLETON( OnlineProfileFriends ); // ----------------------------------------------------------------------------- - -OnlineProfileFriends::OnlineProfileFriends() : OnlineProfileBase("online/profile_friends.stkgui") +/** Constructor for a display of all friends. + */ +OnlineProfileFriends::OnlineProfileFriends() + : OnlineProfileBase("online/profile_friends.stkgui") { - m_selected_friend_index = -1; } // OnlineProfileFriends // ----------------------------------------------------------------------------- - +/** Callback when the xml file was loaded. + */ void OnlineProfileFriends::loadedFromFile() { OnlineProfileBase::loadedFromFile(); - m_friends_list_widget = getWidget("friends_list"); + m_friends_list_widget = getWidget("friends_list"); assert(m_friends_list_widget != NULL); - m_search_button_widget = getWidget("search_button"); + m_search_button_widget = getWidget("search_button"); assert(m_search_button_widget != NULL); - m_search_box_widget = getWidget("search_box"); + m_search_box_widget = getWidget("search_box"); assert(m_search_box_widget != NULL); - } // loadedFromFile // ---------------------------------------------------------------------------- - +/** Callback before widgets are added. Clears all widgets. +*/ void OnlineProfileFriends::beforeAddingWidget() { OnlineProfileBase::beforeAddingWidget(); @@ -72,23 +71,29 @@ void OnlineProfileFriends::beforeAddingWidget() m_friends_list_widget->addColumn( _("Since"), 1 ); m_friends_list_widget->addColumn( _("Status"), 2 ); } -} +} // beforeAddingWidget // ----------------------------------------------------------------------------- - +/** Called when entering this menu (before widgets are added). + */ void OnlineProfileFriends::init() { OnlineProfileBase::init(); - m_profile_tabs->select( m_friends_tab->m_properties[PROP_ID], PLAYER_ID_GAME_MASTER ); + m_profile_tabs->select( m_friends_tab->m_properties[PROP_ID], + PLAYER_ID_GAME_MASTER ); assert(m_visiting_profile != NULL); m_visiting_profile->fetchFriends(); m_waiting_for_friends = true; m_friends_list_widget->clear(); m_friends_list_widget->addItem("loading", Messages::fetchingFriends()); } // init -// ----------------------------------------------------------------------------- -void OnlineProfileFriends::eventCallback(Widget* widget, const std::string& name, const int playerID) +// ----------------------------------------------------------------------------- +/** Called when an event occurs (i.e. user clicks on something). +*/ +void OnlineProfileFriends::eventCallback(Widget* widget, + const std::string& name, + const int playerID) { OnlineProfileBase::eventCallback( widget, name, playerID); if (name == m_search_button_widget->m_properties[GUIEngine::PROP_ID]) @@ -99,44 +104,74 @@ void OnlineProfileFriends::eventCallback(Widget* widget, const std::string& name } else if (name == m_friends_list_widget->m_properties[GUIEngine::PROP_ID]) { - m_selected_friend_index = m_friends_list_widget->getSelectionID(); - new UserInfoDialog(m_visiting_profile->getFriends()[m_selected_friend_index]); + int index = m_friends_list_widget->getSelectionID(); + if (index>-1) + new UserInfoDialog(m_visiting_profile->getFriends()[index]); } } // eventCallback // ---------------------------------------------------------------------------- +/** Displays the friends from a given profile. + */ +void OnlineProfileFriends::displayResults() +{ + m_friends_list_widget->clear(); + const OnlineProfile::IDList &friends = m_visiting_profile->getFriends(); + for (unsigned int i = 0; i < friends.size(); i++) + { + std::vector row; + OnlineProfile* friend_profile = + ProfileManager::get()->getProfileByID(friends[i]); + + // When looking at friends of a friend those profiles are not + // guaranteed to be persistent, so they might not be found in cache. + if (!friend_profile) + { + Log::warn("OnlineProfileFriends", + "Profile for %d not found - ignored.", friends[i]); + continue; + } + row.push_back(ListWidget::ListCell(friend_profile->getUserName(), + -1, 2) ); + if (m_visiting_profile->isCurrentUser()) + { + OnlineProfile::RelationInfo * relation_info = + friend_profile->getRelationInfo(); + row.push_back(ListWidget::ListCell(relation_info->getDate(), + -1, 1, true) ); + irr::core::stringw status(""); + if (relation_info->isPending()) + { + status = (relation_info->isAsker() ? _("New Request") + : _("Pending") ); + } + else + status = (relation_info->isOnline() ? _("Online") + : _("Offline") ); + row.push_back(ListWidget::ListCell(status, -1, 2, true)); + } + m_friends_list_widget->addItem("friend", row); + } + m_waiting_for_friends = false; + +} // displayResults + +// ---------------------------------------------------------------------------- +/** Called each frame to check if results have arrived. + * \param delta Time step size. + */ void OnlineProfileFriends::onUpdate(float delta) { if(m_waiting_for_friends) { if(m_visiting_profile->isReady()) { - m_friends_list_widget->clear(); - for(unsigned int i = 0; i < m_visiting_profile->getFriends().size(); i++) - { - std::vector row; - Profile* friend_profile = ProfileManager::get()->getProfileByID(m_visiting_profile->getFriends()[i]); - row.push_back(GUIEngine::ListWidget::ListCell(friend_profile->getUserName(),-1,2)); - if(m_visiting_profile->isCurrentUser()) - { - Profile::RelationInfo * relation_info = friend_profile->getRelationInfo(); - row.push_back(GUIEngine::ListWidget::ListCell(relation_info->getDate(),-1,1, true)); - irr::core::stringw status(""); - if(relation_info->isPending()) - { - status = (relation_info->isAsker() ? _("New Request") : _("Pending")); - } - else - status = (relation_info->isOnline() ? _("Online") : _("Offline")); - row.push_back(GUIEngine::ListWidget::ListCell(status,-1,2, true)); - } - m_friends_list_widget->addItem("friend", row); - } - m_waiting_for_friends = false; + displayResults(); } else { - m_friends_list_widget->renameItem("loading", Messages::fetchingFriends()); + m_friends_list_widget->renameItem("loading", + Messages::fetchingFriends()); } } -} +} // onUpdate diff --git a/src/states_screens/online_profile_friends.hpp b/src/states_screens/online_profile_friends.hpp index 7416ae68e..f7bcc3195 100644 --- a/src/states_screens/online_profile_friends.hpp +++ b/src/states_screens/online_profile_friends.hpp @@ -31,22 +31,22 @@ namespace GUIEngine { class Widget; } -/** - * \brief Online profiel overview screen - * \ingroup states_screens - */ +/** Online profile overview screen. + * \ingroup states_screens + */ class OnlineProfileFriends : public OnlineProfileBase, public GUIEngine::ScreenSingleton { private: OnlineProfileFriends(); - GUIEngine::ListWidget * m_friends_list_widget; - GUIEngine::ButtonWidget * m_search_button_widget; - GUIEngine::TextBoxWidget * m_search_box_widget; + /** Pointer to the various widgets on the screen. */ + GUIEngine::ListWidget *m_friends_list_widget; + GUIEngine::ButtonWidget *m_search_button_widget; + GUIEngine::TextBoxWidget *m_search_box_widget; - int m_selected_friend_index; bool m_waiting_for_friends; + void displayResults(); public: friend class GUIEngine::ScreenSingleton; @@ -54,16 +54,19 @@ public: virtual void loadedFromFile() OVERRIDE; /** \brief implement callback from parent class GUIEngine::Screen */ - virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name, const int playerID) OVERRIDE; + virtual void eventCallback(GUIEngine::Widget* widget, + const std::string& name, + const int playerID) OVERRIDE; /** \brief implement callback from parent class GUIEngine::Screen */ virtual void init() OVERRIDE; virtual void onUpdate(float delta) OVERRIDE; - virtual void beforeAddingWidget() OVERRIDE; - virtual void refreshFriendsList() {m_waiting_for_friends = true; } + // ------------------------------------------------------------------------ + /** Triggers a reload of the friend list next time this menu is shown. */ + void refreshFriendsList() {m_waiting_for_friends = true; } }; #endif diff --git a/src/states_screens/online_user_search.cpp b/src/states_screens/online_user_search.cpp index bd694fdc7..7ff93d8b7 100644 --- a/src/states_screens/online_user_search.cpp +++ b/src/states_screens/online_user_search.cpp @@ -17,30 +17,30 @@ #include "states_screens/online_user_search.hpp" -#include -#include - +#include "audio/sfx_manager.hpp" #include "guiengine/modaldialog.hpp" +#include "online/current_user.hpp" +#include "online/messages.hpp" #include "states_screens/dialogs/user_info_dialog.hpp" -#include "states_screens/state_manager.hpp" #include "states_screens/dialogs/message_dialog.hpp" +#include "states_screens/state_manager.hpp" #include "utils/translation.hpp" #include "utils/string_utils.hpp" -#include "online/messages.hpp" -#include "online/current_user.hpp" -#include "audio/sfx_manager.hpp" using namespace Online; +#include +#include + DEFINE_SCREEN_SINGLETON( OnlineUserSearch ); // ---------------------------------------------------------------------------- OnlineUserSearch::OnlineUserSearch() : Screen("online/user_search.stkgui") { - m_selected_index = -1; - m_search_request = NULL; - m_search_string = ""; + m_selected_index = -1; + m_search_request = NULL; + m_search_string = ""; m_last_search_string = ""; } // OnlineUserSearch @@ -51,60 +51,8 @@ OnlineUserSearch::~OnlineUserSearch() } // OnlineUserSearch // ---------------------------------------------------------------------------- - -void OnlineUserSearch::tearDown() -{ - delete m_search_request; - m_search_request = NULL; -} // tearDown - - -// ---------------------------------------------------------------------------- - -void OnlineUserSearch::parseResult(const XMLNode * input) -{ - m_users.clear(); - const XMLNode * users_xml = input->getNode("users"); - for (unsigned int i = 0; i < users_xml->getNumNodes(); i++) - { - Profile * profile = new Profile(users_xml->getNode(i)); - ProfileManager::get()->addToCache(profile); - m_users.push_back(profile->getID()); - } -} - -void OnlineUserSearch::showList() -{ - m_user_list_widget->clear(); - for (unsigned int i=0; i < m_users.size(); i++) - { - std::vector row; - Profile * profile = ProfileManager::get()->getProfileByID(m_users[i]); - assert(profile != NULL); - row.push_back(GUIEngine::ListWidget::ListCell(profile->getUserName(),-1,3)); - m_user_list_widget->addItem("user", row); - } -} - -// ---------------------------------------------------------------------------- - -void OnlineUserSearch::search() -{ - if ( m_search_string != "" && m_last_search_string != m_search_string ) - m_search_request = CurrentUser::get()->requestUserSearch(m_search_string); - else - m_fake_refresh = true; - m_user_list_widget->clear(); - m_user_list_widget->addItem("spacer", L""); - m_user_list_widget->addItem("loading", Messages::searching()); - m_back_widget->setDeactivated(); - m_search_box_widget->setDeactivated(); - m_search_button_widget->setDeactivated(); -} - - -// ---------------------------------------------------------------------------- - +/** Callback when the xml file was loaded. + */ void OnlineUserSearch::loadedFromFile() { m_back_widget = getWidget("back"); @@ -117,26 +65,149 @@ void OnlineUserSearch::loadedFromFile() assert(m_user_list_widget != NULL); } // loadedFromFile - // ---------------------------------------------------------------------------- - +/** Callback before widgets are added. Clears all widgets. + */ void OnlineUserSearch::beforeAddingWidget() { m_user_list_widget->clearColumns(); - m_user_list_widget->addColumn( _("Username"), 3 ); + m_user_list_widget->addColumn(_("Username"), 3); } // ---------------------------------------------------------------------------- - +/** Called when entering this menu (before widgets are added). + */ void OnlineUserSearch::init() { Screen::init(); search(); - m_fake_refresh = false; m_search_box_widget->setText(m_search_string); } // init // ---------------------------------------------------------------------------- -void OnlineUserSearch::eventCallback( GUIEngine::Widget* widget, const std::string& name, const int playerID) +/** Callback before the screen is removed. + */ +void OnlineUserSearch::tearDown() +{ + // The search request can be in one of three states: + // 1. It does not exist, nothing more to do. + // 2. It has been executed by the request manager, had its callback done + // and waits for this widget to collect the results. In this case, the + // requests state is 'isDone', and the memory of this object need to be + // freed here. + // 3. It is being executed by the request manager thread. In this case the + // request can not be freed (since the request manager might still + // write to it). In this case we set the flag that the request manager + // should manage the memory for the request, i.e. the request will be + // deleted once it is in the request manager's ready queue. + // Note that there is no race condition here: setting a request to be + // 'done', and checking if its memory need to be freed is done by the + // main thread (i.e. the same thread that executes this function ). So it + // is not possible that the thread stage changes to be 'isDone' while + // this function executes, or that the request is checked if it should + // be freed. + + if (m_search_request) + { + // Check if the request is ready (but its result have not been + // received here ... otherwise it would have been deleted). + if (m_search_request->isDone()) + { + delete m_search_request; + } + else + { + // This request is currently being handled by the request manager. + // We can set the memory management flag, since the separate + // request manager thread does not read or write this flag. + // The actual deletion of the request is done by the main + // thread, so there is no risk that the request is deleted + // between the next two calls!! + m_search_request->setManageMemory(true); + + // Set cancel flag to speed up cancellation of this request + m_search_request->cancel(); + } + } // if m_search_request +} // tearDown + + +// ---------------------------------------------------------------------------- +/** Adds the results of the query to the ProfileManager cache. + * \param input The XML node with all user data. + */ +void OnlineUserSearch::parseResult(const XMLNode * input) +{ + m_users.clear(); + const XMLNode * users_xml = input->getNode("users"); + // Try to reserve enough cache space for all found entries. + unsigned int n = ProfileManager::get() + ->guaranteeCacheSize(users_xml->getNumNodes()); + + if (n >= users_xml->getNumNodes()) + n = users_xml->getNumNodes(); + else + { + Log::warn("OnlineSearch", + "Too many results found, only %d will be displayed.", n); + } + for (unsigned int i = 0; i < n; i++) + { + OnlineProfile * profile = new OnlineProfile(users_xml->getNode(i)); + // The id must be pushed before adding it to the cache, since + // the cache might merge the new data with an existing entry + m_users.push_back(profile->getID()); + ProfileManager::get()->addToCache(profile); + } +} // parseResult + +// ---------------------------------------------------------------------------- +/** Takes the list of user ids from a query and shows it in the list gui. + */ +void OnlineUserSearch::showList() +{ + m_user_list_widget->clear(); + for (unsigned int i=0; i < m_users.size(); i++) + { + std::vector row; + OnlineProfile * profile = ProfileManager::get()->getProfileByID(m_users[i]); + // This could still happen if something pushed results out of the cache. + if (!profile) + { + Log::warn("OnlineSearch", "User %d not in cache anymore, ignored.", + m_users[i]); + continue; + } + row.push_back(GUIEngine::ListWidget::ListCell(profile->getUserName(),-1,3)); + m_user_list_widget->addItem("user", row); + } +} // showList + +// ---------------------------------------------------------------------------- +/** Called when a search is triggered. When it is a new search (and not just + * searching for the same string again), a request will be queued to + * receive the search results + */ +void OnlineUserSearch::search() +{ + if (m_search_string != "" && m_last_search_string != m_search_string) + { + m_search_request = CurrentUser::get()->requestUserSearch(m_search_string); + m_user_list_widget->clear(); + m_user_list_widget->addItem("spacer", L""); + m_user_list_widget->addItem("loading", Messages::searching()); + m_back_widget->setDeactivated(); + m_search_box_widget->setDeactivated(); + m_search_button_widget->setDeactivated(); + } +} // sarch + + +// ---------------------------------------------------------------------------- +/** Called when an event occurs (i.e. user clicks on something). + */ +void OnlineUserSearch::eventCallback(GUIEngine::Widget* widget, + const std::string& name, + const int player_id) { if (name == m_back_widget->m_properties[GUIEngine::PROP_ID]) { @@ -173,7 +244,9 @@ void OnlineUserSearch::setLastSelected() //FIXME actually use this here and in s } // setLastSelected // ---------------------------------------------------------------------------- - +/** Called every frame. It queries the search request for results and + * displays them if necessary. + */ void OnlineUserSearch::onUpdate(float dt) { if(m_search_request != NULL) @@ -201,12 +274,4 @@ void OnlineUserSearch::onUpdate(float dt) m_user_list_widget->renameItem("loading", Messages::searching()); } } - else if(m_fake_refresh) - { - showList(); - m_fake_refresh = false; - m_back_widget->setActivated(); - m_search_box_widget->setActivated(); - m_search_button_widget->setActivated(); - } } // onUpdate diff --git a/src/states_screens/online_user_search.hpp b/src/states_screens/online_user_search.hpp index 220be8b0f..4bc1082e9 100644 --- a/src/states_screens/online_user_search.hpp +++ b/src/states_screens/online_user_search.hpp @@ -20,7 +20,7 @@ #include "guiengine/screen.hpp" #include "guiengine/widgets.hpp" -#include "online/profile.hpp" +#include "online/online_profile.hpp" #include "online/request.hpp" #include "utils/ptr_vector.hpp" @@ -39,19 +39,28 @@ private: OnlineUserSearch(); ~OnlineUserSearch(); + /** Pointer to the back widget. */ GUIEngine::IconButtonWidget * m_back_widget; + /** Pointer to the search button. */ GUIEngine::ButtonWidget * m_search_button_widget; + /** Pointer to the search box. */ GUIEngine::TextBoxWidget * m_search_box_widget; + /** Pointer to the result list. */ GUIEngine::ListWidget * m_user_list_widget; /** The currently selected index, used to re-select this item after * addons_loading is being displayed. */ int m_selected_index; + /** Seach string entered in the search widget. */ irr::core::stringw m_search_string; + /** Last search string, used to avoid doing the same search again. */ irr::core::stringw m_last_search_string; - Online::Profile::IDList m_users; - const Online::XMLRequest * m_search_request; - bool m_fake_refresh; + + /** The list of all IDs found. */ + Online::OnlineProfile::IDList m_users; + + /** The online request to search for users. */ + Online::XMLRequest *m_search_request; void parseResult(const XMLNode * input); void showList(); @@ -78,7 +87,11 @@ public: virtual void onUpdate(float dt) OVERRIDE; void setLastSelected(); - void setSearchString(const irr::core::stringw & search_string) {m_search_string = search_string;} + /** Sets the search string to an initial value. */ + void setSearchString(const irr::core::stringw & search_string) + { + m_search_string = search_string; + } }; diff --git a/src/states_screens/options_screen_audio.cpp b/src/states_screens/options_screen_audio.cpp index 3abd6a514..1a419a7ab 100644 --- a/src/states_screens/options_screen_audio.cpp +++ b/src/states_screens/options_screen_audio.cpp @@ -20,6 +20,7 @@ #include "audio/music_manager.hpp" #include "audio/sfx_manager.hpp" #include "audio/sfx_base.hpp" +#include "config/user_config.hpp" #include "guiengine/screen.hpp" #include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/dynamic_ribbon_widget.hpp" diff --git a/src/states_screens/options_screen_input2.cpp b/src/states_screens/options_screen_input2.cpp index e8e49d033..34107d3b0 100644 --- a/src/states_screens/options_screen_input2.cpp +++ b/src/states_screens/options_screen_input2.cpp @@ -17,6 +17,7 @@ #include "states_screens/options_screen_input2.hpp" +#include "config/user_config.hpp" #include "guiengine/CGUISpriteBank.h" #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" diff --git a/src/states_screens/options_screen_players.cpp b/src/states_screens/options_screen_players.cpp index f89501d10..8aa8a7856 100644 --- a/src/states_screens/options_screen_players.cpp +++ b/src/states_screens/options_screen_players.cpp @@ -18,9 +18,10 @@ #include "states_screens/options_screen_players.hpp" #include "challenges/unlock_manager.hpp" +#include "config/device_config.hpp" #include "config/player_manager.hpp" #include "config/player_profile.hpp" -#include "config/device_config.hpp" +#include "config/user_config.hpp" #include "guiengine/engine.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" @@ -183,8 +184,8 @@ void OptionsScreenPlayers::eventCallback(Widget* widget, const std::string& name } else if (name == "playername") { - UserConfigParams::m_default_player = L""; race_manager->clearKartLastPositionOnOverworld(); + PlayerManager::get()->setCurrentPlayer(NULL,false); StateManager::get()->pushScreen(StoryModeLobbyScreen::getInstance()); } diff --git a/src/states_screens/options_screen_ui.cpp b/src/states_screens/options_screen_ui.cpp index 927355c8e..77c59489d 100644 --- a/src/states_screens/options_screen_ui.cpp +++ b/src/states_screens/options_screen_ui.cpp @@ -21,6 +21,7 @@ #include "audio/music_manager.hpp" #include "audio/sfx_manager.hpp" #include "audio/sfx_base.hpp" +#include "config/user_config.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/widgets/button_widget.hpp" diff --git a/src/states_screens/options_screen_video.cpp b/src/states_screens/options_screen_video.cpp index cf38c1a4e..9b553e02d 100644 --- a/src/states_screens/options_screen_video.cpp +++ b/src/states_screens/options_screen_video.cpp @@ -20,6 +20,7 @@ #include "audio/music_manager.hpp" #include "audio/sfx_manager.hpp" #include "audio/sfx_base.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/screen.hpp" #include "guiengine/widgets/button_widget.hpp" diff --git a/src/states_screens/race_gui_base.cpp b/src/states_screens/race_gui_base.cpp index 04a7d9702..bcb2f83eb 100644 --- a/src/states_screens/race_gui_base.cpp +++ b/src/states_screens/race_gui_base.cpp @@ -21,6 +21,7 @@ #include "states_screens/race_gui_base.hpp" #include "audio/music_manager.hpp" +#include "config/user_config.hpp" #include "graphics/camera.hpp" #include "graphics/glwrap.hpp" #include "graphics/irr_driver.hpp" diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 814c3267a..8c0350297 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -22,6 +22,7 @@ #include "audio/sfx_base.hpp" #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "graphics/glwrap.hpp" #include "graphics/material.hpp" #include "guiengine/engine.hpp" diff --git a/src/states_screens/race_setup_screen.cpp b/src/states_screens/race_setup_screen.cpp index 8fbcb282d..dce58717a 100644 --- a/src/states_screens/race_setup_screen.cpp +++ b/src/states_screens/race_setup_screen.cpp @@ -19,6 +19,7 @@ #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "guiengine/widgets/dynamic_ribbon_widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp" #include "guiengine/widgets/spinner_widget.hpp" diff --git a/src/states_screens/soccer_setup_screen.cpp b/src/states_screens/soccer_setup_screen.cpp index b4416c74f..e8470073f 100644 --- a/src/states_screens/soccer_setup_screen.cpp +++ b/src/states_screens/soccer_setup_screen.cpp @@ -17,20 +17,22 @@ #include "states_screens/soccer_setup_screen.hpp" -#include "input/device_manager.hpp" -#include "input/input_manager.hpp" -#include "states_screens/state_manager.hpp" -#include "states_screens/arenas_screen.hpp" +#include "config/user_config.hpp" #include "guiengine/widgets/button_widget.hpp" #include "guiengine/widgets/spinner_widget.hpp" #include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/label_widget.hpp" #include "guiengine/widgets/model_view_widget.hpp" #include "guiengine/scalable_font.hpp" +#include "input/device_manager.hpp" +#include "input/input_manager.hpp" #include "io/file_manager.hpp" -#include "karts/kart_properties_manager.hpp" -#include "karts/kart_properties.hpp" #include "karts/kart_model.hpp" +#include "karts/kart_properties.hpp" +#include "karts/kart_properties_manager.hpp" +#include "states_screens/arenas_screen.hpp" +#include "states_screens/state_manager.hpp" + using namespace GUIEngine; DEFINE_SCREEN_SINGLETON( SoccerSetupScreen ); diff --git a/src/states_screens/state_manager.cpp b/src/states_screens/state_manager.cpp index 073baf273..b71ab6d02 100644 --- a/src/states_screens/state_manager.cpp +++ b/src/states_screens/state_manager.cpp @@ -101,7 +101,9 @@ void StateManager::updateActivePlayerIDs() // ---------------------------------------------------------------------------- -int StateManager::createActivePlayer(PlayerProfile *profile, InputDevice *device, Online::Profile* user) +int StateManager::createActivePlayer(PlayerProfile *profile, + InputDevice *device, + Online::OnlineProfile* user) { ActivePlayer *p; int i; @@ -253,7 +255,7 @@ void StateManager::onStackEmptied() StateManager::ActivePlayer::ActivePlayer(PlayerProfile* player, InputDevice *device, - Online::Profile* user) + Online::OnlineProfile* user) { #ifdef DEBUG m_magic_number = 0xAC1EF1AE; diff --git a/src/states_screens/state_manager.hpp b/src/states_screens/state_manager.hpp index fff7bd61a..56c777bfb 100644 --- a/src/states_screens/state_manager.hpp +++ b/src/states_screens/state_manager.hpp @@ -36,7 +36,7 @@ class InputDevice; struct Input; namespace Online { - class Profile; + class OnlineProfile; } namespace GUIEngine @@ -76,7 +76,7 @@ public: { friend class StateManager; - Online::Profile *m_online_user; + Online::OnlineProfile *m_online_user; PlayerProfile *m_player; InputDevice *m_device; @@ -86,7 +86,8 @@ public: /** ID of this player within the list of active players */ int m_id; - ActivePlayer(PlayerProfile* player, InputDevice* device, Online::Profile* user); + ActivePlayer(PlayerProfile* player, InputDevice* device, + Online::OnlineProfile* user); #ifdef DEBUG unsigned int m_magic_number; @@ -128,14 +129,17 @@ public: void setPlayerProfile(PlayerProfile* player); // -------------------------------------------------------------------- - Online::Profile* getOnlineUser() + Online::OnlineProfile* getOnlineUser() { return m_online_user; - } + } // getOnlineUser // -------------------------------------------------------------------- /** Call to change the identity of this player (useful when player is * selecting his identity) */ - void setOnlineUser(Online::Profile* user) { m_online_user = user; } + void setOnlineUser(Online::OnlineProfile* user) + { + m_online_user = user; + } // -------------------------------------------------------------------- /** ID of this player within the list of active players */ @@ -193,7 +197,8 @@ public: */ const PlayerProfile* getActivePlayerProfile(const int id); - int createActivePlayer(PlayerProfile *profile, InputDevice *device, Online::Profile* use); + int createActivePlayer(PlayerProfile *profile, InputDevice *device, + Online::OnlineProfile* use); void removeActivePlayer(int id); unsigned int activePlayerCount(); diff --git a/src/states_screens/story_mode_lobby.cpp b/src/states_screens/story_mode_lobby.cpp index a3ecedabb..fbca28b7c 100644 --- a/src/states_screens/story_mode_lobby.cpp +++ b/src/states_screens/story_mode_lobby.cpp @@ -19,6 +19,7 @@ #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/list_widget.hpp" #include "states_screens/dialogs/enter_player_name_dialog.hpp" @@ -54,18 +55,11 @@ void StoryModeLobbyScreen::init() ListWidget* list = getWidget("gameslots"); list->clear(); - core::stringw name = UserConfigParams::m_default_player.toString(); - - - if (UserConfigParams::m_default_player.toString().size() > 0) + PlayerProfile *player = PlayerManager::get()->getCurrentPlayer(); + if(player) { - PlayerProfile *player = PlayerManager::get()->getPlayer(name); - if(player) - { - PlayerManager::get()->setCurrentPlayer(player); - StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); - return; - } + StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); + return; } for (unsigned int n=0; ngetNumPlayers(); n++) @@ -113,13 +107,9 @@ void StoryModeLobbyScreen::eventCallback(Widget* widget, ->getPlayer(list->getSelectionLabel()); if(player) { - PlayerManager::get()->setCurrentPlayer(player); player->computeActive(); CheckBoxWidget* cb = getWidget("rememberme"); - if (cb->getState()) - { - UserConfigParams::m_default_player = list->getSelectionLabel(); - } + PlayerManager::get()->setCurrentPlayer(player,cb->getState()); } else { @@ -145,7 +135,7 @@ void StoryModeLobbyScreen::onNewPlayerWithName(const stringw& new_name) PlayerProfile *player = PlayerManager::get()->getPlayer(new_name); if(player) { - PlayerManager::get()->setCurrentPlayer(player); + PlayerManager::get()->setCurrentPlayer(player,false); player->computeActive(); } else diff --git a/src/states_screens/tracks_screen.cpp b/src/states_screens/tracks_screen.cpp index ddf293651..a9772556e 100644 --- a/src/states_screens/tracks_screen.cpp +++ b/src/states_screens/tracks_screen.cpp @@ -19,6 +19,7 @@ #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/widget.hpp" #include "guiengine/widgets/dynamic_ribbon_widget.hpp" diff --git a/src/tracks/check_cannon.cpp b/src/tracks/check_cannon.cpp index 5f84d0615..4b0120e6b 100644 --- a/src/tracks/check_cannon.cpp +++ b/src/tracks/check_cannon.cpp @@ -20,6 +20,7 @@ #include "animations/animation_base.hpp" #include "animations/ipo.hpp" +#include "config/user_config.hpp" #include "graphics/show_curve.hpp" #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" diff --git a/src/tracks/check_goal.cpp b/src/tracks/check_goal.cpp index 66fc5a172..cfa7a23aa 100644 --- a/src/tracks/check_goal.cpp +++ b/src/tracks/check_goal.cpp @@ -18,10 +18,12 @@ #include "tracks/check_goal.hpp" +#include "config/user_config.hpp" #include "io/xml_node.hpp" #include "tracks/track.hpp" #include "tracks/track_object_manager.hpp" #include "modes/soccer_world.hpp" + #include /** Constructor for a check goal line. @@ -77,7 +79,7 @@ void CheckGoal::update(float dt) m_previous_position[ball_index] = xyz; ball_index++; } -} +} // update // ---------------------------------------------------------------------------- /** Called when the check line is triggered. This function creates a cannon @@ -89,13 +91,15 @@ void CheckGoal::trigger(unsigned int kart_index) SoccerWorld* world = dynamic_cast(World::getWorld()); if(!world) { - fprintf(stderr, "WARNING: no soccer world found, cannot count the points\n"); + Log::warn("CheckGoal", + "No soccer world found, cannot count the points."); return; } world->onCheckGoalTriggered(m_first_goal); -} // CheckGoal +} // trigger +// ---------------------------------------------------------------------------- bool CheckGoal::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, unsigned int indx) { @@ -108,6 +112,7 @@ bool CheckGoal::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, } // isTriggered +// ---------------------------------------------------------------------------- void CheckGoal::reset(const Track &track) { const TrackObjectManager* tom = track.getTrackObjectManager(); diff --git a/src/tracks/check_lap.cpp b/src/tracks/check_lap.cpp index 01865b483..71f6591af 100644 --- a/src/tracks/check_lap.cpp +++ b/src/tracks/check_lap.cpp @@ -20,6 +20,7 @@ #include +#include "config/user_config.hpp" #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" #include "modes/linear_world.hpp" diff --git a/src/tracks/check_line.cpp b/src/tracks/check_line.cpp index f66cdfaff..36015b334 100644 --- a/src/tracks/check_line.cpp +++ b/src/tracks/check_line.cpp @@ -18,6 +18,7 @@ #include "tracks/check_line.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" diff --git a/src/tracks/check_structure.cpp b/src/tracks/check_structure.cpp index 5f2bf1e75..5a3f8b05e 100644 --- a/src/tracks/check_structure.cpp +++ b/src/tracks/check_structure.cpp @@ -18,8 +18,7 @@ #include "tracks/check_structure.hpp" -#include - +#include "config/user_config.hpp" #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" #include "modes/linear_world.hpp" @@ -28,6 +27,8 @@ #include "tracks/check_lap.hpp" #include "tracks/check_manager.hpp" +#include + CheckStructure::CheckStructure(const XMLNode &node, unsigned int index) { diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index e697226bc..b1f8fdc66 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -21,6 +21,7 @@ #include "audio/sfx_base.hpp" #include "audio/sfx_buffer.hpp" #include "challenges/unlock_manager.hpp" +#include "config/user_config.hpp" #include "graphics/irr_driver.hpp" #include "graphics/material_manager.hpp" #include "graphics/particle_emitter.hpp" @@ -186,7 +187,7 @@ TrackObjectPresentationMesh::TrackObjectPresentationMesh(const XMLNode& xml_node // World::getWorld()->getTrack()->getTrackFile(model_name); bool animated = skeletal_animation && (UserConfigParams::m_graphical_effects || - World::getWorld()->getIdent() == IDENT_CUSTSCENE); + World::getWorld()->getIdent() == IDENT_CUTSCENE); bool displacing = false; xml_node.get("displacing", &displacing); animated &= !displacing; @@ -225,7 +226,7 @@ TrackObjectPresentationMesh::TrackObjectPresentationMesh( m_node = NULL; bool animated = (UserConfigParams::m_graphical_effects || - World::getWorld()->getIdent() == IDENT_CUSTSCENE); + World::getWorld()->getIdent() == IDENT_CUTSCENE); if (file_manager->fileExists(model_file)) { @@ -250,12 +251,14 @@ TrackObjectPresentationMesh::TrackObjectPresentationMesh( void TrackObjectPresentationMesh::init(const XMLNode* xml_node, scene::ISceneNode* parent, bool enabled) { bool skeletal_animation = true; // for backwards compatibility, if unspecified assume there is - xml_node->get("skeletal-animation", &skeletal_animation); + if(xml_node) + xml_node->get("skeletal-animation", &skeletal_animation); bool animated = skeletal_animation && (UserConfigParams::m_graphical_effects || - World::getWorld()->getIdent() == IDENT_CUSTSCENE); + World::getWorld()->getIdent() == IDENT_CUTSCENE); bool displacing = false; - xml_node->get("displacing", &displacing); + if(xml_node) + xml_node->get("displacing", &displacing); animated &= !displacing; m_mesh->grab(); @@ -280,11 +283,11 @@ void TrackObjectPresentationMesh::init(const XMLNode* xml_node, scene::ISceneNod m_node = node; m_frame_start = node->getStartFrame(); - if (xml_node != NULL) + if (xml_node) xml_node->get("frame-start", &m_frame_start); m_frame_end = node->getEndFrame(); - if (xml_node != NULL) + if (xml_node) xml_node->get("frame-end", &m_frame_end); } else diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index 1f01875bd..fee8af37f 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -22,6 +22,7 @@ #include "karts/abstract_kart.hpp" #include "graphics/irr_driver.hpp" #include "items/powerup_manager.hpp" +#include "items/attachment.hpp" #include "modes/world.hpp" #include "physics/irr_debug_drawer.hpp" #include "physics/physics.hpp" @@ -72,6 +73,9 @@ enum DebugMenuCommand DEBUG_POWERUP_SWITCH, DEBUG_POWERUP_ZIPPER, DEBUG_POWERUP_NITRO, + DEBUG_ATTACHMENT_PARACHUTE, + DEBUG_ATTACHMENT_BOMB, + DEBUG_ATTACHMENT_ANVIL, DEBUG_TOGGLE_GUI, DEBUG_THROTTLE_FPS }; @@ -89,6 +93,38 @@ void addPowerup(PowerupManager::PowerupType powerup) } } + +void addAttachment(Attachment::AttachmentType type) +{ + World* world = World::getWorld(); + if (world == NULL) return; + for(unsigned int i = 0; i < world->getNumKarts(); i++) + { + AbstractKart *kart = world->getKart(i); + if (kart->getController()->isPlayerController()) { + if (type == Attachment::ATTACH_ANVIL) + { + kart->getAttachment() + ->set(type, stk_config->m_anvil_time); + kart->adjustSpeed(stk_config->m_anvil_speed_factor); + kart->updateWeight(); + } + else if (type == Attachment::ATTACH_PARACHUTE) + { + kart->getAttachment() + ->set(type, stk_config->m_parachute_time); + } + else if (type == Attachment::ATTACH_BOMB) + { + kart->getAttachment() + ->set(type, stk_config->m_bomb_time); + } + } + } + +} + + // ----------------------------------------------------------------------------- // Debug menu handling bool onEvent(const SEvent &event) @@ -136,6 +172,12 @@ bool onEvent(const SEvent &event) sub->addItem(L"Zipper", DEBUG_POWERUP_ZIPPER ); sub->addItem(L"Nitro", DEBUG_POWERUP_NITRO ); + mnu->addItem(L"Attachments >",-1,true, true); + sub = mnu->getSubMenu(2); + sub->addItem(L"Bomb", DEBUG_ATTACHMENT_BOMB); + sub->addItem(L"Anvil", DEBUG_ATTACHMENT_ANVIL); + sub->addItem(L"Parachute", DEBUG_ATTACHMENT_PARACHUTE); + mnu->addItem(L"Profiler",DEBUG_PROFILER); if (UserConfigParams::m_profiler_enabled) mnu->addItem(L"Toggle capture profiler report", DEBUG_PROFILER_GENERATE_REPORT); @@ -325,6 +367,18 @@ bool onEvent(const SEvent &event) kart->setEnergy(100.0f); } } + else if (cmdID == DEBUG_ATTACHMENT_ANVIL) + { + addAttachment(Attachment::ATTACH_ANVIL); + } + else if (cmdID == DEBUG_ATTACHMENT_BOMB) + { + addAttachment(Attachment::ATTACH_BOMB); + } + else if (cmdID == DEBUG_ATTACHMENT_PARACHUTE) + { + addAttachment(Attachment::ATTACH_PARACHUTE); + } else if (cmdID == DEBUG_TOGGLE_GUI) { World* world = World::getWorld(); diff --git a/src/utils/log.hpp b/src/utils/log.hpp index 14207cb68..65fd1d2c4 100644 --- a/src/utils/log.hpp +++ b/src/utils/log.hpp @@ -109,6 +109,11 @@ public: m_min_log_level = (LogLevel)n; } // setLogLevel + // ------------------------------------------------------------------------ + /** Returns the log level. This is useful if some work is necessary to + * preprate output strings, which might not be used at all (example: + * replacing the cleartext password in an http request). */ + static LogLevel getLogLevel() { return m_min_log_level; } // ------------------------------------------------------------------------ /** Disable coloring of log messages. */ static void disableColor()