Merge branch 'master' of https://github.com/supertuxkart/stk-code into ScriptCache

This commit is contained in:
Sachith Hasaranga Seneviratne
2014-11-09 14:55:46 +05:30
155 changed files with 4053 additions and 2145 deletions

1
.gitignore vendored
View File

@@ -39,6 +39,7 @@ src/html
*.vcxproj.filters
*.vcxproj.user
*~
*.swp
packets_log.txt
history.dat

View File

@@ -78,10 +78,6 @@ if(USE_WIIUSE)
include_directories("${PROJECT_SOURCE_DIR}/lib/wiiuse")
endif()
# Build the angelscript library
add_subdirectory("${PROJECT_SOURCE_DIR}/lib/angelscript/projects/cmake")
include_directories("${PROJECT_SOURCE_DIR}/lib/angelscript/include")
# Set include paths
include_directories(${STK_SOURCE_DIR})
@@ -101,6 +97,11 @@ elseif(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") # Enable multi-processor compilation (faster)
endif()
# Build the angelscript library
add_subdirectory("${PROJECT_SOURCE_DIR}/lib/angelscript/projects/cmake")
include_directories("${PROJECT_SOURCE_DIR}/lib/angelscript/include")
# OpenAL
if(APPLE)
# In theory it would be cleaner to let CMake detect the right dependencies. In practice, this means that if a OSX user has
@@ -400,4 +401,4 @@ install(FILES ${STK_DATA_DIR}/supertuxkart.desktop DESTINATION share/application
install(FILES data/supertuxkart_32.png DESTINATION share/icons/hicolor/32x32 RENAME supertuxkart.png)
install(FILES data/supertuxkart_128.png DESTINATION share/icons/hicolor/128x128 RENAME supertuxkart.png)
install(FILES data/supertuxkart_32.png data/supertuxkart_128.png DESTINATION share/pixmaps)
install(FILES data/supertuxkart.appdata DESTINATION share/appdata)
install(FILES data/supertuxkart.appdata.xml DESTINATION share/appdata)

View File

@@ -26,11 +26,11 @@ Hope you enjoy the game.
##Compiling SuperTuxKart
###Windows
1. Install VS 2012 or later. The free express versions work fine.
1. Install VS 2013 (or later). The free express versions work fine.
2. Download and install a source package - either a released package or from our [git/svn repositories](http://supertuxkart.sourceforge.net/Source_control)
3. Download the latest dependency package depdendencies_for_0.8.2.zip from [here](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/Windows/). Unzip it in the root directory, so that the dependencies directory is next to the src and data directory (if you are updating from a previous dependency package, you can delete the .dll files in the root directory, they are not needed anymore).
4. Download cmake and install it. Then start cmake-gui and select the STK root directory as 'Where is the source code', and a new directory in the root directory (next to src, data etc) as build directory (for now I assume that this directory is called bld).
5. Click on configure. You will be asked to create the directory (yes), then for your VS version. Make sure to select the right version (be aware of the easy to confuse version numbers: VS 2012 = version 11; VS 2013 = version 12). Click on configure, then generate. This will create the directory 'bld', and a VS solution in that directory.
5. Click on configure. You will be asked to create the directory (yes), then for your VS version. Make sure to select the right version (be aware of the easy to confuse version numbers: VS 2013 = version 12). Click on configure, then generate. This will create the directory 'bld', and a VS solution in that directory.
6. In Visual Studio open the project file generated in the 'bld' folder
7. Right click on the supertuxkart project in the solution explorer, and select "Set as StartUp Project".
8. Select Build->Build Solution (or press F7) to compile.

View File

@@ -4,7 +4,7 @@
<track id="fortmagma" laps="3" reverse="false" />
<track id="minigolf" laps="3" reverse="false" />
<track id="xr591" laps="3" reverse="false" />
<track id="mines" laps="3" reverse="false" />
<track id="minel" laps="3" reverse="false" />
<track id="lighthouse" laps="4" reverse="false" />
</supertuxkart_grand_prix>

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

@@ -20,13 +20,13 @@
I18N="Menu item" text="Move up" />
<icon-button id="down" width="128" height="128" icon="gui/down.png"
I18N="Menu item" text="Move down" />
<icon-button id="add" width="128" height="128" icon="gui/gp_add_track.png"
<icon-button id="add" width="128" height="128" icon="gui/blue_plus.png"
I18N="Menu item" text="Add" />
<icon-button id="edit" width="128" height="128" icon="gui/gp_edit_track.png"
<icon-button id="edit" width="128" height="128" icon="gui/edit.png"
I18N="Menu item" text="Edit" />
<icon-button id="remove" width="128" height="128" icon="gui/gp_remove_track.png"
<icon-button id="remove" width="128" height="128" icon="gui/remove.png"
I18N="Menu item" text="Remove" />
<icon-button id="save" width="128" height="128" icon="gui/gp_save.png"
<icon-button id="save" width="128" height="128" icon="gui/save.png"
I18N="Menu item" text="Save" />
</buttonbar>
</div>

View File

@@ -35,11 +35,11 @@
I18N="Menu item" text="New" />
<icon-button id="copy" width="128" height="128" icon="gui/gp_copy.png"
I18N="Menu item" text="Copy" />
<icon-button id="edit" width="128" height="128" icon="gui/gp_edit.png"
<icon-button id="edit" width="128" height="128" icon="gui/edit.png"
I18N="Menu item" text="Edit" />
<icon-button id="remove" width="128" height="128" icon="gui/gp_remove.png"
I18N="Menu item" text="Remove" />
<icon-button id="rename" width="128" height="128" icon="gui/gp_rename.png"
<icon-button id="rename" width="128" height="128" icon="gui/rename.png"
I18N="Menu item" text="Rename" />
</buttonbar>

View File

@@ -5,7 +5,7 @@
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the change password dialog" text="Password Change"/>
<spacer height="40" width="50">
<spacer height="40" width="50"/>
<div width="80%" align="center" layout="vertical-row" height="fit" >
<div width="100%" height="fit" layout="horizontal-row" >
@@ -13,14 +13,14 @@
<textbox proportion="2" height="fit" id="current_password" I18N="In the change password dialog"/>
</div>
<spacer height="20" width="20">
<spacer height="20" width="20"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the change password dialog" text="New Password"/>
<textbox proportion="2" height="fit" id="new_password1" I18N="In the change password dialog"/>
</div>
<spacer height="20" width="20">
<spacer height="20" width="20"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the change password dialog" text="Confirm"/>
@@ -28,11 +28,11 @@
</div>
</div>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<buttonbar id="options" width="90%" height="16%" align="center">
<icon-button id="submit" width="64" height="64" icon="gui/green_check.png"

View File

@@ -12,7 +12,7 @@
<textbox proportion="1" id="name" I18N="In the create server screen"/>
</div>
<spacer height="20" width="20">
<spacer height="20" width="20"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the create server screen" text="Max. number of players"/>

View File

@@ -10,7 +10,7 @@
<textbox proportion="2" id="name" I18N="In the login dialog"/>
</div>
<spacer height="20" width="20">
<spacer height="20" width="20"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the lobby settings screen" text="Max. number of players"/>

View File

@@ -4,7 +4,7 @@
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<buttonbar id="options" width="90%" height="30%" align="center">
<icon-button id="view" width="64" height="64" icon="gui/difficulty_medium.png"

View File

@@ -5,12 +5,12 @@
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the registration dialog' dialog" text="Account Recovery"/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" I18N="In the registration dialog"
text="You will receive an email with further instructions on how to reset your password. Please be patient and be sure to check your spam folder."/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<buttonbar id="options" width="25%" height="15%" align="center">
<icon-button id="cancel" width="64" height="64" icon="gui/green_check.png"

View File

@@ -5,12 +5,12 @@
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the recovery dialog' dialog" text="Account Recovery"/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<label id="message" proportion="2" width="90%" align="center" text_align="left" word_wrap="true"
text="Fill in the username and email address you supplied at registration to be able to reset your password."/>
<spacer height="40" width="50">
<spacer height="40" width="50"/>
<div width="80%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" >
@@ -18,7 +18,7 @@
<textbox proportion="2" id="username" I18N="In the recovery dialog"/>
</div>
<spacer height="20" width="20">
<spacer height="20" width="20"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the recovery dialog" text="Email"/>
@@ -27,12 +27,12 @@
</div>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true"
I18N="In the recovery" text=""/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<buttonbar id="options" width="25%" proportion="1" align="center">
<icon-button id="submit" width="64" height="64" icon="gui/green_check.png"

View File

@@ -5,7 +5,7 @@
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the registration dialog' dialog" text="Terms and Agreement"/>
<spacer height="25" width="50">
<spacer height="25" width="50"/>
<box proportion="5" width="90%" align="center" layout="vertical-row" padding="8">
<list id="terms" x="0" y="0" width="100%" height="100%"/>
@@ -16,12 +16,12 @@
text="I agree to the above terms and am 13 years or older. "/>
</div>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true"
I18N="In the registration dialog" text=""/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<buttonbar id="options" width="45%" height="14%" align="center">
<icon-button id="accept" width="64" height="64" icon="gui/green_check.png"

View File

@@ -5,7 +5,7 @@
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the server info dialog' dialog" text="Server Info"/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<div width="80%" align="center" layout="vertical-row" height="fit" >
<div width="100%" height="fit" layout="horizontal-row" >
@@ -14,11 +14,11 @@
</div>
</div>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<buttonbar id="options" width="90%" height="20%" align="center">
<icon-button id="join" width="64" height="64" icon="gui/green_check.png"

View File

@@ -4,7 +4,7 @@
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="User info dialog' dialog" text="User Info"/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<div width="80%" align="center" layout="vertical-row" height="fit" >
<div width="100%" height="fit" layout="horizontal-row" >
@@ -13,11 +13,11 @@
</div>
</div>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<buttonbar id="options" width="90%" height="20%" align="center">
<icon-button id="remove" width="64" height="64" icon="gui/package-uninstall.png"

View File

@@ -8,7 +8,7 @@
<spacer width="10" height="10"/>
<div height="fit" width="100%" layout="horizontal-row" align="center">
<textbox id="search_box" height="fit" proportion="1" height="100%"/>
<textbox id="search_box" height="fit" proportion="1"/>
<spacer width="10" height="10"/>
<button id="search_button" height="100%" width="fit" text="Search" />
</div>

View File

@@ -4,17 +4,17 @@
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the vote dialog' dialog" text="Vote"/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<spacer height="20" width="50"/>
<div width="90%" height="64" align="center" layout="vertical-row" >
<ratingbar id="rating" align="center" height="64" width="192"/>
</div>
<spacer height="40" width="50">
<spacer height="40" width="50"/>
<buttonbar id="options" width="25%" height="20%" align="center">
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"

View File

@@ -16,40 +16,68 @@
<box proportion="1" width="100%" layout="vertical-row">
<spacer height="5" width="10"/>
<spacer height="5" width="10" />
<!-- ************ SKIN CHOICE ************ -->
<div layout="horizontal-row" width="100%" height="fit">
<label I18N="In the graphics settings" text="Skin" align="center"/>
<label I18N="In the ui settings" text="Skin" align="center"/>
<spacer width="20" height="20"/>
<spinner id="skinchoice" width="30%"/>
</div>
<spacer width="20" height="18" />
<div width="75%" height="fit" layout="horizontal-row" >
<checkbox id="showfps"/>
<spacer width="20" height="100%" />
<label height="100%" I18N="In the ui settings" text="Display FPS"/>
<div layout="horizontal-row" width="100%" height="fit">
<div proportion="1" height="fit" layout="horizontal-row">
<checkbox id="showfps"/>
<spacer width="20" height="100%" />
<label height="100%" I18N="In the ui settings" text="Display FPS"/>
</div>
<spacer height="4" width="10" />
<div layout="horizontal-row" proportion="1" height="fit">
<checkbox id="perPlayerDifficulty"/>
<spacer width="20" height="100%" />
<label height="100%" I18N="In the ui settings" text="Enable handicaped users"/>
</div>
</div>
<div width="75%" height="fit" layout="horizontal-row" >
<checkbox id="show-login"/>
<spacer width="20" height="100%" />
<label height="100%" I18N="In the ui settings" text="Always show login screen"/>
<spacer height="4" width="10" />
<div layout="horizontal-row" width="100%" height="fit">
<div layout="horizontal-row" proportion="1" height="fit">
<checkbox id="show-login"/>
<spacer width="20" height="100%" />
<label height="100%" I18N="In the ui settings" text="Always show login screen"/>
</div>
<spacer height="4" width="10" />
<div layout="horizontal-row" proportion="1" height="fit">
<checkbox id="aiHandicap"/>
<spacer width="20" height="100%" />
<label height="100%" I18N="In the ui settings" text="Handicap AI karts"/>
</div>
</div>
<div width="75%" height="fit" layout="horizontal-row" >
<checkbox id="enable-internet"/>
<spacer width="20" height="100%" />
<label height="100%" I18N="In the ui settings" text="Allow STK to connect to the Internet"/>
</div>
<spacer height="4" width="10" />
<div width="75%" height="fit" layout="horizontal-row" >
<checkbox id="enable-hw-report"/>
<spacer width="20" height="100%" />
<label id="label-hw-report" height="100%" I18N="In the ui settings"
text="Allow STK to send anonymous HW statistics"/>
<div layout="horizontal-row" width="100%" height="fit">
<div proportion="1" height="fit" layout="horizontal-row" >
<checkbox id="enable-internet"/>
<spacer width="20" height="100%" />
<label height="100%" I18N="In the ui settings" text="Connect to the Internet"/>
</div>
<spacer height="4" width="10" />
<div layout="horizontal-row" proportion="1" height="fit">
<checkbox id="enable-hw-report"/>
<spacer width="20" height="100%" />
<label height="100%" id="label-hw-report" I18N="In the ui settings"
text="Send anonymous HW statistics"/>
</div>
</div>
<spacer height="18" width="4"/>

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -18,7 +18,7 @@
<div layout="horizontal-row" width="fit" height="35" align="left">
<bright proportion="1" height="100%"
I18N="In soccer setup menu" text="Maximum time (min.)" text_align="left" />
<spacer width="50" height ="25">
<spacer width="50" height ="25"/>
<spinner id="timeamount" width="200" height="90%" min_value="1" max_value="15"/>
</div>

View File

@@ -15,7 +15,7 @@
<spacer height="15" width="10"/>
<div width="90%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="online" I18N="In the login screen" text_align="left"/>
<checkbox width="fit" id="online" I18N="In the user screen" text_align="left"/>
<spacer width="10"/>
<label proportion="1" height="100%" text_align="left" I18N="In the login screen" text="Online"/>
</div>
@@ -28,13 +28,13 @@
<!-- Disable guest accounts for now
<div width="100%" height="fit" layout="horizontal-row" >
<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"/>
I18N="In the user screen" text="Guest login"/>
<checkbox id="guest" I18N="In the user screen" text_align="left"/>
</div>
-->
<div width="100%" height="fit" layout="horizontal-row" >
<label width="40%" id="label_username" height="100%" text_align="left"
I18N="In the login screen" text="Username"/>
I18N="In the user screen" text="Username"/>
<textbox id="username" proportion="2" height="fit" I18N="In the registration dialog"/>
</div>
<spacer height="20" width="20"/>
@@ -52,9 +52,9 @@
<buttonbar id="options" width="90%" height="13%" align="bottom">
<icon-button id="ok" width="64" height="64" icon="gui/green_check.png"
I18N="Login dialog" text="OK" label_location="bottom"/>
<icon-button id="new_user" width="64" height="64" icon="gui/gp_add_track.png"
<icon-button id="new_user" width="64" height="64" icon="gui/blue_plus.png"
I18N="Login dialog" text="Add user" label_location="bottom"/>
<icon-button id="delete" width="64" height="64" icon="gui/gp_remove_track.png"
<icon-button id="delete" width="64" height="64" icon="gui/remove.png"
I18N="Login dialog" text="Delete" label_location="bottom"/>
<icon-button id="rename" width="64" height="64" icon="gui/gp_rename.png"
I18N="Login dialog" text="Rename" label_location="bottom"/>

View File

@@ -32,18 +32,18 @@
<checkbox width="fit" id="remember-user" I18N="In the login screen" text_align="left"/>
<spacer width="10"/>
<label id="label_remember" proportion="1" height="100%" text_align="left"
I18N="In the login screen" text="Remember password"/>
I18N="In the user screen" text="Remember password"/>
</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"
I18N="In the login screen" text="Guest login"/>
<checkbox id="guest" I18N="In the login screen" text_align="left"/>
I18N="In the user screen" text="Guest login"/>
<checkbox id="guest" I18N="In the user screen" text_align="left"/>
</div>
-->
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_username" width="40%" height="100%" text_align="left"
I18N="In the login screen" text="Username"/>
I18N="In the user screen" text="Username"/>
<textbox id="username" proportion="2" height="fit" I18N="In the registration dialog"/>
</div>
<spacer height="20" width="20"/>
@@ -61,11 +61,11 @@
<buttonbar id="options" width="90%" height="13%" align="center">
<icon-button id="ok" width="64" height="64" icon="gui/green_check.png"
I18N="Login dialog" text="OK" label_location="bottom"/>
<icon-button id="new_user" width="64" height="64" icon="gui/gp_add_track.png"
<icon-button id="new_user" width="64" height="64" icon="gui/blue_plus.png"
I18N="Login dialog" text="Add user" label_location="bottom"/>
<icon-button id="delete" width="64" height="64" icon="gui/gp_remove_track.png"
<icon-button id="delete" width="64" height="64" icon="gui/remove.png"
I18N="Login dialog" text="Delete" label_location="bottom"/>
<icon-button id="rename" width="64" height="64" icon="gui/gp_rename.png"
<icon-button id="rename" width="64" height="64" icon="gui/rename.png"
I18N="Login dialog" text="Rename" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="Login dialog" text="Cancel" label_location="bottom"/>

View File

@@ -0,0 +1,142 @@
uniform sampler2D depth;
uniform float split0;
uniform float split1;
uniform float split2;
uniform float splitmax;
uniform mat4 SunCamMatrix;
layout (local_size_x = 8, local_size_y = 8) in;
struct CascadeBoundingBox
{
int xmin;
int xmax;
int ymin;
int ymax;
int zmin;
int zmax;
};
layout (std430) buffer BoundingBoxes
{
CascadeBoundingBox BB[4];
};
vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix);
shared int xmin[4];
shared int xmax[4];
shared int ymin[4];
shared int ymax[4];
shared int zmin[4];
shared int zmax[4];
void main()
{
if (gl_LocalInvocationIndex < 4) {
xmin[gl_LocalInvocationIndex] = ymin[gl_LocalInvocationIndex] = zmin[gl_LocalInvocationIndex] = 1000;
xmax[gl_LocalInvocationIndex] = ymax[gl_LocalInvocationIndex] = zmax[gl_LocalInvocationIndex] = -1000;
}
barrier();
ivec3 lmax0 = ivec3(-1000);
ivec3 lmin0 = ivec3(1000);
ivec3 lmax1 = ivec3(-1000);
ivec3 lmin1 = ivec3(1000);
ivec3 lmax2 = ivec3(-1000);
ivec3 lmin2 = ivec3(1000);
ivec3 lmax3 = ivec3(-1000);
ivec3 lmin3 = ivec3(1000);
vec2 start_xy = gl_LocalInvocationID.xy + gl_WorkGroupID.xy * gl_WorkGroupSize.xy * 8;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
vec2 uv = (start_xy + vec2(i, j) * gl_WorkGroupID.xy) / screen;
float z = texture(depth, uv).x;
vec4 xpos = getPosFromUVDepth(vec3(uv, z), InverseProjectionMatrix);
vec4 lightcoord = InverseViewMatrix * xpos;
lightcoord /= lightcoord.w;
lightcoord = SunCamMatrix * lightcoord;
lightcoord /= lightcoord.w;
ivec3 lc = ivec3(lightcoord.xyz) * 4;
if (xpos.z < split0) {
lmax0 = max(lmax0, lc);
lmin0 = min(lmin0, lc);
} else if (xpos.z < split1) {
lmax1 = max(lmax1, lc);
lmin1 = min(lmin1, lc);
} else if (xpos.z < split2) {
lmax2 = max(lmax2, lc);
lmin2 = min(lmin2, lc);
} else if (xpos.z < splitmax) {
lmax3 = max(lmax3, lc);
lmin3 = min(lmin3, lc);
}
}
}
atomicMax(xmax[0], lmax0.x);
atomicMax(ymax[0], lmax0.y);
atomicMax(zmax[0], lmax0.z);
atomicMin(xmin[0], lmin0.x);
atomicMin(ymin[0], lmin0.y);
atomicMin(zmin[0], lmin0.z);
atomicMax(xmax[1], lmax1.x);
atomicMax(ymax[1], lmax1.y);
atomicMax(zmax[1], lmax1.z);
atomicMin(xmin[1], lmin1.x);
atomicMin(ymin[1], lmin1.y);
atomicMin(zmin[1], lmin1.z);
atomicMax(xmax[2], lmax2.x);
atomicMax(ymax[2], lmax2.y);
atomicMax(zmax[2], lmax2.z);
atomicMin(xmin[2], lmin2.x);
atomicMin(ymin[2], lmin2.y);
atomicMin(zmin[2], lmin2.z);
atomicMax(xmax[3], lmax3.x);
atomicMax(ymax[3], lmax3.y);
atomicMax(zmax[3], lmax3.z);
atomicMin(xmin[3], lmin3.x);
atomicMin(ymin[3], lmin3.y);
atomicMin(zmin[3], lmin3.z);
barrier();
if (gl_LocalInvocationIndex == 0) {
atomicMax(BB[0].xmax, xmax[0]);
atomicMax(BB[0].ymax, ymax[0]);
atomicMax(BB[0].zmax, zmax[0]);
atomicMin(BB[0].xmin, xmin[0]);
atomicMin(BB[0].ymin, ymin[0]);
atomicMin(BB[0].zmin, zmin[0]);
atomicMax(BB[1].xmax, xmax[1]);
atomicMax(BB[1].ymax, ymax[1]);
atomicMax(BB[1].zmax, zmax[1]);
atomicMin(BB[1].xmin, xmin[1]);
atomicMin(BB[1].ymin, ymin[1]);
atomicMin(BB[1].zmin, zmin[1]);
atomicMax(BB[2].xmax, xmax[2]);
atomicMax(BB[2].ymax, ymax[2]);
atomicMax(BB[2].zmax, zmax[2]);
atomicMin(BB[2].xmin, xmin[2]);
atomicMin(BB[2].ymin, ymin[2]);
atomicMin(BB[2].zmin, zmin[2]);
atomicMax(BB[3].xmax, xmax[3]);
atomicMax(BB[3].ymax, ymax[3]);
atomicMax(BB[3].zmax, zmax[3]);
atomicMin(BB[3].xmin, xmin[3]);
atomicMin(BB[3].ymin, ymin[3]);
atomicMin(BB[3].zmin, zmin[3]);
}
}

View File

@@ -0,0 +1,55 @@
uniform sampler2D depth;
layout (local_size_x = 32, local_size_y = 32) in;
layout (std430) buffer Histogram
{
int bin[1024];
int mindepth;
int maxdepth;
int count;
};
vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix);
shared int sbin[1024];
shared int smindepth;
shared int smaxdepth;
shared int scount;
void main()
{
int x = int(gl_GlobalInvocationID.x), y = int(gl_GlobalInvocationID.y);
vec2 uv = vec2(x, y) / screen;
float z = texture(depth, uv).x;
vec4 xpos = getPosFromUVDepth(vec3(uv, z), InverseProjectionMatrix);
int lineardepth = int(xpos.z * 4);
sbin[gl_LocalInvocationIndex] = 0;
if (gl_LocalInvocationIndex == 0) {
smindepth = 1000;
smaxdepth = 0;
scount = 0;
}
barrier();
if (lineardepth < 1000) {
atomicAdd(sbin[lineardepth], 1);
atomicAdd(scount, 1);
atomicMin(smindepth, lineardepth);
atomicMax(smaxdepth, lineardepth);
}
barrier();
atomicAdd(bin[gl_LocalInvocationIndex], sbin[gl_LocalInvocationIndex]);
if (gl_LocalInvocationIndex == 0) {
atomicAdd(count, scount);
atomicMin(mindepth, smindepth);
atomicMax(maxdepth, smaxdepth);
}
}

View File

@@ -49,10 +49,10 @@ void main(void)
vec3 sampleDirection = reflect(-eyedir, normal);
sampleDirection = (InverseViewMatrix * vec4(sampleDirection, 0.)).xyz;
float specval = texture(ntex, uv).z;
float specval = pow(texture(ntex, uv).z, 2.);
// From http://graphics.cs.williams.edu/papers/EnvMipReport2013/
int texSize = textureSize(tex, 0).x;
float lodval = clamp(log2(texSize * sqrt(3)) - .5 * log2(specval + 1), 0., 10.);
float lodval = clamp(log2(texSize * sqrt(3.)) - .5 * log2(specval + 1.), 0., 10.);
vec4 specular = textureLod(tex, sampleDirection, lodval);
Spec = max(specular, vec4(0.));
}

View File

@@ -1,6 +1,8 @@
uniform sampler2D tex;
uniform vec2 pixel;
float sigma = 1.;
// Gaussian separated blur with radius 6.
out vec4 FragColor;
@@ -8,17 +10,22 @@ out vec4 FragColor;
void main()
{
vec2 uv = gl_FragCoord.xy * pixel;
vec4 sum = vec4(0.0);
float X = uv.x;
float Y = uv.y;
sum += texture(tex, vec2(X - 5.13333 * pixel.x, Y)) * 0.00640869;
sum += texture(tex, vec2(X - 3.26667 * pixel.x, Y)) * 0.083313;
sum += texture(tex, vec2(X - 1.4 * pixel.x, Y)) * 0.305481;
sum += texture(tex, vec2(X, Y)) * 0.209473;
sum += texture(tex, vec2(X + 1.4 * pixel.x, Y)) * 0.305481;
sum += texture(tex, vec2(X + 3.26667 * pixel.x, Y)) * 0.083313;
sum += texture(tex, vec2(X + 5.13333 * pixel.x, Y)) * 0.00640869;
float g0, g1, g2;
g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma);
g1 = exp(-0.5 / (sigma * sigma));
g2 = g1 * g1;
vec4 sum = texture(tex, vec2(X, Y)) * g0;
g0 *= g1;
g1 *= g2;
for (int i = 1; i < 6; i++) {
sum += texture(tex, vec2(X - i * pixel.x, Y)) * g0;
sum += texture(tex, vec2(X + i * pixel.x, Y)) * g0;
g0 *= g1;
g1 *= g2;
}
FragColor = sum;
}

View File

