Merge branch 'master' into TangentsCaching

This commit is contained in:
Marianne Gagnon 2014-10-16 18:20:23 -04:00
commit bf5c77d061
166 changed files with 2404 additions and 2681 deletions

View File

@ -10,7 +10,7 @@
* Added Tutorial
* Added new Supertux difficulty
* New bubblegum shield weapon
* New Speeodmeter and nitro meter
* New Speedometer and nitro meter
* Add ability to filter addons
* Updated nitro models
* Add ability to save and resume Grand Prix

View File

@ -87,11 +87,7 @@ if(WIN32)
set(ENV{PATH} "$ENV{PATH};${PROJECT_SOURCE_DIR}/dependencies/include")
set(ENV{LIB} ${PROJECT_SOURCE_DIR}/dependencies/lib)
set(ENV{OPENALDIR} ${PROJECT_SOURCE_DIR}/dependencies)
if(MSVC)
add_definitions(/D_IRR_STATIC_LIB_)
elseif(MINGW)
add_definitions(-D_IRR_STATIC_LIB_)
endif()
add_definitions(-D_IRR_STATIC_LIB_)
endif()
@ -149,7 +145,7 @@ endif()
if(UNIX OR MINGW)
# if(USE_CPP2011)
add_definitions("-std=gnu++0x")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
# endif()
endif()
@ -172,7 +168,7 @@ endif()
# Set some compiler options
if(UNIX OR MINGW)
add_definitions(-Wall)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif()
if(WIN32)
@ -200,7 +196,7 @@ endif()
# TODO: remove this switch
add_definitions(-DHAVE_OGGVORBIS)
if(WIN32 AND NOT MINGW)
if(WIN32)
configure_file("${STK_SOURCE_DIR}/windows_installer/icon_rc.template" "${PROJECT_BINARY_DIR}/tmp/icon.rc")
endif()
@ -291,8 +287,7 @@ if(UNIX AND NOT APPLE)
target_link_libraries(supertuxkart ${IRRLICHT_XF86VM_LIBRARY})
endif()
if(USE_ASAN)
add_definitions("-fsanitize=address")
add_definitions("-fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
target_link_libraries(supertuxkart "-fsanitize=address")
endif()
endif()
@ -318,11 +313,7 @@ if(USE_WIIUSE)
find_library(BLUETOOTH_LIBRARY NAMES IOBluetooth PATHS /Developer/Library/Frameworks/IOBluetooth.framework)
target_link_libraries(supertuxkart wiiuse ${BLUETOOTH_LIBRARY})
elseif(WIN32)
if(MSVC)
add_definitions("/DWIIUSE_STATIC")
else()
add_definitions("-DWIIUSE_STATIC")
endif()
add_definitions(-DWIIUSE_STATIC)
if(WIIUSE_BUILD)
target_link_libraries(supertuxkart wiiuse)
else()

View File

@ -48,4 +48,8 @@
title="Banana Lover" description="Collect at least 5 bananas in one race.">
<banana goal="5"/>
</achievement>
<achievement id="10" secret="yes" check-type="all-at-least" reset-type="race"
title="It's secret" description="Really ... a secret.">
</achievement>
</achievements>

22
data/fonts/materials.xml Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<materials>
<!-- Fonts -->
<material name="title_font.png" shader="unlit" lazy-load="Y"/>
<material name="title_font_2.png" shader="unlit" lazy-load="Y"/>
<material name="sigmar0.png" shader="unlit" lazy-load="Y"/>
<material name="comix.png" shader="unlit" lazy-load="Y"/>
<material name="LayneHansom0.png" shader="unlit" lazy-load="Y"/>
<material name="Mplus2p_JP0.png" shader="unlit" lazy-load="Y"/>
<material name="rasheeq0.png" shader="unlit" lazy-load="Y"/>
<material name="rasheeq3.png" shader="unlit" lazy-load="Y"/>
<material name="rasheeq4.png" shader="unlit" lazy-load="Y"/>
<material name="wqyMicroHei0.png" shader="unlit" lazy-load="Y"/>
<material name="wqyMicroHei1.png" shader="unlit" lazy-load="Y"/>
<material name="wqyMicroHei2.png" shader="unlit" lazy-load="Y"/>
<material name="wqyMicroHei3.png" shader="unlit" lazy-load="Y"/>
<material name="wqyMicroHei4.png" shader="unlit" lazy-load="Y"/>
<material name="wqyMicroHei5.png" shader="unlit" lazy-load="Y"/>
<material name="AR_PL_SungtiL_GB0.png" shader="unlit" lazy-load="Y"/>
<material name="LayneHansomBigDigits.png" shader="unlit" lazy-load="Y"/>
</materials>

View File

@ -9,9 +9,8 @@
<spacer height="25" width="10"/>
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
<icon-button id="tab_overview" width="128" height="128" icon="gui/options_ui.png" />
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png"/>
<icon-button id="tab_achievements" width="128" height="128" icon="gui/options_players.png" I18N="Section in the profile menu" text="Achievements"/>
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png"/>
<icon-button id="tab_settings" width="128" height="128" icon="gui/main_options.png"/>
</tabs>

View File

@ -9,9 +9,8 @@
<spacer height="25" width="10"/>
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
<icon-button id="tab_overview" width="128" height="128" icon="gui/options_ui.png" />
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png" I18N="Section in the profile menu" text="Friends"/>
<icon-button id="tab_achievements" width="128" height="128" icon="gui/options_players.png"/>
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png" I18N="Section in the profile menu" text="Friends"/>
<icon-button id="tab_settings" width="128" height="128" icon="gui/main_options.png"/>
</tabs>

View File

@ -9,9 +9,8 @@
<spacer height="25" width="10"/>
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
<icon-button id="tab_overview" width="128" height="128" icon="gui/options_ui.png"/>
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png" />
<icon-button id="tab_achievements" width="128" height="128" icon="gui/options_players.png"/>
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png" />
<icon-button id="tab_settings" width="128" height="128" icon="gui/main_options.png" I18N="Section in the profile menu" text="Account Settings"/>
</tabs>

View File

@ -8,6 +8,8 @@
<button id="assignEsc" I18N="When configuring input" text="Assign to ESC key" align="center"/>
<spacer height="10" width="10" />
<button id="assignNone" I18N="When configuring input" text="Assign nothing" align="center"/>
<spacer height="10" width="10" />
<button id="cancel" I18N="When configuring input" text="Press ESC to cancel" align="center"/>
</div>

View File

@ -2,7 +2,7 @@
<stkgui>
<div x="5%" y="5%" width="90%" height="90%" layout="vertical-row" >
<header id="title" width="80%" text="Race Setup" align="center" text_align="center" />
<header id="title" width="100%" text="Race Setup" align="center" text_align="center" />
<spacer height="2%" width="1"/>

View File

@ -13,32 +13,32 @@
square_items="true" child_width="128" child_height="128" />
<spacer height="15" width="10"/>
<div width="80%" align="center" layout="vertical-row" height="fit">
<div width="90%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the login screen" text="Online"/>
<checkbox id="online" I18N="In the login screen" text_align="left"/>
<label width="40%" height="100%" text_align="left" I18N="In the login screen" text="Online"/>
<checkbox width="fit" id="online" I18N="In the login screen" text_align="left"/>
</div>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_remember" proportion="1" height="100%" text_align="left"
<label width="40%" id="label_remember" height="100%" text_align="left"
I18N="In the login screen" text="Remember password"/>
<checkbox id="remember-user" I18N="In the login screen" text_align="left"/>
<checkbox width="fit" id="remember-user" I18N="In the login screen" text_align="left"/>
</div>
<!-- Disable guest accounts for now
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_guest" proportion="1" height="100%" text_align="left"
<label width="40%" id="label_guest" height="100%" text_align="left"
I18N="In the login screen" text="Guest login"/>
<checkbox id="guest" I18N="In the login screen" text_align="left"/>
</div>
-->
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_username" proportion="1" height="100%" text_align="left"
<label width="40%" id="label_username" height="100%" text_align="left"
I18N="In the login screen" text="Username"/>
<textbox id="username" proportion="2" height="fit" I18N="In the registration dialog"/>
</div>
<spacer height="20" width="20"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_password" proportion="1" height="100%" text_align="left"
<label id="label_password" width="40%" height="100%" text_align="left"
I18N="In the registration dialog" text="Password"/>
<textbox id="password" proportion="2" height="fit" I18N="In the registration dialog"/>
</div>
@ -54,8 +54,6 @@
I18N="Login dialog" text="Add user" label_location="bottom"/>
<icon-button id="delete" width="64" height="64" icon="gui/gp_remove_track.png"
I18N="Login dialog" text="Delete" label_location="bottom"/>
<icon-button id="recover" width="64" height="64" icon="gui/main_options.png"
I18N="Login dialog" text="Recovery" label_location="bottom"/>
<icon-button id="rename" width="64" height="64" icon="gui/gp_rename.png"
I18N="Login dialog" text="Rename" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"

View File

@ -22,15 +22,15 @@
square_items="true" child_width="128" child_height="128" />
<spacer height="15" width="10"/>
<div width="80%" align="center" layout="vertical-row" height="fit">
<div width="90%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the login screen" text="Online"/>
<checkbox id="online" I18N="In the login screen" text_align="left"/>
<label width="40%" height="100%" text_align="left" I18N="In the login screen" text="Online"/>
<checkbox width="fit" id="online" I18N="In the login screen" text_align="left"/>
</div>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_remember" proportion="1" height="100%" text_align="left"
<label id="label_remember" width="40%" height="100%" text_align="left"
I18N="In the login screen" text="Remember password"/>
<checkbox id="remember-user" I18N="In the login screen" text_align="left"/>
<checkbox width="fit" id="remember-user" I18N="In the login screen" text_align="left"/>
</div>
<!-- Disable guest accounts for now
<div width="100%" height="fit" layout="horizontal-row" >
@ -40,14 +40,14 @@
</div>
-->
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_username" proportion="1" height="100%" text_align="left"
<label id="label_username" width="40%" height="100%" text_align="left"
I18N="In the login screen" text="Username"/>
<textbox id="username" proportion="2" height="fit" I18N="In the registration dialog"/>
</div>
<spacer height="20" width="20"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_password" proportion="1" height="100%" text_align="left"
<label id="label_password" width="40%" height="100%" text_align="left"
I18N="In the registration dialog" text="Password"/>
<textbox id="password" proportion="2" height="fit" I18N="In the registration dialog"/>
</div>

View File

@ -14,5 +14,5 @@ void main()
Yxy.x = smoothstep(WhiteYxy.x, WhiteYxy.x * 4, Yxy.x);
FragColor = vec4(getRGBFromCIEXxy(Yxy), 1.0);
FragColor = vec4(max(vec3(0.), getRGBFromCIEXxy(Yxy)), 1.0);
}

View File

@ -1,9 +1,11 @@
#ifdef GL_ARB_bindless_texture
layout(bindless_sampler) uniform sampler2D Albedo;
layout(bindless_sampler) uniform sampler2D Detail;
layout(bindless_sampler) uniform sampler2D SpecMap;
#else
uniform sampler2D Albedo;
uniform sampler2D Detail;
uniform sampler2D SpecMap;
#endif
#if __VERSION__ >= 130
@ -16,7 +18,7 @@ varying vec2 uv_bis;
#define FragColor gl_FragColor
#endif
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main(void)
{
@ -28,6 +30,6 @@ void main(void)
#endif
vec4 detail = texture(Detail, uv_bis);
color *= detail;
vec3 LightFactor = getLightFactor(1. - color.a);
FragColor = vec4(color.xyz * LightFactor, 1.);
float specmap = texture(SpecMap, uv).g;
FragColor = vec4(getLightFactor(color.xyz, vec3(1.), specmap), 1.);
}

View File

@ -2,11 +2,15 @@ uniform float blueLmn[9];
uniform float greenLmn[9];
uniform float redLmn[9];
uniform sampler2D ntex;
uniform sampler2D dtex;
uniform samplerCube tex;
uniform mat4 TransposeViewMatrix;
out vec4 Diff;
out vec4 Spec;
vec3 DecodeNormal(vec2 n);
vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix);
mat4 getMatrix(float L[9])
{
@ -24,8 +28,9 @@ void main(void)
{
vec2 uv = gl_FragCoord.xy / screen;
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.);
vec4 extendednormal = TransposeViewMatrix * vec4(normal, 0.);
extendednormal.w = 1.;
mat4 rmat = getMatrix(redLmn);
mat4 gmat = getMatrix(greenLmn);
@ -36,4 +41,16 @@ void main(void)
float b = dot(extendednormal, bmat * extendednormal);
Diff = max(0.25 * vec4(r, g, b, .1), vec4(0.));
float z = texture(dtex, uv).x;
vec4 xpos = getPosFromUVDepth(vec3(uv, z), InverseProjectionMatrix);
vec3 eyedir = -normalize(xpos.xyz);
vec3 sampleDirection = reflect(-eyedir, normal);
sampleDirection = (InverseViewMatrix * vec4(sampleDirection, 0.)).xyz;
float specval = texture(ntex, uv).z;
float lodval = 16 * (1. - ((log2(specval) - 1.) / 10.));
vec4 specular = textureLod(tex, sampleDirection, lodval);
Spec = max(specular, vec4(0.));
}

View File

@ -1,9 +1,11 @@
#ifdef GL_ARB_bindless_texture
layout(bindless_sampler) uniform sampler2D Albedo;
layout(bindless_sampler) uniform sampler2D dtex;
layout(bindless_sampler) uniform sampler2D SpecMap;
#else
uniform sampler2D Albedo;
uniform sampler2D dtex;
uniform sampler2D SpecMap;
#endif
uniform vec3 SunDir;
@ -12,10 +14,18 @@ in vec3 nor;
in vec2 uv;
out vec4 FragColor;
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main(void)
{
vec4 color = texture(Albedo, uv);
#ifdef GL_ARB_bindless_texture
#ifdef SRGBBindlessFix
color.xyz = pow(color.xyz, vec3(2.2));
#endif
#endif
if (color.a < 0.5) discard;
vec2 texc = gl_FragCoord.xy / screen;
float z = texture(dtex, texc).x;
@ -30,14 +40,8 @@ void main(void)
float fLdotNBack = max(0., - dot(nor, SunDir) * 0.6 + 0.4);
float scattering = mix(fPowEdotL, fLdotNBack, .5);
float specmap = texture(SpecMap, uv).g;
vec4 color = texture(Albedo, uv);
#ifdef GL_ARB_bindless_texture
#ifdef SRGBBindlessFix
color.xyz = pow(color.xyz, vec3(2.2));
#endif
#endif
if (color.a < 0.5) discard;
vec3 LightFactor = (scattering * 0.3) + getLightFactor(1.);
vec3 LightFactor = color.xyz * (scattering * 0.3) + getLightFactor(color.xyz, vec3(1.), specmap);
FragColor = vec4(color.xyz * LightFactor, 1.);
}

View File

@ -1,22 +1,25 @@
#ifndef GL_ARB_bindless_texture
uniform sampler2D Albedo;
uniform sampler2D Detail;
uniform sampler2D SpecMap;
#endif
#ifdef GL_ARB_bindless_texture
flat in sampler2D handle;
flat in sampler2D secondhandle;
flat in sampler2D thirdhandle;
#endif
in vec2 uv;
in vec2 uv_bis;
out vec4 FragColor;
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main(void)
{
#ifdef GL_ARB_bindless_texture
vec4 color = texture(handle, uv);
float specmap = texture(secondhandle, uv).g;
#ifdef SRGBBindlessFix
color.xyz = pow(color.xyz, vec3(2.2));
#endif
@ -24,8 +27,8 @@ void main(void)
#else
vec4 color = texture(Albedo, uv);
vec4 detail = texture(Detail, uv_bis);
float specmap = texture(SpecMap, uv).g;
#endif
color *= detail;
vec3 LightFactor = getLightFactor(1. - color.a);
FragColor = vec4(color.xyz * LightFactor, 1.);
FragColor = vec4(getLightFactor(color.xyz, vec3(1.), specmap), 1.);
}

View File

@ -11,6 +11,7 @@ layout(location = 8) in vec3 Orientation;
layout(location = 9) in vec3 Scale;
#ifdef GL_ARB_bindless_texture
layout(location = 10) in sampler2D Handle;
layout(location = 11) in sampler2D SecondHandle;
#endif
#else
@ -28,6 +29,7 @@ out vec3 nor;
out vec2 uv;
#ifdef GL_ARB_bindless_texture
flat out sampler2D handle;
flat out sampler2D secondhandle;
#endif
mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale);
@ -42,5 +44,6 @@ void main()
uv = Texcoord;
#ifdef GL_ARB_bindless_texture
handle = Handle;
secondhandle = SecondHandle;
#endif
}

View File

@ -2,6 +2,7 @@
layout(bindless_sampler) uniform sampler2D dtex;
#else
uniform sampler2D Albedo;
uniform sampler2D SpecMap;
uniform sampler2D dtex;
#endif
@ -9,15 +10,28 @@ uniform vec3 SunDir;
#ifdef GL_ARB_bindless_texture
flat in sampler2D handle;
flat in sampler2D secondhandle;
#endif
in vec3 nor;
in vec2 uv;
out vec4 FragColor;
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main(void)
{
#ifdef GL_ARB_bindless_texture
vec4 color = texture(handle, uv);
float specmap = texture(secondhandle, uv).g;
#ifdef SRGBBindlessFix
color.xyz = pow(color.xyz, vec3(2.2));
#endif
#else
vec4 color = texture(Albedo, uv);
float specmap = texture(SpecMap, uv).g;
#endif
if (color.a < 0.5) discard;
vec2 texc = gl_FragCoord.xy / screen;
float z = texture(dtex, texc).x;
@ -33,15 +47,7 @@ void main(void)
float fLdotNBack = max(0., - dot(nor, SunDir) * 0.6 + 0.4);
float scattering = mix(fPowEdotL, fLdotNBack, .5);
#ifdef GL_ARB_bindless_texture
vec4 color = texture(handle, uv);
#ifdef SRGBBindlessFix
color.xyz = pow(color.xyz, vec3(2.2));
#endif
#else
vec4 color = texture(Albedo, uv);
#endif
if (color.a < 0.5) discard;
vec3 LightFactor = (scattering * 0.3) + getLightFactor(1.);
FragColor = vec4(color.xyz * LightFactor, 1.);
vec3 LightFactor = color.xyz * (scattering * 0.3) + getLightFactor(color.xyz, vec3(1.), specmap);
FragColor = vec4(LightFactor, 1.);
}

View File

@ -1,27 +1,30 @@
#ifndef GL_ARB_bindless_texture
uniform sampler2D Albedo;
uniform sampler2D SpecMap;
#endif
#ifdef GL_ARB_bindless_texture
flat in sampler2D handle;
flat in sampler2D secondhandle;
#endif
in vec2 uv;
in vec4 color;
out vec4 FragColor;
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main(void)
{
#ifdef GL_ARB_bindless_texture
vec4 col = texture(handle, uv);
float specmap = texture(secondhandle, uv).g;
#ifdef SRGBBindlessFix
col.xyz = pow(col.xyz, vec3(2.2));
#endif
#else
vec4 col = texture(Albedo, uv);
float specmap = texture(SpecMap, uv).g;
#endif
col.xyz *= pow(color.xyz, vec3(2.2));
vec3 LightFactor = getLightFactor(1.);
FragColor = vec4(col.xyz * LightFactor, 1.);
FragColor = vec4(getLightFactor(col.xyz, vec3(1.), specmap), 1.);
}

View File