@@ -1,6 +1,8 @@
uniform sampler2D tex;
uniform vec2 pixel;
float sigma = 1.;
// Gaussian separated blur with radius 6.
out vec4 FragColor;
@@ -8,17 +10,22 @@ out vec4 FragColor;
void main()
{
vec2 uv = gl_FragCoord.xy * pixel;
vec4 sum = vec4(0.0);
float X = uv.x;
float Y = uv.y;
sum += texture(tex, vec2(X, Y - 5.13333 * pixel.y)) * 0.00640869;
sum += texture(tex, vec2(X, Y - 3.26667 * pixel.y)) * 0.083313;
sum += texture(tex, vec2(X, Y - 1.4 * pixel.y)) * 0.305481;
sum += texture(tex, vec2(X, Y)) * 0.209473;
sum += texture(tex, vec2(X, Y + 1.4 * pixel.y)) * 0.305481;
sum += texture(tex, vec2(X, Y + 3.26667 * pixel.y)) * 0.083313;
sum += texture(tex, vec2(X, Y + 5.13333 * pixel.y)) * 0.00640869;
float g0, g1, g2;
g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma);
g1 = exp(-0.5 / (sigma * sigma));
g2 = g1 * g1;
vec4 sum = texture(tex, vec2(X, Y)) * g0;
g0 *= g1;
g1 *= g2;
for (int i = 1; i < 6; i++) {
sum += texture(tex, vec2(X, Y - i * pixel.y)) * g0;
sum += texture(tex, vec2(X, Y + i * pixel.y)) * g0;
g0 *= g1;
g1 *= g2;
}
FragColor = sum;
}

View File

@@ -17,5 +17,5 @@ void main(void)
vec4 col = texture(tex, uv);
#endif
if (col.a < 0.5) discard;
FragColor = vec4(1.);
FragColor = vec4(exp(8. * (2. * gl_FragCoord.z - 1.) / gl_FragCoord.w));
}

6
data/shaders/shadow.frag Normal file
View File

@@ -0,0 +1,6 @@
out vec4 FragColor;
void main()
{
FragColor = vec4(exp(8. * (2. * gl_FragCoord.z - 1.) / gl_FragCoord.w));
}

View File

@@ -0,0 +1,16 @@
#ifdef GL_ARB_bindless_texture
layout(bindless_sampler) uniform sampler2D tex;
#else
uniform sampler2D tex;
#endif
in vec2 uv;
in vec4 color;
out vec4 FragColor;
void main(void)
{
vec4 col = texture(tex, uv);
if (col.a < 0.5) discard;
FragColor = vec4(exp(8. * (2. * gl_FragCoord.z - 1.) / gl_FragCoord.w));
}

View File

@@ -1,14 +1,14 @@
uniform sampler2D ntex;
uniform sampler2D dtex;
uniform sampler2DArrayShadow shadowtex;
//uniform sampler2D warpx;
///uniform sampler2D warpy;
uniform sampler2DArray shadowtex;
uniform float split0;
uniform float split1;
uniform float split2;
uniform float splitmax;
uniform vec3 direction;
uniform vec3 col;
//uniform int hasclouds;
//uniform vec2 wind;
//uniform float shadowoffset;
in vec2 uv;
out vec4 Diff;
@@ -20,8 +20,7 @@ vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix);
float getShadowFactor(vec3 pos, float bias, int index)
{
//float a[5] = float[](3.4, 4.2, 5.0, 5.2, 1.1);
vec2 shadowoffset[4] = vec2[](
vec2(-1., -1.),
vec2(-1., 1.),
@@ -30,25 +29,12 @@ float getShadowFactor(vec3 pos, float bias, int index)
);
vec4 shadowcoord = (ShadowViewProjMatrixes[index] * InverseViewMatrix * vec4(pos, 1.0));
shadowcoord /= shadowcoord.w;
shadowcoord.xy /= shadowcoord.w;
vec2 shadowtexcoord = shadowcoord.xy * 0.5 + 0.5;
// shadowcoord = (shadowcoord * 0.5) + vec3(0.5);
// float movex = decdepth(texture(warpx, shadowcoord.xy));
// float movey = decdepth(texture(warpy, shadowcoord.xy));
// float dx = movex * 2.0 - 1.0;
// float dy = movey * 2.0 - 1.0;
// shadowcoord.xy += vec2(dx, dy);*/
//float shadowmapz = 2. * texture(shadowtex, vec3(shadowtexcoord, shadowcoord.z).x - 1.;
// bias += smoothstep(0.001, 0.1, moved) * 0.014; // According to the warping
float sum = 0.;
for (float i = -1.5; i <= 1.5; i+= 1.)
{
for (float j = -1.5; j <= 1.5; j+= 1.)
sum += texture(shadowtex, vec4(shadowtexcoord +vec2(i, j) / 1024., float(index), 0.5 * shadowcoord.z + 0.5));
}
return sum / 16.;
float z = texture(shadowtex, vec3(shadowtexcoord, float(index))).x;
float d = shadowcoord.z;
return min(pow(exp(-8. * d) * z, 256.), 1.);
}
void main() {
@@ -70,86 +56,41 @@ void main() {
vec3 outcol = NdotL * col;
// if (hasclouds == 1)
// {
// vec2 cloudcoord = (xpos.xz * 0.00833333) + wind;
// float cloud = texture(cloudtex, cloudcoord).x;
// //float cloud = step(0.5, cloudcoord.x) * step(0.5, cloudcoord.y);
// outcol *= cloud;
// }
// Shadows
float bias = 0.005 * tan(acos(NdotL)); // According to the slope
bias = clamp(bias, 0., 0.01);
float factor;
if (xpos.z < 5.)
if (xpos.z < split0)
factor = getShadowFactor(xpos.xyz, bias, 0);
else if (xpos.z < 6.)
/* else if (xpos.z < 6.)
{
float a = getShadowFactor(xpos.xyz, bias, 0), b = getShadowFactor(xpos.xyz, bias, 1);
factor = mix(a, b, (xpos.z - 5.));
}
else if (xpos.z < 20.)
}*/
else if (xpos.z < split1)
factor = getShadowFactor(xpos.xyz, bias, 1);
else if (xpos.z < 21.)
/* else if (xpos.z < 21.)
{
float a = getShadowFactor(xpos.xyz, bias, 1), b = getShadowFactor(xpos.xyz, bias, 2);
factor = mix(a, b, (xpos.z - 20.));
}
else if (xpos.z < 50.)
}*/
else if (xpos.z < split2)
factor = getShadowFactor(xpos.xyz, bias, 2);
else if (xpos.z < 55.)
/* else if (xpos.z < 55.)
{
float a = getShadowFactor(xpos.xyz, bias, 2), b = getShadowFactor(xpos.xyz, bias, 3);
factor = mix(a, b, (xpos.z - 50.) / 5.);
}
else if (xpos.z < 145.)
}*/
else if (xpos.z < splitmax)
factor = getShadowFactor(xpos.xyz, bias, 3);
else if (xpos.z < 150.)
/* else if (xpos.z < 150.)
{
factor = mix(getShadowFactor(xpos.xyz, bias, 3), 1., (xpos.z - 145.) / 5.);
}
}*/
else
factor = 1.;
Diff = vec4(factor * NdotL * col, 1.);
Spec = vec4(factor * Specular, 1.);
return;
// float moved = (abs(dx) + abs(dy)) * 0.5;
// float avi = 0.002;
// float abi = 0.0025;
/* float avi = 0.0018;
float abi = 0.002;
float bias = avi * tan(acos(NdotL)); // According to the slope
bias += smoothstep(0.001, 0.1, moved) * abi; // According to the warping
bias = clamp(bias, 0.001, abi);
// This ID, and four IDs around this must match for a shadow pixel
float right = texture(shadowtex, shadowcoord.xy + vec2(shadowoffset, 0.0)).a;
float left = texture(shadowtex, shadowcoord.xy + vec2(-shadowoffset, 0.0)).a;
float up = texture(shadowtex, shadowcoord.xy + vec2(0.0, shadowoffset)).a;
float down = texture(shadowtex, shadowcoord.xy + vec2(0.0, -shadowoffset)).a;
float matching = ((right + left + up + down) * 0.25) - shadowread.a;
matching = abs(matching) * 400.0;
// If the ID is different, we're likely in shadow - cut the bias to cut peter panning
float off = 7.0 - step(abs(shadowread.a - depthread.a) - matching, 0.004) * 6.0;
bias /= off;
const float softness = 8.0; // How soft is the light?
float shadowed = step(shadowmapz + bias, shadowcoord.z);
float dist = (shadowcoord.z / shadowmapz) - 1.0;
float penumbra = dist * softness / gl_FragCoord.z;
penumbra *= shadowed;*/
/* outcol.r = (shadowcoord.z - shadowmapz) * 50.0;
outcol.g = moved;*/
// FragColor = vec4(outcol, 0.05);
// OtherOutput = vec4(shadowed, penumbra, shadowed, shadowed);
}

View File

@@ -4,7 +4,7 @@ uniform sampler2D tex;
uniform sampler2D logluminancetex;
uniform float exposure = .09;
uniform float Lwhite = 1.;
uniform float vignette_weight = 0.;
uniform float vignette_weight;
out vec4 FragColor;

View File

@@ -25,13 +25,13 @@
</grand-prix>
<!-- Time in follow-the-leader after which karts are removed.
The last values applies for all remaining karts.
The last values applies for all remaining karts.
time-per-kart Additional time added to the interval
for each kart in the race. -->
<follow-the-leader intervals="30 20 10"
time-per-kart="1.5" />
<!-- Startup information.
<!-- Startup information.
Penalty: Penalty time if a kart accelerates before GO. -->
<startup penalty="1" />
@@ -74,11 +74,11 @@
<!-- Skidmark data: maximum number of skid marks, and
time for skidmarks to fade out. -->
<skid-marks max-number="100" fadeout-time="60"/>
<!-- Defines when the upright constraint should be acctive, it's
<skid-marks max-number="100" fadeout-time="60"/>
<!-- Defines when the upright constraint should be active, it's
disabled when the kart is more than this value from the track. -->
<near-ground distance="2"/>
<near-ground distance="2"/>
<!-- How long the end animation will be shown. -->
<delay-finish time="0.5"/>
@@ -99,16 +99,16 @@
need to be lost.
ubound-fraction is the upper bound fraction of speed when lost will
detach parachute. E.g. at max-speed 30% of speed must be lost.
max-speed is a factor that decides the impact of rate of speed
max-speed is a factor that decides the impact of rate of speed
(distance between bounds) -->
<parachute friction="2.0" time="4.0" time-other="8.0"
<parachute friction="2.0" time="4.0" time-other="8.0"
lbound-fraction="0.95" ubound-fraction="0.7" max-speed="23"/>
<!-- time is the time till a bomb explodes. time-increase is the time added
<!-- time is the time till a bomb explodes. time-increase is the time added
to timer when bomb is passed on. -->
<bomb time="30.0" time-increase="-5.0"/>
<!-- Powerup collect-mode decides what is collected if a kart has already an
<!-- Powerup collect-mode decides what is collected if a kart has already an
powerup: same: get one more item of the same type.
new: always get a new item.
only-if-same: if the random item is the same one as the
@@ -121,9 +121,9 @@
nolok-bubble-gum, easter egg -->
<switch time="5" items="1 0 4 4 2 5 2 7"/>
<!-- disappear-counter: How often bubblegum gets driven over before it disappears.
shield-time: How long the bubblegum shield lasts
restrict-weapons: If true, using weapons will destroy the user's shield -->
<!-- disappear-counter: How often bubblegum gets driven over before it disappears.
shield-time: How long the bubblegum shield lasts
restrict-weapons: If true, using weapons will destroy the user's shield -->
<bubblegum disappear-counter="1" shield-time="10.0" restrict-weapons="false"/>
<!-- explosion-impulse-objects is the impulse that pushes physical objects
@@ -134,10 +134,10 @@
work anymore - so for now don't enable this. -->
<networking enable="false"/>
<!-- disable-while-unskid: Disable steering when stop skidding during
<!-- disable-while-unskid: Disable steering when stop skidding during
the time it takes to adjust the physical body with the graphics.
camera-follow-skid: If true the camera will stay behind the kart,
potentially making it easier to see where the kart is going to
potentially making it easier to see where the kart is going to
after a skid. -->
<steer disable-while-unskid="false"
camera-follow-skid="true" />
@@ -145,23 +145,31 @@
<!-- Default values for all karts
============================ -->
<general-kart-defaults>
<!-- Camera: Distance between kart and camera.
forward-up-angle: Angle between camera and plane of kart (pitch)
<!-- Camera: Distance between kart and camera.
forward-up-angle: Angle between camera and plane of kart (pitch)
when the camera is pointing forward
backward-up-angke: Angle between camera and plane of kart (pitch)
when the camera is pointing backwards. This is usually
backward-up-angle: Angle between camera and plane of kart (pitch)
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.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"/>
<!-- Options to affect the graphical chassis:
y-offset: Additional offset to move graphical chassis with regards
to the physics, used to reduce frequencey of graphical
chassis in terrain.
prevent-chassis-in-terrain: a hard flag to prevent nearly all instances
of chassis in terrain. Can (atm) cause some stuttering. -->
<graphics y-offset="0.0"
prevent-chassis-in-terrain="true"
/>
<!-- Jump animation related values:
animation-time: only if the estimated time for a jump is larger
than this value will the jump animation being shown. -->
<jump animation-time="0.5" />
<!-- Jump animation related values:
animation-time: only if the estimated time for a jump is larger
than this value will the jump animation being
shown. -->
<jump animation-time="0.5" />
<!-- Skidding: increase: multiplicative increase of skidding factor in each frame.
decrease: multiplicative decrease of skidding factor in each frame.
@@ -182,16 +190,16 @@
bonus-force: Additional engine force (this is used to offset the fact
that turning after skidding (e.g. to correct direction) often uses
up the skid bonus).
post-skid-rotate-factor: a factor to be used to determine how much
the chassis of a kart should rotate to match the graphical view.
post-skid-rotate-factor: a factor to be used to determine how much
the chassis of a kart should rotate to match the graphical view.
A factor of 1 is identical, a smaller factor will rotate the kart
less (which might feel better).
less (which might feel better).
physical-jump-time: Time for a physical jump at the beginning of a skid.
graphical-jump-time: Time for a graphics-only jump at the beginning
of a skid.
reduce-turn-min/max: The steering done by the controller (which is in
[-1,1]) is mapped to [reduce-turn-min, reduce-turn-max] when skidding
is active (for left turn, right turn will use [-max, -min]). The
is active (for left turn, right turn will use [-max, -min]). The
effect is that while you skid (say left) you can adjust the direction
of the turn the kart is doing somewhat by steering to the left and right,
but you will always keep on doing a left turn, just more or less. -->
@@ -222,12 +230,12 @@
max-item-angle: Items that would need more than this change in
direction are not considered for collection.
time-full-steer is the time for the AI to go from neutral steering to
extreme left (or right). This can be used to reduce
extreme left (or right). This can be used to reduce
'shaking' of AI karts caused by changing steering direction
too often. It also helps with making it easier to push the
AI karts (otherwise micro-corrections make this nearly
impossible). A value of 1/maxFPS / 2 will guarantee that
the wheel can go from -1 to +1 steering in one frame,
the wheel can go from -1 to +1 steering in one frame,
basically disabling this mechanism.
bad-item-closeness is the maximum distance between a good and a
bad item which can force the AI to abandon a good item in order
@@ -238,7 +246,7 @@
section of the track should have in order to activate a zipper.
competitive when ahead of the player, or more competitive
when behind the player.
when behind the player.
skid-probability: Since the AI is usually very good at using
skidding, this is used to implement some rubber-banding for
@@ -259,7 +267,7 @@
the speed the kart can drive at!
collect-item-probability: Probability of the AI actually
trying to collect an item (if an item is selected for
collection in the first place).
collection in the first place).
-->
<ai>
<easy time-full-steer="0.1"
@@ -335,11 +343,52 @@
skidding-threshold="2.0"
/>
</ai>
<!-- The per-player difficulties in multiplayer games.
These values are multiplied with the current values of a car
so 1 means that nothing changes.
The meaning of the different values is explained below this tag. -->
<difficulties>
<normal>
<mass value="1.0"/>
<engine brake-factor="1.0" brake-time-increase="1.0" max-speed-reverse-ratio="1.0" power="1.0" max-speed="1.0"/>
<nitro consumption="1.0" max-speed-increase="1.0" duration="1.0" fade-out-time="1.0"/>
<bubblegum time="1.0" speed-fraction="1.0" torque="1.0" fade-in-time="1.0"/>
<rescue time="1.0"/>
<explosion time="1.0" radius="1.0" invulnerability-time="1.0"/>
<slipstream length="1.0" width="1.0" collect-time="1.0" use-time="1.0"
add-power="1.0" min-speed="1.0" max-speed-increase="1.0" duration="1.0"
fade-out-time="1.0"/>
<plunger band-max-length="1.0" band-force="1.0" band-duration="1.0"
band-speed-increase="1.0" band-fade-out-time="1.0" in-face-time="1.0"/>
<zipper time="1.0" force="1.0" speed-gain="1.0" max-speed-increase="1.0"
fade-out-time="1.0"/>
<swatter duration="1.0" squash-duration="1.0" squash-slowdown="1.0"/>
<startup time="1.0 1.0" boost="1.0 1.0"/>
</normal>
<handicap>
<mass value="1.0"/>
<engine brake-factor="0.8" brake-time-increase="0.85" max-speed-reverse-ratio="0.8" power="0.8" max-speed="0.8"/>
<nitro consumption="1.1" max-speed-increase="0.9" duration="1.0" fade-out-time="1.0"/>
<bubblegum time="1.5" speed-fraction="1.5" torque="1.5" fade-in-time="1.0"/>
<rescue time="1.5"/>
<explosion time="1.3" invulnerability-time="0.7"/>
<slipstream length="0.8" width="0.8" collect-time="1.5" use-time="0.8"
add-power="0.8" min-speed="0.8" max-speed-increase="0.9" duration="0.8"
fade-out-time="1.0"/>
<plunger band-max-length="0.8" band-force="1.0" band-duration="1.0"
band-speed-increase="0.8" band-fade-out-time="1.0" in-face-time="1.3"/>
<zipper time="0.8" force="0.8" speed-gain="0.8" max-speed-increase="0.8"
fade-out-time="1.0"/>
<swatter duration="0.8" squash-duration="1.5" squash-slowdown="1.8"/>
<startup time="0.8 0.8" boost="0.8 0.8"/>
</handicap>
</difficulties>
<!-- Suspension related values. stiffness: kart's suspension stiffness.
rest: Length of suspension when at rest.
travel-cm: maximum movement of suspension - in cm!!
exp-string-response: dampen the suspension spring reaction
rest: Length of suspension when at rest.
travel-cm: maximum movement of suspension - in cm!!
exp-string-response: dampen the suspension spring reaction
exponentially.
max-force: Maximum suspension force -->
<suspension stiffness="140" rest="0.3" travel-cm="29"
@@ -347,9 +396,9 @@
<!-- Wheel related parameters: damping-relaxation/compression: for
bullet, damping parameters. Radius and width of wheel.
front-right, front-left, rear-right and rear-left give the
front-right, front-left, rear-right and rear-left give the
position of the physics raycast wheels relative to the center of
gravity. Default is to use the corners of the chassis to attach
gravity. Default is to use the corners of the chassis to attach
the wheels to. -->
<wheels damping-relaxation="35" damping-compression="5" radius="0.25">
<front-right position="0.38 0 0.6" />
@@ -357,20 +406,20 @@
<rear-right position="0.38 0 -0.6" />
<rear-left position="-0.38 0 -0.6"/>
</wheels>
<!-- Parameters for the speed-weighted objects:
a bigger value for strength-factor leads to the speed of the kart more quickly affecting
the strength of the animation (up to a maximum value that corresponds to the original animation) -->
<speed-weighted-objects strength-factor="0.05" speed-factor="1.0" texture-speed-x="0.0" texture-speed-y="0.0"/>
<!-- friction: slip used for bullet skidding. A high value
<!-- friction: slip used for bullet skidding. A high value
(like 10000000) disables bullet skidding. -->
<friction slip="10000000"/>
<!-- Values related to stability of the chassis: damping, and reduced
impact of roll.
impact of roll.
downward-impulse-factor: A speed proportional impulse applied each
frame that pushes the vehicle onto the ground.
frame that pushes the vehicle onto the ground.
track-connection-accel: An artificial force that pulls a wheel to
the ground if its off ground. Reduces the affect if a kart loses
contact with the ground (i.e. it then can't steer or accelerate
@@ -391,7 +440,7 @@
'normal': impulse along the normal
'driveline': impulse towards the nearest driveline.
An impulse towards the driveline works nice when the kart is
driving more or less correctly on the track - it pushes the
driving more or less correctly on the track - it pushes the
kart in the right direction. But if the kart is significanlty
off track, it has severe problems (since an incorrect
driveline point can be selected, pusing the kart in the
@@ -403,15 +452,15 @@
period, which results in less abrupt changes. If set to 0,
the impulse is only applied once.
resitution: restitution value to be used for the kart rigid bodies.
bevel-factor: for each point of the chassis collision box one
bevel-factor: for each point of the chassis collision box one
additional point is added, resulting in a bevelled box shape.
The original Z coordinate of the chassis is multiplied by
The original Z coordinate of the chassis is multiplied by
1-bevelZ (i.e. the main box part of the shape is shortened).
The bevel point has the original Z coordinate, and the X and
Y coordinates of the box are multiplied with (1-bevelX) and
The bevel point has the original Z coordinate, and the X and
Y coordinates of the box are multiplied with (1-bevelX) and
(1-bevelY). A value of 0 for all bevel coordinates disables
bevelling, and uses a simple box shape.
As an example, a value of 1 for x and z will result in a
As an example, a value of 1 for x and z will result in a
sharp 'arrow' like shape.
physical-wheel-position: Defines where the 'physical' (raycast)
wheel will be located. It's a weight factor with 0 = being
@@ -420,7 +469,7 @@
physics settings are used which places the raycast wheels
outside of the chassis and results in more stable physical
behaviour of the karts. -->
<collision impulse-type="normal"
<collision impulse-type="normal"
impulse="3000" impulse-time="0.1" terrain-impulse="1600"
restitution="1.0" bevel-factor="0.5 0.0 0.7"
physical-wheel-position="-1" />
@@ -428,131 +477,131 @@
<!-- If a kart starts within the specified time after 'go',
it receives the corresponding bonus from 'boost'. Those
fields must have the same size, and must be sorted by
increasing times. -->
<startup time = "0.3 0.5"
boost = "6 3" />
increasing times. -->
<startup time = "0.3 0.5"
boost = "6 3" />
<!-- Rescue: time: How long it takes the kart to be raised.
height: how height the kart will be raised before it is
dropped back onto the track.
dropped back onto the track.
vert rescue offset: used to raise karts a bit higher before
releasing them on the ground after a rescue. Used to avoid
resetting karts into the track. Not sure if this is still
necessary. -->
<rescue vert-offset="0.0" time="1.2" height="2"/>
<rescue vert-offset="0.0" time="1.2" height="2"/>
<!-- Nitro: engine-force: additional engine power
consumption: nitro consumption - heavier characters can be set
to need more nitro than lighter character.
small-container: how much energy a small container gives.
big-container: how much energy a big container gives.
big-container: how much energy a big container gives.
max-speed-increase: How much the speed of a kart might exceed
its maximum speed (in m/s).
its maximum speed (in m/s).
duration: How long the increased speed will be valid after
the kart stops using nitro (and the fade-out-time starts).
fade-out-time: Duration during which the increased maximum
speed due to nitro fades out.
speed due to nitro fades out.
max: How much nitro a kart can store.
-->
<nitro engine-force="500" consumption="1" small-container="1" big-container="3"
max-speed-increase="5" duration="1" fade-out-time="2" max="20"/>
<nitro engine-force="500" consumption="1" small-container="1" big-container="3"
max-speed-increase="5" duration="1" fade-out-time="2" max="20"/>
<!-- Bubble gum data:
time: How long the bubblegum lasts.
speed-fraction: To what fraction of top-speed the speed is reduced.
torque: To rotate the kart somewhat.
fade-in-time: How quick the slowdown takes effect.
-->
<bubblegum time="1" speed-fraction="0.3" torque="500" fade-in-time="0.01"/>
<!-- time: Time a zipper is active.
force: Additional zipper force.
<bubblegum time="1" speed-fraction="0.3" torque="500" fade-in-time="0.01"/>
<!-- time: Time a zipper is active.
force: Additional zipper force.
speed-gain: One time additional speed.
max-speed-increase: Additional speed allowed on top of the
kart-specific maximum kart speed.
fade-out-time: determines how long it takes for a zipper
max-speed-increase: Additional speed allowed on top of the
kart-specific maximum kart speed.
fade-out-time: determines how long it takes for a zipper
to fade out (after 'time').
-->
<zipper time="3.5" force="250.0" speed-gain="4.5" max-speed-increase="15"
fade-out-time="1.0" />
<zipper time="3.5" force="250.0" speed-gain="4.5" max-speed-increase="15"
fade-out-time="1.0" />
<!-- Skidding: increase: multiplicative increase of skidding factor in each frame.
decrease: multiplicative decrease of skidding factor in each frame.
max: maximum skidding factor = maximum increase of steering angle.
time-till-max: Time till maximum skidding is reached.
visual: Additional graphical rotation of kart. The graphical rotation
of the kart also determines the direction the kart is driving to
when skidding is stopped.
visual-time: How long it takes for the visual skid to reach maximum.
revert-visual-time: how long it takes when stopping a skid to revert
the visual skid and bring visuals and physics in sync again.
angular-velocity: Angular velocity to be used for the kart when skidding.
min-speed: Minimum speed a kart must have before it can skid. Must be
>0, otherwise the kart can skid at the start of the race.
time-till-bonus: How long a kart needs to skid in order to get a bonus.
bonus-force: A speedup applied to the kart whick skidded for a while.
bonus-time: How long the bonus-force is applied.
bonus-force: Additional engine force (this is used to offset the fact
that turning after skidding (e.g. to correct direction) often uses
up the skid bonus).
post-skid-rotate-factor: a factor to be used to determine how much
the chassis of a kart should rotate to match the graphical view.
A factor of 1 is identical, a smaller factor will rotate the kart
less (which might feel better).
physical-jump-time: Time for a physical jump at the beginning of a skid.
graphical-jump-time: Time for a graphics-only jump at the beginning
of a skid.
reduce-turn-min/max: The steering done by the controller (which is in
[-1,1]) is mapped to [reduce-turn-min, reduce-turn-max] when skidding
is active (for left turn, right turn will use [-max, -min]). The
effect is that while you skid (say left) you can adjust the direction
of the turn the kart is doing somewhat by steering to the left and right,
but you will always keep on doing a left turn, just more or less. -->
<!-- Skidding: increase: multiplicative increase of skidding factor in each frame.
decrease: multiplicative decrease of skidding factor in each frame.
max: maximum skidding factor = maximum increase of steering angle.
time-till-max: Time till maximum skidding is reached.
visual: Additional graphical rotation of kart. The graphical rotation
of the kart also determines the direction the kart is driving to
when skidding is stopped.
visual-time: How long it takes for the visual skid to reach maximum.
revert-visual-time: how long it takes when stopping a skid to revert
the visual skid and bring visuals and physics in sync again.
angular-velocity: Angular velocity to be used for the kart when skidding.
min-speed: Minimum speed a kart must have before it can skid. Must be
>0, otherwise the kart can skid at the start of the race.
time-till-bonus: How long a kart needs to skid in order to get a bonus.
bonus-force: A speedup applied to the kart whick skidded for a while.
bonus-time: How long the bonus-force is applied.
bonus-force: Additional engine force (this is used to offset the fact
that turning after skidding (e.g. to correct direction) often uses
up the skid bonus).
post-skid-rotate-factor: a factor to be used to determine how much
the chassis of a kart should rotate to match the graphical view.
A factor of 1 is identical, a smaller factor will rotate the kart
less (which might feel better).
physical-jump-time: Time for a physical jump at the beginning of a skid.
graphical-jump-time: Time for a graphics-only jump at the beginning
of a skid.
reduce-turn-min/max: The steering done by the controller (which is in
[-1,1]) is mapped to [reduce-turn-min, reduce-turn-max] when skidding
is active (for left turn, right turn will use [-max, -min]). The
effect is that while you skid (say left) you can adjust the direction
of the turn the kart is doing somewhat by steering to the left and right,
but you will always keep on doing a left turn, just more or less. -->
<skid increase="1.05" decrease="0.95" max="2.5" time-till-max="0.5"
visual="1.25" visual-time="0.7" revert-visual-time="0.7"
min-speed="10" time-till-bonus="1.0 3.0"
bonus-speed="4.5 6.5" bonus-time="3.0 4.0"
bonus-force="250 350"
physical-jump-time="0" graphical-jump-time="0.4"
post-skid-rotate-factor="1"
reduce-turn-min="0.2" reduce-turn-max="0.8"/>
visual="1.25" visual-time="0.7" revert-visual-time="0.7"
min-speed="10" time-till-bonus="1.0 3.0"
bonus-speed="4.5 6.5" bonus-time="3.0 4.0"
bonus-force="250 350"
physical-jump-time="0" graphical-jump-time="0.4"
post-skid-rotate-factor="1"
reduce-turn-min="0.2" reduce-turn-max="0.8"/>
<!-- Slipstream: length: How far behind a kart slipstream works
width: how wide slipstream works furthest away from the kart.
collect-time: How many seconds of sstream give maximum benefit
use-time: How long the benefit will last.
add-power: Additional power due to sstreaming. 1 = +100%
min-speed: Minimum speed necessary for slipstream to take effect.
min-speed: Minimum speed necessary for slipstream to take effect.
max-speed-increase: How much the speed of the kart might exceed
its normal maximum speed.
duration: How long the higher speed lasts after slipstream stopped
working.
fade-out-time: How long the slip stream speed increase will
fade-out-time: How long the slip stream speed increase will
gradually be reduced. -->
<slipstream length="10" width="2" collect-time="2" use-time="5"
add-power="3" min-speed="10"
max-speed-increase="5" duration="1" fade-out-time="2"/>
<slipstream length="10" width="2" collect-time="2" use-time="5"
add-power="3" min-speed="10"
max-speed-increase="5" duration="1" fade-out-time="2"/>
<!-- Kart-specific settings for the swatter:
duration: how long can the swatter be active.
distance: How close a kart or an item must be before it can be hit.
squash-duration: How long a kart will remain squashed.
squash-slowdown: percentage of max speed that a kart is
restricted to. -->
<swatter duration="10" distance="3" squash-duration="5"
squash-slowdown="0.5"/>
<swatter duration="10" distance="3" squash-duration="5"
squash-slowdown="0.5"/>
<!-- Leaning related parameters, i.e. slightly leaning the karts when
driving a fast curve.
max: maximum leaning (i.e. when steering as much as possible at highest
speed), in degrees.
sped: Speed with which the leaning changes (in degree/second). -->
<lean max="8.6" speed="5.0" />
<!-- turn-radius defines the turn radius of the kart at
a given speed. The actual steering angle is dependent on the
wheel base of the kart: radius = wheel_base/sin(steering_angle).
@@ -574,14 +623,14 @@
0.5 * 0.25 + 0.5 * 0.15 = 0.2 ... which is overall the same
time we had previously.
-->
<turn turn-radius="0:2.0 10:7.5 25:15 45:30"
time-full-steer ="0:0.15 0.5:0.15 0.5:0.25 1.0:0.25"
time-reset-steer="0.1" />
<!-- Speed and acceleration related values: power and max-speed (in m/s)
<turn turn-radius="0:2.0 10:7.5 25:15 45:30"
time-full-steer ="0:0.15 0.5:0.15 0.5:0.25 1.0:0.25"
time-reset-steer="0.1" />
<!-- Speed and acceleration related values: power and max-speed (in m/s)
have 3 values, one for low, medium, and hard.
brake-factor: Value used when braking.
brake-time-increase: The brake force is multiplied by
brake-time-increase: The brake force is multiplied by
(1+brake_time*brake_time_increase - i.e. the longer the brake was
pressed, the harder the kart will brake.
max-speed-reverse-ratio is the percentage of max speed for reverse gear.
@@ -592,117 +641,117 @@
<!-- Simulated gears: switch-ratio defines at what ratio of the maximum
speed what gear is selected, e.g. 0.25 means that if the speed is
bigger or equal to 0.25 x maxSpeed then use gear 1, 0.5 means if
bigger or equal to 0.25 x maxSpeed then use gear 1, 0.5 means if
the speed is bigger or equal to 0.5 x maxSpeed then gear 2.
gear-power-increase contains the increase in max power (to simulate
different gears), e.g. 2.5 as first entry means: 2.5*maxPower in gear 1
| first | second | third | . -->
<gear switch-ratio="0.25 0.7 1.0" power-increase="2.2 1.7 1.3"/>
<gear switch-ratio="0.25 0.7 1.0" power-increase="2.2 1.7 1.3"/>
<!-- mass -->
<mass value="225"/>
<mass value="225"/>
<!-- Kart-specific plunger and rubber band handling: max-length is
the maximum length of rubber band before it snaps. force is
the force a plunger/rubber band applies to the kart(s).
duration is the duration a rubber band acts.
in-face-time determines how long it takes before a plunger
duration is the duration a rubber band acts.
in-face-time determines how long it takes before a plunger
in your face is removed. -->
<plunger band-max-length="50" band-force="1500" band-duration="1"
<plunger band-max-length="50" band-force="1500" band-duration="1"
band-speed-increase="7" band-fade-out-time="3"
in-face-time="3 4 4.5 4.5"/>
<!-- Kart-specific explosion parameters.
<!-- Kart-specific explosion parameters.
Time: how long it takes before the kart can drive again (this
determines how height the kart is being thrown).
Invulnerability-time: how long a kart will be invulnerable
after being hit by an explosion.
radius: Kart closer to this value will be affected by
an explosion as well. -->
<explosion time="2" radius="5"
invulnerability-time="6" />
<kart-type>
<light>
<startup time = "0.3 0.5"
boost = "8.5 4.5" />
<nitro engine-force="350" consumption="1" small-container="1" big-container="3"
max-speed-increase="4.5" duration="1.5" fade-out-time="2.5" max="20"/>
<slipstream length="11" width="2" collect-time="1.5" use-time="2.5"
add-power="3.2" min-speed="9"
max-speed-increase="4" duration="1.2" fade-out-time="2.3"/>
<turn turn-radius="0:3.0 10:10.0 25:20.0 45:40.0"
time-full-steer ="0:0.15 0.5:0.15 0.5:0.25 1.0:0.25"
time-reset-steer="0.1"/>
<engine power="250 300 350 400" max-speed="15.8 18.8 23.85 30.0" brake-factor="15.0"
max-speed-reverse-ratio="0.3"/>
<explosion time="2" radius="5"
invulnerability-time="6" />
<gear switch-ratio="0.20 0.55 1" power-increase="5 4 3"/>
<kart-type>
<light>
<startup time = "0.3 0.5"
boost = "8.5 4.5" />
<mass value="195"/>
<nitro engine-force="350" consumption="1" small-container="1" big-container="3"
max-speed-increase="4.5" duration="1.5" fade-out-time="2.5" max="20"/>
<explosion time="2.1" radius="5.5"
invulnerability-time="7" />
</light>
<medium>
<startup time = "0.3 0.5"
boost = "4.2 2.6" />
<nitro engine-force="425" consumption="1.4" small-container="1" big-container="3"
max-speed-increase="5" duration="1.2" fade-out-time="2" max="20"/>
<slipstream length="10" width="2" collect-time="2" use-time="3.3"
<slipstream length="11" width="2" collect-time="1.5" use-time="2.5"
add-power="3.2" min-speed="9"
max-speed-increase="4" duration="1.2" fade-out-time="2.3"/>
<turn turn-radius="0:3.0 10:10.0 25:20.0 45:40.0"
time-full-steer ="0:0.15 0.5:0.15 0.5:0.25 1.0:0.25"
time-reset-steer="0.1"/>
<engine power="250 300 350 400" max-speed="15.8 18.8 23.85 30.0" brake-factor="15.0"
max-speed-reverse-ratio="0.3"/>
<gear switch-ratio="0.20 0.55 1" power-increase="5 4 3"/>
<mass value="195"/>
<explosion time="2.1" radius="5.5"
invulnerability-time="7" />
</light>
<medium>
<startup time = "0.3 0.5"
boost = "4.2 2.6" />
<nitro engine-force="425" consumption="1.4" small-container="1" big-container="3"
max-speed-increase="5" duration="1.2" fade-out-time="2" max="20"/>
<slipstream length="10" width="2" collect-time="2" use-time="3.3"
add-power="2.8" min-speed="10"
max-speed-increase="5" duration="0.9" fade-out-time="1.6"/>
<turn turn-radius="0:4.5 10:16.0 25:30.0 45:60.0"
time-full-steer ="0:0.17 0.5:0.17 0.5:0.28 1.0:0.28"
time-reset-steer="0.1"/>
max-speed-increase="5" duration="0.9" fade-out-time="1.6"/>
<engine power="425 500 575 600" max-speed="15 20 23.2 27" brake-factor="11.0"
max-speed-reverse-ratio="0.4"/>
<turn turn-radius="0:4.5 10:16.0 25:30.0 45:60.0"
time-full-steer ="0:0.17 0.5:0.17 0.5:0.28 1.0:0.28"
time-reset-steer="0.1"/>
<gear switch-ratio="0.30 0.7 1.0" power-increase="2.2 2.2 2.5"/>
<engine power="425 500 575 600" max-speed="15 20 23.2 27" brake-factor="11.0"
max-speed-reverse-ratio="0.4"/>
<mass value="250"/>
<gear switch-ratio="0.30 0.7 1.0" power-increase="2.2 2.2 2.5"/>
<explosion time="1.8" radius="5"
invulnerability-time="6" />
</medium>
<heavy>
<startup time = "0.3 0.5"
boost = "3.8 2" />
<nitro engine-force="600" consumption="2" small-container="1" big-container="3"
max-speed-increase="8" duration="0.7" fade-out-time="1.3" max="20"/>
<slipstream length="8.5" width="2" collect-time="2" use-time="4"
add-power="2.7" min-speed="10.5"
max-speed-increase="8" duration="0.7" fade-out-time="1"/>
<mass value="250"/>
<swatter duration="10" distance="3" squash-duration="5"
squash-slowdown="0.5"/>
<turn turn-radius="0:4.0 10:18.5 25:43.0 45:72.5"
time-full-steer ="0:0.23 0.5:0.23 0.5:0.41 1.0:0.41"
time-reset-steer="0.1"/>
<explosion time="1.8" radius="5"
invulnerability-time="6" />
</medium>
<engine power="600 700 800 900" max-speed="15 20 23 25" brake-factor="10"
max-speed-reverse-ratio="0.65"/>
<heavy>
<startup time = "0.3 0.5"
boost = "3.8 2" />
<gear switch-ratio="0.45 0.70 1" power-increase="1.5 1.7 2.5"/>
<nitro engine-force="600" consumption="2" small-container="1" big-container="3"
max-speed-increase="8" duration="0.7" fade-out-time="1.3" max="20"/>
<mass value="350"/>
<slipstream length="8.5" width="2" collect-time="2" use-time="4"
add-power="2.7" min-speed="10.5"
max-speed-increase="8" duration="0.7" fade-out-time="1"/>
<explosion time="1.5" radius="4"
invulnerability-time="6" />
</heavy>
</kart-type>
<swatter duration="10" distance="3" squash-duration="5"
squash-slowdown="0.5"/>
<turn turn-radius="0:4.0 10:18.5 25:43.0 45:72.5"
time-full-steer ="0:0.23 0.5:0.23 0.5:0.41 1.0:0.41"
time-reset-steer="0.1"/>
<engine power="600 700 800 900" max-speed="15 20 23 25" brake-factor="10"
max-speed-reverse-ratio="0.65"/>
<gear switch-ratio="0.45 0.70 1" power-increase="1.5 1.7 2.5"/>
<mass value="350"/>
<explosion time="1.5" radius="4"
invulnerability-time="6" />
</heavy>
</kart-type>
</general-kart-defaults>
</config>

View File

@@ -481,6 +481,14 @@ struct SJoystickInfo
//! The presence or absence of a hat cannot be determined.
POV_HAT_UNKNOWN
} PovHat;
//! Set if the name of the joystick is useful:
/** On windows the generic name is useless, since it's always the same
* indepentent of what joystick is connected ("Microsoft PC-joystick driver").
* We will try to get a better name from the registry, but if this should
* fail this flag is set and used by STK. */
bool HasGenericName;
}; // struct SJoystickInfo

View File

@@ -2038,6 +2038,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
ActiveJoysticks.push_back(info);
returnInfo.HasGenericName = false;
returnInfo.Joystick = joystick;
returnInfo.PovHat = SJoystickInfo::POV_HAT_UNKNOWN;
returnInfo.Axes = info.axes;

View File

@@ -557,6 +557,7 @@ bool CIrrDeviceSDL::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
SJoystickInfo info;
info.Joystick = joystick;
info.HasGenericName = false;
info.Axes = SDL_JoystickNumAxes(Joysticks[joystick]);
info.Buttons = SDL_JoystickNumButtons(Joysticks[joystick]);
info.Name = SDL_JoystickName(joystick);

View File

@@ -368,7 +368,8 @@ void setJoystickName(int index, const JOYCAPS &caps, SJoystickInfo *joystick)
{
// As a default use the name given in the joystick structure
// - though that is always the same name, independent of joystick :(
joystick->Name = caps.szPname;
joystick->Name = caps.szPname;
joystick->HasGenericName = true;
core::stringc key = core::stringc(REGSTR_PATH_JOYCONFIG)+"\\"+caps.szRegKey
+ "\\"+REGSTR_KEY_JOYCURR;
@@ -412,6 +413,7 @@ void setJoystickName(int index, const JOYCAPS &caps, SJoystickInfo *joystick)
regresult = RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,
(LPBYTE)name, &regsize );
joystick->Name = name;
joystick->HasGenericName = false;
} // if name
} // if SUCCESS
RegCloseKey(hKey);

View File

@@ -719,7 +719,7 @@ bool CIrrDeviceMacOSX::createWindow()
if (!CreationParams.WindowId)
{
[Window center];
[Window setDelegate:[NSApp delegate]];
[(NSFileManager *)Window setDelegate:[NSApp delegate]];
if(CreationParams.DriverType == video::EDT_OPENGL)
[OGLContext setView:[Window contentView]];
@@ -1709,6 +1709,7 @@ bool CIrrDeviceMacOSX::activateJoysticks(core::array<SJoystickInfo> & joystickIn
SJoystickInfo returnInfo;
returnInfo.Joystick = jindex;
returnInfo.HasGenericName = false;
returnInfo.Axes = info.axes;
//returnInfo.Hats = info.hats;
returnInfo.Buttons = info.buttons;

View File

@@ -1,6 +1,6 @@
# 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/*")
file(GLOB_RECURSE STK_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${PROJECT_BINARY_DIR}/tmp/*.rc")
file(GLOB_RECURSE STK_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${PROJECT_BINARY_DIR}/tmp/*.rc")

View File

@@ -198,7 +198,7 @@ void PlayerProfile::save(UTFWriter &out)
<< L"\" guest=\"" << m_is_guest_account
<< L"\" use-frequency=\"" << m_use_frequency << L"\"\n";
out << L" icon-filename=\"" << m_icon_filename <<L"\"\n";
out << L" icon-filename=\"" << m_icon_filename << L"\"\n";
out << L" unique-id=\"" << m_unique_id
<< L"\" saved-session=\"" << m_saved_session << L"\"\n";

View File

@@ -20,6 +20,7 @@
#define HEADER_PLAYER_PROFILE_HPP
#include "challenges/story_mode_status.hpp"
#include "network/remote_kart_info.hpp"
#include "utils/leak_check.hpp"
#include "utils/no_copy.hpp"
#include "utils/types.hpp"
@@ -66,6 +67,10 @@ public:
private:
LEAK_CHECK()
#ifdef DEBUG
unsigned int m_magic_number;
#endif
/** The name of the player (wide string, so it can be in native
* language). */
core::stringw m_local_name;
@@ -73,10 +78,6 @@ private:
/** True if this account is a guest account. */
bool m_is_guest_account;
#ifdef DEBUG
unsigned int m_magic_number;
#endif
/** Counts how often this player was used (always -1 for guests). */
int m_use_frequency;
@@ -111,8 +112,8 @@ private:
public:
PlayerProfile(const core::stringw &name, bool is_guest = false);
PlayerProfile(const XMLNode *node);
PlayerProfile(const core::stringw &name, bool is_guest = false);
PlayerProfile(const XMLNode *node);
virtual ~PlayerProfile();
void save(UTFWriter &out);
void loadRemainingData(const XMLNode *node);

View File

@@ -27,6 +27,7 @@
#include "io/xml_node.hpp"
#include "items/item.hpp"
#include "karts/kart_properties.hpp"
#include "karts/player_difficulty.hpp"
#include "utils/log.hpp"
STKConfig* stk_config=0;
@@ -387,16 +388,23 @@ void STKConfig::getAllData(const XMLNode * root)
throw std::runtime_error(msg.str());
}
m_default_kart_properties->getAllData(node);
const XMLNode *types = node->getNode("kart-type");
const XMLNode *child_node = node->getNode("kart-type");
for (unsigned int i = 0; i < types->getNumNodes(); ++i)
for (unsigned int i = 0; i < child_node->getNumNodes(); ++i)
{
const XMLNode* type = types->getNode(i);
const XMLNode* type = child_node->getNode(i);
m_kart_properties[type->getName()] = new KartProperties();
m_kart_properties[type->getName()]->copyFrom(m_default_kart_properties);
m_kart_properties[type->getName()]->getAllData(type);
}
child_node = node->getNode("difficulties");
for (unsigned int i = 0; i < child_node->getNumNodes(); ++i)
{
const XMLNode* type = child_node->getNode(i);
m_player_difficulties[i] = new PlayerDifficulty();
m_player_difficulties[i]->getAllData(type);
}
} // getAllData
// ----------------------------------------------------------------------------

View File

@@ -26,6 +26,7 @@
* configuration file.
*/
#include "network/remote_kart_info.hpp"
#include "utils/no_copy.hpp"
#include <vector>
@@ -33,6 +34,7 @@
#include <map>
class KartProperties;
class PlayerDifficulty;
class MusicInformation;
class XMLNode;
@@ -47,8 +49,10 @@ class STKConfig : public NoCopy
{
protected:
/** Default kart properties. */
KartProperties *m_default_kart_properties;
KartProperties *m_default_kart_properties;
std::map<std::string, KartProperties*> m_kart_properties;
/** Per-player difficulties. */
PlayerDifficulty* m_player_difficulties[PLAYER_DIFFICULTY_COUNT];
public:
/** What to do if a kart already has a powerup when it hits a bonus box:
@@ -175,6 +179,9 @@ public:
const KartProperties &
getKartProperties(std::string type) { return *m_kart_properties[type]; }
const PlayerDifficulty * getPlayerDifficulty(PerPlayerDifficulty difficulty)
{ return m_player_difficulties[difficulty]; }
}
; // STKConfig

View File

@@ -672,6 +672,20 @@ namespace UserConfigParams
PARAM_DEFAULT( StringUserConfigParam("Peach.stkskin", "skin_file",
"Name of the skin to use") );
PARAM_PREFIX GroupUserConfigParam m_handicap
PARAM_DEFAULT( GroupUserConfigParam("Handicap",
"Everything related to handicaps.") );
PARAM_PREFIX BoolUserConfigParam m_per_player_difficulty
PARAM_DEFAULT( BoolUserConfigParam(false, "per_player_difficulty",
&m_handicap,
"If handicapped users can be selected") );
PARAM_PREFIX BoolUserConfigParam m_ai_handicap
PARAM_DEFAULT( BoolUserConfigParam(false, "ai_handicap",
&m_handicap,
"If AIs are handicapped") );
// ---- Internet related
PARAM_PREFIX IntUserConfigParam m_internet_status

View File

@@ -64,7 +64,10 @@ Camera::Camera(int camera_index, AbstractKart* kart) : m_kart(NULL)
setupCamera();
if (kart != NULL)
{
m_distance = kart->getKartProperties()->getCameraDistance();
if(UserConfigParams::m_camera_debug==2)
m_distance = kart->getKartModel()->getLength();
else
m_distance = kart->getKartProperties()->getCameraDistance();
setKart(kart);
}
else
@@ -378,37 +381,6 @@ void Camera::smoothMoveCamera(float dt)
}
} // smoothMoveCamera
//-----------------------------------------------------------------------------
/** Computes the wanted camera position and target for normal camera mode.
* Besides being used in update(dt), it is also used when switching the
* camera from reverse mode to normal mode - in which case we don't want
* to have a smooth camera.
* \param wanted_position The position the camera should be.
* \param wanted_target The target position the camera should target.
*/
void Camera::computeNormalCameraPosition(Vec3 *wanted_position,
Vec3 *wanted_target)
{
*wanted_target = m_kart->getXYZ();
wanted_target->setY(wanted_target->getY()+ 0.75f);
// This first line moves the camera around behind the kart, pointing it
// towards where the kart is turning (and turning even more while skidding).
// The skidding effect is dampened.
float steering = m_kart->getSteerPercent()
* (1.0f + (m_kart->getSkidding()->getSkidFactor() - 1.0f)
/2.3f );
// quadratically to dampen small variations (but keep sign)
float dampened_steer = fabsf(steering) * steering;
float tan_up = tan(m_kart->getKartProperties()->getCameraForwardUpAngle());
Vec3 relative_position(-m_distance*m_rotation_range*dampened_steer*0.5f,
m_distance*tan_up+0.75f,
-m_distance);
*wanted_position = m_kart->getTrans()(relative_position);
} // computeNormalCameraPosition
//-----------------------------------------------------------------------------
/** Determine the camera settings for the current frame.
* \param above_kart How far above the camera should aim at.
@@ -549,7 +521,10 @@ void Camera::positionCamera(float dt, float above_kart, float cam_angle,
Vec3 wanted_position;
Vec3 wanted_target = m_kart->getXYZ();
if(UserConfigParams::m_camera_debug==2)
wanted_target.setY(m_kart->getVehicle()->getWheelInfo(2).m_raycastInfo.m_contactPointWS.getY());
{
const btWheelInfo &w = m_kart->getVehicle()->getWheelInfo(2);
wanted_target.setY(w.m_raycastInfo.m_contactPointWS.getY());
}
else
wanted_target.setY(wanted_target.getY()+above_kart);
float tan_up = tan(cam_angle);
@@ -567,7 +542,7 @@ void Camera::positionCamera(float dt, float above_kart, float cam_angle,
}
wanted_position = t(relative_position);
if (smoothing)
if (smoothing && UserConfigParams::m_camera_debug==0)
{
smoothMoveCamera(dt);
}
@@ -591,8 +566,8 @@ void Camera::positionCamera(float dt, float above_kart, float cam_angle,
// Rotate the up vector (0,1,0) by the rotation ... which is just column 1
Vec3 up = m_kart->getTrans().getBasis().getColumn(1);
float f = 0.04f; // weight for new up vector to reduce shaking
m_camera->setUpVector(f * up.toIrrVector() +
(1.0f - f) * m_camera->getUpVector());
m_camera->setUpVector( f * up.toIrrVector() +
(1.0f - f) * m_camera->getUpVector());
} // kart && !flying
else
m_camera->setUpVector(core::vector3df(0, 1, 0));

View File

@@ -186,8 +186,6 @@ private:
void setupCamera();
void smoothMoveCamera(float dt);
void computeNormalCameraPosition(Vec3 *wanted_position,
Vec3 *wanted_target);
void handleEndCamera(float dt);
void getCameraSettings(float *above_kart, float *cam_angle,
float *side_way, float *distance,

View File

@@ -165,7 +165,7 @@ unsigned GPUTimer::elapsedTimeus()
FrameBuffer::FrameBuffer() {}
FrameBuffer::FrameBuffer(const std::vector<GLuint> &RTTs, size_t w, size_t h, bool layered) :
RenderTargets(RTTs), DepthTexture(0), width(w), height(h)
RenderTargets(RTTs), DepthTexture(0), width(w), height(h), fbolayer(0)
{
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
@@ -184,7 +184,7 @@ FrameBuffer::FrameBuffer(const std::vector<GLuint> &RTTs, size_t w, size_t h, bo
}
FrameBuffer::FrameBuffer(const std::vector<GLuint> &RTTs, GLuint DS, size_t w, size_t h, bool layered) :
RenderTargets(RTTs), DepthTexture(DS), width(w), height(h)
RenderTargets(RTTs), DepthTexture(DS), width(w), height(h), fbolayer(0)
{
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
@@ -202,11 +202,15 @@ FrameBuffer::FrameBuffer(const std::vector<GLuint> &RTTs, GLuint DS, size_t w, s
}
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
assert(result == GL_FRAMEBUFFER_COMPLETE_EXT);
if (layered)
glGenFramebuffers(1, &fbolayer);
}
FrameBuffer::~FrameBuffer()
{
glDeleteFramebuffers(1, &fbo);
if (fbolayer)
glDeleteFramebuffers(1, &fbolayer);
}
void FrameBuffer::Bind()
@@ -217,6 +221,16 @@ void FrameBuffer::Bind()
glDrawBuffers((int)RenderTargets.size(), bufs);
}
void FrameBuffer::BindLayer(unsigned i)
{
glBindFramebuffer(GL_FRAMEBUFFER, fbolayer);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, RenderTargets[0], 0, i);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, DepthTexture, 0, i);
glViewport(0, 0, (int)width, (int)height);
GLenum bufs[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers((int)RenderTargets.size(), bufs);
}
void FrameBuffer::Blit(const FrameBuffer &Src, FrameBuffer &Dst, GLbitfield mask, GLenum filter)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, Src.fbo);

View File

@@ -43,7 +43,7 @@ public:
class FrameBuffer
{
private:
GLuint fbo;
GLuint fbo, fbolayer;
std::vector<GLuint> RenderTargets;
GLuint DepthTexture;
size_t width, height;
@@ -53,6 +53,7 @@ public:
FrameBuffer(const std::vector <GLuint> &RTTs, GLuint DS, size_t w, size_t h, bool layered = false);
~FrameBuffer();
void Bind();
void BindLayer(unsigned);
const std::vector<GLuint> &getRTT() const { return RenderTargets; }
GLuint &getDepthTexture() { assert(DepthTexture); return DepthTexture; }
size_t getWidth() const { return width; }

View File

@@ -351,7 +351,7 @@ void IrrDriver::initDevice()
UserConfigParams::m_height = (int)ssize.Height;
}
core::dimension2d<u32> res = core::dimension2du(UserConfigParams::m_width,
core::dimension2d<u32> res = core::dimension2du(UserConfigParams::m_width,
UserConfigParams::m_height);
if (UserConfigParams::m_fullscreen)
@@ -485,6 +485,7 @@ void IrrDriver::initDevice()
m_need_ubo_workaround = false;
m_need_rh_workaround = false;
m_need_srgb_workaround = false;
m_support_sdsm = true;
#ifdef WIN32
// Fix for Intel Sandy Bridge on Windows which supports GL up to 3.1 only
if (strstr((const char *)glGetString(GL_VENDOR), "Intel") != NULL && (m_gl_major_version == 3 && m_gl_minor_version == 1))
@@ -492,7 +493,10 @@ void IrrDriver::initDevice()
#endif
// Fix for Nvidia and instanced RH
if (strstr((const char *)glGetString(GL_VENDOR), "NVIDIA") != NULL)
{
m_need_rh_workaround = true;
m_support_sdsm = false;
}
// Fix for AMD and bindless sRGB textures
if (strstr((const char *)glGetString(GL_VENDOR), "ATI") != NULL)
@@ -513,6 +517,7 @@ void IrrDriver::initDevice()
hasDrawIndirect = false;
hasComputeShaders = false;
hasTextureStorage = false;
hasTextureView = false;
// Default false value for hasVSLayer if --no-graphics argument is used
#if !defined(__APPLE__)
if (!ProfileWorld::isNoGraphics())
@@ -541,6 +546,11 @@ void IrrDriver::initDevice()
hasTextureStorage = true;
Log::info("GLDriver", "ARB Texture Storage enabled");
}
if (hasGLExtension("GL_ARB_texture_view")) {
hasTextureView = true;
Log::info("GLDriver", "ARB Texture View enabled");
}
m_support_sdsm = m_support_sdsm && hasComputeShaders && hasBuffserStorage;
}
#endif

View File

@@ -180,6 +180,8 @@ private:
bool hasBuffserStorage;
bool hasComputeShaders;
bool hasTextureStorage;
bool hasTextureView;
bool m_support_sdsm;
bool m_need_ubo_workaround;
bool m_need_rh_workaround;
bool m_need_srgb_workaround;
@@ -266,6 +268,11 @@ public:
return 120;
}
bool supportsSDSM() const
{
return m_support_sdsm;
}
bool needUBOWorkaround() const
{
return m_need_ubo_workaround;
@@ -311,6 +318,11 @@ public:
return hasTextureStorage;
}
bool hasARBTextureView() const
{
return hasTextureView;
}
video::SColorf getAmbientLight() const;
struct GlowData {
@@ -767,6 +779,7 @@ public:
void renderScene(scene::ICameraSceneNode * const camnode, unsigned pointlightcount, std::vector<GlowData>& glows, float dt, bool hasShadows, bool forceRTT);
unsigned UpdateLightsInfo(scene::ICameraSceneNode * const camnode, float dt);
void UpdateSplitAndLightcoordRangeFromComputeShaders(size_t width, size_t height);
void computeCameraMatrix(scene::ICameraSceneNode * const camnode, size_t width, size_t height);
// --------------------- OLD RTT --------------------

View File

@@ -282,6 +282,8 @@ void PostProcessing::renderSunlight()
DrawFullScreenEffect<FullScreenShader::SunLightShader>(cb->getPosition(), video::SColorf(cb->getRed(), cb->getGreen(), cb->getBlue()));
}
extern float shadowSplit[5];
void PostProcessing::renderShadowedSunlight(const std::vector<core::matrix4> &sun_ortho_matrix, GLuint depthtex)
{
SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT);
@@ -292,7 +294,7 @@ void PostProcessing::renderShadowedSunlight(const std::vector<core::matrix4> &su
glBlendEquation(GL_FUNC_ADD);
FullScreenShader::ShadowedSunLightShader::getInstance()->SetTextureUnits(irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), irr_driver->getDepthStencilTexture(), depthtex);
DrawFullScreenEffect<FullScreenShader::ShadowedSunLightShader>(cb->getPosition(), video::SColorf(cb->getRed(), cb->getGreen(), cb->getBlue()));
DrawFullScreenEffect<FullScreenShader::ShadowedSunLightShader>(shadowSplit[1], shadowSplit[2], shadowSplit[3], shadowSplit[4], cb->getPosition(), video::SColorf(cb->getRed(), cb->getGreen(), cb->getBlue()));
}
@@ -314,6 +316,25 @@ void PostProcessing::renderGaussian3Blur(FrameBuffer &in_fbo, FrameBuffer &auxil
}
}
void PostProcessing::renderGaussian6BlurLayer(FrameBuffer &in_fbo)
{
for (unsigned i = 0; i < 4; i++)
{
// Used as temp
irr_driver->getFBO(FBO_BLOOM_1024).Bind();
GLuint LayerTex;
glGenTextures(1, &LayerTex);
glTextureView(LayerTex, GL_TEXTURE_2D, in_fbo.getRTT()[0], GL_R32F, 0, 1, i, 1);
FullScreenShader::Gaussian6VBlurShader::getInstance()->SetTextureUnits(LayerTex);
DrawFullScreenEffect<FullScreenShader::Gaussian6VBlurShader>(core::vector2df(1. / 1024., 1. / 1024.));
in_fbo.BindLayer(i);
FullScreenShader::Gaussian6HBlurShader::getInstance()->SetTextureUnits(irr_driver->getFBO(FBO_BLOOM_1024).getRTT()[0]);
DrawFullScreenEffect<FullScreenShader::Gaussian6HBlurShader>(core::vector2df(1. / 1024., 1. / 1024.));
glDeleteTextures(1, &LayerTex);
}
}
void PostProcessing::renderGaussian6Blur(FrameBuffer &in_fbo, FrameBuffer &auxiliary)
{
assert(in_fbo.getWidth() == auxiliary.getWidth() && in_fbo.getHeight() == auxiliary.getHeight());
@@ -432,6 +453,7 @@ void PostProcessing::renderSSAO()
DrawFullScreenEffect<FullScreenShader::SSAOShader>(irr_driver->getSSAORadius(), irr_driver->getSSAOK(), irr_driver->getSSAOSigma());
}
void PostProcessing::renderFog()
{
const Track * const track = World::getWorld()->getTrack();
@@ -516,11 +538,11 @@ static void renderGodRay(GLuint tex, const core::vector2df &sunpos)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
static void toneMap(FrameBuffer &fbo, GLuint rtt)
static void toneMap(FrameBuffer &fbo, GLuint rtt, float vignette_weight)
{
fbo.Bind();
FullScreenShader::ToneMapShader::getInstance()->SetTextureUnits(rtt);
DrawFullScreenEffect<FullScreenShader::ToneMapShader>();
DrawFullScreenEffect<FullScreenShader::ToneMapShader>(vignette_weight);
}
static void renderDoF(FrameBuffer &fbo, GLuint rtt)
@@ -718,7 +740,15 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo
{
PROFILER_PUSH_CPU_MARKER("- Tonemap", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_TONEMAP));
toneMap(*out_fbo, in_fbo->getRTT()[0]);
// only enable vignette during race
if(isRace)
{
toneMap(*out_fbo, in_fbo->getRTT()[0], 1.0);
}
else
{
toneMap(*out_fbo, in_fbo->getRTT()[0], 0.0);
}
std::swap(in_fbo, out_fbo);
PROFILER_POP_CPU_MARKER();
}

View File

@@ -88,6 +88,7 @@ public:
/** Blur the in texture */
void renderGaussian3Blur(FrameBuffer &in_fbo, FrameBuffer &auxiliary);
void renderGaussian6Blur(FrameBuffer &in_fbo, FrameBuffer &auxiliary);
void renderGaussian6BlurLayer(FrameBuffer &in_fbo);
void renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &auxiliary);
/** Render tex. Used for blit/texture resize */

View File

@@ -638,12 +638,155 @@ core::matrix4 getTighestFitOrthoProj(const core::matrix4 &transform, const std::
return tmp_matrix;
tmp_matrix.buildProjectionMatrixOrthoLH(left, right,
down, up,
30, zmax);
zmin - 100, zmax);
return tmp_matrix;
}
float shadowSplit[5] = {1., 5., 20., 50., 150 };
struct CascadeBoundingBox
{
int xmin;
int xmax;
int ymin;
int ymax;
int zmin;
int zmax;
};
static size_t currentCBB = 0;
static CascadeBoundingBox *CBB[2];
struct Histogram
{
int bin[1024];
int mindepth;
int maxdepth;
int count;
};
/** Update shadowSplit values and make Cascade Bounding Box pointer valid.
* The function aunches two compute kernel that generates an histogram of the depth buffer value (between 0 and 250 with increment of 0.25)
* and get an axis aligned bounding box (from SunCamMatrix view) containing all depth buffer value.
* It also retrieves the result from the previous computations (in a Round Robin fashion) and update CBB pointer.
* \param width of the depth buffer
* \param height of the depth buffer
* TODO : The depth histogram part is commented out, needs to tweak it when I have some motivation
*/
void IrrDriver::UpdateSplitAndLightcoordRangeFromComputeShaders(size_t width, size_t height)
{
// Value that should be kept between multiple calls
static GLuint ssbo[2];
static Histogram *Hist[2];
static GLsync LightcoordBBFence = 0;
static size_t currentHist = 0;
static GLuint ssboSplit[2];
static float tmpshadowSplit[5] = { 1., 5., 20., 50., 150. };
if (!LightcoordBBFence)
{
glGenBuffers(2, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo[0]);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(CascadeBoundingBox), 0, GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
CBB[0] = (CascadeBoundingBox *)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4 * sizeof(CascadeBoundingBox), GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo[1]);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(CascadeBoundingBox), 0, GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
CBB[1] = (CascadeBoundingBox *)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4 * sizeof(CascadeBoundingBox), GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
/* glGenBuffers(2, ssboSplit);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssboSplit[0]);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, sizeof(Histogram), 0, GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
Hist[0] = (Histogram *)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(Histogram), GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssboSplit[1]);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, sizeof(Histogram), 0, GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
Hist[1] = (Histogram *)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(Histogram), GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);*/
}
// Use bounding boxes from last frame
if (LightcoordBBFence)
{
while (glClientWaitSync(LightcoordBBFence, GL_SYNC_FLUSH_COMMANDS_BIT, 0) != GL_ALREADY_SIGNALED);
glDeleteSync(LightcoordBBFence);
}
/* {
memcpy(shadowSplit, tmpshadowSplit, 5 * sizeof(float));
unsigned numpix = Hist[currentHist]->count;
unsigned split = 0;
unsigned i;
for (i = 0; i < 1022; i++)
{
split += Hist[currentHist]->bin[i];
if (split > numpix / 2)
break;
}
tmpshadowSplit[1] = (float)++i / 4.;
for (; i < 1023; i++)
{
split += Hist[currentHist]->bin[i];
if (split > 3 * numpix / 4)
break;
}
tmpshadowSplit[2] = (float)++i / 4.;
for (; i < 1024; i++)
{
split += Hist[currentHist]->bin[i];
if (split > 7 * numpix / 8)
break;
}
tmpshadowSplit[3] = (float)++i / 4.;
for (; i < 1024; i++)
{
split += Hist[currentHist]->bin[i];
}
tmpshadowSplit[0] = (float)(Hist[currentHist]->bin[1024] - 1) / 4.;
tmpshadowSplit[4] = (float)(Hist[currentHist]->bin[1025] + 1) / 4.;
printf("numpix is %d\n", numpix);
printf("total : %d\n", split);
printf("split 0 : %f\n", tmpshadowSplit[1]);
printf("split 1 : %f\n", tmpshadowSplit[2]);
printf("split 2 : %f\n", tmpshadowSplit[3]);
printf("min %f max %f\n", tmpshadowSplit[0], tmpshadowSplit[4]);
currentHist = (currentHist + 1) % 2;
}*/
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssbo[currentCBB]);
// glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssboSplit[currentHist]);
for (unsigned i = 0; i < 4; i++)
{
CBB[currentCBB][i].xmin = CBB[currentCBB][i].ymin = CBB[currentCBB][i].zmin = 1000;
CBB[currentCBB][i].xmax = CBB[currentCBB][i].ymax = CBB[currentCBB][i].zmax = -1000;
}
// memset(Hist[currentHist], 0, sizeof(Histogram));
// Hist[currentHist]->mindepth = 3000;
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
glUseProgram(FullScreenShader::LightspaceBoundingBoxShader::getInstance()->Program);
FullScreenShader::LightspaceBoundingBoxShader::getInstance()->SetTextureUnits(getDepthStencilTexture());
FullScreenShader::LightspaceBoundingBoxShader::getInstance()->setUniforms(m_suncam->getViewMatrix(), tmpshadowSplit[1], tmpshadowSplit[2], tmpshadowSplit[3], tmpshadowSplit[4]);
glDispatchCompute((int)width / 64, (int)height / 64, 1);
/* glUseProgram(FullScreenShader::DepthHistogramShader::getInstance()->Program);
FullScreenShader::DepthHistogramShader::getInstance()->SetTextureUnits(getDepthStencilTexture());
FullScreenShader::DepthHistogramShader::getInstance()->setUniforms();
glDispatchCompute((int)width / 32, (int)height / 32, 1);*/
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
LightcoordBBFence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
currentCBB = (currentCBB + 1) % 2;
}
void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, size_t width, size_t height)
{
if (irr_driver->supportsSDSM())
UpdateSplitAndLightcoordRangeFromComputeShaders(width, height);
static_cast<scene::CSceneManager *>(m_scene_manager)->OnAnimate(os::Timer::getTime());
camnode->render();
irr_driver->setProjMatrix(irr_driver->getVideoDriver()->getTransform(video::ETS_PROJECTION));
@@ -656,17 +799,17 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz
const float oldnear = camnode->getNearValue();
float FarValues[] =
{
6.,
21.,
55.,
150.,
shadowSplit[1],
shadowSplit[2],
shadowSplit[3],
shadowSplit[4],
};
float NearValues[] =
{
oldnear,
5.,
20.,
50.,
shadowSplit[0],
shadowSplit[1],
shadowSplit[2],
shadowSplit[3]
};
@@ -697,9 +840,12 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz
// Build the 3 ortho projection (for the 3 shadow resolution levels)
for (unsigned i = 0; i < 4; i++)
{
camnode->setFarValue(FarValues[i]);
camnode->setNearValue(NearValues[i]);
camnode->render();
if (!irr_driver->supportsSDSM())
{
camnode->setFarValue(FarValues[i]);
camnode->setNearValue(NearValues[i]);
camnode->render();
}
const scene::SViewFrustum *frustrum = camnode->getViewFrustum();
float tmp[24] = {
frustrum->getFarLeftDown().X,
@@ -737,7 +883,6 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz
core::aabbox3df box = smallcambox;
box = box.intersect(trackbox);
std::vector<vector3df> vectors;
vectors.push_back(frustrum->getFarLeftDown());
vectors.push_back(frustrum->getFarLeftUp());
@@ -748,19 +893,24 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz
vectors.push_back(frustrum->getNearRightDown());
vectors.push_back(frustrum->getNearRightUp());
/* SunCamViewMatrix.transformBoxEx(trackbox);
SunCamViewMatrix.transformBoxEx(box);
core::matrix4 tmp_matrix;
core::vector3df extent = box.getExtent();
const float w = fabsf(extent.X);
const float h = fabsf(extent.Y);
float z = box.MaxEdge.Z;
if (irr_driver->supportsSDSM()){
float left = CBB[currentCBB][i].xmin / 4 - 2;
float right = CBB[currentCBB][i].xmax / 4 + 2;
float up = CBB[currentCBB][i].ymin / 4 - 2;
float down = CBB[currentCBB][i].ymax / 4 + 2;
// Snap to texels
const float units_per_w = w / 1024;
const float units_per_h = h / 1024;*/
// Prevent Matrix without extend
if (left != right && up != down)
tmp_matrix.buildProjectionMatrixOrthoLH(left, right,
down, up,
CBB[currentCBB][i].zmin / 4 - 100, CBB[currentCBB][i].zmax / 4 + 2);
}
else
tmp_matrix = getTighestFitOrthoProj(SunCamViewMatrix, vectors);
m_shadow_camnodes[i]->setProjectionMatrix(getTighestFitOrthoProj(SunCamViewMatrix, vectors) , true);
m_shadow_camnodes[i]->setProjectionMatrix(tmp_matrix , true);
m_shadow_camnodes[i]->render();
sun_ortho_matrix.push_back(getVideoDriver()->getTransform(video::ETS_PROJECTION) * getVideoDriver()->getTransform(video::ETS_VIEW));
@@ -824,16 +974,16 @@ void IrrDriver::renderShadowsDebug()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2);
m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 0);
m_post_processing->renderTextureLayer(m_rtts->getShadowFBO().getRTT()[0], 0);
renderWireFrameFrustrum(m_shadows_cam[0], 0);
glViewport(UserConfigParams::m_width / 2, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2);
m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 1);
m_post_processing->renderTextureLayer(m_rtts->getShadowFBO().getRTT()[0], 1);
renderWireFrameFrustrum(m_shadows_cam[1], 1);
glViewport(0, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2);
m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 2);
m_post_processing->renderTextureLayer(m_rtts->getShadowFBO().getRTT()[0], 2);
renderWireFrameFrustrum(m_shadows_cam[2], 2);
glViewport(UserConfigParams::m_width / 2, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2);
m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 3);
m_post_processing->renderTextureLayer(m_rtts->getShadowFBO().getRTT()[0], 3);
renderWireFrameFrustrum(m_shadows_cam[3], 3);
glViewport(0, 0, UserConfigParams::m_width, UserConfigParams::m_height);
}