@ -12,7 +12,7 @@ out vec4 FragColor;
vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix);
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main() {
vec3 texc = gl_FragCoord.xyz / vec3(screen, 1.);
@ -29,7 +29,6 @@ void main() {
#else
vec4 detail0 = texture(tex, r.xy / m + .5);
#endif
vec3 LightFactor = getLightFactor(1.);
FragColor = vec4(detail0.xyz * LightFactor, 1.);
FragColor = vec4(getLightFactor(detail0.xyz, vec3(1.), 0.), 1.);
}

View File

@ -1,28 +1,31 @@
#ifndef GL_ARB_bindless_texture
uniform sampler2D Albedo;
uniform sampler2D SpecMap;
#endif
#ifdef GL_ARB_bindless_texture
flat in sampler2D handle;
flat in sampler2D secondhandle;
#endif
in vec2 uv;
in vec4 color;
out vec4 FragColor;
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main(void)
{
#ifdef GL_ARB_bindless_texture
vec4 col = texture(handle, uv);
float specmap = texture(secondhandle, uv).g;
#ifdef SRGBBindlessFix
col.xyz = pow(col.xyz, vec3(2.2));
#endif
#else
vec4 col = texture(Albedo, uv);
float specmap = texture(SpecMap, uv).g;
#endif
col.xyz *= pow(color.xyz, vec3(2.2));
if (col.a * color.a < 0.5) discard;
vec3 LightFactor = getLightFactor(1.);
FragColor = vec4(col.xyz * LightFactor, 1.);
FragColor = vec4(getLightFactor(col.xyz, vec3(1.), specmap), 1.);
}

View File

@ -1,14 +1,16 @@
#ifdef GL_ARB_bindless_texture
layout(bindless_sampler) uniform sampler2D Albedo;
layout(bindless_sampler) uniform sampler2D SpecMap;
#else
uniform sampler2D Albedo;
uniform sampler2D SpecMap;
#endif
in vec2 uv;
in vec4 color;
out vec4 FragColor;
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main(void)
{
@ -21,6 +23,6 @@ void main(void)
vec4 col = texture(Albedo, uv);
#endif
col.xyz *= pow(color.xyz, vec3(2.2));
vec3 LightFactor = getLightFactor(1.);
FragColor = vec4(col.xyz * LightFactor, 1.);
float specmap = texture(SpecMap, uv).g;
FragColor = vec4(getLightFactor(col.xyz, vec3(1.), specmap), 1.);
}

View File

@ -15,7 +15,7 @@ varying vec3 nor;
#endif
vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix);
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main() {
vec3 texc = gl_FragCoord.xyz / vec3(screen, 1.);
@ -30,7 +30,6 @@ void main() {
detail0.xyz = pow(detail0.xyz, vec3(2.2));
#endif
#endif
vec3 LightFactor = getLightFactor(1.);
FragColor = vec4(detail0.xyz * LightFactor, 1.);
FragColor = vec4(getLightFactor(detail0.xyz, vec3(1.), 0.), 1.);
}

View File

@ -1,14 +1,16 @@
#ifdef GL_ARB_bindless_texture
layout(bindless_sampler) uniform sampler2D Albedo;
layout(bindless_sampler) uniform sampler2D SpecMap;
#else
uniform sampler2D Albedo;
uniform sampler2D SpecMap;
#endif
in vec2 uv;
in vec4 color;
out vec4 FragColor;
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main(void)
{
@ -20,6 +22,6 @@ void main(void)
#endif
col.xyz *= pow(color.xyz, vec3(2.2));
if (col.a * color.a < 0.5) discard;
vec3 LightFactor = getLightFactor(1.);
FragColor = vec4(col.xyz * LightFactor, 1.);
float specmap = texture(SpecMap, uv).g;
FragColor = vec4(getLightFactor(col.xyz, vec3(1.), specmap), 1.);
}

View File

@ -35,7 +35,7 @@ void main(void)
float updated_lifetime = lifetime + (float(dt)/lifetime_initial);
if (updated_lifetime > 1.)
{
if (gl_VertexID <= level)
if (gl_VertexID < level)
{
float dt_from_last_frame = fract(updated_lifetime) * lifetime_initial;
vec4 updated_initialposition = sourcematrix * vec4(particle_position_initial, 1.0);

View File

@ -9,6 +9,7 @@ uniform mat4 RSMMatrix;
uniform sampler2D dtex;
uniform sampler2D ctex;
uniform sampler2D ntex;
uniform vec3 suncol;
flat in int slice;
layout (location = 0) out vec4 SHRed;
@ -63,7 +64,7 @@ void loop(in int i,
float dotprod = max(dot(RSM_to_RH_dir, normal.xyz), 0.);
float factor = dotprod / (0.1 + dist * dist);
vec3 color = RSMAlbedo.rgb * factor;
vec3 color = RSMAlbedo.rgb * factor * suncol.rgb;
SHr += DirToSh(RSM_to_RH_dir, color.r);
SHg += DirToSh(RSM_to_RH_dir, color.g);

View File

@ -11,8 +11,9 @@ void main(void)
{
vec3 eyedir = gl_FragCoord.xyz / vec3(screen, 1.);
eyedir = 2.0 * eyedir - 1.0;
vec4 tmp = (InverseViewMatrix * InverseProjectionMatrix * vec4(eyedir, 1.));
eyedir = tmp.xyz / tmp.w;
vec4 tmp = (InverseProjectionMatrix * vec4(eyedir, 1.));
tmp /= tmp.w;
eyedir = (InverseViewMatrix * vec4(tmp.xyz, 0.)).xyz;
vec4 color = texture(tex, eyedir);
FragColor = vec4(color.xyz, 1.);
}

View File

@ -22,7 +22,7 @@ varying vec2 uv_bis;
#define FragColor gl_FragColor
#endif
vec3 getLightFactor(float specMapValue);
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue);
void main() {
// Splatting part
@ -46,6 +46,5 @@ void main() {
splatting.b * detail2 +
max(0., (1.0 - splatting.r - splatting.g - splatting.b)) * detail3;
vec3 LightFactor = getLightFactor(1.);
FragColor = vec4(splatted.xyz * LightFactor, 1.);
FragColor = vec4(getLightFactor(splatted.xyz, vec3(1.), 0.), 1.);
}

View File

@ -8,12 +8,12 @@ uniform sampler2D SpecularMap;
uniform sampler2D SSAO;
#endif
vec3 getLightFactor(float specMapValue)
vec3 getLightFactor(vec3 diffuseMatColor, vec3 specularMatColor, float specMapValue)
{
vec2 tc = gl_FragCoord.xy / screen;
vec3 DiffuseComponent = texture(DiffuseMap, tc).xyz;
vec3 SpecularComponent = texture(SpecularMap, tc).xyz;
float ao = texture(SSAO, tc).x;
vec3 tmp = DiffuseComponent + SpecularComponent * specMapValue;
vec3 tmp = diffuseMatColor * DiffuseComponent * (1. - specMapValue) + specularMatColor * SpecularComponent * specMapValue;
return tmp * ao;
}

View File

@ -153,8 +153,8 @@
when the camera is pointing backwards. This is usually
larger than the forward-up-angle, since the kart itself
otherwise obstricts too much of the view. -->
<camera distance="1.5" forward-up-angle="15"
backward-up-angle="30"/>
<camera distance="1.0" forward-up-angle="15"
backward-up-angle="5"/>
<!-- Additional offset to move graphical chassis with regards to the physics. -->
<graphics y-offset="0.0"/>
@ -380,7 +380,7 @@
<stability roll-influence="0.3"
chassis-linear-damping="0.2"
chassis-angular-damping="0"
downward-impulse-factor="0"
downward-impulse-factor="5"
track-connection-accel="2"
smooth-flying-impulse="25"/>

View File

@ -77,6 +77,8 @@ struct btWheelInfo
bool m_bIsFrontWheel;
bool m_was_on_ground;
void* m_clientInfo;//can be used to store pointer to sync transforms...
btWheelInfo(btWheelInfoConstructionInfo& ci)
@ -102,7 +104,7 @@ struct btWheelInfo
m_rollInfluence = btScalar(0.1);
m_bIsFrontWheel = ci.m_bIsFrontWheel;
m_maxSuspensionForce = ci.m_maxSuspensionForce;
m_was_on_ground = true;
}
void updateWheel(const btRigidBody& chassis,RaycastInfo& raycastInfo);

View File

@ -9,7 +9,7 @@ endif()
add_library(glew STATIC
include/GL/glew.h include/GL/glxew.h include/GL/wglew.h
src/glew.c src/glewinfo.c src/visualinfo.c
src/glew.c src/glewinfo.c
)
add_definitions(-DGLEW_STATIC)

File diff suppressed because it is too large Load Diff

View File

@ -277,7 +277,7 @@ void CGUIButton::draw()
pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X);
pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y);
}
driver->draw2DImage(PressedImage,
skin->draw2DImage(PressedImage,
ScaleImage? AbsoluteRect :
core::recti(pos, PressedImageRect.getSize()),
PressedImageRect, &AbsoluteClippingRect,
@ -285,7 +285,7 @@ void CGUIButton::draw()
}
}
if (SpriteBank)
if (false) //SpriteBank)
{
// pressed / unpressed animation
u32 state = Pressed ? (u32)EGBS_BUTTON_DOWN : (u32)EGBS_BUTTON_UP;

View File

@ -584,30 +584,30 @@ void CGUIContextMenu::draw()
skin->getColor(c), false, true, clip);
// draw submenu symbol
if (Items[i].SubMenu && sprites)
{
core::rect<s32> r = rect;
r.UpperLeftCorner.X = r.LowerRightCorner.X - 15;
sprites->draw2DSprite(skin->getIcon(EGDI_CURSOR_RIGHT),
r.getCenter(), clip, skin->getColor(c),
(i == HighLighted) ? ChangeTime : 0,
(i == HighLighted) ? os::Timer::getTime() : 0,
(i == HighLighted), true);
}
//if (Items[i].SubMenu && sprites)
//{
// core::rect<s32> r = rect;
// r.UpperLeftCorner.X = r.LowerRightCorner.X - 15;
//
// sprites->draw2DSprite(skin->getIcon(EGDI_CURSOR_RIGHT),
// r.getCenter(), clip, skin->getColor(c),
// (i == HighLighted) ? ChangeTime : 0,
// (i == HighLighted) ? os::Timer::getTime() : 0,
// (i == HighLighted), true);
//}
// draw checked symbol
if (Items[i].Checked && sprites)
{
core::rect<s32> r = rect;
r.LowerRightCorner.X = r.UpperLeftCorner.X - 15;
r.UpperLeftCorner.X = r.LowerRightCorner.X + 15;
sprites->draw2DSprite(skin->getIcon(EGDI_CHECK_BOX_CHECKED),
r.getCenter(), clip, skin->getColor(c),
(i == HighLighted) ? ChangeTime : 0,
(i == HighLighted) ? os::Timer::getTime() : 0,
(i == HighLighted), true);
}
//if (Items[i].Checked && sprites)
//{
// core::rect<s32> r = rect;
// r.LowerRightCorner.X = r.UpperLeftCorner.X - 15;
// r.UpperLeftCorner.X = r.LowerRightCorner.X + 15;
// sprites->draw2DSprite(skin->getIcon(EGDI_CHECK_BOX_CHECKED),
// r.getCenter(), clip, skin->getColor(c),
// (i == HighLighted) ? ChangeTime : 0,
// (i == HighLighted) ? os::Timer::getTime() : 0,
// (i == HighLighted), true);
//}
}
}

View File

@ -78,20 +78,20 @@ void CGUIImage::draw()
if (Texture)
{
if (ScaleImage)
{
//if (ScaleImage)
//{
const video::SColor Colors[] = {Color,Color,Color,Color};
driver->draw2DImage(Texture, AbsoluteRect,
skin->draw2DImage(Texture, AbsoluteRect,
core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(Texture->getOriginalSize())),
&AbsoluteClippingRect, Colors, UseAlphaChannel);
}
else
{
driver->draw2DImage(Texture, AbsoluteRect.UpperLeftCorner,
core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(Texture->getOriginalSize())),
&AbsoluteClippingRect, Color, UseAlphaChannel);
}
//}
//else
//{
// driver->draw2DImage(Texture, AbsoluteRect.UpperLeftCorner,
// core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(Texture->getOriginalSize())),
// &AbsoluteClippingRect, Color, UseAlphaChannel);
//}
}
else
{

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -35,6 +35,7 @@ AchievementInfo::AchievementInfo(const XMLNode * input)
m_id = 0;
m_title = "";
m_description = "";
m_is_secret = false;
bool all;
all = input->get("id", &m_id ) &&
input->get("title", &m_title ) &&
@ -69,6 +70,7 @@ AchievementInfo::AchievementInfo(const XMLNode * input)
else
Log::warn("AchievementInfo", "Achievement check type '%s' unknown.",
s.c_str());
input->get("secret", &m_is_secret);
// Now load the goal nodes
for (unsigned int n = 0; n < input->getNumNodes(); n++)
@ -113,7 +115,7 @@ irr::core::stringw AchievementInfo::toString() const
count = m_goal_values.begin()->second;
break;
default:
Log::fatal("AchievementInfo", "Missing toString for tpye %d.",
Log::fatal("AchievementInfo", "Missing toString for type %d.",
m_check_type);
}
return StringUtils::toWString(count);

View File

@ -94,6 +94,9 @@ private:
/** Determines when the achievement needs to be reset */
ResetType m_reset_type;
/** A secret achievement has its progress not shown. */
bool m_is_secret;
public:
AchievementInfo(const XMLNode * input);
virtual ~AchievementInfo() {};
@ -119,6 +122,9 @@ public:
/** Returns the check type for this achievement. */
AchievementCheckType getCheckType() const { return m_check_type; }
// ------------------------------------------------------------------------
/** Returns if this achievement is a secret achievement. */
bool isSecret() const { return m_is_secret; }
// ------------------------------------------------------------------------
}; // class AchievementInfo

View File

@ -23,7 +23,6 @@
#include "audio/sfx_base.hpp"
/**
* \brief Dummy sound when ogg or openal aren't available
* \ingroup audio
@ -37,19 +36,28 @@ public:
/** Late creation, if SFX was initially disabled */
virtual bool init() { return true; }
virtual void position(const Vec3 &position) {}
virtual void setLoop(bool status) {}
virtual void play() {}
virtual void stop() {}
virtual void pause() {}
virtual void resume() {}
virtual void speed(float factor) {}
virtual void volume(float gain) {}
virtual SFXManager::SFXStatus getStatus() { return SFXManager::SFX_STOPPED; }
virtual void onSoundEnabledBack() {}
virtual void setRolloff(float rolloff) {}
virtual const SFXBuffer* getBuffer() const { return NULL; }
virtual void setLoop(bool status) {}
virtual void reallySetLoop(bool status) {}
virtual void setPosition(const Vec3 &p) {}
virtual void reallySetPosition(const Vec3 &p) {}
virtual void play() {}
virtual void reallyPlayNow() {}
virtual void stop() {}
virtual void reallyStopNow() {}
virtual void pause() {}
virtual void reallyPauseNow() {}
virtual void resume() {}
virtual void reallyResumeNow() {}
virtual void deleteSFX() { delete this; }
virtual void setSpeed(float factor) {}
virtual void reallySetSpeed(float factor) {}
virtual void setVolume(float gain) {}
virtual void reallySetVolume(float gain) {}
virtual SFXStatus getStatus() { return SFX_STOPPED; }
virtual void onSoundEnabledBack() {}
virtual void setRolloff(float rolloff) {}
virtual bool isPlaying() { return false; }
virtual const SFXBuffer* getBuffer() const { return NULL; }
}; // DummySFX

View File

@ -42,26 +42,42 @@ class Vec3;
class SFXBase : public NoCopy
{
public:
/** Status of a sound effect. */
enum SFXStatus
{
SFX_UNKNOWN = -1, SFX_STOPPED = 0, SFX_PAUSED = 1, SFX_PLAYING = 2,
SFX_INITIAL = 3
};
virtual ~SFXBase() {}
/** Late creation, if SFX was initially disabled */
virtual bool init() = 0;
virtual void position(const Vec3 &position) = 0;
virtual void setLoop(bool status) = 0;
virtual void play() = 0;
virtual void reallyPlayNow() = 0;
virtual void stop() = 0;
virtual void pause() = 0;
virtual void resume() = 0;
virtual void speed(float factor) = 0;
virtual void volume(float gain) = 0;
virtual void setMasterVolume(float gain) = 0;
virtual void onSoundEnabledBack() = 0;
virtual void setRolloff(float rolloff) = 0;
virtual const SFXBuffer* getBuffer() const = 0;
virtual SFXManager::SFXStatus getStatus() = 0;
virtual bool init() = 0;
virtual void setPosition(const Vec3 &p) = 0;
virtual void reallySetPosition(const Vec3 &p) = 0;
virtual void setLoop(bool status) = 0;
virtual void reallySetLoop(bool status) = 0;
virtual bool isPlaying() = 0;
virtual void play() = 0;
virtual void reallyPlayNow() = 0;
virtual void stop() = 0;
virtual void reallyStopNow() = 0;
virtual void pause() = 0;
virtual void reallyPauseNow() = 0;
virtual void resume() = 0;
virtual void reallyResumeNow() = 0;
virtual void deleteSFX() = 0;
virtual void setSpeed(float factor) = 0;
virtual void reallySetSpeed(float factor) = 0;
virtual void setVolume(float gain) = 0;
virtual void reallySetVolume(float gain) = 0;
virtual void setMasterVolume(float gain) = 0;
virtual void onSoundEnabledBack() = 0;
virtual void setRolloff(float rolloff) = 0;
virtual const SFXBuffer* getBuffer() const = 0;
virtual SFXStatus getStatus() = 0;
}; // SfxBase
}; // SFXBase
#endif // HEADER_SFX_HPP

View File

@ -36,27 +36,37 @@
#endif
//----------------------------------------------------------------------------
/** Creates a sfx. The parameter are taken from the parameters:
* \param file File name of the buffer.
* \param positional If the sfx is positional.
* \param rolloff Rolloff value of this sfx.
* \param max_dist Maximum distance the sfx can be heard.
* \param gain Gain value of this sfx.
*/
SFXBuffer::SFXBuffer(const std::string& file,
bool positional,
float rolloff,
float max_width,
float max_dist,
float gain)
{
m_buffer = 0;
m_gain = 1.0f;
m_rolloff = 0.1f;
m_loaded = false;
m_max_dist = max_width;
m_max_dist = max_dist;
m_duration = -1.0f;
m_file = file;
m_rolloff = rolloff;
m_positional = positional;
m_gain = gain;
}
} // SFXBuffer
//----------------------------------------------------------------------------
/** Constructor getting the sfx parameters from an XML node.
* \param file File name of the data.
* \param node XML Node with the data for this sfx.
*/
SFXBuffer::SFXBuffer(const std::string& file,
const XMLNode* node)
{
@ -64,6 +74,7 @@ SFXBuffer::SFXBuffer(const std::string& file,
m_gain = 1.0f;
m_rolloff = 0.1f;
m_max_dist = 300.0f;
m_duration = -1.0f;
m_positional = false;
m_loaded = false;
m_file = file;
@ -72,10 +83,15 @@ SFXBuffer::SFXBuffer(const std::string& file,
node->get("positional", &m_positional );
node->get("volume", &m_gain );
node->get("max_dist", &m_max_dist );
}
node->get("duration", &m_duration );
} // SFXBuffer(XMLNode)
//----------------------------------------------------------------------------
/** \brief load the buffer from file into OpenAL.
* \note If this buffer is already loaded, this call does nothing and
* returns false.
* \return Whether loading was successful.
*/
bool SFXBuffer::load()
{
if (UserConfigParams::m_sfx == false) return false;
@ -103,9 +119,13 @@ bool SFXBuffer::load()
m_loaded = true;
return true;
}
} // load
//----------------------------------------------------------------------------
/** \brief Frees the loaded buffer.
* Cannot appear in destructor because copy-constructors may be used,
* and the OpenAL source must not be deleted on a copy
*/
void SFXBuffer::unload()
{
@ -117,7 +137,7 @@ void SFXBuffer::unload()
}
#endif
m_loaded = false;
}
} // unload
//----------------------------------------------------------------------------
/** Load a vorbis file into an OpenAL buffer
@ -164,7 +184,7 @@ bool SFXBuffer::loadVorbisBuffer(const std::string &name, ALuint buffer)
if(!data)
{
ov_clear(&oggFile);
Log::error("SFXBuffer", "[SFXBuffer] loadVorbisBuffer() - Error : LoadVorbisBuffer() - couldn't allocate decode buffer\n");
Log::error("SFXBuffer", "[SFXBuffer] Could not allocate decode buffer.");
return false;
}
@ -188,9 +208,21 @@ bool SFXBuffer::loadVorbisBuffer(const std::string &name, ALuint buffer)
ov_clear(&oggFile);
fclose(file);
// Allow the xml data to overwrite the duration, but if there is no
// duration (which is the norm), compute it:
if(m_duration < 0)
{
ALint buffer_size, frequency, bits_per_sample, channels;
alGetBufferi(buffer, AL_SIZE, &buffer_size );
alGetBufferi(buffer, AL_FREQUENCY, &frequency );
alGetBufferi(buffer, AL_CHANNELS, &channels );
alGetBufferi(buffer, AL_BITS, &bits_per_sample);
m_duration = float(buffer_size) / (frequency*channels*(bits_per_sample / 8));
}
return success;
#else
return false;
#endif
}
} // loadVorbisBuffer

View File

@ -46,18 +46,32 @@ class SFXBuffer
{
private:
LEAK_CHECK()
/** Whether the contents of the file was loaded */
bool m_loaded;
/** The file that contains the OGG audio data */
std::string m_file;
/** The openal buffer id. */
ALuint m_buffer;
/** If the sound is positional. */
bool m_positional;
/** The roll-off value. */
float m_rolloff;
/** The volume gain value. */
float m_gain;
/** Maximum distance the sfx can be heard. */
float m_max_dist;
/** Duration of the sfx. */
float m_duration;
bool loadVorbisBuffer(const std::string &name, ALuint buffer);
public:
@ -70,41 +84,43 @@ public:
SFXBuffer(const std::string& file,
const XMLNode* node);
~SFXBuffer()
{
}
} // ~SFXBuffer
/**
* \brief load the buffer from file into OpenAL.
* \note If this buffer is already loaded, this call does nothing and returns false
* \return whether loading was successful
*/
bool load();
/**
* \brief Frees the loaded buffer
* Cannot appear in destructor because copy-constructors may be used,
* and the OpenAL source must not be deleted on a copy
*/
void unload();
bool load();
void unload();
// ------------------------------------------------------------------------
/** \return whether this buffer was loaded from disk */
bool isLoaded() const { return m_loaded; }
bool isLoaded() const { return m_loaded; }
// ------------------------------------------------------------------------
/** Only returns a valid buffer if isLoaded() returned true */
ALuint getBufferID() const { return m_buffer; }
ALuint getBufferID() const { return m_buffer; }
// ------------------------------------------------------------------------
/** Returns if the buffer is positional. */
bool isPositional() const { return m_positional; }
// ------------------------------------------------------------------------
/** Returns the rolloff value of this buffer. */
float getRolloff() const { return m_rolloff; }
// ------------------------------------------------------------------------
/** Returns the gain for this sfx. */
float getGain() const { return m_gain; }
// ------------------------------------------------------------------------
/** Returns the maximum distance this sfx can be heard. */
float getMaxDist() const { return m_max_dist; }
// ------------------------------------------------------------------------
/** Returns the file name of this buffer. */
const std::string& getFileName() const { return m_file; }
// ------------------------------------------------------------------------
/** Sets if this buffer is positional or not. */
void setPositional(bool positional) { m_positional = positional; }
// ------------------------------------------------------------------------
/** Returns how long this buffer will play. */
float getDuration() const { return m_duration; }
bool isPositional() const { return m_positional; }
float getRolloff() const { return m_rolloff; }
float getGain() const { return m_gain; }
float getMaxDist() const { return m_max_dist; }
std::string getFileName() const { return m_file; }
void setPositional(bool positional) { m_positional = positional; }
LEAK_CHECK()
};
}; // class SFXBuffer
#endif // HEADER_SFX_BUFFER_HPP

View File

@ -74,7 +74,10 @@ SFXManager::SFXManager()
m_initialized = music_manager->initialized();
m_master_gain = UserConfigParams::m_sfx_volume;
// Init position, since it can be used before positionListener is called.
m_position = Vec3(0,0,0);
// No need to use lock here, since the thread will be created later.
m_listener_position.getData() = Vec3(0, 0, 0);
m_listener_front = Vec3(0, 0, 1);
m_listener_up = Vec3(0, 1, 0);
loadSfx();
@ -106,9 +109,9 @@ SFXManager::SFXManager()
if (!sfxAllowed()) return;
setMasterSFXVolume( UserConfigParams::m_sfx_volume );
m_sfx_to_play.lock();
m_sfx_to_play.getData().clear();
m_sfx_to_play.unlock();
m_sfx_commands.lock();
m_sfx_commands.getData().clear();
m_sfx_commands.unlock();
} // SoundManager
@ -124,13 +127,15 @@ SFXManager::~SFXManager()
pthread_cond_destroy(&m_cond_request);
// ---- clear m_all_sfx
const int sfx_amount = (int) m_all_sfx.size();
// not strictly necessary, but might avoid copy&paste problems
m_all_sfx.lock();
const int sfx_amount = (int) m_all_sfx.getData().size();
for (int n=0; n<sfx_amount; n++)
{
delete m_all_sfx[n];
delete m_all_sfx.getData()[n];
}
m_all_sfx.clear();
m_all_sfx.getData().clear();
m_all_sfx.unlock();
// ---- clear m_quick_sounds
{
std::map<std::string, SFXBase*>::iterator i = m_quick_sounds.begin();
@ -158,32 +163,79 @@ SFXManager::~SFXManager()
} // ~SFXManager
//----------------------------------------------------------------------------
/** Adds a sound effect to the queue of sfx to be started by the sfx manager.
* Starting a sfx can sometimes cause a 5ms delay, so it is done in a
* separate thread.
/** Adds a sound effect command to the queue of the sfx manager. Openal
* commands can sometimes cause a 5ms delay, so it is done in a separate
* thread.
* \param command The command to execute.
* \param sfx The sound effect to be started.
*/
void SFXManager::queue(SFXBase *sfx)
void SFXManager::queue(SFXCommands command, SFXBase *sfx)
{
// Don't add sfx that are either not working correctly (e.g. because sfx
// are disabled);
if(sfx && sfx->getStatus()==SFX_UNKNOWN ) return;
m_sfx_to_play.lock();
m_sfx_to_play.getData().push_back(sfx);
m_sfx_to_play.unlock();
// Wake up the sfx thread
pthread_cond_signal(&m_cond_request);
SFXCommand *sfx_command = new SFXCommand(command, sfx);
queueCommand(sfx_command);
} // queue
//----------------------------------------------------------------------------
/** Adds a sound effect command with a single floating point parameter to the
* queue of the sfx manager. Openal commands can sometimes cause a 5ms delay,
* so it is done in a separate thread.
* \param command The command to execute.
* \param sfx The sound effect to be started.
* \param f Floating point parameter for the command.
*/
void SFXManager::queue(SFXCommands command, SFXBase *sfx, float f)
{
SFXCommand *sfx_command = new SFXCommand(command, sfx, f);
queueCommand(sfx_command);
} // queue(float)
//----------------------------------------------------------------------------
/** Adds a sound effect command with a Vec3 parameter to the queue of the sfx
* manager. Openal commands can sometimes cause a 5ms delay, so it is done in
* a separate thread.
* \param command The command to execute.
* \param sfx The sound effect to be started.
* \param p A Vec3 parameter for the command.
*/
void SFXManager::queue(SFXCommands command, SFXBase *sfx, const Vec3 &p)
{
SFXCommand *sfx_command = new SFXCommand(command, sfx, p);
queueCommand(sfx_command);
} // queue (Vec3)
//----------------------------------------------------------------------------
/** Enqueues a command to the sfx queue threadsafe. Then signal the
* sfx manager to wake up.
* \param command Pointer to the command to queue up.
*/
void SFXManager::queueCommand(SFXCommand *command)
{
m_sfx_commands.lock();
m_sfx_commands.getData().push_back(command);
m_sfx_commands.unlock();
} // queueCommand
//----------------------------------------------------------------------------
/** Make sures that the sfx thread is started at least one per frame. It also
* adds an update command for the music manager.
* \param dt Time step size.
*/
void SFXManager::update(float dt)
{
queue(SFX_UPDATE_MUSIC, NULL, dt);
// Wake up the sfx thread to handle all queued up audio commands.
pthread_cond_signal(&m_cond_request);
} // update
//----------------------------------------------------------------------------
/** Puts a NULL request into the queue, which will trigger the thread to
* exit.
*/
void SFXManager::stopThread()
{
queue(NULL);
queue(SFX_EXIT, NULL);
// Make sure the thread wakes up.
pthread_cond_signal(&m_cond_request);
} // stopThread
//----------------------------------------------------------------------------
@ -198,40 +250,70 @@ void* SFXManager::mainLoop(void *obj)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
me->m_sfx_to_play.lock();
me->m_sfx_commands.lock();
// Wait till we have an empty sfx in the queue
while (me->m_sfx_to_play.getData().empty() ||
me->m_sfx_to_play.getData().front()!=NULL )
while (me->m_sfx_commands.getData().empty() ||
me->m_sfx_commands.getData().front()->m_command!=SFX_EXIT)
{
bool empty = me->m_sfx_to_play.getData().empty();
bool empty = me->m_sfx_commands.getData().empty();
// Wait in cond_wait for a request to arrive. The 'while' is necessary
// since "spurious wakeups from the pthread_cond_wait ... may occur"
// (pthread_cond_wait man page)!
while (empty)
{
pthread_cond_wait(&me->m_cond_request, me->m_sfx_to_play.getMutex());
empty = me->m_sfx_to_play.getData().empty();
pthread_cond_wait(&me->m_cond_request, me->m_sfx_commands.getMutex());
empty = me->m_sfx_commands.getData().empty();
}
SFXBase *current = me->m_sfx_to_play.getData().front();
me->m_sfx_to_play.getData().erase(me->m_sfx_to_play.getData().begin());
SFXCommand *current = me->m_sfx_commands.getData().front();
me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin());
if (!current) // empty sfx indicates to abort the sfx manager
if (current->m_command == SFX_EXIT)
break;
me->m_sfx_to_play.unlock();
current->reallyPlayNow();
me->m_sfx_to_play.lock();
me->m_sfx_commands.unlock();
switch(current->m_command)
{
case SFX_PLAY: current->m_sfx->reallyPlayNow(); break;
case SFX_STOP: current->m_sfx->reallyStopNow(); break;
case SFX_PAUSE: current->m_sfx->reallyPauseNow(); break;
case SFX_RESUME: current->m_sfx->reallyResumeNow(); break;
case SFX_SPEED: current->m_sfx->reallySetSpeed(
current->m_parameter.getX()); break;
case SFX_POSITION: current->m_sfx->reallySetPosition(
current->m_parameter); break;
case SFX_VOLUME: current->m_sfx->reallySetVolume(
current->m_parameter.getX()); break;
case SFX_LOOP: current->m_sfx->reallySetLoop(
current->m_parameter.getX()!=0); break;
case SFX_DELETE: {
current->m_sfx->reallyStopNow();
me->deleteSFX(current->m_sfx); break;
}
case SFX_LISTENER: me->reallyPositionListenerNow(); break;
case SFX_UPDATE_MUSIC: music_manager->update(
current->m_parameter.getX()); break;
default: assert("Not yet supported.");
}
delete current;
current = NULL;
me->m_sfx_commands.lock();
} // while
// Clean up memory to avoid leak detection
while(!me->m_sfx_commands.getData().empty())
{
delete me->m_sfx_commands.getData().front();
me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin());
}
return NULL;
} // mainLoop
//----------------------------------------------------------------------------
/** Called then sound is globally switched on or off. It either pauses or
/** Called when sound is globally switched on or off. It either pauses or
* resumes all sound effects.
* \param on If sound is switched on or off.
*/
@ -248,18 +330,19 @@ void SFXManager::soundToggled(const bool on)
}
resumeAll();
const int sfx_amount = (int)m_all_sfx.size();
m_all_sfx.lock();
const int sfx_amount = (int)m_all_sfx.getData().size();
for (int n=0; n<sfx_amount; n++)
{
m_all_sfx[n]->onSoundEnabledBack();
m_all_sfx.getData()[n]->onSoundEnabledBack();
}
m_all_sfx.unlock();
}
else
{
pauseAll();
}
}
} // soundToggled
//----------------------------------------------------------------------------
/** Returns if sfx can be played. This means sfx are enabled and
@ -437,7 +520,14 @@ SFXBase* SFXManager::createSoundSource(SFXBuffer* buffer,
sfx->setMasterVolume(m_master_gain);
if (add_to_SFX_list) m_all_sfx.push_back(sfx);
if (add_to_SFX_list)
{
m_all_sfx.lock();
m_all_sfx.getData().push_back(sfx);
m_all_sfx.unlock();
}
else
printf("");
return sfx;
} // createSoundSource
@ -497,21 +587,26 @@ void SFXManager::deleteSFXMapping(const std::string &name)
*/
void SFXManager::deleteSFX(SFXBase *sfx)
{
if(sfx) sfx->stop();
if(sfx) sfx->reallyStopNow();
std::vector<SFXBase*>::iterator i;
i=std::find(m_all_sfx.begin(), m_all_sfx.end(), sfx);
// The whole block needs to be locked, otherwise the iterator
// could become invalid.
m_all_sfx.lock();
i=std::find(m_all_sfx.getData().begin(), m_all_sfx.getData().end(), sfx);
if(i==m_all_sfx.end())
if(i==m_all_sfx.getData().end())
{
Log::warn("SFXManager",
"SFXManager::deleteSFX : Warning: sfx not found in list.");
"SFXManager::deleteSFX : Warning: sfx '%s' %lx not found in list.",
sfx->getBuffer()->getFileName().c_str(), sfx);
return;
}
m_all_sfx.getData().erase(i);
delete sfx;
m_all_sfx.erase(i);
m_all_sfx.unlock();
} // deleteSFX
//----------------------------------------------------------------------------
@ -521,11 +616,13 @@ void SFXManager::deleteSFX(SFXBase *sfx)
*/
void SFXManager::pauseAll()
{
for (std::vector<SFXBase*>::iterator i=m_all_sfx.begin();
i!=m_all_sfx.end(); i++)
m_all_sfx.lock();
for (std::vector<SFXBase*>::iterator i= m_all_sfx.getData().begin();
i!=m_all_sfx.getData().end(); i++)
{
(*i)->pause();
} // for i in m_all_sfx
m_all_sfx.unlock();
} // pauseAll
//----------------------------------------------------------------------------
@ -537,19 +634,20 @@ void SFXManager::resumeAll()
// ignore unpausing if sound is disabled
if (!sfxAllowed()) return;
for (std::vector<SFXBase*>::iterator i=m_all_sfx.begin();
i!=m_all_sfx.end(); i++)
m_all_sfx.lock();
for (std::vector<SFXBase*>::iterator i =m_all_sfx.getData().begin();
i!=m_all_sfx.getData().end(); i++)
{
SFXStatus status = (*i)->getStatus();
// Initial happens when
if (status==SFX_PAUSED) (*i)->resume();
(*i)->resume();
} // for i in m_all_sfx
m_all_sfx.unlock();
} // resumeAll
//-----------------------------------------------------------------------------
/** Returns whether or not an openal error has occurred. If so, an error
* message is printed containing the given context.
* \param context Context to specify in the error message.
* \return True if no error happened.
*/
bool SFXManager::checkError(const std::string &context)
{
@ -580,11 +678,13 @@ void SFXManager::setMasterSFXVolume(float gain)
// regular SFX
{
for (std::vector<SFXBase*>::iterator i=m_all_sfx.begin();
i!=m_all_sfx.end(); i++)
m_all_sfx.lock();
for (std::vector<SFXBase*>::iterator i =m_all_sfx.getData().begin();
i!=m_all_sfx.getData().end(); i++)
{
(*i)->setMasterVolume(m_master_gain);
} // for i in m_all_sfx
m_all_sfx.unlock();
}
// quick SFX
@ -621,28 +721,51 @@ const std::string SFXManager::getErrorString(int err)
/** Sets the position and orientation of the listener.
* \param position Position of the listener.
* \param front Which way the listener is facing.
* \param up The up direction of the listener.
*/
void SFXManager::positionListener(const Vec3 &position, const Vec3 &front)
void SFXManager::positionListener(const Vec3 &position, const Vec3 &front,
const Vec3 &up)
{
m_listener_position.lock();
m_listener_position.getData() = position;
m_listener_front = front;
m_listener_up = up;
m_listener_position.unlock();
queue(SFX_LISTENER, NULL);
} // positionListener
//-----------------------------------------------------------------------------
/** Sets the position and orientation of the listener.
* \param position Position of the listener.
* \param front Which way the listener is facing.
*/
void SFXManager::reallyPositionListenerNow()
{
#if HAVE_OGGVORBIS
if (!UserConfigParams::m_sfx || !m_initialized) return;
m_position = position;
m_listener_position.lock();
{
//forward vector
m_listenerVec[0] = front.getX();
m_listenerVec[1] = front.getY();
m_listenerVec[2] = front.getZ();
//forward vector
float orientation[6];
orientation[0] = m_listener_front.getX();
orientation[1] = m_listener_front.getY();
orientation[2] = m_listener_front.getZ();
//up vector
m_listenerVec[3] = 0;
m_listenerVec[4] = 0;
m_listenerVec[5] = 1;
//up vector
orientation[3] = m_listener_up.getX();
orientation[4] = m_listener_up.getY();
orientation[5] = m_listener_up.getZ();
const Vec3 &pos = m_listener_position.getData();
alListener3f(AL_POSITION, pos.getX(), pos.getY(), pos.getZ());
alListenerfv(AL_ORIENTATION, orientation);
}
m_listener_position.unlock();
alListener3f(AL_POSITION, position.getX(), position.getY(), position.getZ());
alListenerfv(AL_ORIENTATION, m_listenerVec);
#endif
}
} // reallyPositionListenerNow
//-----------------------------------------------------------------------------
/** Positional sound is cool, but creating a new object just to play a simple

View File

@ -19,6 +19,7 @@
#ifndef HEADER_SFX_MANAGER_HPP
#define HEADER_SFX_MANAGER_HPP
#include "utils/leak_check.hpp"
#include "utils/no_copy.hpp"
#include "utils/synchronised.hpp"
#include "utils/vec3.hpp"
@ -57,6 +58,24 @@ private:
public:
/** The various commands to be executed by the sfx manager thread
* for each sfx. */
enum SFXCommands
{
SFX_PLAY = 1,
SFX_STOP,
SFX_PAUSE,
SFX_RESUME,
SFX_DELETE,
SFX_SPEED,
SFX_POSITION,
SFX_VOLUME,
SFX_LOOP,
SFX_LISTENER,
SFX_UPDATE_MUSIC,
SFX_EXIT,
}; // SFXCommands
/**
* Entries for custom SFX sounds. These are unique for each kart.
* eg. kart->playCustomSFX(SFX_MANAGER::CUSTOM_HORN)
@ -76,34 +95,68 @@ public:
NUM_CUSTOMS
};
/** Status of a sound effect. */
enum SFXStatus
{
SFX_UNKNOWN = -1, SFX_STOPPED = 0, SFX_PAUSED = 1, SFX_PLAYING = 2,
SFX_INITIAL = 3
};
private:
/** Listener position */
Vec3 m_position;
/** Data structure for the queue, which stores a sfx and the command to
* execute for it. */
class SFXCommand : public NoCopy
{
private:
LEAK_CHECK()
public:
/** The sound effect for which the command should be executed. */
SFXBase *m_sfx;
/** The command to execute. */
SFXCommands m_command;
/** Optional parameter for commands that need more input. */
Vec3 m_parameter;
// --------------------------------------------------------------------
SFXCommand(SFXCommands command, SFXBase *base)
{
m_command = command;
m_sfx = base;
} // SFXCommand()
// --------------------------------------------------------------------
SFXCommand(SFXCommands command, SFXBase *base, float parameter)
{
m_command = command;
m_sfx = base;
m_parameter.setX(parameter);
} // SFXCommand(float)
// --------------------------------------------------------------------
SFXCommand(SFXCommands command, SFXBase *base, const Vec3 &parameter)
{
m_command = command;
m_sfx = base;
m_parameter = parameter;
} // SFXCommand(Vec3)
}; // SFXCommand
// ========================================================================
/** The position of the listener. Its lock will be used to
* access m_listener_{position,front, up}. */
Synchronised<Vec3> m_listener_position;
/** The direction the listener is facing. */
Vec3 m_listener_front;
/** Up vector of the listener. */
Vec3 m_listener_up;
/** The buffers and info for all sound effects. These are shared among all
* instances of SFXOpenal. */
std::map<std::string, SFXBuffer*> m_all_sfx_types;
/** The actual instances (sound sources) */
std::vector<SFXBase*> m_all_sfx;
Synchronised<std::vector<SFXBase*> > m_all_sfx;
/** The list of sound effects to be played in the next update. */
Synchronised< std::vector<SFXBase*> > m_sfx_to_play;
Synchronised< std::vector<SFXCommand*> > m_sfx_commands;
/** To play non-positional sounds without having to create a new object for each */
std::map<std::string, SFXBase*> m_quick_sounds;
/** listener vector (position vector + up vector) */
float m_listenerVec[6];
/** If the sfx manager has been initialised. */
bool m_initialized;
@ -121,10 +174,16 @@ private:
virtual ~SFXManager();
static void* mainLoop(void *obj);
void deleteSFX(SFXBase *sfx);
void queueCommand(SFXCommand *command);
void reallyPositionListenerNow();
public:
static void create();
static void destroy();
void queue(SFXBase *sfx);
void queue(SFXCommands command, SFXBase *sfx);
void queue(SFXCommands command, SFXBase *sfx, float f);
void queue(SFXCommands command, SFXBase *sfx, const Vec3 &p);
// ------------------------------------------------------------------------
/** Static function to get the singleton sfx manager. */
static SFXManager *get()
@ -153,10 +212,10 @@ public:
SFXBase* createSoundSource(const std::string &name,
const bool addToSFXList=true);
void deleteSFX(SFXBase *sfx);
void deleteSFXMapping(const std::string &name);
void pauseAll();
void resumeAll();
void update(float dt);
bool soundExist(const std::string &name);
void setMasterSFXVolume(float gain);
float getMasterSFXVolume() const { return m_master_gain; }
@ -164,7 +223,8 @@ public:
static bool checkError(const std::string &context);
static const std::string getErrorString(int err);
void positionListener(const Vec3 &position, const Vec3 &front);
void positionListener(const Vec3 &position,
const Vec3 &front, const Vec3 &up);
SFXBase* quickSound(const std::string &soundName);
/** Called when sound was muted/unmuted */
@ -177,7 +237,7 @@ public:
// ------------------------------------------------------------------------
/** Returns the current position of the listener. */
Vec3 getListenerPos() const { return m_position; }
Vec3 getListenerPos() const { return m_listener_position.getData(); }
};

View File

@ -23,8 +23,7 @@
#include "audio/sfx_buffer.hpp"
#include "config/user_config.hpp"
#include "io/file_manager.hpp"
#include "race/race_manager.hpp"
#include "modes/world.hpp"
#include "utils/vs.hpp"
#ifdef __APPLE__
@ -38,17 +37,19 @@
#include <stdio.h>
#include <string>
SFXOpenAL::SFXOpenAL(SFXBuffer* buffer, bool positional, float gain, bool ownsBuffer) : SFXBase()
SFXOpenAL::SFXOpenAL(SFXBuffer* buffer, bool positional, float gain, bool owns_buffer) : SFXBase()
{
m_soundBuffer = buffer;
m_soundSource = 0;
m_ok = false;
m_positional = positional;
m_defaultGain = gain;
m_loop = false;
m_gain = -1.0f;
m_master_gain = 1.0f;
m_owns_buffer = ownsBuffer;
m_sound_buffer = buffer;
m_sound_source = 0;
m_status = SFX_UNKNOWN;
m_is_playing = false;
m_positional = positional;
m_defaultGain = gain;
m_loop = false;
m_gain = -1.0f;
m_master_gain = 1.0f;
m_owns_buffer = owns_buffer;
m_end_time = -1.0f;
// Don't initialise anything else if the sfx manager was not correctly
// initialised. First of all the initialisation will not work, and it
@ -60,18 +61,19 @@ SFXOpenAL::SFXOpenAL(SFXBuffer* buffer, bool positional, float gain, bool ownsBu
} // SFXOpenAL
//-----------------------------------------------------------------------------
/** Deletes the sfx source, and if it owns the buffer, also deletes the sound
* buffer. */
SFXOpenAL::~SFXOpenAL()
{
if (m_ok)
if (m_status!=SFX_UNKNOWN)
{
alDeleteSources(1, &m_soundSource);
alDeleteSources(1, &m_sound_source);
}
if (m_owns_buffer && m_soundBuffer != NULL)
if (m_owns_buffer && m_sound_buffer)
{
m_soundBuffer->unload();
delete m_soundBuffer;
m_sound_buffer->unload();
delete m_sound_buffer;
}
} // ~SFXOpenAL
@ -79,56 +81,78 @@ SFXOpenAL::~SFXOpenAL()
bool SFXOpenAL::init()
{
alGenSources(1, &m_soundSource );
alGenSources(1, &m_sound_source );
if (!SFXManager::checkError("generating a source")) return false;
assert( alIsBuffer(m_soundBuffer->getBufferID()) );
assert( alIsSource(m_soundSource) );
assert( alIsBuffer(m_sound_buffer->getBufferID()) );
assert( alIsSource(m_sound_source) );
//std::cout << "Setting a source with buffer " << m_soundBuffer
// << ", rolloff " << rolloff
// << ", gain=" << m_defaultGain << ", positional="
// << (positional ? "true" : "false") << std::endl;
alSourcei (m_soundSource, AL_BUFFER, m_soundBuffer->getBufferID());
alSourcei (m_sound_source, AL_BUFFER, m_sound_buffer->getBufferID());
if (!SFXManager::checkError("attaching the buffer to the source"))
return false;
alSource3f(m_soundSource, AL_POSITION, 0.0, 0.0, 0.0);
alSource3f(m_soundSource, AL_VELOCITY, 0.0, 0.0, 0.0);
alSource3f(m_soundSource, AL_DIRECTION, 0.0, 0.0, 0.0);
alSource3f(m_sound_source, AL_POSITION, 0.0, 0.0, 0.0);
alSource3f(m_sound_source, AL_VELOCITY, 0.0, 0.0, 0.0);
alSource3f(m_sound_source, AL_DIRECTION, 0.0, 0.0, 0.0);
alSourcef (m_soundSource, AL_ROLLOFF_FACTOR, m_soundBuffer->getRolloff());
alSourcef (m_soundSource, AL_MAX_DISTANCE, m_soundBuffer->getMaxDist());
alSourcef (m_sound_source, AL_ROLLOFF_FACTOR, m_sound_buffer->getRolloff());
alSourcef (m_sound_source, AL_MAX_DISTANCE, m_sound_buffer->getMaxDist());
if (m_gain < 0.0f)
{
alSourcef (m_soundSource, AL_GAIN, m_defaultGain * m_master_gain);
alSourcef (m_sound_source, AL_GAIN, m_defaultGain * m_master_gain);
}
else
{
alSourcef (m_soundSource, AL_GAIN, m_gain * m_master_gain);
alSourcef (m_sound_source, AL_GAIN, m_gain * m_master_gain);
}
if (m_positional) alSourcei (m_soundSource, AL_SOURCE_RELATIVE, AL_FALSE);
else alSourcei (m_soundSource, AL_SOURCE_RELATIVE, AL_TRUE);
if (m_positional) alSourcei (m_sound_source, AL_SOURCE_RELATIVE, AL_FALSE);
else alSourcei (m_sound_source, AL_SOURCE_RELATIVE, AL_TRUE);
alSourcei(m_soundSource, AL_LOOPING, m_loop ? AL_TRUE : AL_FALSE);
alSourcei(m_sound_source, AL_LOOPING, m_loop ? AL_TRUE : AL_FALSE);
m_ok = SFXManager::checkError("setting up the source");
if(SFXManager::checkError("setting up the source"))
m_status = SFX_INITIAL;
return m_ok;
return m_status==SFX_INITIAL;
} // init
// ------------------------------------------------------------------------
/** Returns the status of this sfx. */
SFXBase::SFXStatus SFXOpenAL::getStatus()
{
if(m_status==SFX_PLAYING)
{
if(m_loop) return SFX_PLAYING;
if(World::getWorld() && World::getWorld()->getTime() > m_end_time)
{
m_status = SFX_STOPPED;
return m_status;
}
}
return m_status;
} // getStatus;
//-----------------------------------------------------------------------------
/** Changes the pitch of a sound effect.
/** Queues up a change of the pitch of a sound effect to the sfx manager.
* \param factor Speedup/slowdown between 0.5 and 2.0
*/
void SFXOpenAL::speed(float factor)
void SFXOpenAL::setSpeed(float factor)
{
if(!m_ok || isnan(factor)) return;
if(m_status==SFX_UNKNOWN) return;
assert(!isnan(factor));
SFXManager::get()->queue(SFXManager::SFX_SPEED, this, factor);
} // setSpeed
//-----------------------------------------------------------------------------
/** Changes the pitch of a sound effect. Executed from the sfx manager thread.
* \param factor Speedup/slowdown between 0.5 and 2.0
*/
void SFXOpenAL::reallySetSpeed(float factor)
{
if(m_status==SFX_UNKNOWN) return;
//OpenAL only accepts pitches in the range of 0.5 to 2.0
if(factor > 2.0f)
{
@ -138,23 +162,33 @@ void SFXOpenAL::speed(float factor)
{
factor = 0.5f;
}
alSourcef(m_soundSource,AL_PITCH,factor);
SFXManager::checkError("changing the speed");
} // speed
alSourcef(m_sound_source,AL_PITCH,factor);
} // reallySetSpeed
//-----------------------------------------------------------------------------
/** Changes the volume of a sound effect.
* \param gain Volume adjustment between 0.0 (mute) and 1.0 (full volume).
*/
void SFXOpenAL::volume(float gain)
void SFXOpenAL::setVolume(float gain)
{
if(m_status==SFX_UNKNOWN) return;
assert(!isnan(gain)) ;
SFXManager::get()->queue(SFXManager::SFX_VOLUME, this, gain);
} // setVolume
//-----------------------------------------------------------------------------
/** Changes the volume of a sound effect.
* \param gain Volume adjustment between 0.0 (mute) and 1.0 (full volume).
*/
void SFXOpenAL::reallySetVolume(float gain)
{
if(m_status==SFX_UNKNOWN) return;
m_gain = m_defaultGain * gain;
if(!m_ok) return;
if(m_status==SFX_UNKNOWN) return;
alSourcef(m_soundSource, AL_GAIN, m_gain * m_master_gain);
SFXManager::checkError("setting volume");
} // volume
alSourcef(m_sound_source, AL_GAIN, m_gain * m_master_gain);
} // reallySetVolume
//-----------------------------------------------------------------------------
@ -162,9 +196,9 @@ void SFXOpenAL::setMasterVolume(float gain)
{
m_master_gain = gain;
if(!m_ok) return;
if(m_status==SFX_UNKNOWN) return;
alSourcef(m_soundSource, AL_GAIN,
alSourcef(m_sound_source, AL_GAIN,
(m_gain < 0.0f ? m_defaultGain : m_gain) * m_master_gain);
SFXManager::checkError("setting volume");
} //setMasterVolume
@ -174,55 +208,101 @@ void SFXOpenAL::setMasterVolume(float gain)
*/
void SFXOpenAL::setLoop(bool status)
{
m_loop = status;
if(!m_ok) return;
alSourcei(m_soundSource, AL_LOOPING, status ? AL_TRUE : AL_FALSE);
SFXManager::checkError("looping");
} // loop
SFXManager::get()->queue(SFXManager::SFX_LOOP, this, status ? 1.0f : 0.0f);
} // setLoop
//-----------------------------------------------------------------------------
/** Stops playing this sound effect.
/** Loops this sound effect.
*/
void SFXOpenAL::reallySetLoop(bool status)
{
m_loop = status;
if(m_status==SFX_UNKNOWN) return;
alSourcei(m_sound_source, AL_LOOPING, status ? AL_TRUE : AL_FALSE);
SFXManager::checkError("looping");
} // reallySetLoop
//-----------------------------------------------------------------------------
/** Queues a stop for this effect to the sound manager.
*/
void SFXOpenAL::stop()
{
if(!m_ok) return;
m_loop = false;
alSourcei(m_soundSource, AL_LOOPING, AL_FALSE);
alSourceStop(m_soundSource);
SFXManager::checkError("stoping");
SFXManager::get()->queue(SFXManager::SFX_STOP, this);
} // stop
//-----------------------------------------------------------------------------
/** The sfx manager thread executes a stop for this sfx.
*/
void SFXOpenAL::reallyStopNow()
{
if(m_status==SFX_UNKNOWN) return;
m_is_playing = false;
m_status = SFX_STOPPED;
m_loop = false;
alSourcei(m_sound_source, AL_LOOPING, AL_FALSE);
alSourceStop(m_sound_source);
SFXManager::checkError("stoping");
} // reallyStopNow
//-----------------------------------------------------------------------------
/** Queues up a pause command for this sfx.
*/
void SFXOpenAL::pause()
{
SFXManager::get()->queue(SFXManager::SFX_PAUSE, this);
} // pause
//-----------------------------------------------------------------------------
/** Pauses a SFX that's currently played. Nothing happens it the effect is
* currently not being played.
*/
void SFXOpenAL::pause()
void SFXOpenAL::reallyPauseNow()
{
if(!m_ok) return;
alSourcePause(m_soundSource);
// This updates the status, i.e. potentially switches from
// playing to stopped.
getStatus();
if(m_status!=SFX_PLAYING) return;
m_status = SFX_PAUSED;
alSourcePause(m_sound_source);
SFXManager::checkError("pausing");
} // pause
} // reallyPauseNow
//-----------------------------------------------------------------------------
/** Queues up a resume command for this sound effect.
*/
void SFXOpenAL::resume()
{
SFXManager::get()->queue(SFXManager::SFX_RESUME, this);
} // resume
//-----------------------------------------------------------------------------
/** Resumes a sound effect.
*/
void SFXOpenAL::resume()
void SFXOpenAL::reallyResumeNow()
{
if (!m_ok)
// Will init the sfx (lazy) if necessary.
getStatus();
if(m_status==SFX_PAUSED)
{
// lazily create OpenAL source when needed
init();
// creation of OpenAL source failed, giving up
if (!m_ok) return;
alSourcePlay(m_sound_source);
SFXManager::checkError("resuming");
m_status = SFX_PLAYING;
}
} // reallyResumeNow
alSourcePlay(m_soundSource);
SFXManager::checkError("resuming");
} // resume
//-----------------------------------------------------------------------------
/** Queues up a delete request for this object. This is necessary to avoid
* a crash if the sfx manager thread might be delayed and access this object
* after it was deleted.
*/
void SFXOpenAL::deleteSFX()
{
SFXManager::get()->queue(SFXManager::SFX_DELETE, this);
} // deleteSFX
//-----------------------------------------------------------------------------
/** This actually queues up the sfx in the sfx manager. It will be started
@ -230,7 +310,11 @@ void SFXOpenAL::resume()
*/
void SFXOpenAL::play()
{
SFXManager::get()->queue(this);
// Technically the sfx is only playing after the sfx thread starts it,
// but for STK this is correct since we don't want to start the same
// sfx twice.
m_is_playing = true;
SFXManager::get()->queue(SFXManager::SFX_PLAY, this);
} // play
//-----------------------------------------------------------------------------
@ -239,30 +323,68 @@ void SFXOpenAL::play()
void SFXOpenAL::reallyPlayNow()
{
if (!SFXManager::get()->sfxAllowed()) return;
if (!m_ok)
if (m_status==SFX_UNKNOWN)
{
// lazily create OpenAL source when needed
init();
// creation of OpenAL source failed, giving up
if (!m_ok) return;
if (m_status==SFX_UNKNOWN) return;
}
alSourcePlay(m_soundSource);
alSourcePlay(m_sound_source);
m_status = SFX_PLAYING;
SFXManager::checkError("playing");
// At non-race time the end time is not important
if(World::getWorld())
{
float t= World::getWorld()->getTime();
// A special case: the track intro music starts at world clock = 0,
// and has a duration of 3.7 seconds. So if the game is paused in the
// first 3.7 seconds, the sfx wil be considered to be not finished
// (since the world clock stays at 0 before the race start), and
// therefore resumed if the game is resumed, which means it is
// played again. To avoid this, any sound starting at t=0 is set
// to have an end time of 0 - which means the track intro music is
// not resumed in this case.
m_end_time = t>0 ? t+m_sound_buffer->getDuration() : 0;
}
else
m_end_time = 1.0f;
} // reallyPlayNow
//-----------------------------------------------------------------------------
/** Returns true if the sound effect is currently playing.
*/
bool SFXOpenAL::isPlaying()
{
return m_is_playing;
} // isPlaying
//-----------------------------------------------------------------------------
/** Sets the position where this sound effects is played.
* \param position Position of the sound effect.
*/
void SFXOpenAL::position(const Vec3 &position)
void SFXOpenAL::setPosition(const Vec3 &position)
{
if (m_status == SFX_UNKNOWN) return;
SFXManager::get()->queue(SFXManager::SFX_POSITION, this, position);
} // setPosition
//-----------------------------------------------------------------------------
/** Sets the position where this sound effects is played.
* \param position Position of the sound effect.
*/
void SFXOpenAL::reallySetPosition(const Vec3 &position)
{
if(!UserConfigParams::m_sfx)
return;
if (!m_ok)
if (m_status==SFX_UNKNOWN)
{
Log::warn("SFX", "Position called on non-ok SFX <%s>", m_soundBuffer->getFileName().c_str());
Log::warn("SFX", "Position called on non-ok SFX <%s>",
m_sound_buffer->getFileName().c_str());
return;
}
if (!m_positional)
@ -277,39 +399,20 @@ void SFXOpenAL::position(const Vec3 &position)
return;
}
alSource3f(m_soundSource, AL_POSITION,
alSource3f(m_sound_source, AL_POSITION,
(float)position.getX(), (float)position.getY(), (float)position.getZ());
if (SFXManager::get()->getListenerPos().distance(position) > m_soundBuffer->getMaxDist())
if (SFXManager::get()->getListenerPos().distance(position) > m_sound_buffer->getMaxDist())
{
alSourcef(m_soundSource, AL_GAIN, 0);
alSourcef(m_sound_source, AL_GAIN, 0);
}
else
{
alSourcef(m_soundSource, AL_GAIN, (m_gain < 0.0f ? m_defaultGain : m_gain) * m_master_gain);
alSourcef(m_sound_source, AL_GAIN, (m_gain < 0.0f ? m_defaultGain : m_gain) * m_master_gain);
}
SFXManager::checkError("positioning");
} // position
//-----------------------------------------------------------------------------
/** Returns the status of this sound effect.
*/
SFXManager::SFXStatus SFXOpenAL::getStatus()
{
if(!m_ok) return SFXManager::SFX_UNKNOWN;
int state = 0;
alGetSourcei(m_soundSource, AL_SOURCE_STATE, &state);
switch(state)
{
case AL_STOPPED: return SFXManager::SFX_STOPPED;
case AL_PLAYING: return SFXManager::SFX_PLAYING;
case AL_PAUSED: return SFXManager::SFX_PAUSED;
case AL_INITIAL: return SFXManager::SFX_INITIAL;
default: return SFXManager::SFX_UNKNOWN;
}
} // getStatus
} // reallySetPosition
//-----------------------------------------------------------------------------
@ -317,22 +420,22 @@ void SFXOpenAL::onSoundEnabledBack()
{
if (m_loop)
{
if (!m_ok) init();
if (m_ok)
if (m_status==SFX_UNKNOWN) init();
if (m_status!=SFX_UNKNOWN)
{
alSourcef(m_soundSource, AL_GAIN, 0);
alSourcef(m_sound_source, AL_GAIN, 0);
play();
pause();
alSourcef(m_soundSource, AL_GAIN, (m_gain < 0.0f ? m_defaultGain : m_gain) * m_master_gain);
alSourcef(m_sound_source, AL_GAIN, (m_gain < 0.0f ? m_defaultGain : m_gain) * m_master_gain);
}
}
}
} // onSoundEnabledBack
//-----------------------------------------------------------------------------
void SFXOpenAL::setRolloff(float rolloff)
{
alSourcef (m_soundSource, AL_ROLLOFF_FACTOR, rolloff);
alSourcef (m_sound_source, AL_ROLLOFF_FACTOR, rolloff);
}
#endif //if HAVE_OGGVORBIS