View File

@@ -978,14 +978,15 @@ void IrrDriver::renderShadows()
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
m_rtts->getShadowFBO().Bind();
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.5, 0.);
m_rtts->getShadowFBO().Bind();
glClear(GL_DEPTH_BUFFER_BIT);
glDrawBuffer(GL_NONE);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glClearColor(1., 1., 1., 1.);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClearColor(0., 0., 0., 0.);
for (unsigned cascade = 0; cascade < 4; cascade++)
{
@@ -1024,7 +1025,11 @@ void IrrDriver::renderShadows()
}
glDisable(GL_POLYGON_OFFSET_FILL);
glCullFace(GL_BACK);
if (irr_driver->hasARBTextureView())
m_post_processing->renderGaussian6BlurLayer(m_rtts->getShadowFBO());
glBindTexture(GL_TEXTURE_2D_ARRAY, m_rtts->getShadowFBO().getRTT()[0]);
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
}

View File

@@ -164,7 +164,7 @@ void IrrDriver::renderLights(unsigned pointlightcount, bool hasShadow)
{
ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_SUN));
if (World::getWorld() && UserConfigParams::m_shadows && !irr_driver->needUBOWorkaround())
m_post_processing->renderShadowedSunlight(sun_ortho_matrix, m_rtts->getShadowDepthTex());
m_post_processing->renderShadowedSunlight(sun_ortho_matrix, m_rtts->getShadowFBO().getRTT()[0]);
else
m_post_processing->renderSunlight();
}

View File

@@ -24,13 +24,13 @@
#include "utils/log.hpp"
#include <ISceneManager.h>
static GLuint generateRTT3D(GLenum target, size_t w, size_t h, size_t d, GLint internalFormat, GLint format, GLint type)
static GLuint generateRTT3D(GLenum target, size_t w, size_t h, size_t d, GLint internalFormat, GLint format, GLint type, unsigned mipmaplevel = 1)
{
GLuint result;
glGenTextures(1, &result);
glBindTexture(target, result);
if (irr_driver->hasARBTextureStorage())
glTexStorage3D(target, 1, internalFormat, w, h, d);
glTexStorage3D(target, mipmaplevel, internalFormat, w, h, d);
else
glTexImage3D(target, 0, internalFormat, w, h, d, 0, format, type, 0);
return result;
@@ -223,8 +223,8 @@ RTT::RTT(size_t width, size_t height)
if (UserConfigParams::m_shadows && !irr_driver->needUBOWorkaround())
{
shadowColorTex = generateRTT3D(GL_TEXTURE_2D_ARRAY, 1024, 1024, 4, GL_R8, GL_RED, GL_UNSIGNED_BYTE);
shadowDepthTex = generateRTT3D(GL_TEXTURE_2D_ARRAY, 1024, 1024, 4, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
shadowColorTex = generateRTT3D(GL_TEXTURE_2D_ARRAY, 1024, 1024, 4, GL_R32F, GL_RED, GL_FLOAT, 1);
shadowDepthTex = generateRTT3D(GL_TEXTURE_2D_ARRAY, 1024, 1024, 4, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 1);
somevector.clear();
somevector.push_back(shadowColorTex);

View File

@@ -44,7 +44,6 @@ public:
FrameBuffer &getShadowFBO() { return *m_shadow_FBO; }
FrameBuffer &getRH() { return *m_RH_FBO; }
FrameBuffer &getRSM() { return *m_RSM; }
unsigned getShadowDepthTex() const { return shadowDepthTex; }
unsigned getDepthStencilTexture() const { return DepthStencilTexture; }
unsigned getRenderTarget(enum TypeRTT target) const { return RenderTargetTextures[target]; }

View File

@@ -859,11 +859,13 @@ GLuint createShadowSampler()
unsigned id;
glGenSamplers(1, &id);
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glSamplerParameteri(id, GL_TEXTURE_WRAP_S, GL_REPEAT);
glSamplerParameteri(id, GL_TEXTURE_WRAP_T, GL_REPEAT);
glSamplerParameterf(id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glSamplerParameterf(id, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
int aniso = UserConfigParams::m_anisotropic;
if (aniso == 0) aniso = 1;
glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)aniso);
return id;
#endif
}
@@ -1185,14 +1187,14 @@ namespace MeshShader
{
Program = LoadProgram(OBJECT,
GL_VERTEX_SHADER, file_manager->getAsset("shaders/shadow.vert").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/white.frag").c_str());
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/shadow.frag").c_str());
}
else
{
Program = LoadProgram(OBJECT,
GL_VERTEX_SHADER, file_manager->getAsset("shaders/shadow.vert").c_str(),
GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/white.frag").c_str());
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/shadow.frag").c_str());
}
AssignUniforms("layer", "ModelMatrix");
}
@@ -1238,7 +1240,7 @@ namespace MeshShader
Program = LoadProgram(OBJECT,
GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedshadow.vert").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/white.frag").c_str());
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/shadow.frag").c_str());
}
else
{
@@ -1246,7 +1248,7 @@ namespace MeshShader
GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(),
GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedshadow.vert").c_str(),
GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/instanced_shadow.geom").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/white.frag").c_str());
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/shadow.frag").c_str());
}
AssignUniforms("layer");
}
@@ -1260,14 +1262,14 @@ namespace MeshShader
{
Program = LoadProgram(OBJECT,
GL_VERTEX_SHADER, file_manager->getAsset("shaders/shadow.vert").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str());
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/shadowref.frag").c_str());
}
else
{
Program = LoadProgram(OBJECT,
GL_VERTEX_SHADER, file_manager->getAsset("shaders/shadow.vert").c_str(),
GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/object_unlit.frag").c_str());
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/shadowref.frag").c_str());
}
AssignUniforms("layer", "ModelMatrix");
AssignSamplerNames(Program, 0, "tex");
@@ -1567,7 +1569,7 @@ namespace FullScreenShader
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getRGBfromCIEXxy.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getCIEXYZ.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/tonemap.frag").c_str());
AssignUniforms();
AssignUniforms("vignette_weight");
AssignSamplerNames(Program, 0, "text");
}
@@ -1617,7 +1619,7 @@ namespace FullScreenShader
// Use 8 to circumvent a catalyst bug when binding sampler
AssignSamplerNames(Program, 0, "ntex", 1, "dtex", 8, "shadowtex");
AssignUniforms("direction", "col");
AssignUniforms("split0", "split1", "split2", "splitmax", "direction", "col");
}
RadianceHintsConstructionShader::RadianceHintsConstructionShader()
@@ -1787,6 +1789,29 @@ namespace FullScreenShader
AssignSamplerNames(Program, 0, "texture");
}
LightspaceBoundingBoxShader::LightspaceBoundingBoxShader()
{
Program = LoadProgram(OBJECT,
GL_COMPUTE_SHADER, file_manager->getAsset("shaders/Lightspaceboundingbox.comp").c_str(),
GL_COMPUTE_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str());
AssignSamplerNames(Program, 0, "depth");
AssignUniforms("SunCamMatrix", "split0", "split1", "split2", "splitmax");
GLuint block_idx = glGetProgramResourceIndex(Program, GL_SHADER_STORAGE_BLOCK, "BoundingBoxes");
glShaderStorageBlockBinding(Program, block_idx, 2);
}
DepthHistogramShader::DepthHistogramShader()
{
Program = LoadProgram(OBJECT,
GL_COMPUTE_SHADER, file_manager->getAsset("shaders/depthhistogram.comp").c_str(),
GL_COMPUTE_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str());
AssignSamplerNames(Program, 0, "depth");
GLuint block_idx = glGetProgramResourceIndex(Program, GL_SHADER_STORAGE_BLOCK, "Histogram");
glShaderStorageBlockBinding(Program, block_idx, 1);
}
GlowShader::GlowShader()
{
Program = LoadProgram(OBJECT,

View File

@@ -377,9 +377,10 @@ public:
BloomBlendShader();
};
class ToneMapShader : public ShaderHelperSingleton<ToneMapShader>, public TextureRead<Nearest_Filtered>
class ToneMapShader : public ShaderHelperSingleton<ToneMapShader, float>, public TextureRead<Nearest_Filtered>
{
public:
ToneMapShader();
};
@@ -401,7 +402,7 @@ public:
EnvMapShader();
};
class ShadowedSunLightShader : public ShaderHelperSingleton<ShadowedSunLightShader, core::vector3df, video::SColorf>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Shadow_Sampler>
class ShadowedSunLightShader : public ShaderHelperSingleton<ShadowedSunLightShader, float, float, float, float, core::vector3df, video::SColorf>, public TextureRead<Nearest_Filtered, Nearest_Filtered, Shadow_Sampler>
{
public:
ShadowedSunLightShader();
@@ -510,6 +511,18 @@ public:
LinearizeDepthShader();
};
class LightspaceBoundingBoxShader : public ShaderHelperSingleton<LightspaceBoundingBoxShader, core::matrix4, float, float, float, float>, public TextureRead < Nearest_Filtered >
{
public:
LightspaceBoundingBoxShader();
};
class DepthHistogramShader : public ShaderHelperSingleton<DepthHistogramShader>, public TextureRead <Nearest_Filtered>
{
public:
DepthHistogramShader();
};
class GlowShader : public ShaderHelperSingleton<GlowShader>, public TextureRead<Bilinear_Filtered>
{
public:

View File

@@ -23,7 +23,7 @@
#include <IMeshSceneNode.h>
#include <ISceneNode.h>
Shadow::Shadow(video::ITexture *texture, scene::ISceneNode *node,
Shadow::Shadow(video::ITexture *texture, scene::ISceneNode *node,
float scale = 1.0, float x_offset = 0.0, float y_offset = 0.0,
float z_offset = 0.0)
{

View File

@@ -69,9 +69,11 @@ SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart)
setTextureMatrix(&(m_node->getMaterial(0).getTextureMatrix(0)));
m_slipstream_time = 0.0f;
float length = m_kart->getKartProperties()->getSlipstreamLength();
float length = m_kart->getKartProperties()->getSlipstreamLength() *
m_kart->getPlayerDifficulty()->getSlipstreamLength();
float kw = m_kart->getKartWidth();
float ew = m_kart->getKartProperties()->getSlipstreamWidth();
float ew = m_kart->getKartProperties()->getSlipstreamWidth() *
m_kart->getPlayerDifficulty()->getSlipstreamWidth();
float kl = m_kart->getKartLength();
Vec3 p[4];
@@ -299,7 +301,8 @@ void SlipStream::setIntensity(float f, const AbstractKart *kart)
bool SlipStream::isSlipstreamReady() const
{
return m_slipstream_time>
m_kart->getKartProperties()->getSlipstreamCollectTime();
m_kart->getKartProperties()->getSlipstreamCollectTime() *
m_kart->getPlayerDifficulty()->getSlipstreamCollectTime();
} // isSlipstreamReady
//-----------------------------------------------------------------------------
@@ -315,10 +318,14 @@ void SlipStream::updateSlipstreamPower()
setIntensity(2.0f, NULL);
const KartProperties *kp=m_kart->getKartProperties();
m_kart->increaseMaxSpeed(MaxSpeed::MS_INCREASE_SLIPSTREAM,
kp->getSlipstreamMaxSpeedIncrease(),
kp->getSlipstreamAddPower(),
kp->getSlipstreamDuration(),
kp->getSlipstreamFadeOutTime() );
kp->getSlipstreamMaxSpeedIncrease() *
m_kart->getPlayerDifficulty()->getSlipstreamMaxSpeedIncrease(),
kp->getSlipstreamAddPower() *
m_kart->getPlayerDifficulty()->getSlipstreamAddPower(),
kp->getSlipstreamDuration() *
m_kart->getPlayerDifficulty()->getSlipstreamDuration(),
kp->getSlipstreamFadeOutTime() *
m_kart->getPlayerDifficulty()->getSlipstreamFadeOutTime());
}
} // upateSlipstreamPower
@@ -372,7 +379,8 @@ void SlipStream::update(float dt)
// not moving. This is useful for debugging the graphics of SS-ing.
#undef DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
#ifndef DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
if(m_kart->getSpeed()<m_kart->getKartProperties()->getSlipstreamMinSpeed())
if(m_kart->getSpeed()<m_kart->getKartProperties()->getSlipstreamMinSpeed() *
m_kart->getPlayerDifficulty()->getSlipstreamMinSpeed())
{
setIntensity(0, NULL);
m_slipstream_mode = SS_NONE;
@@ -414,7 +422,8 @@ void SlipStream::update(float dt)
// give karts different slipstream properties.
#ifndef DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
if(m_target_kart->getSpeed() <
m_kart->getKartProperties()->getSlipstreamMinSpeed())
m_kart->getKartProperties()->getSlipstreamMinSpeed() *
m_kart->getPlayerDifficulty()->getSlipstreamMinSpeed())
{
if(UserConfigParams::m_slipstream_debug &&
m_kart->getController()->isPlayerController())
@@ -428,7 +437,8 @@ void SlipStream::update(float dt)
// slipstream length+0.5*kart_length()+0.5*target_kart_length
// away from the other kart
Vec3 delta = m_kart->getXYZ() - m_target_kart->getXYZ();
float l = m_target_kart->getKartProperties()->getSlipstreamLength()
float l = m_kart->getKartProperties()->getSlipstreamLength() *
m_kart->getPlayerDifficulty()->getSlipstreamLength()
+ 0.5f*( m_target_kart->getKartLength()
+m_kart->getKartLength() );
if(delta.length2_2d() > l*l)
@@ -469,7 +479,8 @@ void SlipStream::update(float dt)
m_slipstream_mode = SS_USE;
m_kart->handleZipper();
m_slipstream_time =
m_kart->getKartProperties()->getSlipstreamCollectTime();
m_kart->getKartProperties()->getSlipstreamCollectTime() *
m_kart->getPlayerDifficulty()->getSlipstreamCollectTime();
return;
}
}
@@ -490,7 +501,8 @@ void SlipStream::update(float dt)
setIntensity(m_slipstream_time, m_target_kart);
m_slipstream_mode = SS_COLLECT;
if(m_slipstream_time>m_kart->getKartProperties()->getSlipstreamCollectTime())
if(m_slipstream_time>m_kart->getKartProperties()->getSlipstreamCollectTime() *
m_kart->getPlayerDifficulty()->getSlipstreamCollectTime())
{
setIntensity(1.0f, m_target_kart);
}