View File

@ -28,7 +28,6 @@
# include <AL/al.h>
#endif
#include "audio/sfx_base.hpp"
#include "audio/sfx_manager.hpp"
#include "utils/leak_check.hpp"
/**
@ -38,9 +37,17 @@
class SFXOpenAL : public SFXBase
{
private:
SFXBuffer* m_soundBuffer; //!< Buffers hold sound data.
ALuint m_soundSource; //!< Sources are points emitting sound.
bool m_ok;
LEAK_CHECK()
/** Buffers hold sound data. */
SFXBuffer* m_sound_buffer;
/** Sources are points emitting sound. */
ALuint m_sound_source;
/** The status of this SFX. */
SFXStatus m_status;
bool m_positional;
float m_defaultGain;
@ -55,37 +62,52 @@ private:
the sound source won't be created and we'll be left with no clue when enabling
sounds later. */
float m_gain;
/** True when the sfx is currently playing. */
bool m_is_playing;
/** The master gain set in user preferences */
float m_master_gain;
/** If this sfx should also free the sound buffer. */
bool m_owns_buffer;
/** Time at which a sfx ends playing. Used to avoid frequently getting
* the openl status (which can slow down stk). */
float m_end_time;
public:
SFXOpenAL(SFXBuffer* buffer, bool positional, float gain,
bool owns_buffer = false);
virtual ~SFXOpenAL();
SFXOpenAL(SFXBuffer* buffer, bool positional, float gain,
bool owns_buffer = false);
virtual ~SFXOpenAL();
/** Late creation, if SFX was initially disabled */
virtual bool init();
virtual bool init();
virtual void play();
virtual void reallyPlayNow();
virtual void setLoop(bool status);
virtual void reallySetLoop(bool status);
virtual bool isPlaying();
virtual void stop();
virtual void reallyStopNow();
virtual void pause();
virtual void reallyPauseNow();
virtual void resume();
virtual void reallyResumeNow();
virtual void deleteSFX();
virtual void setSpeed(float factor);
virtual void reallySetSpeed(float factor);
virtual void setPosition(const Vec3 &position);
virtual void reallySetPosition(const Vec3 &p);
virtual void setVolume(float gain);
virtual void reallySetVolume(float gain);
virtual void setMasterVolume(float gain);
virtual void onSoundEnabledBack();
virtual void setRolloff(float rolloff);
virtual SFXStatus getStatus();
virtual void play();
virtual void reallyPlayNow();
virtual void setLoop(bool status);
virtual void stop();
virtual void pause();
virtual void resume();
virtual void speed(float factor);
virtual void position(const Vec3 &position);
virtual void volume(float gain);
virtual void setMasterVolume(float gain);
virtual SFXManager::SFXStatus getStatus();
virtual void onSoundEnabledBack();
virtual void setRolloff(float rolloff);
virtual const SFXBuffer* getBuffer() const { return m_soundBuffer; }
LEAK_CHECK()
// ------------------------------------------------------------------------
/** Returns the buffer associated with this sfx. */
virtual const SFXBuffer* getBuffer() const { return m_sound_buffer; }
}; // SFXOpenAL

View File

@ -83,6 +83,10 @@ irr::core::stringw DeviceConfig::getMappingIdString (const PlayerAction action)
returnString += id;
break;
case Input::IT_NONE:
returnString += "none";
break;
default:
assert(false);
returnString += type;

View File

@ -23,15 +23,31 @@
#include "graphics/irr_driver.hpp"
#include "online/http_request.hpp"
#include "utils/random_generator.hpp"
#include "utils/string_utils.hpp"
#ifdef __APPLE__
# include <sys/sysctl.h>
#endif
#include <fstream>
#include <set>
#include <sstream>
#include <string>
#ifndef WIN32
# include <sys/param.h> // To get BSD macro
# include <sys/utsname.h>
#endif
#include <vector>
namespace HardwareStats
{
namespace Private
{
/** Stores the OS version, e.g. "Windows 7", or "Fedora 21". */
static std::string m_os_version;
} // namespace Private
using namespace Private;
// ----------------------------------------------------------------------------
/** Returns the amount of RAM in MB.
@ -40,7 +56,7 @@ namespace HardwareStats
int getRAM()
{
#ifdef __linux__
const uint64_t memory_size = (uint64_t)sysconf(_SC_PHYS_PAGES)
const uint64_t memory_size = (uint64_t)sysconf(_SC_PHYS_PAGES)
* sysconf(_SC_PAGESIZE);
return int(memory_size / (1024*1024));
#endif
@ -102,6 +118,138 @@ int getNumProcessors()
return 0;
} // getNumProcessors
// ----------------------------------------------------------------------------
/** Tries opening and parsing the specified release file in /etc to find
* information about the distro used.
* \param filename Full path of the file to open.
* \return True if file could be read and valid information was paresed,
* false otherwise.
*/
bool readEtcReleaseFile(const std::string &filename)
{
std::ifstream in(filename);
std::string s, distro, version;
while( (distro.empty() || version.empty()) &&
std::getline(in, s) )
{
std::vector<std::string> l = StringUtils::split(s, '=');
if(l.size()==0) continue;
if (l[0]=="NAME" ) distro = l[1];
else if(l[0]=="VERSION_ID") version = l[1];
}
if(!distro.empty() && !version.empty())
{
distro = StringUtils::replace(distro, "\"", "");
version = StringUtils::replace(version, "\"", "");
m_os_version = distro + " " + version;
return true;
}
return false;
} // readEtcReleaseFile
// ----------------------------------------------------------------------------
/** Identify more details about the OS, e.g. on linux which distro
* and which verison; on windows the version number.
* \param json Json data structure to store the os info in.
*/
void determineOSVersion()
{
std::string version, distro;
#ifdef __linux__
// First try the standard /etc/os-release. Then check for older versions
// e.g. /etc/fedora-release, /etc/SuSE-release, /etc/redhat-release
if(readEtcReleaseFile("/etc/os-release")) return;
std::set<std::string> file_list;
file_manager->listFiles(file_list, "./", true);
for(std::set<std::string>::iterator i = file_list.begin();
i != file_list.end(); i++)
{
// Only try reading /etc/*-release files
if(StringUtils::hasSuffix(*i, "-release"))
if (readEtcReleaseFile(*i)) return;
}
// Fallback in case that we can't find any valid information in /etc/*release
struct utsname u;
if (uname(&u))
{
m_os_version = "Linux unknown";
return;
}
// Ignore data after "-", since it could identify a system (self compiled
// kernels).
std::vector<std::string> l = StringUtils::split(std::string(u.release),'-');
m_os_version = std::string(u.sysname) + " " + l[0];
#endif
#ifdef BSD
struct utsname u;
if (uname(&u))
{
m_os_version = "BSD unknown";
return;
}
// Ignore data after "-", since it could identify a system (self compiled
// kernels).
std::vector<std::string> l = StringUtils::split(std::string(u.release),'-');
m_os_version = std::string(u.sysname) + " " + l[0];
#endif
#ifdef WIN32
// (C) 2014 by Wildfire Games (0 A.D.), ported by Joerg Henrichs.
HKEY hKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0,
KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
{
m_os_version = "windows-unknown";
return;
}
char windows_version_string[20];
DWORD size = sizeof(windows_version_string);
RegQueryValueEx(hKey, "CurrentVersion", 0, 0, (LPBYTE)windows_version_string, &size);
unsigned major = 0, minor = 0;
std::stringstream sstr(windows_version_string);
sstr >> major;
if (sstr.peek() == '.')
sstr.ignore();
sstr >> minor;
int windows_version = (major << 8) | minor;
RegCloseKey(hKey);
switch(windows_version)
{
case 0x0500: m_os_version="Windows 2000"; break;
case 0x0501: m_os_version="Windows XP"; break;
case 0x0502: m_os_version="Windows XP64"; break;
case 0x0600: m_os_version="Windows Vista"; break;
case 0x0601: m_os_version="Windows 7"; break;
case 0x0602: m_os_version="Windows 8"; break;
default: {
m_os_version = StringUtils::insertValues("Windows %d",
windows_version);
break;
}
} // switch
#endif
} // determineOSVersion
// ----------------------------------------------------------------------------
/** Returns the OS version, e.g.: "Windows 7", or "Fedora 21".
*/
const std::string& getOSVersion()
{
if(m_os_version.empty())
determineOSVersion();
return m_os_version;
} // getOSVersion
// ----------------------------------------------------------------------------
/** If the configuration of this installation has not been reported for the
* current version, collect the hardware statistics and send it to STK's
@ -144,10 +292,12 @@ void reportHardwareStats()
json.add("build_debug", 1);
#endif
json.add("os_version", getOSVersion());
unsigned int ogl_version = irr_driver->getGLSLVersion();
unsigned int major = ogl_version/100;
unsigned int minor = ogl_version - 100*major;
std::string version =
std::string version =
StringUtils::insertValues("%d.%d", major, minor);
json.add("GL_SHADING_LANGUAGE_VERSION", version);
@ -166,7 +316,7 @@ void reportHardwareStats()
else if(StringUtils::startsWith(card_name, "S3 Graphics"))
card_name="S3";
json.add("gfx_card", card_name+" "+renderer);
json.add("video_xres", UserConfigParams::m_width );
json.add("video_yres", UserConfigParams::m_height);
@ -195,14 +345,14 @@ void reportHardwareStats()
int m_version;
public:
HWReportRequest(int version) : Online::HTTPRequest(/*manage memory*/true, 1)
,m_version(version)
, m_version(version)
{}
// --------------------------------------------------------------------
/** Callback after the request has been executed.
/** Callback after the request has been executed.
*/
virtual void callback()
{
// If the request contains incorrect data, it will not have a
// If the request contains incorrect data, it will not have a
// download error, but return an error string as return value:
if(hadDownloadError() || getData()=="<h1>Bad Request (400)</h1>")
{

View File

@ -25,11 +25,14 @@
#include "utils/no_copy.hpp"
#include "utils/string_utils.hpp"
namespace HardwareStats
{
/** A class to manage json data. */
class Json : public NoCopy
{
private:
/** The accumulated json data. */
std::string m_data;
public:
/** Constructor. */
@ -78,6 +81,7 @@ namespace HardwareStats
// ========================================================================
void reportHardwareStats();
const std::string& getOSVersion();
}; // HardwareStats
#endif

View File

@ -170,7 +170,11 @@ PlayerManager::~PlayerManager()
for_var_in(PlayerProfile*, player, m_all_players)
{
if(!player->rememberPassword())
player->clearSession();
{
// Don't let the player trigger a save, since it
// will be done below anyway.
player->clearSession(/*save*/false);
}
}
save();

View File

@ -235,12 +235,13 @@ void PlayerProfile::saveSession(int user_id, const std::string &token)
// ------------------------------------------------------------------------
/** Unsets any saved session data. */
void PlayerProfile::clearSession()
void PlayerProfile::clearSession(bool save)
{
m_saved_session = false;
m_saved_user_id = 0;
m_saved_token = "";
PlayerManager::get()->save();
if(save)
PlayerManager::get()->save();
} // clearSession
//------------------------------------------------------------------------------

View File

@ -121,7 +121,7 @@ public:
bool operator<(const PlayerProfile &other);
void raceFinished();
void saveSession(int user_id, const std::string &token);
void clearSession();
void clearSession(bool save=true);
void addIcon();
/** Abstract virtual classes, to be implemented by the OnlinePlayer. */

View File

@ -71,7 +71,7 @@ SavedGrandPrix::SavedGrandPrix(unsigned int player_id,
const std::vector<RaceManager::KartStatus> &kart_list)
: m_savedgp_group("SavedGP",
"Represents the saved state of a GP"),
m_player_id(player_id),
m_player_id(player_id, "player_id", &m_savedgp_group),
m_gp_id(gp_id.c_str(), "gp_id", &m_savedgp_group),
m_difficulty((int)difficulty,"difficulty", &m_savedgp_group),
m_player_karts(player_karts,"player_karts", &m_savedgp_group),
@ -94,13 +94,14 @@ SavedGrandPrix::SavedGrandPrix(unsigned int player_id,
SavedGrandPrix::SavedGrandPrix(const XMLNode* node)
: m_savedgp_group("SavedGP",
"Represents the saved state of a GP"),
m_player_id(0),
m_player_id(0, "player_id", &m_savedgp_group),
m_gp_id("-", "gp_id", &m_savedgp_group),
m_difficulty(0,"difficulty", &m_savedgp_group),
m_player_karts(0,"player_karts", &m_savedgp_group),
m_next_track(0,"last_track", &m_savedgp_group)
{
//m_player_group.findYourDataInAChildOf(node);
m_player_id.findYourDataInAnAttributeOf(node);
m_gp_id.findYourDataInAnAttributeOf(node);
m_difficulty.findYourDataInAnAttributeOf(node);
m_player_karts.findYourDataInAnAttributeOf(node);

View File

@ -60,7 +60,7 @@ protected:
* WARNING : m_savedgp_group has to be declared before the other userconfigparams!
*/
GroupUserConfigParam m_savedgp_group;
unsigned int m_player_id;
IntUserConfigParam m_player_id;
/** Identifier of this GP. */
StringUserConfigParam m_gp_id;
@ -145,6 +145,7 @@ public:
for (unsigned int n=0; n<UserConfigParams::m_saved_grand_prix_list.size(); n++)
{
SavedGrandPrix* gp = &UserConfigParams::m_saved_grand_prix_list[n];
if ((gp->getGPID() == gpid) &&
(gp->getPlayerID() == player) &&
(gp->getDifficulty() == difficulty) &&

View File

@ -140,8 +140,7 @@ void GroupUserConfigParam::findYourDataInAChildOf(const XMLNode* node)
const XMLNode* child = node->getNode( m_param_name );
if (child == NULL)
{
//std::cerr << "/!\\ User Config : Couldn't find parameter group "
// << paramName << std::endl;
//Log::error("User Config", "Couldn't find parameter group %s", m_param_name.c_str());
return;
}
@ -271,8 +270,7 @@ void ListUserConfigParam<T, U>::findYourDataInAChildOf(const XMLNode* node)
const XMLNode* child = node->getNode( m_param_name );
if (child == NULL)
{
//std::cerr << "/!\\ User Config : Couldn't find parameter group "
// << paramName << std::endl;
//Log::error("User Config", "Couldn't find parameter group %s", m_param_name.c_str());
return;
}
@ -374,12 +372,12 @@ void IntUserConfigParam::findYourDataInAChildOf(const XMLNode* node)
const XMLNode* child = node->getNode( m_param_name );
if(child == NULL)
{
//std::cout << "Couldn't find int parameter " << paramName << std::endl;
//Log::error("UserConfigParam", "Couldn't find int parameter %s", m_param_name.c_str());
return;
}
child->get( "value", &m_value );
//std::cout << "read int " << paramName << ", value=" << value << std::endl;
//Log::info("UserConfigParam", "Read int %s ,value = %d", m_param_name.c_str(), value);
} // findYourDataInAChildOf
// ----------------------------------------------------------------------------
@ -442,7 +440,7 @@ void TimeUserConfigParam::findYourDataInAChildOf(const XMLNode* node)
const XMLNode* child = node->getNode( m_param_name );
if(child == NULL)
{
//std::cout << "Couldn't find int parameter " << paramName <<std::endl;
//Log::error("UserConfigParam", "Couldn't find int parameter %s", m_param_name.c_str());
return;
}
@ -564,8 +562,7 @@ void BoolUserConfigParam::findYourDataInAChildOf(const XMLNode* node)
}
else
{
std::cerr << "Unknown value for " << m_param_name
<< "; expected true or false\n";
Log::error("User Config", "Unknown value for %s; expected true or false", m_param_name.c_str());
}
} // findYourDataInAChildOf
@ -585,8 +582,7 @@ void BoolUserConfigParam::findYourDataInAnAttributeOf(const XMLNode* node)
}
else
{
std::cerr << "Unknown value for " << m_param_name
<< "; expected true or false\n";
Log::error("User Config", "Unknown value for %s; expected true or false", m_param_name.c_str());
}
} // findYourDataInAnAttributeOf
@ -760,7 +756,7 @@ void UserConfig::saveConfig()
const int paramAmount = all_params.size();
for(int i=0; i<paramAmount; i++)
{
//std::cout << "saving parameter " << i << " to file\n";
//Log::info("UserConfig", "Saving parameter %d to file", i);
all_params[i].write(configfile);
}
@ -769,8 +765,8 @@ void UserConfig::saveConfig()
}
catch (std::runtime_error& e)
{
std::cerr << "[UserConfig::saveConfig] ERROR: Failed to write config to " << filename.c_str()
<< "; cause : " << e.what() << "\n";
Log::error("UserConfig::saveConfig", "Failed to write config to %s, because %s",
filename.c_str(), e.what());
}
} // saveConfig

View File

@ -350,6 +350,18 @@ void Camera::smoothMoveCamera(float dt)
current_position += (wanted_position - current_position) * dt * 5;
}
// Avoid camera crash: if the speed is negative, the current_position
// can oscillate between plus and minus, getting bigger and bigger. If
// this happens often enough, floating point overflow happens (large
// negative speeds can happen when the kart is tumbling/falling)
// To avoid this, we just move the camera to the wanted position if
// the distance becomes too large (see #1356).
if( (current_position - wanted_position).getLengthSQ() > 100)
{
Log::debug("camera", "Resetting camera position to avoid crash");
current_position = wanted_position;
}
if(m_mode!=CM_FALLING)
m_camera->setPosition(current_position);
m_camera->setTarget(current_target);//set new target
@ -360,7 +372,9 @@ void Camera::smoothMoveCamera(float dt)
if (race_manager->getNumLocalPlayers() < 2)
{
SFXManager::get()->positionListener(current_position, current_target - current_position);
SFXManager::get()->positionListener(current_position,
current_target - current_position,
Vec3(0,1,0));
}
} // smoothMoveCamera
@ -566,7 +580,8 @@ void Camera::positionCamera(float dt, float above_kart, float cam_angle,
if (race_manager->getNumLocalPlayers() < 2)
{
SFXManager::get()->positionListener(m_camera->getPosition(),
wanted_target - m_camera->getPosition());
wanted_target - m_camera->getPosition(),
Vec3(0, 1, 0));
}
}

View File