View File

@@ -171,4 +171,4 @@ void STKTextBillboard::collectChar(video::ITexture* texture,
const video::SColor* const colors)
{
m_chars.push_back(STKTextBillboardChar(texture, destRect, sourceRect, colors));
}
}

View File

@@ -286,10 +286,7 @@ SetTexture(GLMesh &mesh, unsigned i, bool isSrgb, const std::string &matname)
{
if (!mesh.textures[i])
{
#ifdef DEBUG
Log::fatal("STKMesh", "Missing texture %d for material %s, mesh <%s>",
i, matname.c_str(), mesh.debug_name.c_str());
#endif
Log::fatal("STKMesh", "Missing texture %d for material %s", i, matname.c_str());
return;
}
compressTexture(mesh.textures[i], isSrgb);

View File

@@ -54,9 +54,6 @@ core::vector3df getWindDir();
class STKMeshCommon
{
protected:
bool m_culledForPlayerCam;
bool m_culledForShadowCam[4];
bool m_culledForRSMCam;
std::string m_debug_name;
public:
@@ -66,12 +63,6 @@ public:
virtual void updateGL() = 0;
virtual bool glow() const = 0;
virtual bool isImmediateDraw() const { return false; }
bool isCulledForPlayerCam() const { return m_culledForPlayerCam; }
void setCulledForPlayerCam(bool v) { m_culledForPlayerCam = v; }
bool isCulledForShadowCam(unsigned cascade) const { return m_culledForShadowCam[cascade]; }
void setCulledForShadowCam(unsigned cascade, bool v) { m_culledForShadowCam[cascade] = v; }
bool isCulledForRSMCam() const { return m_culledForRSMCam; }
void setCulledForRSMCam(bool v) { m_culledForRSMCam = v; }
};
template<typename T, typename... Args>

View File

@@ -110,7 +110,7 @@ void InstanceFiller<GlowInstanceData>::add(GLMesh *mesh, scene::ISceneNode *node
template<typename T>
static void
FillInstances_impl(std::vector<std::pair<GLMesh *, scene::ISceneNode *> > InstanceList, T * InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer,
size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount, std::function<bool (const scene::ISceneNode *)> cull_func)
size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount)
{
// Should never be empty
GLMesh *mesh = InstanceList.front().first;
@@ -120,9 +120,8 @@ FillInstances_impl(std::vector<std::pair<GLMesh *, scene::ISceneNode *> > Instan
{
auto &Tp = InstanceList[i];
scene::ISceneNode *node = Tp.second;
if (cull_func(node))
continue;
InstanceFiller<T>::add(mesh, node, InstanceBuffer[InstanceBufferOffset++]);
assert(InstanceBufferOffset * sizeof(T) < 10000 * sizeof(InstanceDataDualTex));
}
DrawElementsIndirectCommand &CurrentCommand = CommandBuffer[CommandBufferOffset++];
@@ -138,19 +137,18 @@ FillInstances_impl(std::vector<std::pair<GLMesh *, scene::ISceneNode *> > Instan
template<typename T>
static
void FillInstances(const std::unordered_map<scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > &GatheredGLMesh, std::vector<GLMesh *> &InstancedList,
T *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &Polycount,
std::function<bool (const scene::ISceneNode *)> cull_func)
T *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &Polycount)
{
auto It = GatheredGLMesh.begin(), E = GatheredGLMesh.end();
for (; It != E; ++It)
{
FillInstances_impl<T>(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, Polycount, cull_func);
FillInstances_impl<T>(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, Polycount);
if (!UserConfigParams::m_azdo)
InstancedList.push_back(It->second.front().first);
}
}
static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > MeshForSolidPass[Material::SHADERTYPE_COUNT];
static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > MeshForSolidPass[Material::SHADERTYPE_COUNT], MeshForShadowPass[Material::SHADERTYPE_COUNT][4], MeshForRSM[Material::SHADERTYPE_COUNT];
static std::unordered_map <scene::IMeshBuffer *, std::vector<std::pair<GLMesh *, scene::ISceneNode*> > > MeshForGlowPass;
static std::vector <STKMeshCommon *> DeferredUpdate;
@@ -200,7 +198,8 @@ bool isCulledPrecise(const scene::ICameraSceneNode *cam, const scene::ISceneNode
static void
handleSTKCommon(scene::ISceneNode *Node, std::vector<scene::ISceneNode *> *ImmediateDraw,
const scene::ICameraSceneNode *cam, scene::ICameraSceneNode *shadowcam[4], const scene::ICameraSceneNode *rsmcam)
const scene::ICameraSceneNode *cam, scene::ICameraSceneNode *shadowcam[4], const scene::ICameraSceneNode *rsmcam,
bool &culledforcam, bool culledforshadowcam[4], bool &culledforrsm)
{
STKMeshCommon *node = dynamic_cast<STKMeshCommon*>(Node);
if (!node)
@@ -249,6 +248,11 @@ handleSTKCommon(scene::ISceneNode *Node, std::vector<scene::ISceneNode *> *Immed
return;
}
culledforcam = culledforcam || isCulledPrecise(cam, Node);
culledforrsm = culledforrsm || isCulledPrecise(rsmcam, Node);
for (unsigned i = 0; i < 4; i++)
culledforshadowcam[i] = culledforshadowcam[i] || isCulledPrecise(shadowcam[i], Node);
// Transparent
GLMesh *mesh;
if (World::getWorld() && World::getWorld()->isFogEnabled())
@@ -284,21 +288,48 @@ handleSTKCommon(scene::ISceneNode *Node, std::vector<scene::ISceneNode *> *Immed
for_in(mesh, node->TransparentMesh[TM_DISPLACEMENT])
pushVector(ListDisplacement::getInstance(), mesh, Node->getAbsoluteTransformation());
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
if (!culledforcam)
{
if (irr_driver->hasARB_draw_indirect())
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
for_in(mesh, node->MeshSolidMaterial[Mat])
if (irr_driver->hasARB_draw_indirect())
{
if (node->glow())
MeshForGlowPass[mesh->mb].emplace_back(mesh, Node);
if (Mat != Material::SHADERTYPE_SPLATTING && mesh->TextureMatrix.isIdentity())
MeshForSolidPass[Mat][mesh->mb].emplace_back(mesh, Node);
else
for_in(mesh, node->MeshSolidMaterial[Mat])
{
if (node->glow())
MeshForGlowPass[mesh->mb].emplace_back(mesh, Node);
if (Mat != Material::SHADERTYPE_SPLATTING && mesh->TextureMatrix.isIdentity())
MeshForSolidPass[Mat][mesh->mb].emplace_back(mesh, Node);
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
}
}
}
}
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for_in(mesh, node->MeshSolidMaterial[Mat])
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
@@ -307,65 +338,44 @@ handleSTKCommon(scene::ISceneNode *Node, std::vector<scene::ISceneNode *> *Immed
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir);
break;
}
}
}
}
else
{
if (isCulledPrecise(cam, Node))
continue;
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for_in(mesh, node->MeshSolidMaterial[Mat])
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir);
break;
}
}
}
}
if (!UserConfigParams::m_shadows)
return;
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
for (unsigned cascade = 0; cascade < 4; ++cascade)
{
for (unsigned cascade = 0; cascade < 4; ++cascade)
if (culledforshadowcam[cascade])
continue;
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
if (!irr_driver->hasARB_draw_indirect())
if (irr_driver->hasARB_draw_indirect())
{
for_in(mesh, node->MeshSolidMaterial[Mat])
MeshForShadowPass[Mat][cascade][mesh->mb].emplace_back(mesh, Node);
}
else
{
if (isCulledPrecise(shadowcam[cascade], Node))
continue;
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
@@ -403,53 +413,60 @@ handleSTKCommon(scene::ISceneNode *Node, std::vector<scene::ISceneNode *> *Immed
}
if (!UserConfigParams::m_gi)
return;
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
if (!culledforrsm)
{
if (irr_driver->hasARB_draw_indirect())
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
if (Mat == Material::SHADERTYPE_SPLATTING)
if (irr_driver->hasARB_draw_indirect())
{
if (Mat == Material::SHADERTYPE_SPLATTING)
for_in(mesh, node->MeshSolidMaterial[Mat])
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix);
}
else
{
for_in(mesh, node->MeshSolidMaterial[Mat])
MeshForRSM[Mat][mesh->mb].emplace_back(mesh, Node);
}
}
else
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for_in(mesh, node->MeshSolidMaterial[Mat])
{
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix);
}
}
else
{
if (isCulledPrecise(rsmcam, Node))
continue;
core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix;
ModelMatrix.getInverse(InvModelMatrix);
for_in(mesh, node->MeshSolidMaterial[Mat])
{
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir);
break;
switch (Mat)
{
case Material::SHADERTYPE_SOLID:
ListMatDefault::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_ALPHA_TEST:
ListMatAlphaRef::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_NORMAL_MAP:
ListMatNormalMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_DETAIL_MAP:
ListMatDetails::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SOLID_UNLIT:
ListMatUnlit::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPHERE_MAP:
ListMatSphereMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix);
break;
case Material::SHADERTYPE_SPLATTING:
ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix);
break;
case Material::SHADERTYPE_VEGETATION:
ListMatGrass::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir);
break;
}
}
}
}
@@ -458,7 +475,8 @@ handleSTKCommon(scene::ISceneNode *Node, std::vector<scene::ISceneNode *> *Immed
static void
parseSceneManager(core::list<scene::ISceneNode*> List, std::vector<scene::ISceneNode *> *ImmediateDraw,
const scene::ICameraSceneNode* cam, scene::ICameraSceneNode *shadow_cam[4], const scene::ICameraSceneNode *rsmcam)
const scene::ICameraSceneNode* cam, scene::ICameraSceneNode *shadow_cam[4], const scene::ICameraSceneNode *rsmcam,
bool culledforcam, bool culledforshadowcam[4], bool culledforrsm)
{
core::list<scene::ISceneNode*>::Iterator I = List.begin(), E = List.end();
for (; I != E; ++I)
@@ -483,9 +501,13 @@ parseSceneManager(core::list<scene::ISceneNode*> List, std::vector<scene::IScene
continue;
}
handleSTKCommon(*I, ImmediateDraw, cam, shadow_cam, rsmcam);
bool newculledforcam = culledforcam;
bool newculledforrsm = culledforrsm;
bool newculledforshadowcam[4] = { culledforshadowcam[0], culledforshadowcam[1], culledforshadowcam[2], culledforshadowcam[3] };
parseSceneManager((*I)->getChildren(), ImmediateDraw, cam, shadow_cam, rsmcam);
handleSTKCommon(*I, ImmediateDraw, cam, shadow_cam, rsmcam, newculledforcam, newculledforshadowcam, newculledforrsm);
parseSceneManager((*I)->getChildren(), ImmediateDraw, cam, shadow_cam, rsmcam, newculledforcam, newculledforshadowcam, newculledforrsm);
}
}
@@ -493,16 +515,24 @@ template<Material::ShaderType Mat, typename T> static void
GenDrawCalls(unsigned cascade, std::vector<GLMesh *> &InstancedList,
T *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount)
{
std::function<bool(const scene::ISceneNode *)> shadowculling = [&](const scene::ISceneNode *nd) {return dynamic_cast<const STKMeshCommon*>(nd)->isCulledForShadowCam(cascade); };
if (irr_driver->hasARB_draw_indirect())
ShadowPassCmd::getInstance()->Offset[cascade][Mat] = CommandBufferOffset; // Store command buffer offset
FillInstances<T>(MeshForSolidPass[Mat], InstancedList, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, PolyCount, shadowculling);
FillInstances<T>(MeshForShadowPass[Mat][cascade], InstancedList, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, PolyCount);
if (UserConfigParams::m_azdo)
ShadowPassCmd::getInstance()->Size[cascade][Mat] = CommandBufferOffset - ShadowPassCmd::getInstance()->Offset[cascade][Mat];
}
int enableOpenMP;
static void FixBoundingBoxes(scene::ISceneNode* node)
{
for (scene::ISceneNode *child : node->getChildren())
{
FixBoundingBoxes(child);
const_cast<core::aabbox3df&>(node->getBoundingBox()).addInternalBox(child->getBoundingBox());
}
}
void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode)
{
windDir = getWindDir();
@@ -527,24 +557,24 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode)
ListInstancedGlow::getInstance()->clear();
for (unsigned Mat = 0; Mat < Material::SHADERTYPE_COUNT; ++Mat)
{
MeshForSolidPass[Mat].clear();
MeshForRSM[Mat].clear();
for (unsigned i = 0; i < 4; i++)
MeshForShadowPass[Mat][i].clear();
}
MeshForGlowPass.clear();
DeferredUpdate.clear();
core::list<scene::ISceneNode*> List = m_scene_manager->getRootSceneNode()->getChildren();
parseSceneManager(List, ImmediateDrawList::getInstance(), camnode, m_shadow_camnodes, m_suncam);
PROFILER_PUSH_CPU_MARKER("- culling", 0xFF, 0xFF, 0x0);
for (scene::ISceneNode *child : List)
FixBoundingBoxes(child);
#pragma omp parallel for
for (int i = 0; i < (int)DeferredUpdate.size(); i++)
{
scene::ISceneNode *node = dynamic_cast<scene::ISceneNode *>(DeferredUpdate[i]);
DeferredUpdate[i]->setCulledForPlayerCam(isCulledPrecise(camnode, node));
DeferredUpdate[i]->setCulledForRSMCam(isCulledPrecise(m_suncam, node));
DeferredUpdate[i]->setCulledForShadowCam(0, isCulledPrecise(m_shadow_camnodes[0], node));
DeferredUpdate[i]->setCulledForShadowCam(1, isCulledPrecise(m_shadow_camnodes[1], node));
DeferredUpdate[i]->setCulledForShadowCam(2, isCulledPrecise(m_shadow_camnodes[2], node));
DeferredUpdate[i]->setCulledForShadowCam(3, isCulledPrecise(m_shadow_camnodes[3], node));
}
bool cam = false, rsmcam = false;
bool shadowcam[4] = { false, false, false, false };
parseSceneManager(List, ImmediateDrawList::getInstance(), camnode, m_shadow_camnodes, m_suncam, cam, shadowcam, rsmcam);
PROFILER_POP_CPU_MARKER();
// Add a 1 s timeout
if (!m_sync)
@@ -615,7 +645,6 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode)
PROFILER_PUSH_CPU_MARKER("- Draw Command upload", 0xFF, 0x0, 0xFF);
auto playercamculling = [](const scene::ISceneNode *nd) {return dynamic_cast<const STKMeshCommon*>(nd)->isCulledForPlayerCam(); };
#pragma omp parallel sections if(enableOpenMP)
{
#pragma omp section
@@ -632,23 +661,23 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode)
// Default Material
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SOLID], ListInstancedMatDefault::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling);
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SOLID], ListInstancedMatDefault::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_SOLID] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID];
// Alpha Ref
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_ALPHA_TEST] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_ALPHA_TEST], ListInstancedMatAlphaRef::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling);
FillInstances(MeshForSolidPass[Material::SHADERTYPE_ALPHA_TEST], ListInstancedMatAlphaRef::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_ALPHA_TEST] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_ALPHA_TEST];
// Unlit
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID_UNLIT] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SOLID_UNLIT], ListInstancedMatUnlit::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling);
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SOLID_UNLIT], ListInstancedMatUnlit::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_SOLID_UNLIT] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID_UNLIT];
// Spheremap
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SPHERE_MAP] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SPHERE_MAP], ListInstancedMatSphereMap::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling);
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SPHERE_MAP], ListInstancedMatSphereMap::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_SPHERE_MAP] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_SPHERE_MAP];
// Grass
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_VEGETATION] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_VEGETATION], ListInstancedMatGrass::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling);
FillInstances(MeshForSolidPass[Material::SHADERTYPE_VEGETATION], ListInstancedMatGrass::getInstance()->SolidPass, InstanceBufferDualTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_VEGETATION] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_VEGETATION];
if (!irr_driver->hasBufferStorageExtension())
@@ -661,11 +690,11 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode)
// Detail
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_DETAIL_MAP] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_DETAIL_MAP], ListInstancedMatDetails::getInstance()->SolidPass, InstanceBufferThreeTex, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling);
FillInstances(MeshForSolidPass[Material::SHADERTYPE_DETAIL_MAP], ListInstancedMatDetails::getInstance()->SolidPass, InstanceBufferThreeTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_DETAIL_MAP] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_DETAIL_MAP];
// Normal Map
SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_NORMAL_MAP] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->SolidPass, InstanceBufferThreeTex, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling);
FillInstances(MeshForSolidPass[Material::SHADERTYPE_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->SolidPass, InstanceBufferThreeTex, CmdBuffer, offset, current_cmd, SolidPoly);
SolidPassCmd::getInstance()->Size[Material::SHADERTYPE_NORMAL_MAP] = current_cmd - SolidPassCmd::getInstance()->Offset[Material::SHADERTYPE_NORMAL_MAP];
@@ -695,7 +724,7 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode)
for (; It != E; ++It)
{
size_t Polycnt = 0;
FillInstances_impl<GlowInstanceData>(It->second, GlowInstanceBuffer, GlowCmdBuffer, offset, current_cmd, Polycnt, playercamculling);
FillInstances_impl<GlowInstanceData>(It->second, GlowInstanceBuffer, GlowCmdBuffer, offset, current_cmd, Polycnt);
if (!UserConfigParams::m_azdo)
ListInstancedGlow::getInstance()->push_back(It->second.front().first);
}
@@ -747,7 +776,6 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode)
}
#pragma omp section
{
auto rsmcamculling = [](const scene::ISceneNode *nd) {return dynamic_cast<const STKMeshCommon*>(nd)->isCulledForRSMCam(); };
size_t offset = 0, current_cmd = 0;
if (!irr_driver->hasBufferStorageExtension())
{
@@ -759,23 +787,23 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode)
// Default Material
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SOLID], ListInstancedMatDefault::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling);
FillInstances(MeshForRSM[Material::SHADERTYPE_SOLID], ListInstancedMatDefault::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_SOLID] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID];
// Alpha Ref
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_ALPHA_TEST] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_ALPHA_TEST], ListInstancedMatAlphaRef::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling);
FillInstances(MeshForRSM[Material::SHADERTYPE_ALPHA_TEST], ListInstancedMatAlphaRef::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_ALPHA_TEST] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_ALPHA_TEST];
// Unlit
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID_UNLIT] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_SOLID_UNLIT], ListInstancedMatUnlit::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling);
FillInstances(MeshForRSM[Material::SHADERTYPE_SOLID_UNLIT], ListInstancedMatUnlit::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_SOLID_UNLIT] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID_UNLIT];
// Detail
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_DETAIL_MAP] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_DETAIL_MAP], ListInstancedMatDetails::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling);
FillInstances(MeshForRSM[Material::SHADERTYPE_DETAIL_MAP], ListInstancedMatDetails::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_DETAIL_MAP] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_DETAIL_MAP];
// Normal Map
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_NORMAL_MAP] = current_cmd;
FillInstances(MeshForSolidPass[Material::SHADERTYPE_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling);
FillInstances(MeshForRSM[Material::SHADERTYPE_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
RSMPassCmd::getInstance()->Size[Material::SHADERTYPE_NORMAL_MAP] = current_cmd - RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_NORMAL_MAP];
if (!irr_driver->hasBufferStorageExtension())

View File

@@ -67,4 +67,4 @@ public:
};
#endif
#endif

View File

@@ -34,7 +34,7 @@ Weather::Weather(bool lightning, std::string sound)
if (m_lightning)
{
m_thunder_sound = SFXManager::get()->createSoundSource("thunder");
m_thunder_sound = SFXManager::get()->createSoundSource("thunder");
}
if (sound != "")
@@ -50,10 +50,10 @@ Weather::Weather(bool lightning, std::string sound)
Weather::~Weather()
{
if (m_thunder_sound != NULL)
if (m_thunder_sound != NULL)
m_thunder_sound->deleteSFX();
if (m_weather_sound != NULL)
if (m_weather_sound != NULL)
m_weather_sound->deleteSFX();
} // ~Weather
@@ -73,7 +73,7 @@ void Weather::update(float dt)
{
gui_base->doLightning();
if (m_thunder_sound)
if (m_thunder_sound)
{
m_thunder_sound->play();
}
@@ -89,9 +89,9 @@ void Weather::update(float dt)
void Weather::playSound()
{
if (m_weather_sound)
if (m_weather_sound)
{
m_weather_sound->setLoop(true);
m_weather_sound->play();
}
}
}

View File

@@ -2082,6 +2082,20 @@ void Skin::drawBadgeOn(const Widget* widget, const core::recti& rect)
"hourglass.png");
doDrawBadge(texture, rect, max_icon_size, true);
}
if (widget->m_badges & ZIPPER_BADGE)
{
float max_icon_size = 0.43f;
video::ITexture* texture = irr_driver->getTexture(FileManager::MODEL,
"zipper_collect.png");
doDrawBadge(texture, rect, max_icon_size, false);
}
if (widget->m_badges & ANCHOR_BADGE)
{
float max_icon_size = 0.43f;
video::ITexture* texture = irr_driver->getTexture(FileManager::MODEL,
"anchor-icon.png");
doDrawBadge(texture, rect, max_icon_size, false);
}
} // drawBadgeOn
// -----------------------------------------------------------------------------

View File

@@ -60,19 +60,23 @@ namespace GUIEngine
enum BadgeType
{
/** display a lock on the widget, to mean a certain game feature is locked */
LOCKED_BADGE = 1,
LOCKED_BADGE = 1,
/** display a green check on a widget, useful e.g. to display confirmation */
OK_BADGE = 2,
OK_BADGE = 2,
/** display a red mark badge on the widget, useful e.g. to warn of an invalid choice */
BAD_BADGE = 4,
BAD_BADGE = 4,
/** display a trophy badge on the widget, useful e.g. for challenges */
TROPHY_BADGE = 8,
TROPHY_BADGE = 8,
/** A gamepad icon */
GAMEPAD_BADGE = 16,
GAMEPAD_BADGE = 16,
/** A keyboard icon */
KEYBOARD_BADGE = 32,
/** An hourglass badge to indicate loading */
LOADING_BADGE = 64
LOADING_BADGE = 64,
/** A zipper badge to indicate that this player receives a boost */
ZIPPER_BADGE = 128,
/** A anchor badge to indicate that this player receives a handicap */
ANCHOR_BADGE = 256
};