@ -39,7 +39,8 @@ Explosion::Explosion(const Vec3& coord, const char* explosion_sound, const char
{
// short emision time, explosion, not constant flame
m_remaining_time = burst_time;
m_emission_frames = 0;
ParticleKindManager* pkm = ParticleKindManager::get();
ParticleKind* particles = pkm->getParticles(particle_file);
m_emitter = new ParticleEmitter(particles, coord, NULL);
@ -67,6 +68,7 @@ bool Explosion::updateAndDelete(float dt)
// so no need to save the result of the update call.
HitSFX::updateAndDelete(dt);
m_emission_frames++;
m_remaining_time -= dt;
if (m_remaining_time < 0.0f && m_remaining_time >= -explosion_time)
@ -77,15 +79,14 @@ bool Explosion::updateAndDelete(float dt)
node->getMaterial(0).AmbientColor.setGreen(intensity);
node->getMaterial(0).DiffuseColor.setGreen(intensity);
node->getMaterial(0).EmissiveColor.setGreen(intensity);
node->getMaterial(0).AmbientColor.setBlue(intensity);
node->getMaterial(0).DiffuseColor.setBlue(intensity);
node->getMaterial(0).EmissiveColor.setBlue(intensity);
node->getMaterial(0).AmbientColor.setRed(intensity);
node->getMaterial(0).DiffuseColor.setRed(intensity);
node->getMaterial(0).EmissiveColor.setRed(intensity);
}
@ -97,9 +98,14 @@ bool Explosion::updateAndDelete(float dt)
// object is removed.
if (m_remaining_time > -explosion_time)
{
// Stop the emitter and wait a little while for all particles to have time to fade out
m_emitter->getNode()->getEmitter()->setMinParticlesPerSecond(0);
m_emitter->getNode()->getEmitter()->setMaxParticlesPerSecond(0);
// if framerate is very low, emit for at least a few frames, in case
// burst time is lower than the time of 1 frame
if (m_emission_frames > 2)
{
// Stop the emitter and wait a little while for all particles to have time to fade out
m_emitter->getNode()->getEmitter()->setMinParticlesPerSecond(0);
m_emitter->getNode()->getEmitter()->setMaxParticlesPerSecond(0);
}
}
else
{

View File

@ -32,7 +32,7 @@ class Vec3;
class SFXBase;
class ParticleEmitter;
const float explosion_time = 1.5f;
const float explosion_time = 2.0f;
/**
* \ingroup graphics
@ -41,6 +41,7 @@ class Explosion : public HitSFX
{
private:
float m_remaining_time;
int m_emission_frames;
ParticleEmitter* m_emitter;
public:

View File

@ -820,7 +820,6 @@ void getGLLimits(HardwareStats::Json *json)
STRING(VERSION);
STRING(VENDOR);
STRING(RENDERER);
STRING(EXTENSIONS);
INTEGER(SUBPIXEL_BITS);
INTEGER(MAX_TEXTURE_SIZE);
INTEGER(MAX_CUBE_MAP_TEXTURE_SIZE);

View File

@ -449,21 +449,4 @@ void ParticleSystemProxy::render() {
m_first_execution = false;
simulate();
draw();
}
bool ParticleSystemProxy::update()
{
doParticleSystem(os::Timer::getTime());
return (IsVisible && (Particles.size() != 0));
}
void ParticleSystemProxy::OnRegisterSceneNode()
{
doParticleSystem(os::Timer::getTime());
if (IsVisible && (Particles.size() != 0))
{
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT_EFFECT);
ISceneNode::OnRegisterSceneNode();
}
}
}

View File

@ -70,7 +70,6 @@ public:
virtual void setEmitter(scene::IParticleEmitter* emitter);
virtual void render();
virtual void OnRegisterSceneNode();
void setAlphaAdditive(bool val) { m_alpha_additive = val; }
void setIncreaseFactor(float val) { size_increase_factor = val; }
void setColorFrom(float r, float g, float b) { m_color_from[0] = r; m_color_from[1] = g; m_color_from[2] = b; }
@ -79,7 +78,6 @@ public:
const float* getColorTo() const { return m_color_to; }
void setHeightmap(const std::vector<std::vector<float> >&, float, float, float, float);
void setFlip();
bool update();
};
#endif // GPUPARTICLES_H

View File

@ -27,13 +27,13 @@ HitSFX::HitSFX(const Vec3& coord, const char* explosion_sound)
: HitEffect()
{
m_sfx = SFXManager::get()->createSoundSource( explosion_sound );
m_sfx->position(coord);
m_sfx->setPosition(coord);
// in multiplayer mode, sounds are NOT positional (because we have
// multiple listeners) so the sounds of all AIs are constantly heard.
// Therefore reduce volume of sounds.
float vol = race_manager->getNumLocalPlayers() > 1 ? 0.5f : 1.0f;
m_sfx->volume(vol);
m_sfx->setVolume(vol);
m_sfx->play();
} // HitSFX
@ -42,10 +42,7 @@ HitSFX::HitSFX(const Vec3& coord, const char* explosion_sound)
*/
HitSFX::~HitSFX()
{
if (m_sfx->getStatus() == SFXManager::SFX_PLAYING)
m_sfx->stop();
SFXManager::get()->deleteSFX(m_sfx);
m_sfx->deleteSFX();
} // ~HitEffect
//-----------------------------------------------------------------------------
@ -56,7 +53,7 @@ HitSFX::~HitSFX()
void HitSFX::setPlayerKartHit()
{
if(race_manager->getNumLocalPlayers())
m_sfx->volume(1.0f);
m_sfx->setVolume(1.0f);
} // setPlayerKartHit
//-----------------------------------------------------------------------------
@ -67,7 +64,7 @@ void HitSFX::setPlayerKartHit()
*/
bool HitSFX::updateAndDelete(float dt)
{
SFXManager::SFXStatus status = m_sfx->getStatus();
if(status==SFXManager::SFX_INITIAL) return false;
return status!= SFXManager::SFX_PLAYING;
SFXBase::SFXStatus status = m_sfx->getStatus();
if(status==SFXBase::SFX_INITIAL) return false;
return status!= SFXBase::SFX_PLAYING;
} // updateAndDelete

View File

@ -2279,7 +2279,7 @@ void IrrDriver::RTTProvider::setupRTTScene(PtrVector<scene::IMesh, REF>& mesh,
node->setAnimationSpeed(0);
node->updateAbsolutePosition();
node->setScale( mesh_scale[n].toIrrVector() );
//std::cout << "(((( set frame " << model_frames[n] << " ))))\n";
//Log::info("RTTProvider::setupRTTScene", "Set frame %d", model_frames[n]);
}
}

View File

@ -108,31 +108,6 @@ enum TypeFBO
FBO_COUNT
};
enum QueryPerf
{
Q_SOLID_PASS1,
Q_SHADOWS,
Q_RSM,
Q_RH,
Q_GI,
Q_ENVMAP,
Q_SUN,
Q_POINTLIGHTS,
Q_SSAO,
Q_SOLID_PASS2,
Q_TRANSPARENT,
Q_PARTICLES,
Q_DISPLACEMENT,
Q_DOF,
Q_GODRAYS,
Q_BLOOM,
Q_TONEMAP,
Q_MOTIONBLUR,
Q_MLAA,
Q_GUI,
Q_LAST
};
enum TypeRTT
{
RTT_TMP1 = 0,

View File

@ -80,7 +80,11 @@ int LODNode::getLevel()
if (camera == NULL)
return (int)m_detail.size() - 1;
AbstractKart* kart = camera->getKart();
const Vec3 &pos = kart->getFrontXYZ();
// use kart position and not camera position when a kart is available,
// because for some effects the camera will be moved to various locations
// (for instance shadows), so using camera position for LOD may result
// in objects being culled when they shouldn't
const Vec3 &pos = (kart != NULL ? kart->getFrontXYZ() : camera->getCameraSceneNode()->getAbsolutePosition());
const int dist =
(int)((m_nodes[0]->getAbsolutePosition()).getDistanceFromSQ(pos.toIrrVector() ));

View File

@ -57,8 +57,7 @@ Material::Material(const XMLNode *node, bool deprecated)
m_shader_type = SHADERTYPE_SOLID;
m_deprecated = deprecated;
node->get("name", &m_texname);
node->get("name", &m_texname);
if (m_texname=="")
{
throw std::runtime_error("[Material] No texture name specified "
@ -66,6 +65,7 @@ Material::Material(const XMLNode *node, bool deprecated)
}
init();
node->get("lazy-load", &m_lazy_load);
bool b = false;
node->get("clampu", &b); if (b) m_clamp_tex |= UCLAMP; //blender 2.4 style
@ -412,10 +412,10 @@ Material::Material(const std::string& fname, bool is_full_path,
*/
void Material::init()
{
m_lazy_load = false;
m_texture = NULL;
m_clamp_tex = 0;
m_shader_type = SHADERTYPE_SOLID;
//m_lightmap = false;
//m_adjust_image = ADJ_NONE;
m_backface_culling = true;
m_high_tire_adhesion = false;
m_below_surface = false;
@ -455,6 +455,9 @@ void Material::init()
//-----------------------------------------------------------------------------
void Material::install(bool is_full_path, bool complain_if_not_found)
{
// Don't load a texture that is lazily loaded.
if(m_lazy_load) return;
const std::string &full_path = is_full_path
? m_texname
: file_manager->searchTexture(m_texname);
@ -643,14 +646,14 @@ void Material::setSFXSpeed(SFXBase *sfx, float speed, bool should_be_paused) con
if (speed < 0) speed = -speed;
// If we paused it due to too low speed earlier, we can continue now.
if (sfx->getStatus() == SFXManager::SFX_PAUSED)
if (sfx->getStatus() == SFXBase::SFX_PAUSED)
{
if (speed<m_sfx_min_speed || should_be_paused == 1) return;
// TODO: Do we first need to stop the sound completely so it
// starts over?
sfx->play();
}
else if (sfx->getStatus() == SFXManager::SFX_PLAYING)
else if (sfx->getStatus() == SFXBase::SFX_PLAYING)
{
if (speed<m_sfx_min_speed || should_be_paused == 1)
{
@ -661,12 +664,12 @@ void Material::setSFXSpeed(SFXBase *sfx, float speed, bool should_be_paused) con
}
if (speed > m_sfx_max_speed)
{
sfx->speed(m_sfx_max_pitch);
sfx->setSpeed(m_sfx_max_pitch);
return;
}
float f = m_sfx_pitch_per_speed*(speed-m_sfx_min_speed) + m_sfx_min_pitch;
sfx->speed(f);
sfx->setSpeed(f);
} // setSFXSpeed
//-----------------------------------------------------------------------------

View File

@ -22,13 +22,11 @@
#include "utils/no_copy.hpp"
#include <assert.h>
#include <map>
#include <string>
#include <vector>
#include <IShaderConstantSetCallBack.h>
namespace irr
{
namespace video { class ITexture; class SMaterial; }
@ -81,9 +79,18 @@ public:
private:
/** Pointer to the texture. */
video::ITexture *m_texture;
//unsigned int m_index;
/** Name of the texture. */
std::string m_texname;
/** If true, the texture will not automatically be loaded and bound
* at load time, it must be loaded elsewhere. This is used to store
* material settings for font textures, without loading fonts for
* languages that might not be needed at all. */
bool m_lazy_load;
/** Name of a special sfx to play when a kart is on this terrain, or
* "" if no special sfx exists. */
std::string m_sfx_name;
@ -114,7 +121,7 @@ private:
/** If a kart is rescued when driving on this surface. */
bool m_drive_reset;
/** True if this is a texture that will start the jump animatoin when
/** True if this is a texture that will start the jump animation when
* leaving it and being in the air. */
bool m_is_jump_texture;
@ -244,27 +251,45 @@ public:
void setSFXSpeed(SFXBase *sfx, float speed, bool should_be_paused) const;
void setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* mb);
void adjustForFog(scene::ISceneNode* parent, video::SMaterial *m, bool use_fog) const;
void adjustForFog(scene::ISceneNode* parent, video::SMaterial *m,
bool use_fog) const;
void onMadeVisible(scene::IMeshBuffer* who);
void onHidden(scene::IMeshBuffer* who);
void isInitiallyHidden(scene::IMeshBuffer* who);
/** Returns the ITexture associated with this material. */
video::ITexture *getTexture() const { return m_texture; }
video::ITexture *getTexture() const
{
// Note that atm lazy load means that the textures are not loaded
// via the material. So getTexture should only get called for non
// lazily loaded textures (used atm for font textures.
assert(!m_lazy_load);
return m_texture;
} // getTexture
// ------------------------------------------------------------------------
bool isIgnore () const { return m_ignore; }
// ------------------------------------------------------------------------
/** Returns true if this material is a zipper. */
bool isZipper () const { return m_zipper; }
// ------------------------------------------------------------------------
/** Returns if this material should trigger a rescue if a kart
* is driving on it. */
bool isDriveReset () const { return m_drive_reset; }
// ------------------------------------------------------------------------
/** Returns if this material should trigger a rescue if a kart
* crashes against it. */
CollisionReaction getCollisionReaction() const { return m_collision_reaction; }
// ------------------------------------------------------------------------
std::string getCrashResetParticles() const { return m_collision_particles; }
// ------------------------------------------------------------------------
bool highTireAdhesion () const { return m_high_tire_adhesion; }
// ------------------------------------------------------------------------
const std::string&
getTexFname () const { return m_texname; }
//int getIndex () const { return m_index; }
// ------------------------------------------------------------------------
bool isTransparent () const
{
return m_shader_type == SHADERTYPE_ADDITIVE ||
@ -272,12 +297,6 @@ public:
m_shader_type == SHADERTYPE_ALPHA_TEST;
}
// ------------------------------------------------------------------------
/** Returns true if this materials need pre-multiply of alpha. */
//bool isPreMul() const {return m_adjust_image==ADJ_PREMUL; }
// ------------------------------------------------------------------------
/** Returns true if this materials need pre-division of alpha. */
//bool isPreDiv() const {return m_adjust_image==ADJ_DIV; }
// ------------------------------------------------------------------------
/** Returns the fraction of maximum speed on this material. */
float getMaxSpeedFraction() const { return m_max_speed_fraction; }
@ -300,17 +319,20 @@ public:
// ------------------------------------------------------------------------
/** Returns the name of a special sfx to play while a kart is on this
* terrain. The string will be "" if no special sfx exists. */
const std::string &
getSFXName () const { return m_sfx_name; }
const std::string &getSFXName() const { return m_sfx_name; }
// ------------------------------------------------------------------------
/** Returns if fog is enabled. */
bool isFogEnabled() const { return m_fog; }
/**
* \brief Get the kind of particles that are to be used on this material, in the given conditions
* \return The particles to use, or NULL if none
*/
const ParticleKind* getParticlesWhen(ParticleConditions cond) const { return m_particles_effects[cond]; }
// ------------------------------------------------------------------------
/** \brief Get the kind of particles that are to be used on this material,
* in the given conditions.
* \return The particles to use, or NULL if none. */
const ParticleKind* getParticlesWhen(ParticleConditions cond) const
{
return m_particles_effects[cond];
} // getParticlesWhen
// ------------------------------------------------------------------------
/** Returns true if a kart falling over this kind of material triggers
* the special falling camera. */
@ -346,9 +368,6 @@ public:
// ------------------------------------------------------------------------
ShaderType getShaderType() const { return m_shader_type; }
// ------------------------------------------------------------------------
void onMadeVisible(scene::IMeshBuffer* who);
void onHidden(scene::IMeshBuffer* who);
void isInitiallyHidden(scene::IMeshBuffer* who);
} ;

View File

@ -221,19 +221,19 @@ void renderBloom(GLuint in)
DrawFullScreenEffect<FullScreenShader::BloomShader>();
}
void PostProcessing::renderDiffuseEnvMap(const float *bSHCoeff, const float *gSHCoeff, const float *rSHCoeff)
void PostProcessing::renderEnvMap(const float *bSHCoeff, const float *gSHCoeff, const float *rSHCoeff, GLuint skybox)
{
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
glUseProgram(FullScreenShader::DiffuseEnvMapShader::getInstance()->Program);
glUseProgram(FullScreenShader::EnvMapShader::getInstance()->Program);
glBindVertexArray(SharedObject::FullScreenQuadVAO);
FullScreenShader::DiffuseEnvMapShader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH)));
FullScreenShader::EnvMapShader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), irr_driver->getDepthStencilTexture(), skybox));
core::matrix4 TVM = irr_driver->getViewMatrix().getTransposed();
FullScreenShader::DiffuseEnvMapShader::getInstance()->setUniforms(TVM, std::vector<float>(bSHCoeff, bSHCoeff + 9), std::vector<float>(gSHCoeff, gSHCoeff + 9), std::vector<float>(rSHCoeff, rSHCoeff + 9));
FullScreenShader::EnvMapShader::getInstance()->setUniforms(TVM, std::vector<float>(bSHCoeff, bSHCoeff + 9), std::vector<float>(gSHCoeff, gSHCoeff + 9), std::vector<float>(rSHCoeff, rSHCoeff + 9));
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
@ -662,7 +662,8 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo
// Blend
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glBlendColor(0., 0., 0., track->getGodRaysOpacity());
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
in_fbo->Bind();

View File

@ -81,7 +81,7 @@ public:
void renderFog();
void renderSSAO();
void renderDiffuseEnvMap(const float *bSHCoeff, const float *gSHCoeff, const float *rSHCoeff);
void renderEnvMap(const float *bSHCoeff, const float *gSHCoeff, const float *rSHCoeff, unsigned skycubemap);
void renderRHDebug(unsigned SHR, unsigned SHG, unsigned SHB, const core::matrix4 &rh_matrix, const core::vector3df &rh_extend);
void renderGI(const core::matrix4 &RHMatrix, const core::vector3df &rh_extend, unsigned shr, unsigned shg, unsigned shb);

View File

@ -11,6 +11,7 @@
#include "utils/profiler.hpp"
#include "utils/tuple.hpp"
#include "stkscenemanager.hpp"
#include "utils/profiler.hpp"
#include <S3DVertex.h>
@ -74,7 +75,7 @@ struct DefaultMaterial
};
const std::vector<size_t> DefaultMaterial::FirstPassTextures = { 1 };
const std::vector<size_t> DefaultMaterial::SecondPassTextures = { 0 };
const std::vector<size_t> DefaultMaterial::SecondPassTextures = { 0, 1 };
struct AlphaRef
{
@ -92,7 +93,7 @@ struct AlphaRef
};
const std::vector<size_t> AlphaRef::FirstPassTextures = { 0, 1 };
const std::vector<size_t> AlphaRef::SecondPassTextures = { 0 };
const std::vector<size_t> AlphaRef::SecondPassTextures = { 0, 1 };
struct SphereMap
{
@ -145,8 +146,8 @@ struct GrassMat
static const std::vector<size_t> SecondPassTextures;
};
const std::vector<size_t> GrassMat::FirstPassTextures = { 0 };
const std::vector<size_t> GrassMat::SecondPassTextures = { 0 };
const std::vector<size_t> GrassMat::FirstPassTextures = { 0, 1 };
const std::vector<size_t> GrassMat::SecondPassTextures = { 0, 1 };
struct NormalMat
{
@ -164,7 +165,7 @@ struct NormalMat
};
const std::vector<size_t> NormalMat::FirstPassTextures = { 2, 1 };
const std::vector<size_t> NormalMat::SecondPassTextures = { 0 };
const std::vector<size_t> NormalMat::SecondPassTextures = { 0, 1 };
struct DetailMat
{
@ -182,7 +183,7 @@ struct DetailMat
};
const std::vector<size_t> DetailMat::FirstPassTextures = { 1 };
const std::vector<size_t> DetailMat::SecondPassTextures = { 0, 2 };
const std::vector<size_t> DetailMat::SecondPassTextures = { 0, 2, 1 };
struct SplattingMat
{
@ -530,15 +531,15 @@ void IrrDriver::renderSolidSecondPass()
if (UserConfigParams::m_azdo)
{
multidraw2ndPass<DefaultMaterial>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0));
multidraw2ndPass<AlphaRef>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0));
multidraw2ndPass<DefaultMaterial>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0, 0));
multidraw2ndPass<AlphaRef>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0, 0));
multidraw2ndPass<SphereMap>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0));
multidraw2ndPass<UnlitMat>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0));
SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT);
multidraw2ndPass<GrassMat>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, DepthHandle, 0), windDir, cb->getPosition());
multidraw2ndPass<GrassMat>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, DepthHandle, 0, 0), windDir, cb->getPosition());
multidraw2ndPass<NormalMat>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0));
multidraw2ndPass<DetailMat>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0, 0));
multidraw2ndPass<NormalMat>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0, 0));
multidraw2ndPass<DetailMat>(createVector<uint64_t>(DiffuseHandle, SpecularHandle, SSAOHandle, 0, 0, 0));
}
else if (irr_driver->hasARB_draw_indirect())
{
@ -860,8 +861,6 @@ static void multidrawShadow(unsigned i, Args ...args)
void IrrDriver::renderShadows()
{
ScopedGPUTimer Timer(getGPUTimer(Q_SHADOWS));
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
@ -875,7 +874,7 @@ void IrrDriver::renderShadows()
for (unsigned cascade = 0; cascade < 4; cascade++)
{
ScopedGPUTimer Timer(getGPUTimer(Q_SHADOWS_CASCADE0 + cascade));
std::vector<GLuint> noTexUnits;
renderShadow<MeshShader::ShadowShader, video::EVT_STANDARD, 1>(noTexUnits, cascade, ListMatDefault::getInstance()->Shadows[cascade]);

View File

@ -9,6 +9,7 @@
#include "modes/world.hpp"
#include "tracks/track.hpp"
#include "utils/profiler.hpp"
#include "callbacks.hpp"
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
#define MIN2(a, b) ((a) > (b) ? (b) : (a))
@ -114,6 +115,7 @@ void IrrDriver::renderLights(unsigned pointlightcount, bool hasShadow)
glDisable(GL_BLEND);
m_rtts->getRH().Bind();
glBindVertexArray(SharedObject::FullScreenQuadVAO);
SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT);
if (irr_driver->needRHWorkaround())
{
glUseProgram(FullScreenShader::NVWorkaroundRadianceHintsConstructionShader::getInstance()->Program);
@ -121,7 +123,7 @@ void IrrDriver::renderLights(unsigned pointlightcount, bool hasShadow)
createVector<GLuint>(m_rtts->getRSM().getRTT()[0], m_rtts->getRSM().getRTT()[1], m_rtts->getRSM().getDepthTexture()));
for (unsigned i = 0; i < 32; i++)
{
FullScreenShader::NVWorkaroundRadianceHintsConstructionShader::getInstance()->setUniforms(rsm_matrix, rh_matrix, rh_extend, i);
FullScreenShader::NVWorkaroundRadianceHintsConstructionShader::getInstance()->setUniforms(rsm_matrix, rh_matrix, rh_extend, i, video::SColorf(cb->getRed(), cb->getGreen(), cb->getBlue()));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
@ -135,7 +137,7 @@ void IrrDriver::renderLights(unsigned pointlightcount, bool hasShadow)
m_rtts->getRSM().getDepthTexture()
)
);
FullScreenShader::RadianceHintsConstructionShader::getInstance()->setUniforms(rsm_matrix, rh_matrix, rh_extend);
FullScreenShader::RadianceHintsConstructionShader::getInstance()->setUniforms(rsm_matrix, rh_matrix, rh_extend, video::SColorf(cb->getRed(), cb->getGreen(), cb->getBlue()));
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 32);
}
}
@ -152,13 +154,13 @@ void IrrDriver::renderLights(unsigned pointlightcount, bool hasShadow)
m_post_processing->renderGI(rh_matrix, rh_extend, m_rtts->getRH().getRTT()[0], m_rtts->getRH().getRTT()[1], m_rtts->getRH().getRTT()[2]);
}
m_rtts->getFBO(FBO_COMBINED_DIFFUSE_SPECULAR).Bind();
{
ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_ENVMAP));
m_post_processing->renderDiffuseEnvMap(blueSHCoeff, greenSHCoeff, redSHCoeff);
m_post_processing->renderEnvMap(blueSHCoeff, greenSHCoeff, redSHCoeff, SkyboxCubeMap);
}
m_rtts->getFBO(FBO_COMBINED_DIFFUSE_SPECULAR).Bind();
// Render sunlight if and only if track supports shadow
if (!World::getWorld() || World::getWorld()->getTrack()->hasShadows())
{

View File

@ -787,7 +787,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass1.frag").c_str());
AssignUniforms("ModelMatrix", "InverseModelMatrix", "windDir");
AssignSamplerNames(Program, 0, "tex");
AssignSamplerNames(Program, 0, "tex", 1, "glosstex");
}
NormalMapShader::NormalMapShader()
@ -832,7 +832,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_objectref_pass1.frag").c_str());
AssignUniforms("windDir");
AssignSamplerNames(Program, 0, "tex");
AssignSamplerNames(Program, 0, "tex", 1, "glosstex");
}
InstancedNormalMapShader::InstancedNormalMapShader()
@ -854,7 +854,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_pass2.frag").c_str());
AssignUniforms("ModelMatrix", "TextureMatrix");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "SpecMap");
}
InstancedObjectPass2Shader::InstancedObjectPass2Shader()
@ -865,7 +865,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_object_pass2.frag").c_str());
AssignUniforms();
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "SpecMap");
}
InstancedObjectRefPass2Shader::InstancedObjectRefPass2Shader()
@ -876,7 +876,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_objectref_pass2.frag").c_str());
AssignUniforms();
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "SpecMap");
}
DetailledObjectPass2Shader::DetailledObjectPass2Shader()
@ -886,7 +886,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/detailledobject_pass2.frag").c_str());
AssignUniforms("ModelMatrix");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "Detail");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "Detail", 5, "SpecMap");
}
InstancedDetailledObjectPass2Shader::InstancedDetailledObjectPass2Shader()
@ -897,7 +897,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_detailledobject_pass2.frag").c_str());
AssignUniforms();
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "Detail");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "Detail", 5, "SpecMap");
}
ObjectUnlitShader::ObjectUnlitShader()
@ -926,7 +926,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass2.frag").c_str());
AssignUniforms("ModelMatrix", "TextureMatrix");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "SpecMap");
}
GrassPass2Shader::GrassPass2Shader()
@ -936,7 +936,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/grass_pass2.frag").c_str());
AssignUniforms("ModelMatrix", "windDir");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "Albedo", 4, "SpecMap");
}
InstancedGrassPass2Shader::InstancedGrassPass2Shader()
@ -947,7 +947,7 @@ namespace MeshShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/instanced_grass_pass2.frag").c_str());
AssignUniforms("windDir", "SunDir");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "dtex", 4, "Albedo");
AssignSamplerNames(Program, 0, "DiffuseMap", 1, "SpecularMap", 2, "SSAO", 3, "dtex", 4, "Albedo", 5, "SpecMap");
}
SphereMapShader::SphereMapShader()
@ -1455,14 +1455,15 @@ namespace FullScreenShader
AssignUniforms("direction", "col");
}
DiffuseEnvMapShader::DiffuseEnvMapShader()
EnvMapShader::EnvMapShader()
{
Program = LoadProgram(OBJECT,
GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/decodeNormal.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/diffuseenvmap.frag").c_str());
AssignUniforms("TransposeViewMatrix", "blueLmn[0]", "greenLmn[0]", "redLmn[0]");
AssignSamplerNames(Program, 0, "ntex");
AssignSamplerNames(Program, 0, "ntex", 1, "dtex", 2, "tex");
}
ShadowedSunLightShader::ShadowedSunLightShader()
@ -1495,7 +1496,7 @@ namespace FullScreenShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/rh.frag").c_str());
}
AssignUniforms("RSMMatrix", "RHMatrix", "extents");
AssignUniforms("RSMMatrix", "RHMatrix", "extents", "suncol");
AssignSamplerNames(Program, 0, "ctex", 1, "ntex", 2, "dtex");
}
@ -1506,7 +1507,7 @@ namespace FullScreenShader
GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/rhpassthrough.geom").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/rh.frag").c_str());
AssignUniforms("RSMMatrix", "RHMatrix", "extents", "slice");
AssignUniforms("RSMMatrix", "RHMatrix", "extents", "slice", "suncol");
AssignSamplerNames(Program, 0, "ctex", 1, "ntex", 2, "dtex");
}

View File

@ -65,7 +65,7 @@ public:
ObjectRefPass1Shader();
};
class GrassPass1Shader : public ShaderHelperSingleton<GrassPass1Shader, core::matrix4, core::matrix4, core::vector3df>, public TextureRead<Trilinear_Anisotropic_Filtered>
class GrassPass1Shader : public ShaderHelperSingleton<GrassPass1Shader, core::matrix4, core::matrix4, core::vector3df>, public TextureRead<Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
GrassPass1Shader();
@ -89,7 +89,7 @@ public:
InstancedObjectRefPass1Shader();
};
class InstancedGrassPass1Shader : public ShaderHelperSingleton<InstancedGrassPass1Shader, core::vector3df>, public TextureRead<Trilinear_Anisotropic_Filtered>
class InstancedGrassPass1Shader : public ShaderHelperSingleton<InstancedGrassPass1Shader, core::vector3df>, public TextureRead<Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
InstancedGrassPass1Shader();
@ -101,31 +101,31 @@ public:
InstancedNormalMapShader();
};
class ObjectPass2Shader : public ShaderHelperSingleton<ObjectPass2Shader, core::matrix4, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered>
class ObjectPass2Shader : public ShaderHelperSingleton<ObjectPass2Shader, core::matrix4, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
ObjectPass2Shader();
};
class InstancedObjectPass2Shader : public ShaderHelperSingleton<InstancedObjectPass2Shader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered>
class InstancedObjectPass2Shader : public ShaderHelperSingleton<InstancedObjectPass2Shader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
InstancedObjectPass2Shader();
};
class InstancedObjectRefPass2Shader : public ShaderHelperSingleton<InstancedObjectRefPass2Shader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered>
class InstancedObjectRefPass2Shader : public ShaderHelperSingleton<InstancedObjectRefPass2Shader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
InstancedObjectRefPass2Shader();
};
class DetailledObjectPass2Shader : public ShaderHelperSingleton<DetailledObjectPass2Shader, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
class DetailledObjectPass2Shader : public ShaderHelperSingleton<DetailledObjectPass2Shader, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
DetailledObjectPass2Shader();
};
class InstancedDetailledObjectPass2Shader : public ShaderHelperSingleton<InstancedDetailledObjectPass2Shader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
class InstancedDetailledObjectPass2Shader : public ShaderHelperSingleton<InstancedDetailledObjectPass2Shader>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
InstancedDetailledObjectPass2Shader();
@ -143,19 +143,19 @@ public:
InstancedObjectUnlitShader();
};
class ObjectRefPass2Shader : public ShaderHelperSingleton<ObjectRefPass2Shader, core::matrix4, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered>
class ObjectRefPass2Shader : public ShaderHelperSingleton<ObjectRefPass2Shader, core::matrix4, core::matrix4>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
ObjectRefPass2Shader();
};
class GrassPass2Shader : public ShaderHelperSingleton<GrassPass2Shader, core::matrix4, core::vector3df>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered>
class GrassPass2Shader : public ShaderHelperSingleton<GrassPass2Shader, core::matrix4, core::vector3df>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
GrassPass2Shader();
};
class InstancedGrassPass2Shader : public ShaderHelperSingleton<InstancedGrassPass2Shader, core::vector3df, core::vector3df>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Nearest_Filtered, Trilinear_Anisotropic_Filtered>
class InstancedGrassPass2Shader : public ShaderHelperSingleton<InstancedGrassPass2Shader, core::vector3df, core::vector3df>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Bilinear_Filtered, Nearest_Filtered, Trilinear_Anisotropic_Filtered, Trilinear_Anisotropic_Filtered>
{
public:
InstancedGrassPass2Shader();
@ -395,10 +395,10 @@ public:
SunLightShader();
};
class DiffuseEnvMapShader : public ShaderHelperSingleton<DiffuseEnvMapShader, core::matrix4, std::vector<float>, std::vector<float>, std::vector<float> >, public TextureRead<Nearest_Filtered>
class EnvMapShader : public ShaderHelperSingleton<EnvMapShader, core::matrix4, std::vector<float>, std::vector<float>, std::vector<float> >, public TextureRead<Nearest_Filtered, Nearest_Filtered, Trilinear_cubemap>
{
public:
DiffuseEnvMapShader();
EnvMapShader();
};
class ShadowedSunLightShader : public ShaderHelperSingleton<ShadowedSunLightShader, core::vector3df, video::SColorf>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Shadow_Sampler>
@ -407,14 +407,14 @@ public:
ShadowedSunLightShader();
};
class RadianceHintsConstructionShader : public ShaderHelperSingleton<RadianceHintsConstructionShader, core::matrix4, core::matrix4, core::vector3df>, public TextureRead<Bilinear_Filtered, Bilinear_Filtered, Bilinear_Filtered>
class RadianceHintsConstructionShader : public ShaderHelperSingleton<RadianceHintsConstructionShader, core::matrix4, core::matrix4, core::vector3df, video::SColorf>, public TextureRead<Bilinear_Filtered, Bilinear_Filtered, Bilinear_Filtered>
{
public:
RadianceHintsConstructionShader();
};
// Workaround for a bug found in kepler nvidia linux and fermi nvidia windows
class NVWorkaroundRadianceHintsConstructionShader : public ShaderHelperSingleton<NVWorkaroundRadianceHintsConstructionShader, core::matrix4, core::matrix4, core::vector3df, int>, public TextureRead<Bilinear_Filtered, Bilinear_Filtered, Bilinear_Filtered>
class NVWorkaroundRadianceHintsConstructionShader : public ShaderHelperSingleton<NVWorkaroundRadianceHintsConstructionShader, core::matrix4, core::matrix4, core::vector3df, int, video::SColorf>, public TextureRead<Bilinear_Filtered, Bilinear_Filtered, Bilinear_Filtered>
{
public:
NVWorkaroundRadianceHintsConstructionShader();

View File

@ -142,7 +142,11 @@ void STKAnimatedMesh::updateGL()
if (!rnd->isTransparent())
{
Material* material = material_manager->getMaterialFor(mb->getMaterial().getTexture(0), mb);
Material::ShaderType MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType(), material);
Material* material2 = NULL;
if (mb->getMaterial().getTexture(1) != NULL)
material2 = material_manager->getMaterialFor(mb->getMaterial().getTexture(1), mb);
Material::ShaderType MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType(), material, material2);
InitTextures(mesh, MatType);
}

View File

@ -11,12 +11,16 @@
#include "modes/world.hpp"
Material::ShaderType MaterialTypeToMeshMaterial(video::E_MATERIAL_TYPE MaterialType, video::E_VERTEX_TYPE tp, Material* material)
Material::ShaderType MaterialTypeToMeshMaterial(video::E_MATERIAL_TYPE MaterialType, video::E_VERTEX_TYPE tp,
Material* material, Material* layer2Material)
{
if (layer2Material != NULL && layer2Material->getShaderType() == Material::SHADERTYPE_SPLATTING)
return Material::SHADERTYPE_SPLATTING;
switch (material->getShaderType())
{
default:
return material->getShaderType();
return material->getShaderType();
case Material::SHADERTYPE_SOLID:
if (MaterialType == irr_driver->getShader(ES_NORMAL_MAP))
return Material::SHADERTYPE_NORMAL_MAP;

View File

@ -174,7 +174,8 @@ class ListDisplacement : public MiscList<ListDisplacement, GLMesh *, core::matri
class ListInstancedGlow : public Singleton<ListInstancedGlow>, public std::vector<GLMesh *>
{};
Material::ShaderType MaterialTypeToMeshMaterial(video::E_MATERIAL_TYPE MaterialType, video::E_VERTEX_TYPE tp, Material* material);
Material::ShaderType MaterialTypeToMeshMaterial(video::E_MATERIAL_TYPE MaterialType, video::E_VERTEX_TYPE tp,
Material* material, Material* layer2Material);
TransparentMaterial MaterialTypeToTransparentMaterial(video::E_MATERIAL_TYPE, f32 MaterialTypeParam, Material* material);
void InitTextures(GLMesh &mesh, Material::ShaderType);

View File

@ -143,7 +143,10 @@ void STKMeshSceneNode::updateNoGL()
else
{
assert(!isDisplacement);
Material::ShaderType MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType(), material);
Material* material2 = NULL;
if (mb->getMaterial().getTexture(1) != NULL)
material2 = material_manager->getMaterialFor(mb->getMaterial().getTexture(1), mb);
Material::ShaderType MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType(), material, material2);
if (!immediate_draw)
MeshSolidMaterial[MatType].push_back(&mesh);
}
@ -179,7 +182,10 @@ void STKMeshSceneNode::updateGL()
if (!rnd->isTransparent())
{
Material* material = material_manager->getMaterialFor(mb->getMaterial().getTexture(0), mb);
Material::ShaderType MatType = material->getShaderType();// MaterialTypeToMeshMaterial(type, mb->getVertexType(), material);
Material* material2 = NULL;
if (mb->getMaterial().getTexture(1) != NULL)
material2 = material_manager->getMaterialFor(mb->getMaterial().getTexture(1), mb);
Material::ShaderType MatType = MaterialTypeToMeshMaterial(type, mb->getVertexType(), material, material2);
if (!immediate_draw)
InitTextures(mesh, MatType);
}
@ -319,7 +325,8 @@ void STKMeshSceneNode::render()
irr_driver->getRenderTargetTexture(RTT_DIFFUSE),
irr_driver->getRenderTargetTexture(RTT_SPECULAR),
irr_driver->getRenderTargetTexture(RTT_HALF1_R),
getTextureGLuint(mesh.textures[0])));
getTextureGLuint(mesh.textures[0]),
getTextureGLuint(mesh.textures[1])));
MeshShader::ObjectPass2Shader::getInstance()->setUniforms(AbsoluteTransformation, mesh.TextureMatrix);
assert(mesh.vao);
glBindVertexArray(mesh.vao);

View File

@ -435,7 +435,7 @@ parseSceneManager(core::list<scene::ISceneNode*> List, std::vector<scene::IScene
if (ParticleSystemProxy *node = dynamic_cast<ParticleSystemProxy *>(*I))
{
if (!isCulledPrecise(cam, *I) && node->update())
if (!isCulledPrecise(cam, *I))
ParticlesList::getInstance()->push_back(node);
continue;
}

View File

@ -51,11 +51,11 @@ Weather::Weather(bool lightning, std::string sound)
Weather::~Weather()
{
if (m_thunder_sound != NULL)
SFXManager::get()->deleteSFX(m_thunder_sound);
m_thunder_sound->deleteSFX();
if (m_weather_sound != NULL)
SFXManager::get()->deleteSFX(m_weather_sound);
}
m_weather_sound->deleteSFX();
} // ~Weather
// ----------------------------------------------------------------------------

View File

@ -93,8 +93,8 @@ void AbstractStateManager::pushMenu(std::string name)
if (UserConfigParams::logGUI())
{
std::cout << "[AbstractStateManager::pushMenu] switching to screen "
<< name.c_str() << std::endl;
Log::info("AbstractStateManager::pushMenu", "Switching to screen %s",
name.c_str());
}
// Send tear-down event to previous menu
@ -125,8 +125,8 @@ void AbstractStateManager::pushScreen(Screen* screen)
if (UserConfigParams::logGUI())
{
std::cout << "[AbstractStateManager::pushScreen] switching to screen "
<< screen->getName().c_str() << std::endl;
Log::info("AbstractStateManager::pushScreen", "Switching to screen %s",
screen->getName().c_str());
}
if (!screen->isLoaded()) screen->loadFromFile();
@ -152,8 +152,8 @@ void AbstractStateManager::replaceTopMostScreen(Screen* screen, GUIEngine::GameS
if (UserConfigParams::logGUI())
{
std::cout << "[AbstractStateManager::replaceTopmostScreen] "
"switching to screen " << name.c_str() << std::endl;
Log::info("AbstractStateManager::replaceTopMostScreen", "Switching to screen %s",
name.c_str());
}
assert(m_menu_stack.size() > 0);
@ -215,8 +215,8 @@ void AbstractStateManager::popMenu()
if (UserConfigParams::logGUI())
{
std::cout << "[AbstractStateManager::popMenu] switching to screen "
<< m_menu_stack[m_menu_stack.size()-1].c_str() << std::endl;
Log::info("AbstractStateManager::popMenu", "Switching to screen %s",
m_menu_stack[m_menu_stack.size()-1].c_str());
}
if (m_menu_stack[m_menu_stack.size()-1] == RACE_STATE_NAME)
@ -247,10 +247,8 @@ void AbstractStateManager::resetAndGoToScreen(Screen* screen)
std::string name = screen->getName();
if (UserConfigParams::logGUI())
{
std::cout << "[AbstractStateManager::resetAndGoToScreen] "
"switching to screen " << name.c_str() << std::endl;
}
Log::info("AbstractStateManager::resetAndGoToScreen", "Switching to screen %s",
name.c_str());
if (m_game_mode != GAME) getCurrentScreen()->tearDown();
m_menu_stack.clear();

View File

@ -167,6 +167,10 @@ namespace GUIEngine
virtual void onTopMostScreenChanged() = 0;
// --------------------------------------------------------------------
/** Returns the number of screens on the stack. Is used to decide
* if exiting a screen would cause STK to end or not. */
unsigned int getMenuStackSize() const { return m_menu_stack.size(); }
}; // Class AbstractStateManager
} // GUIEngine

View File

@ -72,18 +72,16 @@ void AbstractTopLevelContainer::addWidgetsRecursively(
widgets[n].getType() != WTYPE_ICON_BUTTON &&
widgets[n].getType() != WTYPE_SPACER)
{
std::cerr << "/!\\ Warning /!\\ : widget "
<< widgets[n].m_properties[PROP_ID].c_str()
<< " of type " << widgets[n].getType()
<< " has no dimensions" << std::endl;
Log::warn("AbstractTopLevelContainer::addWidgetsRecursively",
"Widget %s of type %d has no dimensions",
widgets[n].m_properties[PROP_ID].c_str(), widgets[n].getType());
}
if (widgets[n].m_x == -1 || widgets[n].m_y == -1)
{
std::cerr << "/!\\ Warning /!\\ : widget "
<< widgets[n].m_properties[PROP_ID].c_str()
<< " of type " << widgets[n].getType()
<< " has no position" << std::endl;
Log::warn("AbstractTopLevelContainer::addWidgetsRecursively",
"Widget %s of type %d has no position",
widgets[n].m_properties[PROP_ID].c_str(), widgets[n].getType());
}
widgets[n].add();
@ -197,10 +195,8 @@ Widget* AbstractTopLevelContainer::getWidget(const int id,
if (widget.searchInsideMe() && widget.getChildren().size() > 0)
{
// std::cout << "widget = <"
// << widget.m_properties[PROP_ID].c_str()
// << "> widget.m_children.size()="
// << widget.m_children.size() << std::endl;
//Log::info("AbstractTopLevelContainer", "widget = <%s> widget.m_children.size() = ",
// widget.m_properties[PROP_ID].c_str(), widget.m_children.size());
Widget* el = getWidget(id, &(widget.m_children));
if(el != NULL) return el;
}

View File

@ -1019,12 +1019,10 @@ namespace GUIEngine
g_skin->drop(); // GUI env grabbed it
assert(g_skin->getReferenceCount() == 1);
}
catch (std::runtime_error& err)
catch (std::runtime_error& /*err*/)
{
(void)err; // avoid warning about unused variable
std::cerr <<
"ERROR, cannot load skin specified in user config. Falling "
"back to defaults.\n";
Log::error("Engine::init", "Cannot load skin specified in user config. "
"Falling back to defaults.");
UserConfigParams::m_skin_file.revertToDefaults();
try
@ -1036,8 +1034,7 @@ namespace GUIEngine
}
catch (std::runtime_error& err)
{
std::cerr << "FATAL, cannot load default GUI skin\n";
throw err;
Log::fatal("Engine::init", "Canot load default GUI skin");
}
}
@ -1135,10 +1132,9 @@ namespace GUIEngine
// one so that the fallback skin is not dropped
newSkin = new Skin(fallbackSkin);
}
catch (std::runtime_error& err)
catch (std::runtime_error& /*err*/)
{
(void)err; // avoid warning about unused variable
std::cerr << "ERROR, cannot load newly specified skin!\n";
Log::error("Engine::reloadSkin", "Canot load newly specified skin");
return;
}
@ -1369,8 +1365,8 @@ namespace GUIEngine
}
else
{
std::cerr << "WARNING: GUIEngine::addLoadingIcon given "
"NULL icon\n";
Log::warn("Engine::addLoadingIcon", "Given "
"NULL icon");
}
} // addLoadingIcon

View File