View File

@@ -38,14 +38,11 @@ using namespace irr;
// -----------------------------------------------------------------------------
KartStatsWidget::KartStatsWidget(core::recti area, const int player_id,
std::string kart_group,
bool multiplayer) : Widget(WTYPE_DIV)
std::string kart_group, bool multiplayer,
bool display_text) : Widget(WTYPE_DIV)
{
m_player_id = player_id;
setSize(area.UpperLeftCorner.X, area.UpperLeftCorner.Y,
area.getWidth(), area.getHeight() );
const std::string default_kart = UserConfigParams::m_default_kart;
const KartProperties* props =
kart_properties_manager->getKart(default_kart);
@@ -72,19 +69,16 @@ KartStatsWidget::KartStatsWidget(core::recti area, const int player_id,
}
const int offset = (m_h - (SKILL_COUNT*m_skill_bar_h)) / 2;
for (int i = 0; i < SKILL_COUNT; ++i)
{
irr::core::recti skillArea(m_skill_bar_x, m_skill_bar_y + offset*i,
m_skill_bar_x + m_skill_bar_w,
m_skill_bar_y + m_skill_bar_h + offset*i);
irr::core::recti skillArea(0, 0, 1, 1);
SkillLevelWidget* skill_bar = NULL;
skill_bar = new SkillLevelWidget(skillArea, m_player_id, multiplayer);
skill_bar = new SkillLevelWidget(skillArea, m_player_id, multiplayer, display_text);
m_skills.push_back(skill_bar);
m_children.push_back(skill_bar);
m_skills.push_back(skill_bar);
m_children.push_back(skill_bar);
}
m_skills[SKILL_MASS]->setValue((int)(props->getMass()/5));
@@ -99,6 +93,8 @@ KartStatsWidget::KartStatsWidget(core::recti area, const int player_id,
m_skills[SKILL_POWER]->setLabel("POWER");
m_skills[SKILL_POWER]->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_power", m_player_id);
move(area.UpperLeftCorner.X, area.UpperLeftCorner.Y,
area.getWidth(), area.getHeight());
} // KartStatsWidget
// -----------------------------------------------------------------------------
@@ -114,11 +110,14 @@ void KartStatsWidget::move(int x, int y, int w, int h)
{
Widget::move(x,y,w,h);
setSize(m_x, m_y, m_w, m_h);
int offset = (m_h - (SKILL_COUNT*m_skill_bar_h)) / 2;
int margin = m_h / SKILL_COUNT - m_skill_bar_h / 2;
if (margin > m_skill_bar_h)
margin = m_skill_bar_h;
int offset = (m_h - (SKILL_COUNT * margin)) / 2;
for (int i = 0; i < SKILL_COUNT; ++i)
{
m_skills[i]->move(m_skill_bar_x,
m_y + offset + m_skill_bar_h*i,
m_y + offset + margin * i,
m_skill_bar_w,
m_skill_bar_h);
}
@@ -163,4 +162,13 @@ void KartStatsWidget::setSize(const int x, const int y, const int w, const int h
m_skill_bar_y = y + h/2 - m_skill_bar_h/2;
} // setSize
void KartStatsWidget::setDisplayText(bool display_text)
{
for (int i = 0; i < SKILL_COUNT; ++i)
{
m_skills[i]->setDisplayText(display_text);
}
} // setDisplayText
// -----------------------------------------------------------------------------

View File

@@ -37,28 +37,26 @@ namespace GUIEngine
* \brief A progress bar widget.
* \ingroup widgetsgroup
*/
class KartStatsWidget : public Widget
class KartStatsWidget : public Widget
{
/** When inferring widget size from its label length, this method will be called to
* if/how much space must be added to the raw label's size for the widget to be large enough */
virtual int getWidthNeededAroundLabel() const { return 35; }
/** When inferring widget size from its label length, this method will be called to
* if/how much space must be added to the raw label's size for the widget to be large enough */
virtual int getHeightNeededAroundLabel() const { return 4; }
/** widget coordinates */
int m_skill_bar_x, m_skill_bar_y, m_skill_bar_h, m_skill_bar_w;
int m_player_id;
std::vector<SkillLevelWidget*> m_skills;
public:
enum Stats
{
SKILL_MASS,
@@ -68,10 +66,10 @@ class KartStatsWidget : public Widget
};
LEAK_CHECK()
KartStatsWidget(core::recti area, const int player_id,
std::string kart_group,
bool multiplayer);
std::string kart_group, bool multiplayer,
bool display_text);
virtual ~KartStatsWidget() {};
// ------------------------------------------------------------------------
@@ -95,9 +93,12 @@ class KartStatsWidget : public Widget
/** Change the value of the widget, it must be a percent. */
void setValue(Stats type, int value);
/** Get the current values of the widget. */
int getValue(Stats type);
/** If the labels should be displayed. */
void setDisplayText(bool display_text);
};
}

View File

@@ -0,0 +1,711 @@
// SuperTuxKart - a fun racing game with go-kart
//
// Copyright (C) 2006-2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "config/player_manager.hpp"
#include "guiengine/widgets/kart_stats_widget.hpp"
#include "guiengine/widgets/model_view_widget.hpp"
#include "guiengine/widgets/player_kart_widget.hpp"
#include "guiengine/widgets/player_name_spinner.hpp"
#include "input/input_device.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
#include "online/online_profile.hpp"
#include "states_screens/kart_selection.hpp"
#include <IGUIEnvironment.h>
static const char RANDOM_KART_ID[] = "randomkart";
using namespace GUIEngine;
PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent,
StateManager::ActivePlayer* associated_player,
Online::OnlineProfile* associated_user,
core::recti area, const int player_id,
std::string kart_group,
const int irrlicht_widget_id) : Widget(WTYPE_DIV)
{
#ifdef DEBUG
if (associated_player)
assert(associated_player->ok());
m_magic_number = 0x33445566;
#endif
m_ready_text = NULL;
m_parent_screen = parent;
m_associated_user = associated_user;
m_associated_player = associated_player;
x_speed = 1.0f;
y_speed = 1.0f;
w_speed = 1.0f;
h_speed = 1.0f;
m_ready = false;
m_handicapped = false;
m_not_updated_yet = true;
m_irrlicht_widget_id = irrlicht_widget_id;
m_player_id = player_id;
m_properties[PROP_ID] = StringUtils::insertValues("@p%i", m_player_id);
setSize(area.UpperLeftCorner.X, area.UpperLeftCorner.Y,
area.getWidth(), area.getHeight() );
target_x = m_x;
target_y = m_y;
target_w = m_w;
target_h = m_h;
// ---- Player identity spinner
m_player_ident_spinner = NULL;
m_player_ident_spinner = new PlayerNameSpinner(parent, m_player_id);
m_player_ident_spinner->m_x = player_name_x;
m_player_ident_spinner->m_y = player_name_y;
m_player_ident_spinner->m_w = player_name_w;
m_player_ident_spinner->m_h = player_name_h;
// ---- KartStatsWidget
m_kart_stats = NULL;
// area for the stats widget
core::recti statsArea;
if (!parent->m_multiplayer)
{
statsArea = core::recti(m_kart_stats_x,
m_kart_stats_y,
m_kart_stats_x + m_kart_stats_w,
m_kart_stats_y + m_kart_stats_h);
}
else
{
statsArea = core::recti(m_x , m_y + m_h/2,
m_x + m_w, m_y + m_h);
}
m_kart_stats = new GUIEngine::KartStatsWidget(statsArea, player_id, kart_group,
m_parent_screen->m_multiplayer,
!m_parent_screen->m_multiplayer || parent->m_kart_widgets.size() == 0);
m_kart_stats->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_stats", m_player_id);
m_children.push_back(m_kart_stats);
if (parent->m_multiplayer && associated_player)
{
if (associated_player->getDevice()->getType() == DT_KEYBOARD)
{
m_player_ident_spinner->setBadge(KEYBOARD_BADGE);
}
else if (associated_player->getDevice()->getType() == DT_GAMEPAD)
{
m_player_ident_spinner->setBadge(GAMEPAD_BADGE);
}
}
else if (m_associated_user) // online user, FIXME is that useful ?
{
m_player_ident_spinner->setBadge(OK_BADGE);
}
if (irrlicht_widget_id == -1)
{
m_player_ident_spinner->m_tab_down_root = g_root_id;
}
spinnerID = StringUtils::insertValues("@p%i_spinner", m_player_id);
m_player_ident_spinner->m_properties[PROP_ID] = spinnerID;
if (parent->m_multiplayer)
{
const int player_amount = PlayerManager::get()->getNumPlayers();
m_player_ident_spinner->m_properties[PROP_MIN_VALUE] = "0";
m_player_ident_spinner->m_properties[PROP_MAX_VALUE] =
StringUtils::toString(player_amount-1);
m_player_ident_spinner->m_properties[PROP_WRAP_AROUND] = "true";
}
else
{
m_player_ident_spinner->m_properties[PROP_MIN_VALUE] = "0";
m_player_ident_spinner->m_properties[PROP_MAX_VALUE] = "0";
}
//m_player_ident_spinner->m_event_handler = this;
m_children.push_back(m_player_ident_spinner);
// ----- Kart model view
m_model_view = new ModelViewWidget();
m_model_view->m_x = model_x;
m_model_view->m_y = model_y;
m_model_view->m_w = model_w;
m_model_view->m_h = model_h;
m_model_view->m_properties[PROP_ID] =
StringUtils::insertValues("@p%i_model", m_player_id);
//m_model_view->setParent(this);
m_children.push_back(m_model_view);
// Init kart model
const std::string default_kart = UserConfigParams::m_default_kart;
const KartProperties* props =
kart_properties_manager->getKart(default_kart);
if(!props)
{
// If the default kart can't be found (e.g. previously a addon
// kart was used, but the addon package was removed), use the
// first kart as a default. This way we don't have to hardcode
// any kart names.
int id = kart_properties_manager->getKartByGroup(kart_group, 0);
if (id == -1)
{
props = kart_properties_manager->getKartById(0);
}
else
{
props = kart_properties_manager->getKartById(id);
}
if(!props)
Log::fatal("KartSelectionScreen", "Can't find default "
"kart '%s' nor any other kart.",
default_kart.c_str());
}
m_kartInternalName = props->getIdent();
const KartModel &kart_model = props->getMasterKartModel();
float scale = 35.0f;
if (kart_model.getLength() > 1.45f)
{
// if kart is too long, size it down a bit so that it fits
scale = 30.0f;
}
m_model_view->addModel( kart_model.getModel(), Vec3(0,0,0),
Vec3(scale, scale, scale),
kart_model.getBaseFrame() );
m_model_view->addModel( kart_model.getWheelModel(0),
kart_model.getWheelGraphicsPosition(0) );
m_model_view->addModel( kart_model.getWheelModel(1),
kart_model.getWheelGraphicsPosition(1) );
m_model_view->addModel( kart_model.getWheelModel(2),
kart_model.getWheelGraphicsPosition(2) );
m_model_view->addModel( kart_model.getWheelModel(3),
kart_model.getWheelGraphicsPosition(3) );
for(size_t i=0 ; i < kart_model.getSpeedWeightedObjectsCount() ; i++)
{
const SpeedWeightedObject& obj = kart_model.getSpeedWeightedObject((int)i);
m_model_view->addModel(obj.m_model, obj.m_position);
}
m_model_view->setRotateContinuously( 35.0f );
// ---- Kart name label
m_kart_name = new LabelWidget(true, true);
m_kart_name->setText(props->getName(), false);
m_kart_name->m_properties[PROP_TEXT_ALIGN] = "center";
m_kart_name->m_properties[PROP_ID] =
StringUtils::insertValues("@p%i_kartname", m_player_id);
m_kart_name->m_x = kart_name_x;
m_kart_name->m_y = kart_name_y;
m_kart_name->m_w = kart_name_w;
m_kart_name->m_h = kart_name_h;
m_children.push_back(m_kart_name);
} // PlayerKartWidget
// ------------------------------------------------------------------------
PlayerKartWidget::~PlayerKartWidget()
{
if (GUIEngine::getFocusForPlayer(m_player_id) == this)
{
GUIEngine::focusNothingForPlayer(m_player_id);
}
if (m_player_ident_spinner != NULL)
{
m_player_ident_spinner->setListener(NULL);
if (m_player_ident_spinner->getIrrlichtElement() != NULL)
{
m_player_ident_spinner->getIrrlichtElement()->remove();
}
}
if (m_model_view->getIrrlichtElement() != NULL)
m_model_view->getIrrlichtElement()->remove();
if (m_kart_name->getIrrlichtElement() != NULL)
m_kart_name->getIrrlichtElement()->remove();
getCurrentScreen()->manualRemoveWidget(this);
#ifdef DEBUG
m_magic_number = 0xDEADBEEF;
#endif
} // ~PlayerKartWidget
// ------------------------------------------------------------------------
/** Called when players are renumbered (changes the player ID) */
void PlayerKartWidget::setPlayerID(const int newPlayerID)
{
assert(m_magic_number == 0x33445566);
if (StateManager::get()->getActivePlayer(newPlayerID)
!= m_associated_player)
{
Log::error("KartSelectionScreen", "Internal "
"inconsistency, PlayerKartWidget has IDs and "
"pointers that do not correspond to one player");
Log::fatal("KartSelectionScreen", " Player: %p - Index: %d - m_associated_player: %p",
StateManager::get()->getActivePlayer(newPlayerID),
newPlayerID, m_associated_player);
}
// Remove current focus, but remember it
Widget* focus = GUIEngine::getFocusForPlayer(m_player_id);
GUIEngine::focusNothingForPlayer(m_player_id);
// Change the player ID
m_player_id = newPlayerID;
if (!m_ready)
m_player_ident_spinner->setID(m_player_id);
m_kart_stats->setDisplayText(m_player_id == 0);
// restore previous focus, but with new player ID
if (focus != NULL) focus->setFocusForPlayer(m_player_id);
if (m_player_ident_spinner != NULL)
{
m_player_ident_spinner->setID(m_player_id);
}
} // setPlayerID
// ------------------------------------------------------------------------
/** Returns the ID of this player */
int PlayerKartWidget::getPlayerID() const
{
assert(m_magic_number == 0x33445566);
return m_player_id;
} // getPlayerID
// ------------------------------------------------------------------------
/** Add the widgets to the current screen */
void PlayerKartWidget::add()
{
assert(m_magic_number == 0x33445566);
assert(KartSelectionScreen::getRunningInstance()
->m_kart_widgets.contains(this));
if (m_associated_player) // if player is local
{
bool mineInList = false;
for (unsigned int p=0; p<StateManager::get()->activePlayerCount(); p++)
{
#ifdef DEBUG
assert(StateManager::get()->getActivePlayer(p)->ok());
#endif
if (StateManager::get()->getActivePlayer(p) == m_associated_player)
{
mineInList = true;
}
}
assert(mineInList);
}
// the first player will have an ID of its own to allow for keyboard
// navigation despite this widget being added last
if (m_irrlicht_widget_id != -1)
m_player_ident_spinner->m_reserved_id = m_irrlicht_widget_id;
else
m_player_ident_spinner->m_reserved_id = Widget::getNewNoFocusID();
m_player_ident_spinner->add();
m_player_ident_spinner->getIrrlichtElement()->setTabStop(false);
m_player_ident_spinner->setListener(this);
m_kart_stats->add();
m_model_view->add();
m_kart_name->add();
m_model_view->update(0);
m_player_ident_spinner->clearLabels();
irr::core::stringw name; // name of the player
if (m_associated_player)
name = m_associated_player->getProfile()->getName();
if (m_associated_user)
name = m_associated_user->getUserName();
if (m_parent_screen->m_multiplayer)
{
const int player_amount = PlayerManager::get()->getNumPlayers();
for (int n=0; n<player_amount; n++)
{
core::stringw name = PlayerManager::get()->getPlayer(n)->getName();
m_player_ident_spinner->addLabel(translations->fribidize(name));
if (UserConfigParams::m_per_player_difficulty)
// The second player is the same, but with handicap
m_player_ident_spinner->addLabel(translations->fribidize(name));
}
// select the right player profile in the spinner
m_player_ident_spinner->setValue(name);
}
else
{
m_player_ident_spinner->addLabel(name);
m_player_ident_spinner->setVisible(false);
}
// Add anchor badge if the player is handicapped
int spinner_value = m_player_ident_spinner->getValue();
assert(m_player_ident_spinner->getStringValue() == name);
} // add
// ------------------------------------------------------------------------
/** Get the associated ActivePlayer object*/
StateManager::ActivePlayer* PlayerKartWidget::getAssociatedPlayer()
{
assert(m_magic_number == 0x33445566);
return m_associated_player;
} // getAssociatedPlayer
// ------------------------------------------------------------------------
/** Starts a 'move/resize' animation, by simply passing destination coords.
* The animation will then occur on each call to 'onUpdate'. */
void PlayerKartWidget::move(const int x, const int y, const int w, const int h)
{
assert(m_magic_number == 0x33445566);
target_x = x;
target_y = y;
target_w = w;
target_h = h;
x_speed = abs( m_x - x ) / 300.0f;
y_speed = abs( m_y - y ) / 300.0f;
w_speed = abs( m_w - w ) / 300.0f;
h_speed = abs( m_h - h ) / 300.0f;
} // move
// ------------------------------------------------------------------------
/** Call when player confirmed his identity and kart */
void PlayerKartWidget::markAsReady()
{
assert(m_magic_number == 0x33445566);
if (m_ready) return; // already ready
m_ready = true;
stringw playerNameString = m_player_ident_spinner->getStringValue();
core::rect<s32> rect(core::position2di(m_player_ident_spinner->m_x,
m_player_ident_spinner->m_y),
core::dimension2di(m_player_ident_spinner->m_w,
m_player_ident_spinner->m_h));
// 'playerNameString' is already fribidize, so we need to use
// 'insertValues' and not _("...", a) so it's not flipped again
m_ready_text =
GUIEngine::getGUIEnv()->addStaticText(
StringUtils::insertValues(_("%s is ready"),
playerNameString).c_str(),
rect );
m_ready_text->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER );
m_children.remove(m_player_ident_spinner);
m_player_ident_spinner->setListener(NULL);
m_player_ident_spinner->getIrrlichtElement()->remove();
m_player_ident_spinner->elementRemoved();
delete m_player_ident_spinner;
m_player_ident_spinner = NULL;
SFXManager::get()->quickSound( "wee" );
m_model_view->setRotateTo(30.0f, 1.0f);
player_name_w = 0;
m_model_view->setBadge(OK_BADGE);
} // markAsReady
// ------------------------------------------------------------------------
/** \return Whether this player confirmed his kart and indent selection */
bool PlayerKartWidget::isReady()
{
assert(m_magic_number == 0x33445566);
return m_ready;
} // isReady
// ------------------------------------------------------------------------
/** \return Whether this player is handicapped or not */
bool PlayerKartWidget::isHandicapped()
{
assert(m_magic_number == 0x33445566);
return m_handicapped;
} // isHandicapped
// -------------------------------------------------------------------------
/** Updates the animation (moving/shrinking/etc.) */
void PlayerKartWidget::onUpdate(float delta)
{
assert(m_magic_number == 0x33445566);
if (target_x == m_x && target_y == m_y &&
target_w == m_w && target_h == m_h) return;
int move_step = (int)(delta*1000.0f);
// move x towards target
if (m_x < target_x)
{
m_x += (int)(move_step*x_speed);
// don't move to the other side of the target
if (m_x > target_x) m_x = target_x;
}
else if (m_x > target_x)
{
m_x -= (int)(move_step*x_speed);
// don't move to the other side of the target
if (m_x < target_x) m_x = target_x;
}
// move y towards target
if (m_y < target_y)
{
m_y += (int)(move_step*y_speed);
// don't move to the other side of the target
if (m_y > target_y) m_y = target_y;
}
else if (m_y > target_y)
{
m_y -= (int)(move_step*y_speed);
// don't move to the other side of the target
if (m_y < target_y) m_y = target_y;
}
// move w towards target
if (m_w < target_w)
{
m_w += (int)(move_step*w_speed);
// don't move to the other side of the target
if (m_w > target_w) m_w = target_w;
}
else if (m_w > target_w)
{
m_w -= (int)(move_step*w_speed);
// don't move to the other side of the target
if (m_w < target_w) m_w = target_w;
}
// move h towards target
if (m_h < target_h)
{
m_h += (int)(move_step*h_speed);
// don't move to the other side of the target
if (m_h > target_h) m_h = target_h;
}
else if (m_h > target_h)
{
m_h -= (int)(move_step*h_speed);
// don't move to the other side of the target
if (m_h < target_h) m_h = target_h;
}
setSize(m_x, m_y, m_w, m_h);
if (m_player_ident_spinner != NULL)
{
m_player_ident_spinner->move(player_name_x,
player_name_y,
player_name_w,
player_name_h );
}
if (m_ready_text != NULL)
{
m_ready_text->setRelativePosition(
core::recti(core::position2di(player_name_x, player_name_y),
core::dimension2di(player_name_w, player_name_h)) );
}
if (!m_parent_screen->m_multiplayer)
{
m_kart_stats->move(m_kart_stats_x,
m_kart_stats_y,
m_kart_stats_w,
m_kart_stats_h);
}
else
{
m_kart_stats->move(m_x, m_y + m_h/2,
m_w, m_h/2);
}
m_model_view->move(model_x,
model_y,
model_w,
model_h);
m_kart_name->move(kart_name_x,
kart_name_y,
kart_name_w,
kart_name_h);
// When coming from the overworld, we must rebuild the preview scene at
// least once, since the scene is being cleared by leaving the overworld
if (m_not_updated_yet)
{
m_model_view->clearRttProvider();
m_not_updated_yet = false;
}
} // onUpdate
// -------------------------------------------------------------------------
/** Event callback */
GUIEngine::EventPropagation PlayerKartWidget::transmitEvent(Widget* w,
const std::string& originator,
const int m_player_id )
{
assert(m_magic_number == 0x33445566);
// if it's declared ready, there is really nothing to process
if (m_ready) return EVENT_LET;
//std::cout << "= kart selection :: transmitEvent "
// << originator << " =\n";
std::string name = w->m_properties[PROP_ID];
//std::cout << " (checking if that's me: I am "
// << spinnerID << ")\n";
// update player profile when spinner changed
if (originator == spinnerID)
{
if(UserConfigParams::logGUI())
{
Log::info("[KartSelectionScreen]", "Identity changed "
"for player %s : %s",m_player_id,
irr::core::stringc(
m_player_ident_spinner->getStringValue()
.c_str()).c_str());
}
if (m_parent_screen->m_multiplayer)
{
int spinner_value = m_player_ident_spinner->getValue();
PlayerProfile* profile = PlayerManager::get()->getPlayer(
UserConfigParams::m_per_player_difficulty ? spinner_value / 2 : spinner_value);
m_associated_player->setPlayerProfile(profile);
if(UserConfigParams::m_per_player_difficulty && spinner_value % 2 != 0)
{
m_handicapped = true;
m_model_view->setBadge(ANCHOR_BADGE);
}
else
{
m_handicapped = false;
m_model_view->unsetBadge(ANCHOR_BADGE);
}
}
}
return EVENT_LET; // continue propagating the event
} // transmitEvent
// -------------------------------------------------------------------------
/** Sets the size of the widget as a whole, and placed children widgets
* inside itself */
void PlayerKartWidget::setSize(const int x, const int y, const int w, const int h)
{
assert(m_magic_number == 0x33445566);
m_x = x;
m_y = y;
m_w = w;
m_h = h;
// -- sizes
player_name_h = 40;
player_name_w = std::min(400, w);
kart_name_w = w;
kart_name_h = 25;
// for shrinking effect
if (h < 175)
{
const float factor = h / 175.0f;
kart_name_h = (int)(kart_name_h*factor);
player_name_h = (int)(player_name_h*factor);
}
// --- layout
player_name_x = x + w/2 - player_name_w/2;
player_name_y = y;
if (m_parent_screen->m_multiplayer)
{
const int modelMaxHeight = (h - kart_name_h - player_name_h)/2;
const int modelMaxWidth = w;
const int bestSize = std::min(modelMaxWidth, modelMaxHeight);
model_x = x + w/2 - (int)(bestSize/2);
model_y = y + player_name_h;
model_w = bestSize;
model_h = bestSize;
m_kart_stats_w = model_w;
m_kart_stats_h = model_h;
m_kart_stats_x = x + w/2 - (int)(bestSize/2);
m_kart_stats_y = model_y + model_h;
}
else
{
const int modelMaxHeight = h - kart_name_h - player_name_h;
const int modelMaxWidth = w;
const int bestSize = std::min(modelMaxWidth, modelMaxHeight);
const int modelY = y + player_name_h;
model_x = x + w/4 - (int)(bestSize/2);
model_y = modelY + modelMaxHeight/2 - bestSize/2;
model_w = bestSize;
model_h = bestSize;
m_kart_stats_w = w/2;
m_kart_stats_h = h;
m_kart_stats_x = x + w/2;
m_kart_stats_y = y;
}
kart_name_x = x;
kart_name_y = y + h - kart_name_h;
} // setSize
// -------------------------------------------------------------------------
/** Sets which kart was selected for this player */
void PlayerKartWidget::setKartInternalName(const std::string& whichKart)
{
assert(m_magic_number == 0x33445566);
m_kartInternalName = whichKart;
} // setKartInternalName
// -------------------------------------------------------------------------
const std::string& PlayerKartWidget::getKartInternalName() const
{
assert(m_magic_number == 0x33445566);
return m_kartInternalName;
} // getKartInternalName
// -------------------------------------------------------------------------
/** \brief Event callback from ISpinnerConfirmListener */
EventPropagation PlayerKartWidget::onSpinnerConfirmed()
{
KartSelectionScreen::getRunningInstance()->playerConfirm(m_player_id);
return EVENT_BLOCK;
} // onSpinnerConfirmed

View File