@ -199,7 +199,7 @@ bool EventHandler::OnEvent (const SEvent &event)
// mode ignore this error message, but leave it in for debugging.
if(std::string(event.LogEvent.Text)=="Unsupported texture format")
#ifdef DEBUG
printf("The following message will not be printed in release mode:\n");
Log::info("EventHandler", "The following message will not be printed in release mode");
#else
return true; // EVENT_BLOCK
#endif
@ -414,7 +414,7 @@ void EventHandler::navigate(const int playerID, Input::InputType type, const boo
if (el == NULL)
{
std::cerr << "WARNING : m_tab_down/up_root is set to an ID for which I can't find the widget\n";
Log::warn("EventHandler::navigate", "m_tab_down/up_root is set to an ID for which I can't find the widget");
return;
}
}
@ -448,7 +448,7 @@ void EventHandler::navigate(const int playerID, Input::InputType type, const boo
if (NAVIGATION_DEBUG)
{
std::cout << "Navigating " << (reverse ? "up" : "down") << " to " << closest->getID() << std::endl;
Log::info("EventHandler", "Navigating %s to %d", (reverse ? "up" : "down"), closest->getID());
}
assert(closestWidget != NULL);
@ -474,7 +474,7 @@ void EventHandler::navigate(const int playerID, Input::InputType type, const boo
if (!found)
{
if (NAVIGATION_DEBUG)
std::cout << "EventHandler::navigat : wrap around\n";
Log::info( "EventHandler::navigate", "Wrap around");
// select the last/first widget
Widget* wrapWidget = NULL;
@ -529,7 +529,7 @@ EventPropagation EventHandler::onWidgetActivated(GUIEngine::Widget* w, const int
if (w->m_event_handler == NULL) return EVENT_LET;
}
//std::cout << "**** widget activated : " << w->m_properties[PROP_ID].c_str() << " ****" << std::endl;
//Log::info("EventHandler", "Widget activated: %s", w->m_properties[PROP_ID].c_str());
if (w->m_event_handler != NULL)
{

View File

@ -21,9 +21,6 @@
#include <IGUIFont.h>
#include <ITexture.h>
using namespace irr;
using namespace gui;
using namespace video;
#include "graphics/irr_driver.hpp"
#include "guiengine/abstract_top_level_container.hpp"
@ -35,6 +32,9 @@ using namespace video;
#include "utils/string_utils.hpp"
#include "utils/vs.hpp"
using namespace irr;
using namespace gui;
using namespace video;
using namespace GUIEngine;
/** Like atoi, but on error prints an error message to stderr */
@ -420,7 +420,7 @@ void LayoutManager::doCalculateLayout(PtrVector<Widget>& widgets, AbstractTopLev
horizontal = false;
else
{
std::cerr << "Unknown layout name : " << layout_name.c_str() << std::endl;
Log::error("LayoutManager::doCalculateLayout", "Unknown layout name: %s", layout_name.c_str());
break;
}
@ -475,11 +475,9 @@ void LayoutManager::doCalculateLayout(PtrVector<Widget>& widgets, AbstractTopLev
int proportion = 1;
std::istringstream myStream(prop);
if (!(myStream >> proportion))
{
std::cerr << "/!\\ Warning /!\\ : proportion '" << prop.c_str()
<< "' is not a number for widget " << widgets[n].m_properties[PROP_ID].c_str()
<< std::endl;
}
Log::warn("LayoutManager::doCalculateLayout",
"Proportion '%s' is not a number for widget %s", prop.c_str(),
widgets[n].m_properties[PROP_ID].c_str());
const float fraction = (float)proportion/(float)total_proportion;
@ -522,9 +520,9 @@ void LayoutManager::doCalculateLayout(PtrVector<Widget>& widgets, AbstractTopLev
}
else
{
std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str()
<< "' is unknown (widget '" << widgets[n].m_properties[PROP_ID].c_str()
<< "', in a horiozntal-row layout)\n";
Log::warn("LayoutManager::doCalculateLayout",
"Alignment '%s' is unknown (widget '%s', in a horiozntal-row layout)",
align.c_str(), widgets[n].m_properties[PROP_ID].c_str());
}
widgets[n].m_w = (int)(left_space*fraction);
@ -597,9 +595,9 @@ void LayoutManager::doCalculateLayout(PtrVector<Widget>& widgets, AbstractTopLev
}
else
{
std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str()
<< "' is unknown (widget '" << widgets[n].m_properties[PROP_ID].c_str()
<< "', in a vertical-row layout)\n";
Log::warn("LayoutManager::doCalculateLayout",
"Alignment '%s' is unknown (widget '%s', in a vertical-row layout)",
align.c_str(), widgets[n].m_properties[PROP_ID].c_str());
}
widgets[n].m_y = y;
@ -651,9 +649,9 @@ void LayoutManager::doCalculateLayout(PtrVector<Widget>& widgets, AbstractTopLev
}
else
{
std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str()
<< "' is unknown in widget " << widgets[n].m_properties[PROP_ID].c_str()
<< std::endl;
Log::warn("LayoutManager::doCalculateLayout",
"Alignment '%s' is unknown in widget '%s'",
align.c_str(), widgets[n].m_properties[PROP_ID].c_str());
}
x += widgets[n].m_w;
@ -697,8 +695,9 @@ void LayoutManager::doCalculateLayout(PtrVector<Widget>& widgets, AbstractTopLev
}
else
{
std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str()
<< "' is unknown in widget " << widgets[n].m_properties[PROP_ID].c_str() << std::endl;
Log::warn("LayoutManager::doCalculateLayout",
"Alignment '%s' is unknown in widget '%s'",
align.c_str(), widgets[n].m_properties[PROP_ID].c_str());
}
widgets[n].m_y = y;

View File

@ -95,7 +95,7 @@ std::priority_queue<Message*, std::vector<Message*>,
float g_current_display_time = -1.0f;
/** How long the current message should be displaed. */
float g_max_display_time = -1.0f;
float g_max_display_time = 5.0f;
/** The label widget used to show the current message. */
SkinWidgetContainer *g_container = NULL;

View File

@ -101,7 +101,7 @@ void ScalableFont::doReadXmlFile(io::IXMLReader* xml)
/*
const wchar_t* iflangis = xml->getAttributeValue(L"iflanguage");
printf("langcode = %s\n", translations->getCurrentLanguageCode().c_str());
Log::info("ScalableFont", "langcode = %s", translations->getCurrentLanguageCode().c_str());
if (iflangis != NULL &&
core::stringc(iflangis) != translations->getCurrentLanguageCode().c_str())
@ -128,8 +128,10 @@ void ScalableFont::doReadXmlFile(io::IXMLReader* xml)
float scale=1.0f;
if(xml->getAttributeValue(L"scale"))
{
scale = xml->getAttributeValueAsFloat(L"scale");
//std::cout << "scale = " << scale << std::endl;
//Log::info("ScalableFont", "scale = %f", scale);
}
bool excludeFromMaxHeightCalculation = false;
if (xml->getAttributeValue(L"excludeFromMaxHeightCalculation"))
@ -137,7 +139,7 @@ void ScalableFont::doReadXmlFile(io::IXMLReader* xml)
core::stringw alpha = xml->getAttributeValue(L"hasAlpha");
//std::cout << "---- Adding font texture " << fn.c_str() << "; alpha=" << alpha.c_str() << std::endl;
//Log::info("ScalableFont", "Adding font texture %s; alpha = %s", fn.c_str(), alpha.c_str());
// make sure the sprite bank has enough textures in it
@ -227,7 +229,7 @@ void ScalableFont::doReadXmlFile(io::IXMLReader* xml)
CharacterMap[ch] = Areas.size();
//std::cout << "Inserting character '" << (int)ch << "' with area " << Areas.size() << std::endl;
//Log::info("ScalableFont", "Inserting character '%d' with area %d", (int)ch, Areas.size());
// make frame
f.rectNumber = SpriteBank->getPositions().size();
@ -366,18 +368,18 @@ s32 ScalableFont::getAreaIDFromCharacter(const wchar_t c, bool* fallback_font) c
if (n != CharacterMap.end())
{
if (fallback_font != NULL) *fallback_font = false;
// std::cout << "Character " << (int)c << " found in font\n";
//Log::info("ScalableFont", "Character %d found in font", (int)c);
return (*n).second;
}
else if (m_fallback_font != NULL && fallback_font != NULL)
{
// std::cout << "Font does not have this character : <" << (int)c << ">, trying fallback font" << std::endl;
//Log::warn("ScalableFont", "Font does not have this character: <%d>, try fallback font", (int)c);
*fallback_font = true;
return m_fallback_font->getAreaIDFromCharacter(c, NULL);
}
else
{
// std::cout << "The font does not have this character : <" << (int)c << ">" << std::endl;
//Log::warn("ScalableFont", "The font does not have this character: <%d>", (int)c);
if (fallback_font != NULL) *fallback_font = false;
return WrongCharacter;
}
@ -453,12 +455,12 @@ core::dimension2d<u32> ScalableFont::getDimension(const wchar_t* text) const
dim.Height += thisLine.Height;
if (dim.Width < thisLine.Width) dim.Width = thisLine.Width;
// std::cout << "ScalableFont::getDimension returns : " << dim.Width << ", " << dim.Height << " --> ";
//Log::info("ScalableFont", "ScalableFont::getDimension returns: %d, %d", dim.Width, dim.Height);
dim.Width = (int)(dim.Width + 0.9f); // round up
dim.Height = (int)(dim.Height + 0.9f);
//std::cout << dim.Width << ", " << dim.Height << std::endl;
//Log::info("ScalableFont", "After: %d, %d", dim.Width, dim.Height);
return dim;
}
@ -616,10 +618,9 @@ void ScalableFont::doDraw(const core::stringw& text,
/*
if (fallback[n])
{
std::cout << "USING fallback font " << core::stringc(texture->getName()).c_str()
<< "; source area is " << source.UpperLeftCorner.X << ", " << source.UpperLeftCorner.Y
<< ", size " << source.getWidth() << ", " << source.getHeight() << "; dest = "
<< offsets[n].X << ", " << offsets[n].Y << std::endl;
Log::info("ScalableFont", "Using fallback font %s; source area is %d, %d; size %d, %d; dest = %d, %d",
core::stringc(texture->getName()).c_str(), source.UpperLeftCorner.X, source.UpperLeftCorner.Y,
source.getWidth(), source.getHeight(), offsets[n].X, offsets[n].Y);
}
*/
@ -773,7 +774,7 @@ int ScalableFont::getCharWidth(const SFontArea& area, const bool fallback) const
assert(info.m_file_name.size() > 0);
const float char_scale = info.m_scale;
//std::cout << "area.spriteno=" << area.spriteno << ", char_scale=" << char_scale << std::endl;
//Log::info("ScalableFont", "area.spriteno = %d, char_scale = %f", area.spriteno, char_scale);
if (fallback) return (int)(((area.width + area.overhang)*m_fallback_font_scale + m_fallback_kerning_width) * m_scale * char_scale);
else return (int)((area.width + area.overhang + GlobalKerningWidth) * m_scale * char_scale);

View File

@ -187,11 +187,11 @@ void Screen::addWidgets()
addWidgetsRecursively( m_widgets );
//std::cout << "*****ScreenAddWidgets " << m_filename.c_str() << " : focusing the first widget*****\n";
//Log::info("Screen::AddWidgets", "%s: focusing the first widget", m_filename.c_str());
// select the first widget (for first players only; if other players need some focus the Screen must provide it).
Widget* w = getFirstWidget();
//std::cout << "First widget is " << (w == NULL ? "null" : w->m_properties[PROP_ID].c_str()) << std::endl;
//Log::info("Screen::AddWidgets", "First widget is %s", (w == NULL ? "null" : w->m_properties[PROP_ID].c_str()));
if (w != NULL) w->setFocusForPlayer( PLAYER_ID_GAME_MASTER );
else Log::warn("Screen::AddWidgets", "Couldn't select first widget, NULL was returned");
} // addWidgets

View File

@ -181,8 +181,7 @@ void Screen::parseScreenFileDiv(irr::io::IXMLReader* xml, PtrVector<Widget>& app
}
else
{
std::cerr << "/!\\ Warning /!\\ : unknown tag found in STK GUI file : '"
<< xml->getNodeName() << "'" << std::endl;
Log::warn("Screen::parseScreenFileDiv", "unknown tag found in STK GUI file '%s'", xml->getNodeName());
continue;
}

View File

@ -1512,13 +1512,13 @@ void Skin::drawIconButton(const core::recti &rect, Widget* widget,
SColor(100,255,255,255),
SColor(100,255,255,255) };
core::recti r(0,0,icon_widget->m_texture_w, icon_widget->m_texture_h);
draw2DImage(icon_widget->m_texture, sized_rect,
draw2DImage(icon_widget->getTexture(), sized_rect,
r, 0 /* no clipping */, colors,
true /* alpha */);
}
else
{
video::ITexture* t = icon_widget->m_texture;
const video::ITexture* t = icon_widget->getTexture();
const bool mouseInside =
rect.isPointInside(irr_driver->getDevice()->getCursorControl()

View File

@ -16,13 +16,13 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "guiengine/engine.hpp"
#include "guiengine/scalable_font.hpp"
#include "guiengine/widgets/dynamic_ribbon_widget.hpp"
#include "io/file_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/vs.hpp"
#include <IGUIEnvironment.h>
#include <sstream>
#include <iostream>
#include <algorithm>
@ -36,6 +36,7 @@ DynamicRibbonWidget::DynamicRibbonWidget(const bool combo, const bool multi_row)
m_needed_cols = 0;
m_col_amount = 0;
m_previous_item_count = 0;
m_max_label_length = 0;
m_multi_row = multi_row;
m_combo = combo;
m_has_label = false;
@ -44,6 +45,7 @@ DynamicRibbonWidget::DynamicRibbonWidget(const bool combo, const bool multi_row)
m_check_inside_me = true;
m_supports_multiplayer = true;
m_scrolling_enabled = true;
m_animated_contents = false;
// by default, set all players to have no selection in this ribbon
for (unsigned int n=0; n<MAX_PLAYER_COUNT; n++)
@ -53,10 +55,14 @@ DynamicRibbonWidget::DynamicRibbonWidget(const bool combo, const bool multi_row)
m_selected_item[0] = 0; // only player 0 has a selection by default
m_item_count_hint = 0;
m_font = GUIEngine::getFont()->getHollowCopy();
m_max_label_width = 0;
}
// -----------------------------------------------------------------------------
DynamicRibbonWidget::~DynamicRibbonWidget()
{
delete m_font;
if (m_animated_contents)
{
GUIEngine::needsUpdate.remove(this);
@ -252,9 +258,9 @@ void DynamicRibbonWidget::add()
const float score = log(2.0f*visible_items) *
std::min(ratio, 1.0f) * std::min(taken_area/total_area, 1.0f);
//std::cout << " " << row_count << " rows : " << visible_items << " visible items; area = "
// << taken_area << "; size penalty = " << std::min((float)item_height / (float)m_child_height, 1.0f)
// << "; score = " << score << "\n";
//Log::info("DynamicRibbonWidget", "%d rown: %d visible items; area = %f; "
// "size penalty = %f; score = %f", row_count, visible_items, taken_area,
// std::min((float)item_height / (float)m_child_height, 1.0f), score);
if (score > max_score_so_far)
{
@ -270,8 +276,8 @@ void DynamicRibbonWidget::add()
const int max_rows = atoi(m_properties[PROP_MAX_ROWS].c_str());
if (max_rows < 1)
{
std::cout << "/!\\ WARNING : the 'max_rows' property must be an integer greater than zero."
<< " Ingoring current value '" << m_properties[PROP_MAX_ROWS] << "'\n";
Log::warn("DynamicRibbonWidget", "The 'max_rows' property must be an integer greater than zero; "
"Ignoring current value '%s'", m_properties[PROP_MAX_ROWS].c_str());
}
else
{
@ -294,7 +300,7 @@ void DynamicRibbonWidget::add()
for (int i=0; i<m_row_amount; i++)
{
m_ids[i] = getNewID();
//std::cout << "ribbon : getNewID returns " << m_ids[i] << std::endl;
//Log::info("DynamicRibbonWidget", "getNewID returns %d", m_ids[i]);
}
buildInternalStructure();
@ -328,11 +334,11 @@ void DynamicRibbonWidget::buildInternalStructure()
// ajust column amount to not add more item slots than we actually need
const int item_count = (int) m_items.size();
//std::cout << "item_count=" << item_count << ", row_amount*m_col_amount=" << m_row_amount*m_col_amount << std::endl;
//Log::info("DynamicRibbonWidget", "%d items; %d cells", item_count, row_amount * m_col_amount);
if (m_row_amount*m_col_amount > item_count)
{
m_col_amount = (int)ceil((float)item_count/(float)m_row_amount);
//std::cout << "Adjusting m_col_amount to be " << m_col_amount << std::endl;
//Log::info("DynamicRibbonWidget", "Adjusting m_col_amount to be %d", m_col_amount);
}
assert( m_left_widget->ok() );
@ -379,6 +385,13 @@ void DynamicRibbonWidget::buildInternalStructure()
ribbon->m_properties[PROP_ID] = name.str();
ribbon->m_event_handler = this;
// calculate font size
if (m_col_amount > 0)
{
m_font->setScale(GUIEngine::getFont()->getScale() *
getFontScale((ribbon->m_w / m_col_amount) - 30));
}
// add columns
for (int i=0; i<m_col_amount; i++)
{
@ -392,12 +405,13 @@ void DynamicRibbonWidget::buildInternalStructure()
icon->m_properties[PROP_HEIGHT] = m_properties[PROP_CHILD_HEIGHT];
icon->m_w = atoi(icon->m_properties[PROP_WIDTH].c_str());
icon->m_h = atoi(icon->m_properties[PROP_HEIGHT].c_str());
icon->setLabelFont(m_font);
// If we want each icon to have its own label, we must make it non-empty, otherwise
// it will assume there is no label and none will be created (FIXME: that's ugly)
if (m_properties[PROP_LABELS_LOCATION] == "each") icon->m_text = " ";
// std::cout << "ribbon text = " << m_properties[PROP_TEXT].c_str() << std::endl;
//Log::info("DynamicRibbonWidget", "Ribbon text = %s", m_properties[PROP_TEXT].c_str());
ribbon->m_children.push_back( icon );
added_item_count++;
@ -438,14 +452,14 @@ void DynamicRibbonWidget::buildInternalStructure()
assert(childrenCount == (int)m_items.size());
}
#endif
}
}
// -----------------------------------------------------------------------------
void DynamicRibbonWidget::addItem( const irr::core::stringw& user_name, const std::string& code_name,
const std::string& image_file, const unsigned int badges,
IconButtonWidget::IconPathType image_path_type)
{
ItemDescription desc;
desc.m_user_name = user_name;
desc.m_user_name = getUserName(user_name);
desc.m_code_name = code_name;
desc.m_sshot_file = image_file;
desc.m_badges = badges;
@ -453,6 +467,8 @@ void DynamicRibbonWidget::addItem( const irr::core::stringw& user_name, const st
desc.m_image_path_type = image_path_type;
m_items.push_back(desc);
setLabelSize(desc.m_user_name);
}
// -----------------------------------------------------------------------------
@ -462,7 +478,7 @@ void DynamicRibbonWidget::addAnimatedItem( const irr::core::stringw& user_name,
const unsigned int badges, IconButtonWidget::IconPathType image_path_type )
{
ItemDescription desc;
desc.m_user_name = user_name;
desc.m_user_name = getUserName(user_name);
desc.m_code_name = code_name;
desc.m_all_images = image_files;
desc.m_badges = badges;
@ -473,6 +489,8 @@ void DynamicRibbonWidget::addAnimatedItem( const irr::core::stringw& user_name,
m_items.push_back(desc);
setLabelSize(desc.m_user_name);
if (!m_animated_contents)
{
m_animated_contents = true;
@ -498,6 +516,7 @@ void DynamicRibbonWidget::clearItems()
m_items.clear();
m_animated_contents = false;
m_scroll_offset = 0;
m_max_label_width = 0;
}
// -----------------------------------------------------------------------------
void DynamicRibbonWidget::elementRemoved()
@ -593,12 +612,12 @@ EventPropagation DynamicRibbonWidget::rightPressed(const int playerID)
getSelectedRibbon(playerID)->getSelectionText(playerID), playerID);
}
}
//std::cout << "rightpressed (dynamic ribbon) " << m_properties[PROP_ID] << "\n";
//Log::info("DynamicRibbonWidget", "Rightpressed %s", m_properties[PROP_ID].c_str());
assert(m_rows.size() >= 1);
if (m_rows[0].m_ribbon_type == RIBBON_TOOLBAR) return EVENT_BLOCK;
//std::cout << " rightpressed returning EVENT_LET\n";
//Log::info("DynamicRibbonWidget", "Rightpressed returning EVENT_LET");
return EVENT_LET;
}
@ -663,7 +682,7 @@ EventPropagation DynamicRibbonWidget::transmitEvent(Widget* w,
EventPropagation DynamicRibbonWidget::mouseHovered(Widget* child, const int playerID)
{
if (m_deactivated) return EVENT_LET;
//std::cout << "DynamicRibbonWidget::mouseHovered " << playerID << std::endl;
//Log::info("DynamicRibbonWidget", "mouseHovered %d", playerID);
updateLabel();
propagateSelection();
@ -738,9 +757,9 @@ void DynamicRibbonWidget::onRibbonWidgetFocus(RibbonWidget* emitter, const int p
#pragma mark Setters / Actions
#endif
void DynamicRibbonWidget::scroll(const int x_delta)
void DynamicRibbonWidget::scroll(int x_delta, bool evenIfDeactivated)
{
if (m_deactivated) return;
if (m_deactivated && !evenIfDeactivated) return;
// Refuse to scroll when everything is visible
if ((int)m_items.size() <= m_row_amount*m_col_amount) return;
@ -1062,19 +1081,18 @@ bool DynamicRibbonWidget::setSelection(int item_id, const int playerID,
while (!findItemInRows(name.c_str(), &row, &id))
{
// if we get here it means the item is scrolled out. Try to find it.
scroll(1);
scroll(1, evenIfDeactivated);
if (iterations > 50)
{
assert(false);
std::cerr << "DynamicRibbonWidget::setSelection cannot find item " << item_id << " (" << name.c_str() << ")\n";
Log::error("DynamicRibbonWidget::setSelection", "Cannot find item %d (%s)", item_id, name.c_str());
return false;
}
iterations++;
}
//std::cout << "Player " << playerID << " has item " << item_id << " (" << name.c_str() << ") in row " << row << std::endl;
//Log::info("DynamicRibbonWidget", "Player %d has item %d (%s) in row %d", playerID, item_id, name.c_str(), row);
m_rows[row].setSelection(id, playerID);
if (focusIt)
{
@ -1097,7 +1115,9 @@ bool DynamicRibbonWidget::setSelection(int item_id, const int playerID,
propagateSelection();
return true;
}
// ----------------------------------------------------------------------------
bool DynamicRibbonWidget::setSelection(const std::string &item_codename,
const int playerID, const bool focusIt,
bool evenIfDeactivated)
@ -1117,4 +1137,29 @@ bool DynamicRibbonWidget::setSelection(const std::string &item_codename,
// -----------------------------------------------------------------------------
void DynamicRibbonWidget::setLabelSize(const irr::core::stringw& text)
{
int w = GUIEngine::getFont()->getDimension(text.c_str()).Width;
if (w > m_max_label_width)
m_max_label_width = w;
}
// -----------------------------------------------------------------------------
float DynamicRibbonWidget::getFontScale(int icon_width) const
{
if (m_max_label_width <= icon_width || m_max_label_width == 0 || icon_width == 0)
return 1.0f;
else
return std::max (0.5f, ((float)icon_width / (float)m_max_label_width));
}
// -----------------------------------------------------------------------------
irr::core::stringw DynamicRibbonWidget::getUserName(const irr::core::stringw& user_name) const
{
if (m_max_label_length == 0 || user_name.size() < m_max_label_length)
return user_name;
else
return (user_name.subString(0, m_max_label_length - 3) + L"...");
}

View File

@ -30,7 +30,7 @@
namespace GUIEngine
{
class IconButtonWidget;
/**
* Even if you have a ribbon that only acts on click/enter, you may wish to know which
* item is currently highlighted. In this case, create a listener and pass it to the ribbon.
@ -44,7 +44,7 @@ namespace GUIEngine
const irr::core::stringw& selectionText,
const int playerID) = 0;
};
/** The description of an item added to a DynamicRibbonWidget */
struct ItemDescription
{
@ -52,16 +52,16 @@ namespace GUIEngine
std::string m_code_name;
std::string m_sshot_file;
IconButtonWidget::IconPathType m_image_path_type;
bool m_animated;
/** used instead of 'm_sshot_file' if m_animated is true */
std::vector<std::string> m_all_images;
float m_curr_time;
float m_time_per_frame;
unsigned int m_badges;
};
/**
* \brief An extended version of RibbonWidget, with more capabilities.
* A dynamic ribbon builds upon RibbonWidget, adding dynamic contents creation and sizing,
@ -73,55 +73,55 @@ namespace GUIEngine
class DynamicRibbonWidget : public Widget, public RibbonWidget::IRibbonListener
{
friend class RibbonWidget;
/** A list of all listeners that registered to be notified on hover/selection */
PtrVector<DynamicRibbonHoverListener> m_hover_listeners;
virtual ~DynamicRibbonWidget();
/** Used for ribbon grids that have a label at the bottom */
bool m_has_label;
irr::gui::IGUIStaticText* m_label;
/** Height of ONE label text line (if label is multiline only one line is measured here).
* If there is no label, will be 0.
*/
int m_label_height;
/** Whether this ribbon contains at least one animated item */
bool m_animated_contents;
/** Whether there are more items than can fit in a single screen; arrows will then appear
* on each side of the ribbon to scroll the contents
*/
bool m_scrolling_enabled;
/** Used to keep track of item count changes */
int m_previous_item_count;
/** List of items in the ribbon */
std::vector<ItemDescription> m_items;
/** Width of the scrolling arrows on each side */
int m_arrows_w;
/** Current scroll offset within items */
int m_scroll_offset;
/** Width and height of children as declared in the GUI file */
int m_child_width, m_child_height;
/** Number of rows and columns. Number of columns can dynamically change, number of row is
determined at creation */
int m_row_amount;
int m_col_amount;
/** The total number of columns given item count and row count (even counting not visible with current scrolling) */
int m_needed_cols;
/** Whether this ribbon can have multiple rows (i.e. ribbon grid) or is a single line */
bool m_multi_row;
/** irrlicht relies on consecutive IDs to perform keyboard navigation between widgets. However, since this
widget is dynamic, irrlicht widgets are not created as early as all others, so by the time we're ready
to create the full contents of this widget, the ID generator is already incremented, thus messing up
@ -129,65 +129,81 @@ namespace GUIEngine
number of IDs (the number of rows) and store them here. Then, when we're finally ready to create the
contents dynamically, we can re-use these IDs and get correct navigation order. */
std::vector<int> m_ids;
/** Whether this is a "combo" style ribbon grid widget */
bool m_combo;
/* reference pointers only, the actual instances are owned by m_children */
IconButtonWidget* m_left_widget;
IconButtonWidget* m_right_widget;
/** Returns the currently selected row */
RibbonWidget* getSelectedRibbon(const int playerID);
/** Returns the row */
RibbonWidget* getRowContaining(Widget* w);
/** Updates the visible label to match the currently selected item */
void updateLabel(RibbonWidget* from_this_ribbon=NULL);
/** Even though the ribbon grid widget looks like a grid, it is really a vertical stack of
independant ribbons. When moving selection horizontally, this method is used to notify
other rows above and below of which column is selected, so that moving vertically to
another row keeps the same selected column. */
void propagateSelection();
/** Callback called widget is focused */
EventPropagation focused(const int playerID);
/** Removes all previously added contents icons, and re-adds them (calculating the new amount) */
void buildInternalStructure();
/** Call this to scroll within a scrollable ribbon */
void scroll(const int x_delta);
void scroll(int x_delta, bool evenIfDeactivated = false);
/** Used for combo ribbons, to contain the ID of the currently selected item for each player */
int m_selected_item[MAX_PLAYER_COUNT];
/** Callbacks */
virtual void add();
virtual EventPropagation mouseHovered(Widget* child, const int playerID);
virtual EventPropagation transmitEvent(Widget* w, const std::string& originator, const int playerID);
bool findItemInRows(const char* name, int* p_row, int* p_id);
int m_item_count_hint;
float getFontScale(int icon_width) const;
void setLabelSize(const irr::core::stringw& text);
irr::core::stringw getUserName(const irr::core::stringw& user_name) const;
/**
* Font used to write the labels, can be scaled down depending on the
* length of the text
*/
irr::gui::ScalableFont* m_font;
/** Max width of a label, in pixels */
int m_max_label_width;
/** Max length of a label, in characters */
unsigned int m_max_label_length;
public:
LEAK_CHECK()
/**
* \param combo Whether this is a "combo" ribbon, i.e. whether there is always one selected item.
* If set to false, will behave more like a toolbar.
* \param multi_row Whether this ribbon can have more than one row
*/
DynamicRibbonWidget(const bool combo, const bool multi_row);
/** Reference pointers only, the actual instances are owned by m_children. Used to create mtultiple-row
ribbons (what appears to be a grid of icons is actually a vector of stacked basic ribbons) */
PtrVector<RibbonWidget, REF> m_rows;
/** Dynamically add an item to the ribbon's list of items (will not be visible until you
* call 'updateItemDisplay' or 'add').
*
@ -200,7 +216,7 @@ namespace GUIEngine
void addItem( const irr::core::stringw& user_name, const std::string& code_name,
const std::string& image_file, const unsigned int badge=0,
IconButtonWidget::IconPathType image_path_type=IconButtonWidget::ICON_PATH_TYPE_RELATIVE);
/** Dynamically add an animated item to the ribbon's list of items (will not be visible until you
* call 'updateItemDisplay' or 'add'). Animated means it has many images that will be shown in
* a slideshown fashion.
@ -220,7 +236,7 @@ namespace GUIEngine
/** Clears all items added through 'addItem'. You can then add new items with 'addItem' and call
'updateItemDisplay' to update the display. */
void clearItems();
/**
* \brief Register a listener to be notified of selection changes within the ribbon.
* \note The ribbon takes ownership of this listener and will delete it.
@ -228,26 +244,26 @@ namespace GUIEngine
* want to add a listener in the "init" callback of your screen.
*/
void registerHoverListener(DynamicRibbonHoverListener* listener);
/** Called when right key is pressed */
EventPropagation rightPressed(const int playerID);
/** Called when left key is pressed */
EventPropagation leftPressed(const int playerID);
/** Updates icons/labels given current items and scrolling offset, taking care of resizing
the dynamic ribbon if the number of items changed */
void updateItemDisplay();
/** Get the internal name (ID) of the selected item */
const std::string& getSelectionIDString(const int playerID);
/** Get the user-visible text of the selected item */
irr::core::stringw getSelectionText(const int playerID);
/** Returns a read-only list of items added to this ribbon */
const std::vector<ItemDescription>& getItems() const { return m_items; }
/**
* \brief Select an item from its numerical ID. Only for [1-row] combo ribbons.
*
@ -255,7 +271,7 @@ namespace GUIEngine
* \return Whether setting the selection was successful (whether the item exists)
*/
bool setSelection(int item_id, const int playerID, const bool focusIt, bool evenIfDeactivated=false);
/**
* \brief Select an item from its codename.
*
@ -264,26 +280,29 @@ namespace GUIEngine
bool setSelection(const std::string &item_codename,
const int playerID, const bool focusIt,
bool evenIfDeactivated=false);
/** \brief Callback from parent class Widget. */
virtual void elementRemoved();
/** \brief callback from IRibbonListener */
virtual void onRibbonWidgetScroll(const int delta_x);
/** \brief callback from IRibbonListener */
virtual void onRibbonWidgetFocus(RibbonWidget* emitter, const int playerID);
/** \brief callback from IRibbonListener */
virtual void onSelectionChange(){}
virtual void update(float delta);
/** Set approximately how many items are expected to be in this ribbon; will help the layout
* algorithm next time add() is called */
void setItemCountHint(int hint) { m_item_count_hint = hint; }
/** Set max length of displayed text. */
void setMaxLabelLength(int length) { m_max_label_length = length; }
};
}
#endif

View File

@ -28,6 +28,7 @@
#include <IGUIEnvironment.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <algorithm>
using namespace GUIEngine;
using namespace irr::video;
@ -39,10 +40,15 @@ IconButtonWidget::IconButtonWidget(ScaleMode scale_mode, const bool tab_stop,
const bool focusable, IconPathType pathType) : Widget(WTYPE_ICON_BUTTON)
{
m_label = NULL;
m_font = NULL;
m_texture = NULL;
m_deactivated_texture = NULL;
m_highlight_texture = NULL;
m_custom_aspect_ratio = 1.0f;
m_texture_w = 0;
m_texture_h = 0;
m_tab_stop = tab_stop;
m_focusable = focusable;
m_scale_mode = scale_mode;
@ -57,12 +63,12 @@ void IconButtonWidget::add()
{
if (m_icon_path_type == ICON_PATH_TYPE_ABSOLUTE)
{
m_texture = irr_driver->getTexture(m_properties[PROP_ICON]);
setTexture(irr_driver->getTexture(m_properties[PROP_ICON]));
}
else if (m_icon_path_type == ICON_PATH_TYPE_RELATIVE)
{
std::string file = file_manager->getAsset(m_properties[PROP_ICON]);
m_texture = irr_driver->getTexture(file);
setTexture(irr_driver->getTexture(file));
}
}
@ -72,13 +78,11 @@ void IconButtonWidget::add()
"add() : error, cannot find texture '%s'.",
m_properties[PROP_ICON].c_str());
std::string file = file_manager->getAsset(FileManager::GUI,"main_help.png");
m_texture = irr_driver->getTexture(file);
setTexture(irr_driver->getTexture(file));
if(!m_texture)
Log::fatal("IconButtonWidget",
"Can't find fallback texture 'gui/main_help.png, aborting.");
}
m_texture_w = m_texture->getSize().Width;
m_texture_h = m_texture->getSize().Height;
if (m_properties[PROP_FOCUS_ICON].size() > 0)
{
@ -174,13 +178,7 @@ void IconButtonWidget::add()
m_label->setVisible(false);
}
const int max_w = m_label->getAbsolutePosition().getWidth();
if (!word_wrap &&
(int)GUIEngine::getFont()->getDimension(message.c_str()).Width > max_w + 4) // arbitrarily allow for 4 pixels
{
m_label->setOverrideFont( GUIEngine::getSmallFont() );
}
setLabelFont();
#if IRRLICHT_VERSION_MAJOR > 1 || (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8)
m_label->setRightToLeft( translations->isRTLLanguage() );
@ -192,6 +190,9 @@ void IconButtonWidget::add()
m_id = m_element->getID();
if (m_tab_stop) m_element->setTabOrder(m_id);
m_element->setTabGroup(false);
if (!m_is_visible)
m_element->setVisible(false);
}
// -----------------------------------------------------------------------------
@ -207,12 +208,12 @@ void IconButtonWidget::setImage(const char* path_to_texture, IconPathType pathTy
if (m_icon_path_type == ICON_PATH_TYPE_ABSOLUTE)
{
m_texture = irr_driver->getTexture(m_properties[PROP_ICON]);
setTexture(irr_driver->getTexture(m_properties[PROP_ICON]));
}
else if (m_icon_path_type == ICON_PATH_TYPE_RELATIVE)
{
std::string file = file_manager->getAsset(m_properties[PROP_ICON]);
m_texture = irr_driver->getTexture(file);
setTexture(irr_driver->getTexture(file));
}
if (!m_texture)
@ -220,11 +221,8 @@ void IconButtonWidget::setImage(const char* path_to_texture, IconPathType pathTy
Log::error("icon_button", "Texture '%s' not found!\n",
m_properties[PROP_ICON].c_str());
std::string file = file_manager->getAsset(FileManager::GUI,"main_help.png");
m_texture = irr_driver->getTexture(file);
setTexture(irr_driver->getTexture(file));
}
m_texture_w = m_texture->getSize().Width;
m_texture_h = m_texture->getSize().Height;
}
// -----------------------------------------------------------------------------
@ -233,39 +231,28 @@ void IconButtonWidget::setImage(ITexture* texture)
{
if (texture != NULL)
{
m_texture = texture;
m_texture_w = m_texture->getSize().Width;
m_texture_h = m_texture->getSize().Height;
setTexture(texture);
}
else
{
Log::error("icon_button",
"setImage invoked with NULL image pointer\n");
std::string file = file_manager->getAsset(FileManager::GUI,"main_help.png");
m_texture = irr_driver->getTexture(file);
setTexture(irr_driver->getTexture(file));
}
}
// -----------------------------------------------------------------------------
void IconButtonWidget::setLabel(stringw new_label)
void IconButtonWidget::setLabel(const stringw& new_label)
{
if (m_label == NULL) return;
m_label->setText( new_label.c_str() );
const bool word_wrap = (m_properties[PROP_WORD_WRAP] == "true");
const int max_w = m_label->getAbsolutePosition().getWidth();
if (!word_wrap &&
(int)GUIEngine::getFont()->getDimension(new_label.c_str()).Width
> max_w + 4) // arbitrarily allow for 4 pixels
{
m_label->setOverrideFont( GUIEngine::getSmallFont() );
}
else
{
m_label->setOverrideFont( NULL );
}
setLabelFont();
}
// -----------------------------------------------------------------------------
void IconButtonWidget::setLabelFont(irr::gui::ScalableFont* font)
{
m_font = font;
}
// -----------------------------------------------------------------------------
EventPropagation IconButtonWidget::focused(const int playerID)
@ -287,5 +274,95 @@ void IconButtonWidget::unfocused(const int playerID, Widget* new_focus)
m_label->setVisible(false);
}
}
// -----------------------------------------------------------------------------
const video::ITexture* IconButtonWidget::getTexture()
{
if (Widget::isActivated())
{
return m_texture;
}
else
{
if (m_deactivated_texture == NULL)
m_deactivated_texture = getDeactivatedTexture(m_texture);
return m_deactivated_texture;
}
}
// -----------------------------------------------------------------------------
video::ITexture* IconButtonWidget::getDeactivatedTexture(video::ITexture* texture)
{
video::ITexture* t;
std::string name = texture->getName().getPath().c_str();
name += "_disabled";
t = irr_driver->getTexture(name);
if (t == NULL)
{
SColor c;
u32 g;
video::IVideoDriver* driver = irr_driver->getVideoDriver();
std::auto_ptr<video::IImage> image (driver->createImageFromData (texture->getColorFormat(),
texture->getSize(), texture->lock(), false));
texture->unlock();
//Turn the image into grayscale
for (u32 x = 0; x < image->getDimension().Width; x++)
{
for (u32 y = 0; y < image->getDimension().Height; y++)
{
c = image->getPixel(x, y);
g = ((c.getRed() + c.getGreen() + c.getBlue()) / 3);
c.set(std::max (0, (int)c.getAlpha() - 120), g, g, g);
image->setPixel(x, y, c);
}
}
t = driver->addTexture(name.c_str(), image.get ());
}
return t;
}
// -----------------------------------------------------------------------------
void IconButtonWidget::setTexture(video::ITexture* texture)
{
m_texture = texture;
if (texture == NULL)
{
m_deactivated_texture = NULL;
m_texture_w = 0;
m_texture_h = 0;
}
else
{
m_texture_w = texture->getSize().Width;
m_texture_h = texture->getSize().Height;
}
}
// -----------------------------------------------------------------------------
void IconButtonWidget::setLabelFont()
{
if (m_font != NULL)
{
m_label->setOverrideFont( m_font );
}
else
{
const bool word_wrap = (m_properties[PROP_WORD_WRAP] == "true");
const int max_w = m_label->getAbsolutePosition().getWidth();
if (!word_wrap &&
(int)GUIEngine::getFont()->getDimension(m_label->getText()).Width
> max_w + 4) // arbitrarily allow for 4 pixels
{
m_label->setOverrideFont( GUIEngine::getSmallFont() );
}
else
{
m_label->setOverrideFont( NULL );
}
}
}

View File

@ -23,13 +23,16 @@
#include <irrString.h>
namespace irr
{
namespace gui { class IGUIStaticText; }
namespace gui
{
class IGUIStaticText;
class ScalableFont;
}
namespace video { class ITexture; }
}
#include "guiengine/widget.hpp"
#include "utils/leak_check.hpp"
#include "utils/ptr_vector.hpp"
namespace GUIEngine
{
@ -38,6 +41,15 @@ namespace GUIEngine
*/
class IconButtonWidget : public Widget
{
private:
irr::video::ITexture* m_texture;
irr::video::ITexture* m_deactivated_texture;
irr::video::ITexture* m_highlight_texture;
int m_texture_w, m_texture_h;
video::ITexture* getDeactivatedTexture(video::ITexture* texture);
void setLabelFont();
public:
enum ScaleMode
{
@ -54,42 +66,41 @@ namespace GUIEngine
* the path type as it currently is */
ICON_PATH_TYPE_NO_CHANGE
};
protected:
IconPathType m_icon_path_type;
friend class Skin;
irr::gui::IGUIStaticText* m_label;
irr::video::ITexture* m_texture;
irr::video::ITexture* m_highlight_texture;
int m_texture_w, m_texture_h;
protected:
IconPathType m_icon_path_type;
friend class Skin;
irr::gui::IGUIStaticText* m_label;
irr::gui::ScalableFont* m_font;
ScaleMode m_scale_mode;
float m_custom_aspect_ratio;
void setTexture(video::ITexture* texture);
public:
LEAK_CHECK()
/** Whether to make the widget included in keyboard navigation order when adding */
bool m_tab_stop;
IconButtonWidget(ScaleMode scale_mode=SCALE_MODE_KEEP_TEXTURE_ASPECT_RATIO, const bool tab_stop=true,
const bool focusable=true, IconPathType pathType=ICON_PATH_TYPE_RELATIVE);
virtual ~IconButtonWidget() {}
virtual ~IconButtonWidget() {};
/** \brief Implement callback from base class Widget */
virtual void add();
/**
* \brief Call this if scale mode is SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO.
* \param custom_aspect_ratio The width/height aspect ratio
*/
void setCustomAspectRatio(float custom_aspect_ratio) { m_custom_aspect_ratio = custom_aspect_ratio; }
/**
* \brief Temporarily change the text label if there is a label (next time this screen is
* visited, the previous label will be back. For a permanent change, edit the 'text'
@ -98,8 +109,15 @@ namespace GUIEngine
* \pre Must be called after this widget is add()ed to have any effect
* \note Calling this method on a button without label will have no effect
*/
void setLabel(irr::core::stringw new_label);
void setLabel(const irr::core::stringw& new_label);
/**
* \brief Sets the font used to draw the label.
*
* \note Calling this method on a button without label will have no effect
*/
void setLabelFont(irr::gui::ScalableFont* font);
/**
* Change the texture used for this icon.
* \pre At the moment, the new texture must have the same aspct ratio
@ -109,7 +127,7 @@ namespace GUIEngine
*/
void setImage(const char* path_to_texture,
IconPathType path_type=ICON_PATH_TYPE_NO_CHANGE);
// --------------------------------------------------------------------
// --------------------------------------------------------------------
/** Convenience function taking std::string. */
void setImage(const std::string &path_to_texture,
IconPathType path_type=ICON_PATH_TYPE_NO_CHANGE)
@ -126,23 +144,23 @@ namespace GUIEngine
* \note May safely be called no matter if the widget is add()ed or not
*/
void setImage(irr::video::ITexture* texture);
// --------------------------------------------------------------------
void setHighlightedImage(irr::video::ITexture* texture)
{
m_highlight_texture = texture;
}
// --------------------------------------------------------------------
/** \brief override from base class */
virtual EventPropagation focused(const int playerID);
// --------------------------------------------------------------------
/** \brief override from base class */
virtual void unfocused(const int playerID, Widget* new_focus);
// --------------------------------------------------------------------
/** Returns the texture of this button. */
const video::ITexture* getTexture() const { return m_texture; }
const video::ITexture* getTexture();
};
}

View File

@ -136,8 +136,9 @@ void ModelViewWidget::update(float delta)
distance_with_negative_rotation = (int)(angle - m_rotation_target);
}
//std::cout << "distance_with_positive_rotation=" << distance_with_positive_rotation <<
//" distance_with_negative_rotation=" << distance_with_negative_rotation << " angle="<< angle <<std::endl;
//Log::info("ModelViewWidget", "distance_with_positive_rotation = %d; "
// "distance_with_negative_rotation = %d; angle = %f", distance_with_positive_rotation,
// distance_with_negative_rotation, angle);
if (distance_with_positive_rotation < distance_with_negative_rotation)
{
@ -242,7 +243,7 @@ void ModelViewWidget::setupRTTScene(PtrVector<scene::IMesh, REF>& mesh,
node->setAnimationSpeed(0);
node->updateAbsolutePosition();
node->setScale(mesh_scale[n].toIrrVector());
//std::cout << "(((( set frame " << model_frames[n] << " ))))\n";
//Log::info("ModelViewWidget", "Set frame %d", model_frames[n]);
}
}

View File

@ -141,14 +141,8 @@ void RibbonWidget::add()
total_needed_space += m_active_children[i].m_w;
}
int free_w_space = m_w - total_needed_space;
//int biggest_y = 0;
const int button_y = 10;
float global_zoom = 1;
const int min_free_space = 50;
global_zoom = (float)m_w / (float)( m_w - free_w_space + min_free_space );
const int one_button_space =
int(roundf((float)m_w / (float)subbuttons_amount));
@ -320,22 +314,10 @@ void RibbonWidget::add()
float image_h = (float)image->getSize().Height;
float image_w = image_h*imageRatio;
// scale to fit (FIXME: calculate the right value directly...)
float zoom = global_zoom;
if (button_y + image_h*zoom + needed_space_under_button > m_h)
{
// scale down
while (button_y + image_h*zoom +
needed_space_under_button > m_h) zoom -= 0.01f;
}
else
{
// scale up
while (button_y + image_h*zoom +
needed_space_under_button < m_h) zoom += 0.01f;
}
float zoom = (float) (m_h - button_y - needed_space_under_button) / image_h;
float zoom_x = (float) one_button_space / image_w;
if(zoom_x < zoom)
zoom = zoom_x;
// ---- add bitmap button part
// backup and restore position in case the same object is added
@ -612,7 +594,7 @@ EventPropagation RibbonWidget::mouseHovered(Widget* child,
if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS)
{
//std::cout << "SETTING m_mouse_focus\n";
//Log::info("RibbonWidget", "Setting m_mouse_focus");
m_mouse_focus = child;
}
@ -660,7 +642,6 @@ void RibbonWidget::updateSelection()
// FIXME: m_selection, m_selected, m_mouse_focus... what a mess...
//std::cout << "----\n";
// Update selection flags for mouse player
for (unsigned int p=0; p<MAX_PLAYER_COUNT; p++)
{

View File

@ -231,7 +231,7 @@ EventPropagation SpinnerWidget::rightPressed(const int playerID)
// if widget is deactivated, do nothing
if (m_deactivated) return EVENT_BLOCK;
//std::cout << "Right pressed\n";
//Log::info("SpinnerWidget", "Right pressed");
if (m_value+1 <= m_max)
{
setValue(m_value+1);
@ -253,7 +253,7 @@ EventPropagation SpinnerWidget::leftPressed(const int playerID)
// if widget is deactivated, do nothing
if (m_deactivated) return EVENT_BLOCK;
//std::cout << "Left pressed\n";
//Log::info("SpinnerWidget", "Left pressed");
if (m_value-1 >= m_min)
{
setValue(m_value-1);
@ -386,9 +386,7 @@ void SpinnerWidget::setValue(irr::core::stringw new_value)
}
}
std::cerr << "ERROR [SpinnerWidget::setValue] : cannot find element named '"
<< irr::core::stringc(new_value.c_str()).c_str() << "'\n";
assert(false);
Log::fatal("SpinnerWidget::setValue", "Cannot find element named '%s'", irr::core::stringc(new_value.c_str()).c_str());
}
// -----------------------------------------------------------------------------

View File

@ -145,9 +145,9 @@ void DeviceManager::setAssignMode(const PlayerAssignMode assignMode)
m_assign_mode = assignMode;
#if INPUT_MODE_DEBUG
if (assignMode == NO_ASSIGN) std::cout << "====== DeviceManager::setAssignMode(NO_ASSIGN) ======\n";
if (assignMode == ASSIGN) std::cout << "====== DeviceManager::setAssignMode(ASSIGN) ======\n";
if (assignMode == DETECT_NEW) std::cout << "====== DeviceManager::setAssignMode(DETECT_NEW) ======\n";
if (assignMode == NO_ASSIGN) Log::info("DeviceManager::setAssignMode(NO_ASSIGN)");
if (assignMode == ASSIGN) Log::info("DeviceManager::setAssignMode(ASSIGN)");
if (assignMode == DETECT_NEW) Log::info("DeviceManager::setAssignMode(DETECT_NEW)");
#endif
// when going back to no-assign mode, do some cleanup
@ -289,7 +289,7 @@ InputDevice* DeviceManager::mapKeyboardInput( int btnID, InputManager::InputDriv
{
const int keyboard_amount = m_keyboards.size();
//std::cout << "mapKeyboardInput " << btnID << " to " << keyboard_amount << " keyboards\n";
//Log::info("DeviceManager::mapKeyboardInput", "Map %d to %d", btnID, keyboard_amount);
for (int n=0; n<keyboard_amount; n++)
{
@ -297,10 +297,10 @@ InputDevice* DeviceManager::mapKeyboardInput( int btnID, InputManager::InputDriv
if (keyboard->processAndMapInput(btnID, mode, action))
{
//std::cout << " binding found in keyboard #" << (n+1) << "; action is " << KartActionStrings[*action] << "\n";
//Log::info("DeviceManager::mapKeyboardInput", "Binding found in keyboard #%d; action is %s", n + 1, KartActionStrings[*action]);
if (m_single_player != NULL)
{
//printf("Single player\n");
//Log::info("DeviceManager", "Single player");
*player = m_single_player;
}
else if (m_assign_mode == NO_ASSIGN) // Don't set the player in NO_ASSIGN mode
@ -423,7 +423,7 @@ InputDevice* DeviceManager::getLatestUsedDevice()
if (m_latest_used_device == NULL)
{
//std::cout<< "========== No latest device, returning keyboard ==========\n";
//Log::info("DeviceManager", "No latest device, returning keyboard);
return m_keyboards.get(0); // FIXME: is this right?
}

View File

@ -298,7 +298,7 @@ void InputManager::inputSensing(Input::InputType type, int deviceID,
int value)
{
#if INPUT_MODE_DEBUG
std::cout << "INPUT SENSING... ";
Log::info("InputManager::inputSensing", "Start sensing input");
#endif
// don't store if we're trying to do something like bindings keyboard
@ -310,7 +310,7 @@ void InputManager::inputSensing(Input::InputType type, int deviceID,
return;
#if INPUT_MODE_DEBUG
std::cout << (store_new ? "storing it" : "ignoring it") << "\n";
Log::info("InputManager::inputSensing", store_new ? "storing it" : "ignoring it");
#endif
@ -350,10 +350,9 @@ void InputManager::inputSensing(Input::InputType type, int deviceID,
break;
case Input::IT_STICKMOTION:
{
std::cout << "%% storing new axis binding, value=" << value <<
" deviceID=" << deviceID << " button=" << button <<
" axisDirection=" <<
(axisDirection == Input::AD_NEGATIVE ? "-" : "+") << "\n";
Log::info("InputManager::inputSensing", "Storing new axis binding, value = %d; "
"deviceID = %d; button = %d; axisDirection = %s", value, deviceID, button,
axisDirection == Input::AD_NEGATIVE ? "-" : "+");
// We have to save the direction in which the axis was moved.
// This is done by storing it as a sign (and since button can
// be zero, we add one before changing the sign).
@ -573,8 +572,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID,
InputDevice *device = NULL;
if (type == Input::IT_KEYBOARD)
{
//std::cout << "==== New Player Joining with Key " <<
// button << " ====" << std::endl;
//Log::info("InputManager", "New Player Joining with Key %d", button);
device = m_device_manager->getKeyboardFromBtnID(button);
}
else if (type == Input::IT_STICKBUTTON ||
@ -609,8 +607,8 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID,
if (pk == NULL)
{
std::cerr <<
"Error, trying to process action for an unknown player\n";
Log::error("InputManager::dispatchInput", "Trying to process "
"action for an unknown player");
return;
}
@ -700,8 +698,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID,
void InputManager::setMasterPlayerOnly(bool enabled)
{
#if INPUT_MODE_DEBUG
std::cout <<
"====== InputManager::setMasterPlayerOnly(" << enabled << ") ======\n";
Log::info("InputManager::setMasterPlayerOnly", enabled ? "enabled" : "disabled");
#endif
m_master_player_only = enabled;
}
@ -955,7 +952,7 @@ void InputManager::setMode(InputDriverMode new_mode)
{
case MENU:
#if INPUT_MODE_DEBUG
std::cout << "====== InputManager::setMode(MENU) ======\n";
Log::info("InputManager::setMode", "MENU");
#endif
switch (m_mode)
{
@ -1017,7 +1014,7 @@ void InputManager::setMode(InputDriverMode new_mode)
break;
case INGAME:
#if INPUT_MODE_DEBUG
std::cout << "====== InputManager::setMode(INGAME) ======\n";
Log::info("InputManager::setMode", "INGAME");
#endif
// We must be in menu mode now in order to switch.
assert (m_mode == MENU);
@ -1036,7 +1033,7 @@ void InputManager::setMode(InputDriverMode new_mode)
case INPUT_SENSE_KEYBOARD:
case INPUT_SENSE_GAMEPAD:
#if INPUT_MODE_DEBUG
std::cout << "====== InputManager::setMode(INPUT_SENSE_*) ======\n";
Log::info("InputManager::setMode", "INPUT_SENSE_*");
#endif
// We must be in menu mode now in order to switch.
assert (m_mode == MENU);
@ -1050,7 +1047,7 @@ void InputManager::setMode(InputDriverMode new_mode)
/*
case LOWLEVEL:
#if INPUT_MODE_DEBUG
std::cout << "====== InputManager::setMode(LOWLEVEL) ======\n";
Log::info("InputManager::setMode", "LOWLEVEL");
#endif
// We must be in menu mode now in order to switch.
assert (m_mode == MENU);

Some files were not shown because too many files have changed in this diff Show More