@@ -0,0 +1,177 @@
// SuperTuxKart - a fun racing game with go-kart
//
// Copyright (C) 2006-2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef PLAYER_KART_WIDGET_HPP
#define PLAYER_KART_WIDGET_HPP
#include "guiengine/widgets/spinner_widget.hpp"
#include "states_screens/state_manager.hpp"
#include <IGUIStaticText.h>
#include <IGUIImage.h>
#include <string>
namespace Online
{
class OnlineProfile;
}
class KartSelectionScreen;
namespace GUIEngine
{
class PlayerNameSpinner;
class KartStatsWidget;
class ModelViewWidget;
class LabelWidget;
/** A widget representing the kart selection for a player (i.e. the player's
* number, name, the kart view, the kart's name) */
class PlayerKartWidget : public GUIEngine::Widget,
public GUIEngine::SpinnerWidget::ISpinnerConfirmListener
{
/** Whether this player confirmed their selection */
bool m_ready;
/** If the player is handicapped. */
bool m_handicapped;
/** widget coordinates */
int player_name_x, player_name_y, player_name_w, player_name_h;
int model_x, model_y, model_w, model_h;
int kart_name_x, kart_name_y, kart_name_w, kart_name_h;
int m_kart_stats_x, m_kart_stats_y, m_kart_stats_w, m_kart_stats_h;
/** A reserved ID for this widget if any, -1 otherwise. (If no ID is
* reserved, widget will not be in the regular tabbing order */
int m_irrlicht_widget_id;
/** For animation purposes (see method 'move') */
int target_x, target_y, target_w, target_h;
float x_speed, y_speed, w_speed, h_speed;
/** Object representing this player */
/** Local info about the player. */
StateManager::ActivePlayer* m_associated_player;
int m_player_id;
/** Network info about the user. */
Online::OnlineProfile* m_associated_user;
/** Internal name of the spinner; useful to interpret spinner events,
* which contain the name of the activated object */
std::string spinnerID;
#ifdef DEBUG
long m_magic_number;
#endif
public:
LEAK_CHECK()
/** Sub-widgets created by this widget */
PlayerNameSpinner* m_player_ident_spinner;
KartStatsWidget* m_kart_stats;
ModelViewWidget* m_model_view;
LabelWidget* m_kart_name;
KartSelectionScreen* m_parent_screen;
irr::gui::IGUIStaticText* m_ready_text;
core::stringw deviceName;
std::string m_kartInternalName;
bool m_not_updated_yet;
PlayerKartWidget(KartSelectionScreen* parent,
StateManager::ActivePlayer* associated_player,
Online::OnlineProfile* associated_user,
core::recti area, const int player_id,
std::string kart_group,
const int irrlicht_idget_id=-1);
// ------------------------------------------------------------------------
~PlayerKartWidget();
// ------------------------------------------------------------------------
/** Called when players are renumbered (changes the player ID) */
void setPlayerID(const int newPlayerID);
// ------------------------------------------------------------------------
/** Returns the ID of this player */
int getPlayerID() const;
// ------------------------------------------------------------------------
/** Add the widgets to the current screen */
virtual void add();
// ------------------------------------------------------------------------
/** Get the associated ActivePlayer object*/
StateManager::ActivePlayer* getAssociatedPlayer();
// ------------------------------------------------------------------------
/** Starts a 'move/resize' animation, by simply passing destination coords.
* The animation will then occur on each call to 'onUpdate'. */
void move(const int x, const int y, const int w, const int h);
// ------------------------------------------------------------------------
/** Call when player confirmed his identity and kart */
void markAsReady();
// ------------------------------------------------------------------------
/** \return Whether this player confirmed his kart and indent selection */
bool isReady();
// ------------------------------------------------------------------------
/** \return Whether this player is handicapped or not */
bool isHandicapped();
// -------------------------------------------------------------------------
/** Updates the animation (moving/shrinking/etc.) */
void onUpdate(float delta);
// -------------------------------------------------------------------------
/** Event callback */
virtual GUIEngine::EventPropagation transmitEvent(
GUIEngine::Widget* w,
const std::string& originator,
const int m_player_id);
// -------------------------------------------------------------------------
/** Sets the size of the widget as a whole, and placed children widgets
* inside itself */
void setSize(const int x, const int y, const int w, const int h);
// -------------------------------------------------------------------------
/** Sets which kart was selected for this player */
void setKartInternalName(const std::string& whichKart);
// -------------------------------------------------------------------------
const std::string& getKartInternalName() const;
// -------------------------------------------------------------------------
/** \brief Event callback from ISpinnerConfirmListener */
virtual GUIEngine::EventPropagation onSpinnerConfirmed();
}; // PlayerKartWidget
}
#endif

View File

@@ -0,0 +1,77 @@
// SuperTuxKart - a fun racing game with go-kart
//
// Copyright (C) 2006-2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "guiengine/widgets/player_name_spinner.hpp"
#include "guiengine/engine.hpp"
#include "graphics/irr_driver.hpp"
#include "io/file_manager.hpp"
#include <IGUIEnvironment.h>
using namespace GUIEngine;
PlayerNameSpinner::PlayerNameSpinner(KartSelectionScreen* parent,
const int player_id)
{
m_player_id = player_id;
m_incorrect = false;
m_red_mark_widget = NULL;
m_parent = parent;
setUseBackgroundColor();//except for multiplayer kart selection, this is false
setSpinnerWidgetPlayerID(m_player_id);
} // PlayerNameSpinner
// ------------------------------------------------------------------------
void PlayerNameSpinner::setID(const int m_player_id)
{
PlayerNameSpinner::m_player_id = m_player_id;
setSpinnerWidgetPlayerID(m_player_id);
} // setID
// ------------------------------------------------------------------------
/** Add a red mark on the spinner to mean "invalid choice" */
void PlayerNameSpinner::markAsIncorrect()
{
if (m_incorrect) return; // already flagged as incorrect
m_incorrect = true;
irr::video::ITexture* texture = irr_driver->getTexture(FileManager::GUI,
"red_mark.png" );
const int mark_size = m_h;
const int mark_x = m_w - mark_size*2;
const int mark_y = 0;
core::recti red_mark_area(mark_x, mark_y, mark_x + mark_size,
mark_y + mark_size);
m_red_mark_widget = GUIEngine::getGUIEnv()->addImage( red_mark_area,
/* parent */ m_element );
m_red_mark_widget->setImage(texture);
m_red_mark_widget->setScaleImage(true);
m_red_mark_widget->setTabStop(false);
m_red_mark_widget->setUseAlphaChannel(true);
} // markAsIncorrect
// ------------------------------------------------------------------------
/** Remove any red mark set with 'markAsIncorrect' */
void PlayerNameSpinner::markAsCorrect()
{
if (m_incorrect)
{
m_red_mark_widget->remove();
m_red_mark_widget = NULL;
m_incorrect = false;
}
} // markAsCorrect

View File

@@ -0,0 +1,54 @@
// SuperTuxKart - a fun racing game with go-kart
//
// Copyright (C) 2006-2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef PLAYER_NAME_SPINNER_HPP
#define PLAYER_NAME_SPINNER_HPP
#include "guiengine/widgets/spinner_widget.hpp"
#include <IGUIImage.h>
class KartSelectionScreen;
namespace GUIEngine
{
/** A small extension to the spinner widget to add features like player ID
* management or badging */
class PlayerNameSpinner : public GUIEngine::SpinnerWidget
{
int m_player_id;
bool m_incorrect;
irr::gui::IGUIImage* m_red_mark_widget;
KartSelectionScreen* m_parent;
//virtual EventPropagation focused(const int m_playerID) ;
public:
PlayerNameSpinner(KartSelectionScreen* parent, const int playerID);
// ------------------------------------------------------------------------
void setID(const int m_playerID);
// ------------------------------------------------------------------------
/** Add a red mark on the spinner to mean "invalid choice" */
void markAsIncorrect();
// ------------------------------------------------------------------------
/** Remove any red mark set with 'markAsIncorrect' */
void markAsCorrect();
};
}
#endif

View File

@@ -33,9 +33,17 @@ using namespace irr;
ProgressBarWidget::ProgressBarWidget(bool show_label) : Widget(WTYPE_PROGRESS)
{
m_value = 0;
m_target_value = 0;
m_previous_value = 0;
m_show_label = show_label;
setFocusable(false);
}
} // ProgressBarWidget
// -----------------------------------------------------------------------------
ProgressBarWidget::~ProgressBarWidget()
{
GUIEngine::needsUpdate.remove(this);
} // ~ProgressBarWidget
// -----------------------------------------------------------------------------
@@ -43,29 +51,68 @@ void ProgressBarWidget::add()
{
rect<s32> widget_size = rect<s32>(m_x, m_y, m_x + m_w, m_y + m_h);
stringw& message = m_text;
m_element = GUIEngine::getGUIEnv()->addButton(widget_size, m_parent, getNewNoFocusID(), message.c_str(), L"");
m_element = GUIEngine::getGUIEnv()->addButton(widget_size, m_parent,
getNewNoFocusID(),
message.c_str(), L"");
m_id = m_element->getID();
m_element->setTabStop(false);
m_element->setTabGroup(false);
}
/* Copied from model_view_widget.cpp
FIXME: remove this unclean thing, I think irrlicht provides this feature:
virtual void IGUIElement::OnPostRender (u32 timeMs)
\brief animate the element and its children.
*/
GUIEngine::needsUpdate.push_back(this);
} // add
// -----------------------------------------------------------------------------
void ProgressBarWidget::setValue(int value)
{
m_value = value;
m_target_value = value;
m_previous_value = value;
if (m_show_label)
{
setLabel(std::string(StringUtils::toString(value) + "%").c_str());
} // setValue
// -----------------------------------------------------------------------------
void ProgressBarWidget::moveValue(int value)
{
m_previous_value = m_value;
m_target_value = value;
if (m_show_label)
setLabel(std::string(StringUtils::toString(value) + "%").c_str());
} // moveValue
// -----------------------------------------------------------------------------
void ProgressBarWidget::update(float delta)
{
if (m_target_value != m_value)
{
// Compute current progress in the animation
float cur = (static_cast<float>(m_value) - m_previous_value)
/ (m_target_value - m_previous_value);
// Animation time: 1.0 seconds
cur += delta * 10;
if (cur > 1)
cur = 1;
m_value = int(m_previous_value +
cur * (m_target_value - m_previous_value) );
}
}
} // update
// -----------------------------------------------------------------------------
void ProgressBarWidget::setLabel(irr::core::stringw label)
{
m_element->setText( label.c_str() );
m_text = label;
}
} // setLabel
// -----------------------------------------------------------------------------

View File

@@ -37,31 +37,39 @@ namespace GUIEngine
/** When inferring widget size from its label length, this method will be called to
* if/how much space must be added to the raw label's size for the widget to be large enough */
virtual int getWidthNeededAroundLabel() const { return 35; }
/** When inferring widget size from its label length, this method will be called to
* if/how much space must be added to the raw label's size for the widget to be large enough */
virtual int getHeightNeededAroundLabel() const { return 4; }
/** Change the label on the widget */
void setLabel(const irr::core::stringw label);
int m_value;
bool m_show_label;
/** Values for animation */
int m_target_value;
int m_previous_value;
public:
LEAK_CHECK()
ProgressBarWidget(bool show_label = true);
virtual ~ProgressBarWidget() {}
virtual ~ProgressBarWidget();
/** Change the value of the widget, it must be a percent. */
void setValue(int value);
/** Change the value of the widget smooth, it must be a percent. */
void moveValue(int value);
virtual void update(float delta);
void add();
/** Get the current value of the widget. */
int getValue() {return m_value; };
};
}

View File

@@ -38,10 +38,12 @@ using namespace irr;
// -----------------------------------------------------------------------------
SkillLevelWidget::SkillLevelWidget(core::recti area, const int player_id,
bool multiplayer, const int value,
const stringw& label) : Widget(WTYPE_DIV)
bool multiplayer, bool display_text,
const int value, const stringw& label)
: Widget(WTYPE_DIV)
{
m_player_id = player_id;
m_display_text = display_text;
setSize(area.UpperLeftCorner.X, area.UpperLeftCorner.Y,
area.getWidth(), area.getHeight() );
@@ -79,6 +81,7 @@ void SkillLevelWidget::add()
{
m_bar->add();
m_label->add();
m_label->setVisible(m_display_text);
}
// -----------------------------------------------------------------------------
@@ -115,7 +118,10 @@ void SkillLevelWidget::setSize(const int x, const int y, const int w, const int
m_h = h;
// -- sizes
m_bar_w = 3*(w/2)/4;
if (m_display_text)
m_bar_w = (w / 2) * 3 / 4;
else
m_bar_w = w * 2 / 3;
m_bar_h = h;
m_label_w = w/2;
m_label_h = h;
@@ -128,7 +134,10 @@ void SkillLevelWidget::setSize(const int x, const int y, const int w, const int
m_label_h = (int)(m_label_h*factor);
}
m_bar_x = x + w/2;
if (m_display_text)
m_bar_x = x + w / 2;
else
m_bar_x = x + w / 6;
m_bar_y = y + m_h/2 - m_bar_h/2;
m_label_x = x;
@@ -139,8 +148,7 @@ void SkillLevelWidget::setSize(const int x, const int y, const int w, const int
void SkillLevelWidget::setValue(const int value)
{
m_bar->setValue(value);
m_bar->moveValue(value);
}
// -----------------------------------------------------------------------------
@@ -150,3 +158,13 @@ void SkillLevelWidget::setLabel(const irr::core::stringw& label)
m_label->setText(label, false);
}
void SkillLevelWidget::setDisplayText(bool display_text)
{
if(m_display_text != display_text)
{
m_display_text = display_text;
m_label->setVisible(display_text);
setSize(m_x, m_y, m_w, m_h);
}
}

View File

@@ -36,8 +36,7 @@ namespace GUIEngine
* \brief A skill level widget.
* \ingroup widgetsgroup
*/
class SkillLevelWidget : public Widget
class SkillLevelWidget : public Widget
{
/** When inferring widget size from its label length, this method will be called to
* if/how much space must be added to the raw label's size for the widget to be large enough */
@@ -54,6 +53,7 @@ class SkillLevelWidget : public Widget
std::string m_label_name;
int m_player_id;
bool m_display_text;
public:
@@ -62,7 +62,7 @@ class SkillLevelWidget : public Widget
LabelWidget* m_label;
ProgressBarWidget* m_bar;
SkillLevelWidget(core::recti area, const int player_id, bool multiplayer,
SkillLevelWidget(core::recti area, const int player_id, bool multiplayer, bool display_text,
const int value = 0, const irr::core::stringw& label = "default");
virtual ~SkillLevelWidget() {};
@@ -91,11 +91,13 @@ class SkillLevelWidget : public Widget
void setLabel(const irr::core::stringw& label);
/** Get the current label of the widget. */
const irr::core::stringw& getLabel()
const irr::core::stringw getLabel()
{
return m_label->getText();
}
/** If the label should be displayed. */
void setDisplayText(bool display_text);
};
}

View File

@@ -165,7 +165,7 @@ namespace GUIEngine
* value is set to the new maximum. */
void setMax(int n)
{
m_max = n;
m_max = n;
if(getValue()>m_max) setValue(m_max);
} // setMax
// --------------------------------------------------------------------
@@ -179,7 +179,7 @@ namespace GUIEngine
* value is set to the new minimum. */
void setMin(int n)
{
m_min = n;
m_min = n;
if(getValue()<m_min) setValue(m_min);
} // setMin

View File

@@ -19,6 +19,8 @@
#include "input/device_config.hpp"
#include "input/gamepad_config.hpp"
#include "input/keyboard_config.hpp"
#include "io/xml_node.hpp"
#include "utils/log.hpp"
@@ -28,9 +30,42 @@
using namespace irr;
DeviceConfig::DeviceConfig(DeviceConfigType type)
// ------------------------------------------------------------------------
/** A simple factory that creates either a gamepad or a keyboard
* configuration.
* \param type "gamepad" or "keyboard".
* \param config The XML node with additional configuration parameters.
*/
DeviceConfig* DeviceConfig::create(const XMLNode *config)
{
m_type = type;
DeviceConfig *device_config = NULL;
if(config->getName()=="keyboard")
{
device_config = new KeyboardConfig();
}
else if(config->getName()=="gamepad")
{
device_config = new GamepadConfig();
}
else
{
Log::error("DeviceConfig", "Incorrect type: '%s'.",
config->getName().c_str());
return NULL;
}
// A default keyboard etc is created without
if(config && !device_config->load(config))
{
delete device_config;
return NULL;
}
return device_config;
} // create
// ------------------------------------------------------------------------
DeviceConfig::DeviceConfig()
{
m_name = "";
m_enabled = true;
m_plugged = 0;
} // DeviceConfig
@@ -38,7 +73,7 @@ DeviceConfig::DeviceConfig(DeviceConfigType type)
// ------------------------------------------------------------------------
/** Get a user-readable string describing the bound action.
*/
irr::core::stringw DeviceConfig::getBindingAsString (const PlayerAction action) const
irr::core::stringw DeviceConfig::getBindingAsString(const PlayerAction action) const
{
irr::core::stringw return_string = "";
@@ -243,11 +278,16 @@ bool DeviceConfig::doGetAction(Input::InputType type,
} // doGetAction
//------------------------------------------------------------------------------
/** Saves the configuration to a file.
/** Saves the configuration to a file. The calling node must have written
* the beginning of the xml node, so that this function can immediately
* start writing attributes.
* \param stream The stream to save to.
*/
void DeviceConfig::save (std::ofstream& stream)
{
stream << "enabled=\""
<< (m_enabled ? "true\">\n" : "false\">\n");
for(int n = 0; n < PA_COUNT; n++) // Start at 0?
{
stream << " "
@@ -265,6 +305,8 @@ void DeviceConfig::save (std::ofstream& stream)
*/
bool DeviceConfig::load(const XMLNode *config)
{
config->get("name", &m_name);
config->get("enabled", &m_enabled);
bool error = false;
for(unsigned int i=0; i<config->getNumNodes(); i++)
{

View File

@@ -23,6 +23,7 @@
#include "input/input.hpp"
#include "utils/no_copy.hpp"
#include <assert.h>
#include <iosfwd>
#include <irrString.h>
#include <string>
@@ -39,30 +40,23 @@
*/
class DeviceConfig : public NoCopy
{
public:
enum DeviceConfigType
{
DEVICE_CONFIG_TYPE_GAMEPAD,
DEVICE_CONFIG_TYPE_KEYBOARD
};
protected:
Binding m_bindings[PA_COUNT];
/** How many devices connected to the system which uses this config? */
int m_plugged;
private:
/** If set to false, this device will be ignored.
* Currently for gamepads only. */
bool m_enabled;
/** How many devices connected to the system which uses this config? */
int m_plugged;
/** Name of this configuratiom. */
std::string m_name;
/** Configuration type. */
DeviceConfigType m_type;
protected:
DeviceConfig(DeviceConfigType type);
Binding m_bindings[PA_COUNT];
DeviceConfig();
bool doGetAction(Input::InputType type,
const int id,
@@ -78,8 +72,12 @@ protected:
const int id,
int* value, /* inout */
PlayerAction* action /* out */);
public:
virtual ~DeviceConfig() {}
static DeviceConfig* create(const XMLNode *config);
irr::core::stringw toString();
bool hasBindingFor(const int buttonID) const;
bool hasBindingFor(const int buttonID, PlayerAction from,
@@ -95,11 +93,41 @@ public:
int* value,
PlayerAction* action /* out */);
irr::core::stringw getMappingIdString (const PlayerAction action) const;
irr::core::stringw getBindingAsString(const PlayerAction action) const;
virtual irr::core::stringw getBindingAsString(const PlayerAction action) const;
virtual bool isGamePad() const = 0;
virtual bool isKeyboard() const = 0;
virtual DeviceConfigType getType() const = 0;
virtual void save(std::ofstream& stream);
virtual bool load(const XMLNode *config);
// ------------------------------------------------------------------------
/** Returns true if this device has analog axis, so that steering values
* will not be affected by time-full-steer delays. */
virtual bool isAnalog() const { return false;}
// ------------------------------------------------------------------------
/** Returns true if this device should desensitize its input at values
* close to 0 (to avoid 'oversteering'). */
virtual bool desensitize() const { return false;}
// ------------------------------------------------------------------------
/** Should only be called for gamepads, which has its own implementation.
* of this function. */
virtual int getNumberOfButtons() const
{
assert(false); return 0;
} // getNumberOfButtons
// ------------------------------------------------------------------------
/** Should only be called for gamepads, which has its own implementation.
* of this function. */
virtual int getNumberOfAxes() const
{
assert(false); return 0;
} // getNumberOfAxes
// ------------------------------------------------------------------------
/** Sets the name of this device. */
void setName(const std::string &name) { m_name = name; }
// ------------------------------------------------------------------------
/** Returns the name for this device configuration. */
const std::string& getName() const { return m_name; };
@@ -118,7 +146,7 @@ public:
// ------------------------------------------------------------------------
/** Returns the binding of a given index. */
Binding& getBinding(int i) {return m_bindings[i];}
const Binding& getBinding(int i) const {return m_bindings[i];}
// ------------------------------------------------------------------------
/** At this time only relevant for gamepads, keyboards are always enabled */

View File

@@ -101,13 +101,15 @@ bool DeviceManager::initialize()
// Some linux systems report a disk accelerometer as a gamepad, skip that
if (name.find("LIS3LV02DL") != -1) continue;
#ifdef WIN32
// On Windows, unless we use DirectInput, all gamepads are given the
// same name ('microsoft pc-joystick driver'). This makes configuration
// totally useless, so append an ID to the name. We can't test for the
// name, since the name is even translated.
name = name + " " + StringUtils::toString(id).c_str();
#endif
if(m_irrlicht_gamepads[id].HasGenericName)
{
// On Windows all gamepads are given the same name ('microsoft
// pc-joystick driver'). Irrlicht now tries to get a better name
// from the registry, but in case this should fail we still have
// all gamepads with the same name shown in the GUI. This makes
// configuration totally useless, so append an ID to the name.
name = name + " " + StringUtils::toString(id).c_str();
}
if (UserConfigParams::logMisc())
{
@@ -115,7 +117,7 @@ bool DeviceManager::initialize()
}
// Returns true if new configuration was created
if (getConfigForGamepad(id, name, &gamepadConfig) == true)
if (getConfigForGamepad(id, name.c_str(), &gamepadConfig) == true)
{
if(UserConfigParams::logMisc())
Log::info("Device manager","creating new configuration.");
@@ -184,7 +186,7 @@ GamePadDevice* DeviceManager::getGamePadFromIrrID(const int id)
const int count = m_gamepads.size();
for (int i = 0; i < count; i++)
{
if (m_gamepads[i].m_index == id)
if (m_gamepads[i].getIrrIndex()== id)
{
return m_gamepads.get(i);
@@ -200,7 +202,7 @@ GamePadDevice* DeviceManager::getGamePadFromIrrID(const int id)
* otherwise false.
*/
bool DeviceManager::getConfigForGamepad(const int irr_id,
const core::stringc& name,
const std::string& name,
GamepadConfig **config)
{
bool found = false;
@@ -209,7 +211,7 @@ bool DeviceManager::getConfigForGamepad(const int irr_id,
// Find appropriate configuration
for(unsigned int n=0; n < m_gamepad_configs.size(); n++)
{
if(m_gamepad_configs[n].getName() == name.c_str())
if(m_gamepad_configs[n].getName() == name)
{
*config = m_gamepad_configs.get(n);
found = true;
@@ -221,7 +223,7 @@ bool DeviceManager::getConfigForGamepad(const int irr_id,
{
if(irr_id < (int)(m_irrlicht_gamepads.size()))
{
*config = new GamepadConfig( name.c_str(),
*config = new GamepadConfig( name,
m_irrlicht_gamepads[irr_id].Axes,
m_irrlicht_gamepads[irr_id].Buttons );
}
@@ -317,7 +319,7 @@ InputDevice* DeviceManager::mapKeyboardInput(int button_id,
{
KeyboardDevice *keyboard = m_keyboards.get(n);
if (keyboard->processAndMapInput(action, Input::IT_KEYBOARD, button_id, mode))
if (keyboard->processAndMapInput(Input::IT_KEYBOARD, button_id, mode, action))
{
if (m_single_player != NULL)
{
@@ -363,7 +365,7 @@ InputDevice *DeviceManager::mapGamepadInput(Input::InputType type,
if (gPad != NULL)
{
if (gPad->processAndMapInput(action, type, button_id, mode, value))
if (gPad->processAndMapInput(type, button_id, mode, action, value))
{
if (m_single_player != NULL)
{
@@ -504,29 +506,24 @@ bool DeviceManager::load()
for(unsigned int i=0; i<input->getNumNodes(); i++)
{
const XMLNode *config = input->getNode(i);
if(config->getName()=="keyboard")
{
KeyboardConfig* keyboard_config = new KeyboardConfig();
if(!keyboard_config->load(config))
{
Log::error("Device manager",
"Ignoring an ill-formed keyboard action in input config.");
}
m_keyboard_configs.push_back(keyboard_config);
}
else if (config->getName()=="gamepad")
{
GamepadConfig* gamepad_config = new GamepadConfig(config);
gamepad_config->load(config);
m_gamepad_configs.push_back(gamepad_config);
}
else
DeviceConfig *device_config = DeviceConfig::create(config);
if(!device_config)
{
Log::warn("DeviceManager",
"Invalid node '%s' in input.xml - ignored.",
config->getName().c_str());
continue;
}
if(config->getName()=="keyboard")
{
KeyboardConfig *kc = static_cast<KeyboardConfig*>(device_config);
m_keyboard_configs.push_back(kc);
}
else if (config->getName()=="gamepad")
{
GamepadConfig *gc = static_cast<GamepadConfig*>(device_config);
m_gamepad_configs.push_back(gc);
}
} // for i < getNumNodes
if (UserConfigParams::logMisc())

View File

@@ -19,7 +19,6 @@
#ifndef DEVICE_MANAGER_HPP
#define DEVICE_MANAGER_HPP
#include "input/device_config.hpp"
#include "input/gamepad_config.hpp"
#include "input/input_manager.hpp"
#include "input/keyboard_config.hpp"
@@ -31,6 +30,7 @@
#include <IEventReceiver.h>
using namespace irr;
class DeviceConfig;
class InputDevice;
class GamePadDevice;
class KeyboardDevice;
@@ -115,7 +115,9 @@ public:
GamePadDevice* getGamePadFromIrrID(const int i);
void clearGamepads();
/** Returns the keyboard that has a binding for this button, or NULL if none */
bool getConfigForGamepad(const int sdl_id, const core::stringc& pname, GamepadConfig **config);
bool getConfigForGamepad(const int sdl_id,
const std::string& name,
GamepadConfig **config);
// ---- Keyboard(s) ----
void addEmptyKeyboard();

View File

@@ -21,6 +21,8 @@
#include "io/xml_node.hpp"
#include "utils/log.hpp"
#include "utils/string_utils.hpp"
#include "utils/translation.hpp"
#include <SKeyMap.h>
@@ -29,52 +31,95 @@
using namespace irr;
GamepadConfig::GamepadConfig ( const std::string &name,
const int axis_count,
const int button_count )
: DeviceConfig( DEVICE_CONFIG_TYPE_GAMEPAD )
GamepadConfig::GamepadConfig( const std::string &name,
const int axis_count,
const int button_count )
: DeviceConfig()
{
m_name = name;
setName(name);
m_axis_count = axis_count;
m_button_count = button_count;
m_deadzone = 2000;
m_plugged = 0;
m_deadzone = 4096;
m_is_analog = true;
m_desensitize = false;
setDefaultBinds();
detectType();
} // GamepadConfig
//------------------------------------------------------------------------------
GamepadConfig::GamepadConfig(const XMLNode *config)
: DeviceConfig( DEVICE_CONFIG_TYPE_GAMEPAD )
GamepadConfig::GamepadConfig() : DeviceConfig()
{
if(!config->get("name", &m_name))
Log::error("DeviceConfig", "Unnamed joystick in config file.");
config->get("enabled", &m_enabled);
m_plugged = 0;
m_deadzone = 2000;
m_axis_count = 0;
m_button_count = 0;
m_deadzone = 4096;
m_is_analog = true;
m_desensitize = false;
setDefaultBinds();
} // GamepadConfig(XMLNode)
} // GamepadConfig
//------------------------------------------------------------------------------
/** Loads this configuration from the given XML node.
* \param config The XML tree.
* \return False in case of an error.
*/
bool GamepadConfig::load(const XMLNode *config)
{
m_deadzone = 2000;
config->get("deadzone", &m_deadzone);
return DeviceConfig::load(config);
config->get("deadzone", &m_deadzone );
config->get("analog", &m_is_analog );
config->get("desensitize", &m_desensitize );
bool ok = DeviceConfig::load(config);
if(getName()=="")
{
Log::error("DeviceConfig", "Unnamed joystick in config file.");
return false;
}
detectType();
return ok;
} // load
// ----------------------------------------------------------------------------
/** Saves the configuration to a file. It writes the name for a gamepad
* config, saves the device specific parameters, and calls
* DeviceConfig::save() to save the rest.
* \param stream The stream to save to.
*/
void GamepadConfig::save (std::ofstream& stream)
{
stream << "<gamepad name =\"" << m_name.c_str() << "\" enabled=\""
<< (m_enabled ? "true\"\n" : "false\"\n");
stream << " deadzone=\""<<m_deadzone << "\">\n";
stream << "<gamepad name =\"" << getName()
<< "\" deadzone=\"" << m_deadzone
<< "\" desensitize=\"" << m_desensitize
<< "\" analog=\"" << m_is_analog<<"\"\n";
stream << " ";
DeviceConfig::save(stream);
stream << "</gamepad>\n\n";
} // save
//-----------------------------------------------------------------------------
/** Try to identify a gamepad type (e.g. 'xbox'), so that better defaults
* and button names can be set. Atm the gamepad name is used.
*/
void GamepadConfig::detectType()
{
m_type = GP_UNIDENTIFIED;
std::string lower = StringUtils::toLowerCase(getName());
// xbox appears to be xbox 360
if(lower.find("xbox")!=std::string::npos)
{
m_type = GP_XBOX360;
return;
}
// The original xbox gamepad
if(lower.find("x-box")!=std::string::npos)
{
m_type = GP_XBOX_ORIGINAL;
return;
}
} // detectType
//------------------------------------------------------------------------------
void GamepadConfig::setDefaultBinds ()
@@ -96,9 +141,99 @@ void GamepadConfig::setDefaultBinds ()
setBinding(PA_MENU_RIGHT, Input::IT_STICKMOTION, 0, Input::AD_POSITIVE);
setBinding(PA_MENU_SELECT, Input::IT_STICKBUTTON, 0);
setBinding(PA_MENU_CANCEL, Input::IT_STICKBUTTON, 3);
}
} // setDefaultBinds
//------------------------------------------------------------------------------
core::stringw GamepadConfig::getBindingAsString(const PlayerAction action) const
{
// Default names if gamepad is not identified
if(m_type==GP_UNIDENTIFIED) return DeviceConfig::getBindingAsString(action);
const Binding &b = getBinding(action);
int id = b.getId();
Input::AxisDirection ad = b.getDirection();
Input::InputType it = b.getType();
// XBOX-360 controller
// -------------------
if(m_type==GP_XBOX_ORIGINAL)
{
// Handle only the differences to the xbox 360 controller, the rest
// will 'fall trough' to the xbox 360 code below
if(it==Input::IT_STICKBUTTON)
{
switch(id)
{
// I18N: Name of the black button on xbox controller
case 2: return _("Black");
case 3: return "X";
case 4: return "Y";
// I18N: Name of the white button on xbox controller
case 5: return _("White");
}
}
if(it==Input::IT_STICKMOTION)
{
switch(id)
{
case 2: return _("Left trigger");
case 3: return (ad==Input::AD_POSITIVE) ? _("Right thumb right")
: _("Right thumb left");
case 4: return (ad==Input::AD_POSITIVE) ? _("Right thumb down")
: _("Right thumb up");
case 5: return _("Right trigger");
case 6: return (ad == Input::AD_POSITIVE) ? _("DPad right")
: _("DPad left");
case 7: return (ad == Input::AD_POSITIVE) ? _("DPad down")
: _("DPad up");
} // switch
} // stickmotion
} // xbox (original)
if(m_type==GP_XBOX360 || m_type==GP_XBOX_ORIGINAL)
{
if(it==Input::IT_STICKBUTTON)
{
switch(id)
{
case 0: return "A";
case 1: return "B";
case 2: return "X";
case 3: return "Y";
case 4: return _("Left bumper");
case 5: return _("Right bumper");
case 6: return _("Back");
case 7: return _("Start");
case 8: return _("Left thumb button");
case 9: return _("Right thumb button");
default: return DeviceConfig::getBindingAsString(action);
} // switch
} // if IT_STICKBUTTON
if(it==Input::IT_STICKMOTION)
{
switch(id)
{
case 0: return (ad==Input::AD_POSITIVE) ? _("Left thumb right")
: _("Left thumb left");
case 1: return (ad==Input::AD_POSITIVE) ? _("Left thumb down")
: _("Left thumb up");
case 2: return (ad==Input::AD_POSITIVE) ? _("Left trigger")
: _("Right trigger");
case 3: return (ad==Input::AD_POSITIVE) ? _("Right thumb down")
: _("Right thumb up");
case 4: return (ad==Input::AD_POSITIVE) ? _("Right thumb right")
: _("Right thumb left");
case Input::HAT_H_ID: return (ad == Input::AD_POSITIVE) ? _("DPad up")
: _("DPad down");
case Input::HAT_V_ID: return (ad == Input::AD_POSITIVE) ? _("DPad right")
: _("DPad left");
} // switch
}
} // xbox
// Offer a fallback ... just in case
Log::warn("GamepadConfig", "Missing action string for pad '%s' action '%d'",
getName().c_str(), action);
return DeviceConfig::getBindingAsString(action);
} // getBindingAsString
//------------------------------------------------------------------------------
/** Converts the configuration to a string.

View File

@@ -22,56 +22,91 @@
#include "input/binding.hpp"
#include "input/device_config.hpp"
#include "input/input.hpp"
#include "utils/cpp2011.hpp"
#include "utils/no_copy.hpp"
#include <iosfwd>
#include <irrString.h>
#include <string>
//==== G A M E P A D C O N F I G ===============================================
using namespace irr;
/**
* \brief specialisation of DeviceConfig for gamepad type devices
* \ingroup config
*/
/** \brief specialisation of DeviceConfig for gamepad type devices
* \ingroup config
*/
class GamepadConfig : public DeviceConfig
{
private:
/** Number of axis this device has. */
int m_axis_count;
int m_axis_count;
/** Number of buttons this device has. */
int m_button_count;
int m_button_count;
/** Deadzone of this gamepad. */
int m_deadzone;
/** If this device has analog axis, steering etc. must be set immediately
* from the input values, not having a delayed time (time-full-steer). */
bool m_is_analog;
/** If set to true, map any analog axis from x in [0,1] to x^x --> at
* values close to 0 the joystick will react less sensitive. */
bool m_desensitize;
/** A type to keep track if the gamepad has been identified (which is
* used to display better button names and better defaults). */
enum {GP_UNIDENTIFIED, GP_XBOX360, GP_XBOX_ORIGINAL} m_type;
void detectType();
public:
irr::core::stringw toString ();
GamepadConfig ();
GamepadConfig(const std::string &name,
const int axis_count=0,
const int button_ount=0);
virtual ~GamepadConfig() {}
core::stringw toString();
virtual void save(std::ofstream& stream);
void setDefaultBinds ();
GamepadConfig (const XMLNode *config);
GamepadConfig (const std::string &name,
const int axis_count=0,
const int button_ount=0);
virtual bool load(const XMLNode *config);
virtual core::stringw getBindingAsString(const PlayerAction action) const OVERRIDE;
virtual bool load(const XMLNode *config) OVERRIDE;
// ------------------------------------------------------------------------
/** Returns if this device uses analog axes. */
virtual bool isAnalog() const OVERRIDE { return m_is_analog; }
// ------------------------------------------------------------------------
/** Returns true if this device should desensitize its input at values
* close to 0 (to avoid 'oversteering'). */
virtual bool desensitize() const { return m_desensitize;}
// ------------------------------------------------------------------------
/** Returns the number of buttons in this configuration. */
virtual int getNumberOfButtons() const OVERRIDE { return m_button_count; }
// ------------------------------------------------------------------------
/** Sets the number of buttons this device has. */
void setNumberOfButtons(int count) { m_button_count = count; }
// ------------------------------------------------------------------------
/** Sets the number of axis this device has. */
void setNumberOfAxis(int count) { m_axis_count = count; }
// ~GamepadConfig();
/** Returns the number of axis of this configufation. */
virtual int getNumberOfAxes() const OVERRIDE { return m_axis_count; }
// ------------------------------------------------------------------------
/** Returns the type of this configuration. */
virtual DeviceConfig::DeviceConfigType getType() const
{
return DeviceConfig::DEVICE_CONFIG_TYPE_GAMEPAD;
} // getType
};
/** Sets the number of axis this device has. */
void setNumberOfAxis(int count) { m_axis_count = count; }
// ------------------------------------------------------------------------
/** Return deadzone of this configuration. */
int getDeadzone() const { return m_deadzone; }
// ------------------------------------------------------------------------
virtual bool isGamePad() const { return true; }
// ------------------------------------------------------------------------
virtual bool isKeyboard() const { return false; }
}; // class GamepadConfig
#endif

View File

@@ -23,19 +23,31 @@
#include "karts/abstract_kart.hpp"
#include "karts/controller/player_controller.hpp"
GamePadDevice::GamePadDevice(const int irrIndex, const std::string name,
/** Constructor for GamePadDevice from a connected gamepad for which no
* configuration existed (defaults will be used)
* \param irrIndex Index of stick as given by irrLicht.
*/
GamePadDevice::GamePadDevice(const int irr_index, const std::string &name,
const int axis_count, const int button_count,
GamepadConfig *configuration)
{
m_type = DT_GAMEPAD;
m_prev_axis_directions = NULL;
m_configuration = configuration;
m_axis_count = axis_count;
GamepadConfig *config = static_cast<GamepadConfig*>(m_configuration);
if(m_configuration->getNumberOfButtons()<button_count)
{
static_cast<GamepadConfig*>(m_configuration)->setNumberOfButtons(button_count);
}
if(m_configuration->getNumberOfAxes()<axis_count)
{
static_cast<GamepadConfig*>(m_configuration)->setNumberOfAxis(axis_count);
}
m_prev_axis_directions = new Input::AxisDirection[axis_count];
m_prev_axis_value = new int[axis_count];
m_axis_ok = new bool[axis_count];
m_button_count = button_count;
m_index = irrIndex;
m_irr_index = irr_index;
m_name = name;
for (int i = 0; i < axis_count; i++)
@@ -62,7 +74,21 @@ GamePadDevice::~GamePadDevice()
} // ~GamePadDevice
// ----------------------------------------------------------------------------
/** Returns if the specified value is larger than the deadzone. */
bool GamePadDevice::moved(int value) const
{
int dz = static_cast<GamepadConfig*>(m_configuration)->getDeadzone();
return abs(value) > dz;
} // moved
// ----------------------------------------------------------------------------
/** Returns the number of buttons of this gamepad. */
int GamePadDevice::getNumberOfButtons() const
{
return m_configuration->getNumberOfButtons();
} // getNumberOfButtons
// ----------------------------------------------------------------------------
bool GamePadDevice::isButtonPressed(const int i)
{
return m_buttonPressed[i];
@@ -90,9 +116,9 @@ void GamePadDevice::resetAxisDirection(const int axis,
return;
}
for(int n=0; n<PA_COUNT; n++)
for(int n=PA_BEFORE_FIRST+1; n<PA_COUNT; n++)
{
Binding& bind = m_configuration->getBinding(n);
const Binding& bind = m_configuration->getBinding(n);
if(bind.getType() == Input::IT_STICKMOTION &&
bind.getId() == axis &&
bind.getDirection()== direction &&
@@ -107,21 +133,59 @@ void GamePadDevice::resetAxisDirection(const int axis,
} // resetAxisDirection
// ----------------------------------------------------------------------------
/** Invoked when this device it used. Verifies if the key/button that was
* pressed is associated with a binding. If yes, sets action and returns
* true; otherwise returns false. It can also modify the value used.
* \param type Type of input (e.g. IT_STICKMOTION, ...).
* \param id ID of the key that was pressed or of the axis that was
* triggered (depending on the value of the 'type' parameter).
* \param mode Used to determine whether to map menu actions or
* game actions
* \param[out] action The action associated to this input (only check
* this value if method returned true)
* \param[in,out] value The value associated with this type (typically
* how far a gamepad axis is moved).
*
* \return Whether the pressed key/button is bound with an action
*/
bool GamePadDevice::processAndMapInput(PlayerAction* action /* out */,
Input::InputType type, const int id,
bool GamePadDevice::processAndMapInput(Input::InputType type, const int id,
InputManager::InputDriverMode mode,
int* value/* inout */)
PlayerAction* action /* out */,
int* value /* inout */ )
{
if (!m_configuration->isEnabled()) return false;
// A digital input value is 32767 or -32768 (which then triggers
// time-full-steer to be used to adjust actual steering values.
// To prevent this delay for analog gamesticks, make sure that
// 32767/-32768 are never used.
if(m_configuration->isAnalog())
{
if(*value==32767)
*value = 32766;
else if(*value==-32768)
*value = -32767;
}
// Desensitizing means to map an input in the range x in [0,1] to
// x^2. This results in changes close to 0 to have less impact
// (less sensitive).
if(m_configuration->desensitize())
{
// x/32767 is in [-1,1], (x/32767)^2 is in [0,1]. Take care of the
// sign and map this back to [0,32767] by multiplying by 32767.
// Which all in all results in:
*value = int( (*value / 32767.0f) * fabsf(float(*value)) );
}
bool success = false;
if(m_prev_axis_directions == NULL) return false; // device not open
if (type == Input::IT_STICKMOTION)
{
// this gamepad doesn't even have that many axes
if (id >= m_axis_count) return false;
if (id >= m_configuration->getNumberOfAxes()) return false;
if (getPlayer())
{
@@ -157,8 +221,9 @@ bool GamePadDevice::processAndMapInput(PlayerAction* action /* out */,
}
}
int dz = static_cast<GamepadConfig*>(m_configuration)->getDeadzone();
// check if within deadzone
if(*value > -m_deadzone && *value < m_deadzone && getPlayer())
if(*value > -dz && *value < dz && getPlayer())
{
// Axis stands still: This is reported once for digital axes and
// can be called multipled times for analog ones. Uses the

View File

@@ -20,8 +20,10 @@
#define HEADER_GAMEPAD_DEVICE_HPP
#include "input/input_device.hpp"
#include "utils/cpp2011.hpp"
class GamepadConfig;
/**
* \brief specialisation of Inputdevice for gamepad type devices
* \ingroup input
@@ -31,7 +33,6 @@ class GamePadDevice : public InputDevice
void resetAxisDirection(const int axis, Input::AxisDirection direction);
bool m_buttonPressed[SEvent::SJoystickEvent::NUMBER_OF_BUTTONS];
public:
Input::AxisDirection *m_prev_axis_directions;
/** used to determine if an axis is valid; an axis is considered valid
@@ -43,46 +44,35 @@ public:
* uninteresting axis values)
*/
int *m_prev_axis_value;
/** \see m_prev_axis_value */
bool *m_axis_ok;
int m_deadzone;
int m_index;
int m_axis_count;
int m_button_count;
/** Irrlicht index of this gamepad. */
int m_irr_index;
/** Constructor for GamePadDevice from a connected gamepad for which no
* configuration existed (defaults will be used)
* \param irrIndex Index of stick as given by irrLicht.
*/
GamePadDevice(const int irrIndex, const std::string name,
const int axis_number,
const int btnAmount, GamepadConfig *configuration);
public:
GamePadDevice(const int irrIndex, const std::string &name,
const int axis_number,
const int button_count,
GamepadConfig *configuration);
virtual ~GamePadDevice();
bool isButtonPressed(const int i);
void setButtonPressed(const int i, bool isButtonPressed);
bool isButtonPressed(const int i);
void setButtonPressed(const int i, bool isButtonPressed);
virtual bool processAndMapInput(Input::InputType type, const int id,
InputManager::InputDriverMode mode,
PlayerAction *action, int* value = NULL
) OVERRIDE;
int getNumberOfButtons() const;
bool moved(int value) const;
/**
* Invoked when this device it used. Verifies if the key/button that
* was pressed is associated with a binding. If yes, sets action and
* returns true; otherwise returns false.
*
* \param id ID of the key that was pressed or of the axis
* that was triggered (depending on
* the value of the 'type' parameter)
* \param mode Used to determine whether to map menu actions or
* game actions
* \param[out] action The action associated to this input (only check
* this value if method returned true)
*
* \return Whether the pressed key/button is bound with an action
*/
bool processAndMapInput(PlayerAction* action, Input::InputType type,
const int id,
InputManager::InputDriverMode mode, int* value);
// ------------------------------------------------------------------------
/** Returns the irrlicht index of this gamepad. */
int getIrrIndex() const { return m_irr_index; }
};
// ------------------------------------------------------------------------
}; // class GamepadDevice
#endif

View File

@@ -28,13 +28,6 @@
#include <string>
#include <irrString.h>
class Binding;
const int DEADZONE_MOUSE = 150;
const int DEADZONE_MOUSE_SENSE = 200;
const int DEADZONE_JOYSTICK = 2000;
const int MULTIPLIER_MOUSE = 750;
/**
* \ingroup input
*/

View File

@@ -20,7 +20,6 @@
#define HEADER_INPUT_DEVICE_HPP
#include "input/device_config.hpp"
#include "input/input.hpp"
#include "input/input_manager.hpp"
#include "states_screens/state_manager.hpp"
@@ -28,6 +27,8 @@
#include <string>
class DeviceConfig;
/**
* \brief Input device type
* \ingroup input
@@ -62,20 +63,25 @@ public:
InputDevice();
virtual ~InputDevice();
bool processAndMapInput(PlayerAction* action, Input::InputType type, int id, InputManager::InputDriverMode mode);
bool processAndMapInput(PlayerAction* action, Input::InputType type, const int id,
int* value, InputManager::InputDriverMode mode);
#ifdef NOTYET
virtual bool processAndMapInput(PlayerAction *action,
Input::InputType type,
const int id,
int* value,
/** Invoked when this device it used. Verifies if the key/button that was
* pressed is associated with a binding. If yes, sets action and returns
* true; otherwise returns false. It can also modify the value used.
* \param type Type of input (e.g. IT_STICKMOTION, ...).
* \param id ID of the key that was pressed or of the axis that was
* triggered (depending on the value of the 'type' parameter).
* \param mode Used to determine whether to map menu actions or
* game actions
* \param[out] action The action associated to this input (only check
* this value if method returned true)
* \param[in,out] value The value associated with this type (typically
* how far a gamepad axis is moved).
*
* \return Whether the pressed key/button is bound with an action
*/
virtual bool processAndMapInput(Input::InputType type, const int id,
InputManager::InputDriverMode mode,
PlayerAction* action) = 0;
#endif
PlayerAction *action, int* value = NULL
) = 0;
// ------------------------------------------------------------------------
/** Sets which players uses this device; or pass NULL to say no player

View File

@@ -352,9 +352,6 @@ void InputManager::inputSensing(Input::InputType type, int deviceID,
break;
case Input::IT_STICKMOTION:
{
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).
@@ -389,7 +386,10 @@ void InputManager::inputSensing(Input::InputType type, int deviceID,
}
else m_sensed_input_high_gamepad.insert(input_id);
}
else if ( abs(value) < Input::MAX_VALUE/8.0f )
// At least with xbox controller they can come to a 'rest' with a value of
// around 6000! So in order to detect that an axis was released, we need to
// test with a rather high deadzone value
else if ( abs(value) < Input::MAX_VALUE/3.0f )
{
if( id_was_high )
{
@@ -639,8 +639,8 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID,
GamePadDevice* gp =
getDeviceManager()->getGamePadFromIrrID(deviceID);
if (gp != NULL &&
abs(value)>gp->m_deadzone)
// Check for deadzone
if (gp != NULL && gp->moved(value))
{
//I18N: message shown when an input device is used but
// is not associated to any player
@@ -778,7 +778,7 @@ EventPropagation InputManager::input(const SEvent& event)
return EVENT_BLOCK;
}
for(int i=0; i<gp->m_button_count; i++)
for(int i=0; i<gp->getNumberOfButtons(); i++)
{
const bool isButtonPressed = event.JoystickEvent.IsButtonPressed(i);

View File

@@ -28,14 +28,23 @@
using namespace irr;
// KeyboardConfig & GamepadConfig classes really should be in a separate cpp
// file but they are so small that we'll just leave them here for now.
//==== K E Y B O A R D C O N F I G =============================================
KeyboardConfig::KeyboardConfig()
: DeviceConfig()
{
setDefaultBinds();
setPlugged();
} // KeyboardConfig
// ----------------------------------------------------------------------------
/** Saves the configuration to a file. It writes the name for a gamepad
* config, saves the device specific parameters, and calls
* DeviceConfig::save() to save the rest.
* \param stream The stream to save to.
*/
void KeyboardConfig::save(std::ofstream& stream)
{
stream << "<keyboard>\n";
stream << "<keyboard ";
DeviceConfig::save(stream);
stream << "</keyboard>\n\n";
} // save
@@ -65,10 +74,3 @@ void KeyboardConfig::setDefaultBinds()
//------------------------------------------------------------------------------
KeyboardConfig::KeyboardConfig() : DeviceConfig(DEVICE_CONFIG_TYPE_KEYBOARD)
{
m_name = "Keyboard";
m_plugged = 1;
setDefaultBinds();
}

View File

@@ -23,12 +23,9 @@
#include "input/device_config.hpp"
#include "input/input.hpp"
#include "utils/no_copy.hpp"
#include "utils/cpp2011.hpp"
#include <iosfwd>
#include <irrString.h>
#include <string>
//==== K E Y B O A R D C O N F I G =============================================
/**
* \brief specialisation of DeviceConfig for keyboard type devices
@@ -39,17 +36,17 @@ class KeyboardConfig : public DeviceConfig
public:
KeyboardConfig();
virtual ~KeyboardConfig() {}
void setDefaultBinds ();
virtual void save(std::ofstream& stream);
KeyboardConfig ();
// ------------------------------------------------------------------------
/** Returns the type of this configuration. */
virtual DeviceConfigType getType() const
{
return DEVICE_CONFIG_TYPE_KEYBOARD;
} // getType
};
virtual bool isGamePad() const { return false; }
// ------------------------------------------------------------------------
virtual bool isKeyboard() const { return true; }
}; // class KeyboardConfig
#endif

View File

@@ -38,11 +38,24 @@ KeyboardDevice::KeyboardDevice()
} // KeyboardDevice
// ----------------------------------------------------------------------------
bool KeyboardDevice::processAndMapInput(PlayerAction* action /* out */,
Input::InputType type,
const int id,
InputManager::InputDriverMode mode)
/** Invoked when this device it used. Verifies if the key/button that was
* pressed is associated with a binding. If yes, sets action and returns
* true; otherwise returns false. It can also modify the value used.
* \param type Type of input (e.g. IT_STICKMOTION, ...).
* \param id ID of the key that was pressed or of the axis that was
* triggered (depending on the value of the 'type' parameter).
* \param mode Used to determine whether to map menu actions or
* game actions
* \param[out] action The action associated to this input (only check
* this value if method returned true)
* \param[in,out] value The value associated with this type (typically
* how far a gamepad axis is moved).
*
* \return Whether the pressed key/button is bound with an action
*/
bool KeyboardDevice::processAndMapInput(Input::InputType type, const int id,
InputManager::InputDriverMode mode,
PlayerAction *action, int* value)
{
assert(type==Input::IT_KEYBOARD);
if (mode == InputManager::INGAME)

View File

@@ -22,7 +22,7 @@
#include "input/input_device.hpp"
#include "input/input.hpp"
#include "utils/cpp2011.hpp"
class KeyboardConfig;
@@ -37,20 +37,10 @@ public:
KeyboardDevice(KeyboardConfig *configuration);
virtual ~KeyboardDevice() {}
/**
* Checks if this key belongs to this device. if yes, sets action and
* returns true; otherwise returns false
*
* \param id ID of the key that was pressed
* \param mode Used to determine whether to bind menu actions or
* game actions
* \param[out] action The action associated to this input (only check
* this value if method returned true)
*/
bool processAndMapInput(PlayerAction* action, Input::InputType type,
const int id,
InputManager::InputDriverMode mode);
virtual bool processAndMapInput(Input::InputType type, const int id,
InputManager::InputDriverMode mode,
PlayerAction *action, int* value = NULL
) OVERRIDE;
}; // KeyboardDevice

View File

@@ -83,7 +83,7 @@ Attachment::~Attachment()
m_bomb_sound->deleteSFX();
m_bomb_sound = NULL;
}
if (m_bubble_explode_sound)
{
m_bubble_explode_sound->deleteSFX();
@@ -125,7 +125,7 @@ void Attachment::set(AttachmentType type, float time,
clear();
m_node_scale = 0.3f;
// If necessary create the appropriate plugin which encapsulates
// the associated behavior
switch(type)
@@ -266,7 +266,8 @@ void Attachment::hitBanana(Item *item, int new_attachment)
// same banana again once the explosion animation is finished, giving
// the kart the same penalty twice.
float f = std::max(item->getDisableTime(),
m_kart->getKartProperties()->getExplosionTime()+2.0f);
m_kart->getKartProperties()->getExplosionTime() *
m_kart->getPlayerDifficulty()->getExplosionTime() + 2.0f);
item->setDisableTime(f);
break;
}
@@ -329,7 +330,7 @@ void Attachment::hitBanana(Item *item, int new_attachment)
void Attachment::handleCollisionWithKart(AbstractKart *other)
{
Attachment *attachment_other=other->getAttachment();
if(getType()==Attachment::ATTACH_BOMB)
{
// Don't attach a bomb when the kart is shielded
@@ -386,11 +387,11 @@ void Attachment::update(float dt)
{
if(m_type==ATTACH_NOTHING) return;
m_time_left -=dt;
bool is_shield = (m_type == ATTACH_BUBBLEGUM_SHIELD|| m_type == ATTACH_NOLOK_BUBBLEGUM_SHIELD);
float m_wanted_node_scale = is_shield ? std::max(1.0f, m_kart->getHighestPoint()*1.1f) : 1.0f;
if (m_node_scale < m_wanted_node_scale)
{
m_node_scale += dt*1.5f;
@@ -476,7 +477,7 @@ void Attachment::update(float dt)
m_bubble_explode_sound = SFXManager::get()->createSoundSource("bubblegum_explode");
m_bubble_explode_sound->setPosition(m_kart->getXYZ());
m_bubble_explode_sound->play();
// drop a small bubble gum
Vec3 hit_point;
Vec3 normal;
@@ -493,7 +494,7 @@ void Attachment::update(float dt)
normal.normalize();
pos.setY(hit_point.getY()-0.05f);
ItemManager::get()->newItem(Item::ITEM_BUBBLEGUM, pos, normal, m_kart);
}
}

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