Merge branch 'master' into Characteristics

This commit is contained in:
Alayan-stk-2
2018-09-13 01:55:06 +02:00
committed by GitHub
261 changed files with 21633 additions and 11277 deletions

View File

@@ -3,7 +3,6 @@ environment:
DEPS_BRANCH: master
ASSETS_DIR: c:\\projects\stk-assets
APPVEYOR_CACHE_ENTRY_ZIP_ARGS: -t7z -m0=lzma2 -mx=9
IRC_NOTIFY_SCRIPT: c:\\projects\stk-code\tools\appveyor-irc-notify.py
os: Visual Studio 2015
clone_depth: 1
@@ -57,10 +56,3 @@ before_build:
build:
parallel: true
project: build\ALL_BUILD.vcxproj
on_success:
- "python %IRC_NOTIFY_SCRIPT% supertuxkart [{author}:{branch}] {short_commit}: {message} {color_green}Succeeded,Details: {build_url},Commit: {commit_url}"
on_failure:
- "python %IRC_NOTIFY_SCRIPT% supertuxkart [{author}:{branch}] {short_commit}: {message} {color_red}Failed,Details: {build_url},Commit: {commit_url}"

View File

@@ -54,16 +54,3 @@ script:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then /usr/local/opt/cmake/bin/cmake .. -DFREETYPE_INCLUDE_DIRS=/usr/local/opt/freetype/include/freetype2/ -DUSE_SYSTEM_GLEW=1 -DOPENAL_INCLUDE_DIR=/usr/local/opt/openal-soft/include/ -DOPENAL_LIBRARY=/usr/local/opt/openal-soft/lib/libopenal.dylib -DFREETYPE_LIBRARY=/usr/local/opt/freetype/lib/libfreetype.dylib -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off; fi
- if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off; fi
- make VERBOSE=1 -j3
notifications:
irc:
channels:
- "irc.freenode.org#supertuxkart"
skip_join: false
use_notice: true
template:
#- "[%{commit}: %{author}] %{message}"
#- "%{build_url}"
- "[%{repository}#%{branch} @%{commit}] %{author}): %{message}"
- "Diff: %{compare_url}"
- "Build: %{build_url}"

View File

@@ -1,14 +1,35 @@
## SuperTuxKart 0.9.4
* Better random item distribution for various numbers of karts
* Improved powerup handling in AI
# Changelog
This file documents notable changes to SuperTuxKart across versions since its inception.
## SuperTuxKart 0.9.3
It should be kept in mind that some versions have a less complete changelog than others, and that this changelog do not list the details of the many small bugfixes and improvements which together make a significant part of the progress between releases.
For similar reasons, and because some features are vastly more complex than others, attributions of main changes should not be taken as a shorcut for overall contribution.
## Unreleased
* Networking game for normal race, time trial, free for all, capture the flag and soccer
* Better random item distribution for various numbers of karts by Alayan and hiker
* Numerous improvements to input on Android by deveee
* Unlockable SuperTux challenges in Story Mode by Alayan
* Race UI improvements (new speedometer, nitro gauge, bigger minimap) by Alayan
* Improvements to ghost replays (more data saved, live time difference, replay comparison, UI improvements, egg hunt replays) by Alayan
* Kart color customization by Benau
* Improved powerup handling in AI by Alayan
* Local multiplayer improvements by Fantasmos
* New coal skin by Alayan
* Visual improvements (new skidding particles, better rescue, bubblegum flashing before ending)
* Audio improvements (crash sound depending on speed/direction, sound cue in nitro challenges)
* Gameplay improvements (much better slipstreaming, GP points...)
* Terrain slowdown works again as intended on several tracks where it was missing
* Many bugfixes
### Tracks and modeling
#### Tracks
* Many unwanted shortcuts and exploits fixed by Auria
* Las Dunas Soccer by samuncle
## SuperTuxKart 0.9.3 (28. October 2017)
* Reduced RAM and VRAM usage, reducing load times by Auria and Benau
* New mesh format optimized for space and hardware skinning
* Code refactoring of both render pipeline by Benau and Elderme
* New kart Wilber and Hexley by Jymis
* New kart Kiki and updated Konqi by Benau
* New tracks Candela City, Cornfield Crossing and Las Dunas Arena by samuncle
* Physics improvements and various physics bugfixes by hiker
* Kart GFX improvements (exhaust and headlight)
* In-game screen recording powered by libopenglrecorder
@@ -17,92 +38,113 @@
* New grand prix win scene
* Gamepad configuration bugfixes
* 3 Strikes Battles : added spare tire karts
* Various improvements (wall driving fixes, parachutes, GP points, cannon fixes, colorization shader)
* Visual representation of the start line in all tracks
* Various improvements (starting boost effect, wall driving fixes, parachutes, GP points, help page for bananas, cannon fixes, colorization shader)
### Tracks and modeling
#### Karts
* New kart Wilber and Hexley by Jymis
* New kart Kiki and updated Konqi by Benau
#### Tracks
* All tracks drivable in reverse, with arrows pointing in the correct direction
* Candela City by samuncle (replace Shiny Suburbs)
* Cornfield Crossing by samuncle (replace Bovine Barnyard)
* New battle track Las Dunas Arena by samuncle
## SuperTuxKart 0.9.2
## SuperTuxKart 0.9.2 (1. July 2016)
* Ghost replay races by Benau
* Battle mode AI by Benau
* Soccer mode AI by Benau
* New icy soccer field by samuncle and Benau
* New subsea track by samuncle
* New volcano track by Ponzino
* TTF font rendering by Benau
* New ruby and forest skins by Benau
* Kart properties refactor by Flakebi
* Scripting work under the hood
* Work on the track editor by mhp
* Tweak to challenges
* New farm track song by 0zone0ne and Krobonil
* Bugfixes
### Tracks and modeling
#### Tracks
* Antediluvian Abysses by samuncle (replace Subsea)
* Volcano Island by Ponzino
* New icy soccer field by samuncle and Benau
## SuperTuxKart 0.9.1
## SuperTuxKart 0.9.1 (17. October 2015)
* Many bug fixes
* Started to use scripting in tracks
* Significant audio performance improvements
* Smaller tweaks and improvements to several tracks including
** Math class
** XR591
** Fort Magma
** Gran Paradiso
** Subsea
* Tweak to challenges
### Tracks and modeling
#### Tracks
* Better support for driving tracks in reverse
* Smaller tweaks and improvements to several tracks including
* Math class
* XR591
* Fort Magma
* Gran Paradiso Island
* Subsea
## SupertTuxKart 0.9 (April 2015)
## SupertTuxKart 0.9 (24. April 2015)
* Fully shader-based rendering engine
* New tracks Cocoa Temple and Gran Paradiso
* Graphical improvements to many other tracks
* New karts amanda and gavroche
* New and improved tux, adiumy, sara the wizard and the racer, xue kart
* Online login which allows to:
** connect with friends and see when they are playing
** vote for addons
** collect online achievements
* connect with friends and see when they are playing
* vote for addons
* collect online achievements
* Grand Prix editor, including creation of random GPs
* Different kart physics
### Tracks and modeling
#### Karts
* New karts Amanda and Gavroche by XGhost
* New and improved Tux, Adiumy, Sara the Wizard and the Racer, Xue
#### Tracks
* Cocoa Temple by samuncle (replace Amazonian Journey)
* Gran Paradiso Island by samuncle (replace The Island)
* Graphical improvements to many other tracks
## SuperTuxKart 0.8.1 (26. November 2013)
* New track STK Enterprise
* Updated track The old mines
* Updated Lighthouse track
* Updated Zen Garden track
* New Soccer mode
* New Egg Hunt mode
* New karts Xue and Sara
* Updated Beastie kart
* Added Tutorial
* Added new Supertux difficulty
* New bubblegum shield weapon
* New Speedometer and nitro meter
* Add ability to filter addons
* Updated nitro models
* Add ability to save and resume Grand Prix
* Improve skid marks and nitro effects
* Wiimote support
### Tracks and modeling
#### Karts
* New karts Xue and Sara
* Updated Beastie kart
#### Tracks
* STK Enterprise by Rubberduck (replace Star Track)
* Gameplay and graphical updates to several tracks :
* The Old Mine
* Lighthouse
* Zen Garden
#### Miscellaneous
* Updated nitro models
## SuperTuxKart 0.8 (11. December 2012)
* Story mode and new challenge set
* Improved AI
* Skidding and better collision physics
* Reverse mode
* New green valley track
* New Blackhill Mansion track
* Updated XR591 track
* Updated Fort Magma track
* Updated jungle track
* Updates Sand track
* Updated menus
* New music
### Tracks and modeling
#### Tracks
* Green Valley by Wolfs (replace Tux Tollway)
* Blackhill Mansion by samuncle (replace Crescent Crossing)
* Gameplay and graphical updates to several tracks :
* XR591
* Fort Magma
* Jungle
* Sand
## SuperTuxKart 0.7.3 (2. November 2011)
* New Zen Garden and Subsea tracks
* New Island battle arena
* New Suzanne kart
* New graphical effects
* New weapons 'Swatter' and 'Rubber Ball'
* Added Thunderbird as race referee
* 3 Strikes Battles now displays lives as spare tires
* Improved bubble gum
* See progression during Grand Prix
@@ -111,16 +153,28 @@
* Improved kart control at high speeds
* Better placement of rescued karts
* Transition track-making to blender 2.5/2.6
### Tracks and modeling
#### Karts
* New Suzanne kart
#### Tracks
* Zen Garden by samuncle (replace Secret Garden)
* New Subsea
* New Island battle arena
#### Miscellaneous
* Added Thunderbird as race referee
## SuperTuxKart 0.7.2 (15. July 2011)
* Added in-game addon manager
* Fixed major memory leaks
* New Snow Peak track by Samuncle
* Improved star track UFO by Rudy
* New Beastie kart.
* Show when you get a highscore
* Improve gamepad configuration under Windows (add ability to tell gamepads apart)
* Various other tweaks done and glitches fixed
### Tracks and modeling
#### Karts
* New Beastie kart.
#### Tracks
* Improved Snow Peak by samuncle
* Improved Star Track UFO by Rudy
## SuperTuxKart 0.7.1b (21. April 2011)
* Fix circular dependency in challenges
@@ -128,8 +182,6 @@
## SuperTuxKart 0.7.1 (15. April 2011)
* Particle (smoke, splash, fire) and weather effects
* New Fort Magma by Samuncle, new Shiny Suburbs track by Horace
* New Beagle kart by wolterh
* Added internet news
* Support for live language switch
* Added optional minimal race UI
@@ -144,6 +196,12 @@
* Fixed character names that contain non-ASCII characters
* Full RTL (right to left) support
* Various other tweaks done and glitches fixed
### Tracks and modeling
#### Karts
* New Beagle kart by wolterh
#### Tracks
* New Fort Magma by samuncle
* New Shiny Suburbs by Horace
## SuperTuxKart 0.7 (December 2010)
Too many to list them all. Main points:
@@ -156,8 +214,12 @@ Too many to list them all. Main points:
* Other improvements
- Allowed alternative ways/shortcuts in tracks
- New item 'switch'
* New art:
- New tracks farm, hacienda, scotland, secret garden
### Tracks and modeling
#### Tracks
- Farm
- Hacienda by samuncle (replace Beach)
- Scotland by Canis Lupus
- Secret Garden
## SuperTuxKart 0.6.2a (October 2009)
* Bugfix: STK would crash while trying to save the config file
@@ -177,7 +239,7 @@ Too many to list them all. Main points:
* Bugfix: battle mode would not display track groups.
## SuperTuxKart 0.6.1 (February 2009)
* Added new kart ("Puffy"), new battle map ("Cave"), and new music for Snow Mountain.
* New music for Snow Mountain.
* Fixed bug in track selection screen that could cause a crash when track groups were used.
* Fixed crash in character selection that could happen if an old user config file existed.
* Fixed incorrect rescues in Fort Magma.
@@ -185,15 +247,19 @@ Too many to list them all. Main points:
* A plunger in the face is now removed when restarting.
* Added slow-down for karts driving backwards.
* Somewhat reduced 'shaking' of AI driven karts.
### Tracks and modeling
#### Karts
- New Puffy kart
#### Tracks
- New Cave battle map
## SuperTuxKart 0.6 (January 2009)
* New improved physics and kart handling
* Added sharp turns and nitro speed boost (replacing wheelies and jump)
* Totally rewrote powerups (plunger, bowling ball, cake, bubblegum) and new look for bananas
* New and improved tracks : skyline, snow mountain, race track, space track, old mine, XR591
* New game mode : 3-Strikes Battle
* Major improvements to AI
* New/improved karts (and removed some old ones) : wilber, eviltux, hexley
* Improved user interface
* Karts now have a visible suspension effect
* Fully positional audio with OpenAL
@@ -208,9 +274,23 @@ Too many to list them all. Main points:
* Bug fixes and code refactor/cleanup/documentation
- Fixed 'joystick locks' (kart would turn even if the joystick is in neutral),
thanks to Samjam for the patch.
### Tracks and modeling
#### Karts
* Improved Wilber
* Eviltux
* Hexley
* Some old karts have been removed
#### Tracks
* Skyline
* Snow Mountain
* Race track
* Old Mine
* XR591
* Improved track :
* Star track
## SuperTuxKart 0.5 (May 2008)
* Six new tracks and one improved track: Fort Magma, SnowTux Peak, Amazonian Journey, City, Canyon, Crescent Crossing and StarTrack
* Complete Challenges to unlock game modes, new tracks and a skidding preview
* New Follow the Leader game mode
* New Grand Prix
@@ -221,18 +301,29 @@ Too many to list them all. Main points:
* Many Bugfixes including:
- a memory leak fix (Charlie Head)
- an AI crash fix (Chris Morris)
### Tracks and modeling
#### Tracks
* SnowTux Peak
* Amazonian Journey
* City
* Canyon
* BSODs Battlements renamed to Fort Magma
* Improved Crescent Crossing, Fort Magma, and Star Track
## SuperTuxKart 0.4 (February 2008)
* New physics handling using the bullet physics engine
* New kart: wilber
* Improved 'Shifting Sands' and 'Lighthouse' tracks
* Improved AI
* New GUI handling, including resolution switching GUI
* Improved input handling
* Jump and look-back featue
* Additional music and main theme
### Tracks and modeling
#### Karts
* New kart: wilber
#### Tracks
* Improved 'Shifting Sands' and 'Lighthouse'
## SuperTuxKart 0.3 (May 2007)
* Highscore lists
@@ -264,7 +355,7 @@ Too many to list them all. Main points:
- Fixed keyboard keys unable to work on the first key press bug
- And others
##SuperTuxKart 0.2 (22. Sep 2006)
## SuperTuxKart 0.2 (22. Sep 2006)
* Significant performance improvement by using display lists
* Improved AI
* Support for different grand prixs
@@ -282,7 +373,7 @@ Too many to list them all. Main points:
* Added help and about screens, added credits to track designer
* Items were added to all tracks
##SuperTuxKart 0.1 (04. May 2006) (not officially released)
## SuperTuxKart 0.1 (04. May 2006) (not officially released)
* Significant speedup by using a new HOT and collision algorithm --> all tracks are now playable
* Removed all SDL dependencies, only plib is needed
* Single and multi-window menu can be used
@@ -290,7 +381,7 @@ Too many to list them all. Main points:
* Some bug fixes and small improvements
* Added profile option to support automatic profiling
##SuperTuxKart 0.0.0 (22. Dec 2004)
## SuperTuxKart 0.0.0 (22. Dec 2004)
* new tracks
* new characters and karts
* new user-interface

View File

@@ -24,6 +24,8 @@ option(USE_SYSTEM_ANGELSCRIPT "Use system angelscript instead of built-in angels
option(USE_SYSTEM_ENET "Use system ENET instead of the built-in version, when available." ON)
option(USE_SYSTEM_GLEW "Use system GLEW instead of the built-in version, when available." ON)
CMAKE_DEPENDENT_OPTION(USE_CRYPTO_OPENSSL "Use OpenSSL instead of Nettle for cryptography in STK." OFF
"NOT APPLE" ON)
CMAKE_DEPENDENT_OPTION(BUILD_RECORDER "Build opengl recorder" ON
"NOT SERVER_ONLY;NOT APPLE" OFF)
CMAKE_DEPENDENT_OPTION(USE_FRIBIDI "Support for right-to-left languages" ON
@@ -453,26 +455,45 @@ else()
target_link_libraries(supertuxkart ${PTHREAD_LIBRARY})
endif()
# CURL and OpenSSL
# CURL and OpenSSL or Nettle
# 1.0.1d for compatible AES GCM handling
SET(OPENSSL_MINIMUM_VERSION "1.0.1d")
if(MSVC)
set(USE_CRYPTO_OPENSSL ON)
target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libcurl.lib)
target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libeay32.lib)
elseif(MINGW)
set(USE_CRYPTO_OPENSSL ON)
target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libcurldll.a)
target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libeay32.dll)
else()
find_package(CURL REQUIRED)
find_package(OpenSSL REQUIRED)
if(${OPENSSL_VERSION} VERSION_LESS ${OPENSSL_MINIMUM_VERSION} OR
(${OPENSSL_VERSION} VERSION_EQUAL ${OPENSSL_MINIMUM_VERSION} AND ${OPENSSL_VERSION} STRLESS ${OPENSSL_MINIMUM_VERSION}))
message(FATAL_ERROR "OpenSSL version found (${OPENSSL_VERSION}) is less then the minimum required (${OPENSSL_MINIMUM_VERSION}), aborting.")
endif()
include_directories(${CURL_INCLUDE_DIRS})
include_directories(${OpenSSL_INCLUDE_DIRS})
find_path(NETTLE_INCLUDE_DIRS nettle/gcm.h nettle/sha.h nettle/base64.h nettle/version.h nettle/yarrow.h)
find_library(NETTLE_LIBRARY NAMES nettle libnettle)
if (NOT NETTLE_INCLUDE_DIRS OR NOT NETTLE_LIBRARY OR USE_CRYPTO_OPENSSL)
set(USE_CRYPTO_OPENSSL ON)
find_package(OpenSSL REQUIRED)
if(${OPENSSL_VERSION} VERSION_LESS ${OPENSSL_MINIMUM_VERSION} OR
(${OPENSSL_VERSION} VERSION_EQUAL ${OPENSSL_MINIMUM_VERSION} AND ${OPENSSL_VERSION} STRLESS ${OPENSSL_MINIMUM_VERSION}))
message(FATAL_ERROR "OpenSSL version found (${OPENSSL_VERSION}) is less then the minimum required (${OPENSSL_MINIMUM_VERSION}), aborting.")
endif()
include_directories(${OpenSSL_INCLUDE_DIRS})
else()
set(USE_CRYPTO_OPENSSL OFF)
include_directories(${NETTLE_INCLUDE_DIRS})
endif()
endif()
if (USE_CRYPTO_OPENSSL)
message(STATUS "OpenSSL will be used for cryptography in STK.")
add_definitions(-DENABLE_CRYPTO_OPENSSL)
else()
message(STATUS "Nettle will be used for cryptography in STK.")
add_definitions(-DENABLE_CRYPTO_NETTLE)
endif()
# Common library dependencies
@@ -484,9 +505,14 @@ target_link_libraries(supertuxkart
stkirrlicht
${Angelscript_LIBRARIES}
${CURL_LIBRARIES}
${OPENSSL_CRYPTO_LIBRARY}
)
if (USE_CRYPTO_OPENSSL)
target_link_libraries(supertuxkart ${OPENSSL_CRYPTO_LIBRARY})
else()
target_link_libraries(supertuxkart ${NETTLE_LIBRARY})
endif()
if(NOT SERVER_ONLY)
if(NOT USE_GLES2)
target_link_libraries(supertuxkart ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARIES})

150
NETWORKING.md Normal file
View File

@@ -0,0 +1,150 @@
# Online networking games for STK
## Hosting server
### Hosting WAN (public internet) server
You are required to have an stk online account first, go [here](https://addons.supertuxkart.net/register.php) for registration.
It is recommended you have a saved user in your computer to allow hosting multiple servers simultaneously with the same account, if you have a fresh STK installation, first run:
`supertuxkart --init-user --login=your_registered_name --password=your_password`
After that you should see `Done saving user, leaving` in terminal if it successfully logged in.
Than you can just run:
`supertuxkart --server-config=your_config.xml --network-console`
It will create that xml configuration file if not found in current directory, you can type `quit` in terminal, than you can edit that file for further configuration as required.
The current server configuration xml looks like this:
```xml
<?xml version="1.0"?>
<server-config version="1" >
<!-- Name of server, encode in XML if you want to use unicode characters. -->
<server-name value="stk server" />
<!-- Port used in server, if you specify 0, it will use the server port specified in stk_config.xml or if random-server-port is enabled in user config, than any port. STK will auto change to random port if the port you specify failed to be bound. -->
<server-port value="0" />
<!-- Game mode in server, 0 is normal race (grand prix), 1 is time trial (grand prix), 3 is normal race, 4 time trial, 6 is soccer, 7 is free-for-all and 8 is capture the flag. Notice: grand prix server doesn't allow for players to join and wait for ongoing game. -->
<server-mode value="3" />
<!-- Difficulty in server, 0 is beginner, 1 is intermediate, 2 is expert and 3 is supertux (the most difficult). -->
<server-difficulty value="0" />
<!-- Number of grand prix tracks per game (If grand prix enabled). -->
<gp-track-count value="3" />
<!-- Use goal torget in soccer. -->
<soccer-goal-target value="false" />
<!-- Enable wan server, which requires you to have an stk-addons account with a saved session. Check init-user command for details. -->
<wan-server value="true" />
<!-- Enable network console, which can do for example kickban. -->
<enable-console value="false" />
<!-- Maximum number of players on the server, setting it more than 8 will have performance degradation. -->
<server-max-players value="8" />
<!-- Password for private server, empty for a public server. -->
<private-server-password value="" />
<!-- Message of today shown in lobby, you can enter encoded XML words here or a file.txt and let STK load it. -->
<motd value="" />
<!-- Timeout in seconds for voting tracks in server. -->
<voting-timeout value="20" />
<!-- Timeout in seconds for validation of clients in wan, currently stk will use the stk-addons server to share AES key between client and server. -->
<validation-timeout value="20" />
<!-- By default WAN server will always validate player and LAN will not, disable it to allow non-validated player in WAN. -->
<validating-player value="true" />
<!-- Disable it to turn off all stun related code in server, it allows saving server resource if your server is not behind a firewall. -->
<firewalled-server value="true" />
<!-- No server owner in lobby which can control the starting of game or kick any players. -->
<owner-less value="false" />
<!-- Time to wait before entering kart selection screen if satisfied start-game-threshold below for owner less or ranked server. -->
<start-game-counter value="30" />
<!-- Only auto start kart selection when number of connected player is larger than max player * this value, for owner less or ranked server, after start-game-counter. -->
<start-game-threshold value="0.5" />
<!-- Automatically end linear race game after 1st player finished for some time (currently his finished time * 0.25 + 15.0). -->
<auto-end value="false" />
<!-- Enable team choosing in lobby in team game (soccer and CTF). If owner-less is enabled, than this option is always disabled. -->
<team-choosing value="true" />
<!-- Server will submit ranking to stk addons server for linear race games, you require permission for that. validating-player, auto-end and owner-less will be turned on. -->
<ranked value="false" />
<!-- Time in seconds when a flag is dropped a by player in CTF returning to its own base. -->
<flag-return-timemout value="20" />
<!-- Value used to calculate hit limit in free for all, which is min(number of players * hit-limit-threshold, 40), negative value to disable hit limit. -->
<hit-limit-threshold value="5" />
<!-- Value used to calculate time limit in free for all, which is max(number of players * time-limit-threshold-ffa, 3.0) * 60, negative value to disable time limit. -->
<time-limit-threshold-ffa value="0.7" />
<!-- Value used to calculate capture limit in CTF, which is max(3.0, number of players * capture-limit-threshold), negative value to disable capture limit. -->
<capture-limit-threshold value="0.7" />
<!-- Value used to calculate time limit in CTF, which is max(3.0, number of players * (time-limit-threshold-ctf + flag-return-timemout / 60.0)) * 60.0, negative value to disable time limit. -->
<time-limit-threshold-ctf value="0.9" />
<!-- Value used by server to automatically calculate lap of each race in network game, if more than 0.0f, the number of lap of each track vote in linear race will be determined by max(1.0f, auto-lap-ratio * default lap of that track). -->
<auto-lap-ratio value="-1" />
<!-- Maximum ping allowed for a player (in ms). -->
<max-ping value="300" />
<!-- Tolerance of jitter in network allowed (in ms). -->
<jitter-tolerance value="100" />
<!-- Kick players whose ping is above max-ping. -->
<kick-high-ping-players value="false" />
<!-- ip: IP in X.X.X.X/Y (CIDR) format for banning, use Y of 32 for a specific ip, expired-time: unix timestamp to expire, if -1 (uint32_t max) than a permanent ban. -->
<server-ip-ban-list>
<ban ip="0.0.0.0/0" expired-time="0"/>
</server-ip-ban-list>
<!-- online-id: online id for banning, expired-time: unix timestamp to expire, if -1 (uint32_t max) than a permanent ban. -->
<server-online-id-ban-list>
<ban online-id="0" expired-time="0"/>
</server-online-id-ban-list>
</server-config>
```
At the moment STK has a list of STUN servers for NAT penetration which allows players or servers behind a firewall or router to make connectable to each other, but in case it doesn't work, you have to manually disable firewall / do a port-forward for the server port STK using.
By default STK uses `2759` for server port, for example in Ubuntu alike Linux distribution do the following to disable firewall on such port:
`sudo ufw allow 2759`
You may also need to handle the server discovery port `2757` for connecting your WAN server in LAN / localhost.
Notice: You don't need to make any firewall or router configuration if you connect to our official servers.
### Hosting LAN (local internet) server
Everything is basically the same as WAN one, except you don't need an stk online account, just do:
`supertuxkart --server-config=your_config.xml --lan-server=your_server_name --network-console`
In LAN network it is required that the server and server discovery port is connectable by clients directly, no NAT penetration will be done in LAN.
------
After the first time configuration, you can just start the server with the command:
`supertuxkart --server-config=your_config.xml`, regardless of whether LAN or WAN server is chosen (of course you need to have a saved user for the WAN one), by default your server logging will be saved to the STK configuration directory with a name of `your_config.log`, given that the server configuration filename is `your_config.xml`.
You can find out that directory location [here (See Where is the configuration stored?)](https://supertuxkart.net/FAQ)

View File

@@ -161,6 +161,7 @@ LOCAL_CFLAGS := -I../lib/angelscript/include \
-Iobj/openssl/include \
-DUSE_GLES2 \
-DENABLE_SOUND \
-DENABLE_CRYPTO_OPENSSL \
-DNDEBUG \
-DANDROID_PACKAGE_NAME=\"$(PACKAGE_NAME)\" \
-DANDROID_APP_DIR_NAME=\"$(APP_DIR_NAME)\" \

View File

@@ -64,7 +64,6 @@ Add-ons website
= Additional Programming =
Main Contributors
- Dawid Gan (deveee) : general improvements and many many bugfixes
- Marc Coll : Grand Prix editor
- Flakebi
- Konstin
@@ -91,7 +90,8 @@ Bug fixes & misc contributions
- Stephen Dunn (Work on audio)
- Patrick Ammann
- Ward Muylaert
- Fantasmos
- QwertyChouskie
= Visual art =

View File

@@ -42,6 +42,8 @@ ghost_plus.png by Alayan, based on https://openclipart.org/detail/17847/cartoon-
options_language.png by Alayan, based on http://www.languageicon.org/, released under CC-BY-SA 3+
blue_flag.png, heart.png and red_flag.png by Benau, released under CC-BY-SA 4
====
Glass Skin by Auria, under CC-BY-SA 3+

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
data/gui/blue_flag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -2,25 +2,26 @@
<stkgui>
<div x="2%" y="1%" width="96%" height="98%" layout="vertical-row" padding="10">
<header id="selected_track" width="80%" height="30"
<header id="selected_track" width="80%"
I18N="No neeed to translate this, it will be overwritten by the track name"
text="" align="center" text_align="center" />
<spacer height="20" />
<!-- Track selection -->
<box width="100%" height="60%" layout="vertical-row">
<ribbon_grid id="tracks" proportion="1" width="100%" height="100%" square_items="true"
label_location="each" align="center" child_width="240" child_height="160" />
<box proportion="3" width="100%" layout="vertical-row">
<ribbon_grid id="tracks" proportion="1" width="100%" square_items="true"
label_location="each" align="center" max_rows="2" child_width="160"
child_height="120"/>
</box>
<!-- Populated dynamically at runtime -->
<tabs width="100%" height="5%" id="trackgroups"> </tabs>
<spacer height="50" />
<spacer height="10%" />
<!-- Laps and reverse -->
<div width="100%" height="100" layout="horizontal-row" align="center">
<div width="100%" height="fit" layout="horizontal-row" align="center">
<spacer proportion="1" />
@@ -40,8 +41,10 @@
<spacer proportion="1" />
</div>
<spacer height="5%" />
<!-- Dialog buttons -->
<div width="100%" height="60" layout="horizontal-row">
<div width="100%" height="fit" layout="horizontal-row">
<spacer proportion="2" />
<button id="ok" text="OK" proportion="1" />
<spacer proportion="1" />
@@ -49,5 +52,7 @@
<spacer proportion="2" />
</div>
<spacer height="2%" />
</div>
</stkgui>

View File

@@ -3,13 +3,13 @@
<div x="2%" y="10%" width="96%" height="80%" layout="vertical-row" >
<label id="title" raw_text="Text" proportion="1"/>
<spacer height="25" width="10" />
<spacer height="7%" width="10" />
<textbox id="textfield" width="75%" align="center"/>
<spacer height="20" width="20" />
<spacer height="7%" width="20" />
<button id="ok" I18N="In the general textfield dialog" text="OK" align="center" proportion="1"/>
<spacer height="15" width="20" />
<spacer height="5%" width="20" />
<button id="cancel" I18N="In the general textfield dialog" text="Cancel" align="center" proportion="1"/>
</div>
</stkgui>

View File

@@ -38,9 +38,14 @@
<div width="99%" align="center" layout="horizontal-row" height="fit">
<div proportion="2" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="replay_difficulty_toggle" text_align="left"/>
<spacer width="1%" height="fit"/>
<spacer width="2%" height="fit"/>
<label height="100%" text_align="left" I18N="In the ghost replay selection screen" text="Only show replays matching the current difficulty"/>
</div>
<div proportion="1" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="replay_multiplayer_toggle" text_align="left"/>
<spacer width="2%" height="fit"/>
<label height="100%" text_align="left" I18N="In the ghost replay selection screen" text="Hide multiplayer replays"/>
</div>
</div>
<div width="99%" align="center" layout="horizontal-row" height="fit">

View File

@@ -3,55 +3,56 @@
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
<div x="2%" y="2%" width="96%" height="96%" layout="vertical-row">
<header id="name" height="7%" width="80%" align="center" text_align="center"/>
<header id="name" height="5%" width="80%" align="center" text_align="center"/>
<spacer width="1" height="5%"/>
<spacer width="1" height="2%"/>
<box width="100%" height="40%" padding="10" layout="horizontal-row">
<spacer width="10" height="100%"/>
<!-- Left pane -->
<div width="45%" height="100%" align="center" layout="vertical-row">
<div proportion="1" height="100%" layout="vertical-row">
<icon-button proportion="1" width="100%" height="100%" id="screenshot" custom_ratio="1.33333"/>
</div>
<spacer width="5%" height="100%"/>
<!-- Right pane -->
<div width="45%" height="95%" align="center" layout="vertical-row">
<div proportion="1" height="100%" layout="vertical-row">
<list id="tracks" width="100%" height="100%"/>
</div>
</box>
<spacer width="1" height="5%"/>
<box width="100%" height="28%" padding="20" layout="vertical-row">
<div width="100%" height="20%" layout="horizontal-row" >
<label id="ai-text" width="50%" I18N="In the grand prix info screen" text="AI karts" text_align="right"/>
<spacer width="30"/>
<spinner id="ai-spinner" width="30%" min_value="1" max_value="20" align="center" wrap_around="true" />
<spacer width="1" height="1%"/>
<box width="100%" height="33%" layout="vertical-row">
<div width="100%" height="fit" layout="horizontal-row" >
<label id="ai-text" proportion="1" I18N="In the grand prix info screen" text="AI karts" text_align="right"/>
<spacer width="40"/>
<div proportion="1" height="fit" layout="horizontal-row">
<spinner id="ai-spinner" width="50%" min_value="1" max_value="20" align="center" wrap_around="true" />
</div>
</div>
<spacer height="5%" />
<div width="100%" height="20%" layout="horizontal-row" >
<label id="reverse-text" width="50%" I18N="In the grand prix info screen" text="Reverse" text_align="right"/>
<spacer width="30"/>
<spinner id="reverse-spinner" width="30%" align="center" wrap_around="true" />
<spacer width="1" height="1%"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="reverse-text" proportion="1" I18N="In the grand prix info screen" text="Reverse" text_align="right"/>
<spacer width="40"/>
<div proportion="1" height="fit" layout="horizontal-row">
<spinner id="reverse-spinner" width="50%" align="center" wrap_around="true" />
</div>
</div>
<spacer height="5%" />
<div width="100%" height="20%" layout="horizontal-row">
<label id="track-text" width="50%" I18N="In the grand prix info screen" text="Tracks" text_align="right"/>
<spacer width="30"/>
<spinner id="track-spinner" width="30%" min_value="1" max_value="20" align="center" wrap_around="true" />
<spacer width="1" height="1%"/>
<div width="100%" height="fit" layout="horizontal-row">
<label id="track-text" proportion="1" I18N="In the grand prix info screen" text="Tracks" text_align="right"/>
<spacer width="40"/>
<div proportion="1" height="fit" layout="horizontal-row">
<spinner id="track-spinner" width="50%" min_value="1" max_value="20" align="center" wrap_around="true" />
</div>
</div>
<spacer height="5%" />
<div width="100%" height="20%" layout="horizontal-row" >
<label id="group-text" width="50%" I18N="In the grand prix info screen" text="Track group" text_align="right"/>
<spacer width="30"/>
<spinner id="group-spinner" width="30%" align="center" wrap_around="true" />
<spacer width="1" height="1%"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="group-text" proportion="1" I18N="In the grand prix info screen" text="Track group" text_align="right"/>
<spacer width="40"/>
<div proportion="1" height="fit" layout="horizontal-row">
<spinner id="group-spinner" width="50%" align="center" wrap_around="true" />
</div>
</div>
</box>
<spacer height="2%"/>
<buttonbar id="buttons" height="15%" width="100%" align="center">
<spacer width="1" height="1%"/>
<buttonbar id="buttons" height="17%" width="100%" align="center">
<icon-button id="start" width="64" height="64" icon="gui/green_check.png"
I18N="In the grand prix info screen" text="Start Race"/>

View File

@@ -7,9 +7,9 @@
<header width="80%" I18N="Title in grand prix editor screen" text="Grand Prix editor"
align="center" text_align="center" />
<spacer height="20" />
<spacer height="10" />
<box proportion="4" width="100%" layout="vertical-row">
<box proportion="8" width="100%" layout="vertical-row">
<ribbon_grid id="gplist" proportion="1" width="100%" square_items="true"
label_location="each" align="left" max_rows="2" child_width="160"
child_height="120" keep_selection="true" />
@@ -20,7 +20,7 @@
<spacer height="20" />
<box proportion="2" width="100%" layout="vertical-row">
<box proportion="5" width="100%" layout="vertical-row">
<label id="gpname" text_align="center" width="100%" text="" />
<ribbon_grid id="tracks" proportion="1" width="100%" square_items="true"
label_location="each" align="left" max_rows="1"
@@ -29,7 +29,7 @@
<spacer height="20" />
<buttonbar proportion="1" id="menu" height="135" width="100%" align="center">
<buttonbar proportion="3" id="menu" height="135" width="100%" align="center">
<icon-button id="new" width="128" height="128" icon="gui/gp_new.png"
I18N="Menu item" text="New" />
<icon-button id="copy" width="128" height="128" icon="gui/gp_copy.png"

View File

@@ -70,7 +70,7 @@
<spacer width="25" height="25"/>
<bubble proportion="2" height="100%" word_wrap="true"
I18N="In the help menu"
text="The 'skidding' key allows you to skid. Short skids help to take sharp turns. If you skid long enough, you will get a boost. You can't stop turning while skidding, so orient your kart carefully before !"/>
text="The 'skidding' key allows you to skid. Short skids help to take sharp turns. If you skid long enough, you will get a boost. You can't stop turning while skidding, so orient your kart carefully before!"/>
</div>
<spacer height="3%" width="10"/>

View File

@@ -56,11 +56,11 @@
</div>
<div width="100%" proportion="2" layout="horizontal-row">
<icon align="center" width="64" height="64" icon="gui/mode_3strikes.png"/>
<icon align="center" width="64" height="64" icon="gui/weapons.png"/>
<spacer width="25" height="25"/>
<bubble proportion="1" height="100%"
I18N="In the help menu"
text="3 Strikes Battle: Hit others with weapons until they lose all their lives."/>
text="There are 3 types of battle mode: In 3 Strikes Battle, you need to hit others with weapons until they lose all their lives. In Free-For-All, the player who hits others the most will win in a given hit or time limit. In Capture The Flag, your team needs to bring the flag of the other team to your own flag base, as long as your flag is not captured by the other team."/>
</div>
<div width="100%" proportion="2" layout="horizontal-row">

View File

@@ -40,7 +40,7 @@
<div width="100%" proportion="1" layout="horizontal-row">
<icon align="center" width="64" height="64" icon="models/zipper_collect.png"/>
<spacer width="25" height="25"/>
<bubble proportion="1" height="100%" text="Zipper - will give you a strong speed boost. But beware of not losing control of your kart !"/>
<bubble proportion="1" height="100%" text="Zipper - will give you a strong speed boost. But beware of not losing control of your kart!"/>
</div>
<div width="100%" proportion="1" layout="horizontal-row">

View File

@@ -41,7 +41,7 @@
<spacer width="25" height="25"/>
<bubble proportion="1" height="100%"
I18N="In the help menu"
text="Once in a server, a race will begin once its owner (symbolized with the crown) decides so. Official servers may auto-start races only when there are enough players. Then, you can choose your kart and vote for the next track to race on. An addon kart or track is allowed only if it exists on all joinned players and the server."/>
text="Once in a server, a race will begin once its owner (symbolized with the crown) decides so. Official servers may auto-start races only when there are enough players. Then, you can choose your kart and vote for the next track to race on. An addon kart or track is allowed only if it exists on all joined players and the server."/>
</div>
<label align="center" I18N="In the help menu" text="... or on the same computer:"/>
@@ -59,7 +59,7 @@
<spacer width="25" height="25"/>
<bubble proportion="1" height="100%"
I18N="In the help menu"
text="When input devices are configured, select the 'multiplayer race' icon in the main menu. Each player can press the 'fire' key of their gamepad or keyboard to join the game, and use their input device to select their kart. The game continues when everyone selected their kart. Note that the mouse may not be used for this operation."/>
text="When input devices are configured, select the 'multiplayer' icon in the main menu. Each player can press the 'fire' key of their gamepad or keyboard to join the game, and use their input device to select their kart. The game continues when everyone selected their kart. Note that the mouse may not be used for this operation."/>
</div>
<spacer width="50" height="25" />
</box>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -25,9 +25,9 @@
I18N="Main menu button" text="Addons"/>
</buttonbar>
<spacer width="10" height="7%"/>
<spacer width="10" height="6%"/>
<bottombar width="100%" height="10%" layout="horizontal-row">
<bottombar width="100%" height="11%" layout="horizontal-row">
<spacer width="10" height="10" />
@@ -38,7 +38,7 @@
<spacer width="10" height="10" />
<buttonbar id="menu_bottomrow" x="0" y="0" width="38%" height="100%" align="center">
<buttonbar id="menu_bottomrow" x="0" y="0" width="42%" height="100%" align="center">
<icon-button id="test_gpwin" width="64" height="64" icon="gui/main_options.png"
raw_text="TEST: GPWin" label_location="hover"/>
<icon-button id="test_gplose" width="64" height="64" icon="gui/main_options.png"

View File

@@ -42,8 +42,8 @@
I18N="Multiplayer game mode" text="Normal Race"/>
<icon-button id="timetrial" width="128" height="128" icon="gui/mode_tt.png"
I18N="Multiplayer game mode" text="Time Trial"/>
<icon-button id="3strikes" width="128" height="128" icon="gui/mode_3strikes.png"
I18N="Multiplayer game mode" text="3 Strikes Battle"/>
<icon-button id="3strikes" width="128" height="128" icon="gui/weapons.png"
I18N="Multiplayer game mode" text="Battle"/>
<icon-button id="soccer" width="128" height="128" icon="gui/mode_soccer.png"
I18N="Multiplayer game mode" text="Soccer"/>
</ribbon>

View File

@@ -15,14 +15,14 @@
</div>
</div>
<spacer height="2%"/>
<div proportion="2" x="2%" width="96%" layout="horizontal-row">
<box proportion="4" height="100%" layout="vertical-row">
<textbox id="chat" width="100%" height="30%"/>
<div x="2%" width="96%" height="fit" layout="horizontal-row">
<box proportion="4" height="fit" layout="vertical-row">
<textbox id="chat" width="100%"/>
<spacer height="10"/>
<div width="100%" height="30%" proportion="1" layout="horizontal-row">
<button id="send" width="10%" height="fit" I18N="In the network lobby" text="Send" />
<spacer width="10"/>
<label id="timeout-message" width="80%" height="fit"/>
<div width="100%" height="fit" layout="horizontal-row">
<button id="send" width="20%" height="fit" I18N="In the network lobby" text="Send" />
<spacer width="1%"/>
<label id="timeout-message" width="79%" height="fit"/>
</div>
</box>
<spacer width="3%"/>

View File

@@ -6,13 +6,13 @@
<button id="user-id" width="20%" height="fit" align="center"/>
<spacer height="20"/>
<box width="50%" height="10%" layout="horizontal-row" align="center" valign="center">
<spacer proportion="1"/>
<box width="fit" height="fit" layout="horizontal-row" align="center" valign="center">
<spacer width="25"/>
<label I18N="In the networking menu" align="center"
text="Enable splitscreen or player handicaps" text_align="right"/>
<spacer width="25"/>
<checkbox id="enable-splitscreen" align="center" />
<spacer proportion="1"/>
<spacer width="25"/>
</box>
<spacer height="15" width="10"/>

View File

@@ -1,44 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<stkgui>
<div x="2%" y="5%" width="96%" height="85%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the server info dialog" text="Server Info"/>
<spacer height="20" width="50"/>
<div width="80%" align="center" layout="vertical-row" height="fit" >
<!--
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the server info dialog" text="Name"/>
<label id="name" proportion="2" text_align="left" text=""/>
</div>
-->
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the networking lobby" text="Server name:"/>
<label proportion="2" text_align="left" id="server_name" text=""/>
</div>
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the networking lobby" text="Difficulty:"/>
<label proportion="2" text_align="left" id="server_difficulty" text=""/>
</div>
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the networking lobby" text="Game mode:"/>
<label proportion="2" text_align="left" id="server_game_mode" text=""/>
</div>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_password" text_align="left" proportion="1" text="Password"/>
<textbox id="password" proportion="2" height="fit"/>
</div>
<div x="2%" y="0%" width="96%" height="100%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"/>
<spacer height="30"/>
<label id="server-info" width="90%" height="fit" align="left" text_align="left" text=""/>
<box x="0%" width="90%" height="50%" align="center" layout="vertical-row">
<list id="player-list" x="0" y="0" width="100%" height="100%"/>
</box>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="label_password" text_align="left" proportion="1" text="Password"/>
<textbox id="password" proportion="2" height="fit"/>
</div>
<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"/>
<buttonbar id="options" width="90%" height="20%" align="center">
<buttonbar id="options" width="90%" height="15%" align="center">
<icon-button id="join" width="64" height="64" icon="gui/green_check.png"
I18N="In the server info dialog" text="Join" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"

View File

@@ -9,7 +9,8 @@
</div>
<box proportion="1" width="98%" align="center" layout="vertical-row" padding="6">
<list id="server_list" x="0" y="0" width="100%" height="100%"/>
<list id="server_list" x="0" y="0" width="100%" height="93%"/>
<textbox id="searcher" width="100%" height="7%"/>
</box>
<div width="99%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" >
@@ -17,6 +18,10 @@
<spacer width="10"/>
<label proportion="1" height="100%" text_align="left"
I18N="In the server selection screen" text="Show only private server(s)"/>
<checkbox width="fit" id="game_started" text_align="left"/>
<spacer width="10"/>
<label proportion="1" height="100%" text_align="left"
I18N="In the server selection screen" text="Hide servers with an ongoing game"/>
</div>
</div>
</div>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<stkgui>
<div x="5%" y="5%" width="90%" height="90%" layout="vertical-row" >
<header id="title" width="100%" text_align="center" text="Paused" proportion="3" />
<header id="title" width="100%" text_align="center" text="Paused" proportion="2" />
<!-- FIXME: some play in proportions occur below because the text of an icon
button is added UNDER it and not within its allocated height -->

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<stkgui>
<div x="5%" y="5%" width="90%" height="90%" layout="vertical-row" >
<header id="title" width="100%" text_align="center" text="Paused" proportion="3" />
<div x="2%" y="5%" width="96%" height="90%" layout="vertical-row" >
<header id="title" width="100%" text_align="center" text="Paused" proportion="2" />
<!-- FIXME: some play in proportions occur below because the text of an icon
button is added UNDER it and not within its allocated height -->

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
data/gui/red_flag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -2,27 +2,30 @@
<stkgui>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
<div x="5%" y="5%" width="90%" height="90%" layout="vertical-row" >
<icon id="red_team" I18N="In soccer setup screen" text="Red Team" icon="gui/soccer_ball_red.png" width="7%" height="7%"/>
<icon id="blue_team" I18N="In soccer setup screen" text="Blue Team" icon="gui/soccer_ball_blue.png" width="7%" height="7%"/>
<div x="2%" y="1%" width="96%" height="98%" layout="vertical-row" >
<header width="80%" text="Race Setup" align="center" text_align="center" />
<spacer height="10" width="25"/>
<div layout="horizontal-row" width="fit" height="35" align="left">
<div layout="horizontal-row" width="fit" height="fit" align="left">
<bright proportion="1" height="100%"
I18N="In soccer setup screen" text="Number of goals to win" text_align="left" />
<spacer width="10" height="25"/>
<spinner id="goalamount" width="200" height="90%" min_value="1" max_value="10"/>
<spinner id="goalamount" width="200" min_value="1" max_value="10"/>
</div>
<div layout="horizontal-row" width="fit" height="35" align="left">
<div layout="horizontal-row" width="fit" height="fit" align="left">
<bright proportion="1" height="100%"
I18N="In soccer setup screen" text="Maximum time (min.)" text_align="left" />
<spacer width="10" height ="25"/>
<spinner id="timeamount" width="200" height="90%" min_value="1" max_value="15"/>
<spinner id="timeamount" width="200" min_value="1" max_value="15"/>
</div>
<div layout="horizontal-row" width="fit" height="35" align="left">
<div layout="horizontal-row" width="fit" height="fit" align="left">
<bright proportion="1" height="100%"
I18N="In soccer setup screen" text="Game type (Goals limit / Time limit)" text_align="left" />
<spacer width="10" height="25"/>
@@ -33,14 +36,16 @@
<bubble height="fit" width="100%" id="lblLeftRight" I18N="In soccer setup screen" text="Use left/right to choose your team and press fire" word_wrap="true" text_align="center"/>
<spacer height="10" width="25"/>
<div id="central_div" layout="horizontal-row" width="100%" proportion="1" align="center">
<roundedbox y="5%" width="100%" layout="horizontal-row" height="95%">
<roundedbox width="100%" layout="horizontal-row" height="100%">
<!-- Content is added programmatically -->
</roundedbox>
<icon id="red_team" I18N="In soccer setup screen" text="Red Team" icon="gui/soccer_ball_red.png" width="font" height="font"/> <!-- Layout is done programmatically -->
<icon id="blue_team" I18N="In soccer setup screen" text="Blue Team" icon="gui/soccer_ball_blue.png" width="font" height="font"/>
</div>
<spacer height="10" width="25"/>
<button id="continue" I18N="In soccer setup screen" text="Continue" align="center" width="60%"/>
</div>
</stkgui>

View File

@@ -5,7 +5,7 @@
<div x="2%" y="2%" width="96%" height="96%" layout="vertical-row">
<header id="name" height="7%" width="80%" align="center" text_align="center"/>
<spacer width="1" height="1%"/>
<spacer width="1" height="2%"/>
<box width="100%" height="40%" padding="10" layout="horizontal-row">
<!-- Left pane -->
@@ -50,7 +50,7 @@
</box>
<spacer width="1" height="1%"/>
<box width="100%" height="33%" padding="15" layout="vertical-row">
<box width="100%" height="33%" layout="vertical-row">
<div width="100%" height="fit" layout="horizontal-row" >
<label id="lap-text" proportion="1" I18N="In the track info screen" text="Number of laps" text_align="right"/>
<spacer width="40"/>
@@ -59,7 +59,7 @@
wrap_around="true" />
</div>
</div>
<spacer height="10"/>
<spacer width="1" height="1%"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="ai-text" proportion="1" I18N="In the track info screen" text="Number of AI karts" text_align="right"/>
<spacer width="40"/>
@@ -68,7 +68,7 @@
wrap_around="true" />
</div>
</div>
<spacer height="10"/>
<spacer width="1" height="1%"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="option-text" proportion="1" I18N="In the track info screen" text_align="right"/>
<spacer width="40"/>
@@ -78,6 +78,7 @@
</div>
</div>
</div>
<spacer width="1" height="1%"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="record-race-text" proportion="1" I18N="In the track info screen" text="Record the race for ghost replay" text_align="right"/>
<spacer width="40"/>
@@ -87,10 +88,9 @@
</div>
</div>
</div>
<spacer width="1" height="1%"/>
</box>
<spacer width="1" height="1%"/>
<buttonbar id="buttons" height="15%" width="100%" align="center">
<buttonbar id="buttons" height="17%" width="100%" align="center">
<icon-button id="start" width="64" height="64" icon="gui/green_check.png"
I18N="In the track info screen" text="Start Race"/>

View File

@@ -75,7 +75,7 @@
<spacer width="20" height="2%"/>
<div width="90%" align="center" layout="vertical-row" height="18%">
<div width="100%" align="center" layout="vertical-row" height="18%">
<buttonbar id="options" width="100%" height="100%" align="center">
<icon-button id="ok" width="fit" height="fit" icon="gui/green_check.png"
I18N="In the user screen" text="OK" label_location="bottom"/>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,22 +2,30 @@
#
# ./data/po/update_pot.sh
CPP_FILE_LIST="`find ./src \
-name '*.cpp' -or \
-name '*.c' -or \
-name '*.hpp' -or \
-name "*.h" \
CPP_FILE_LIST="`find ./src \
-name '*.cpp' -or \
-name '*.c' -or \
-name '*.hpp' -or \
-name "*.h" | sort -n \
`"
XML_FILE_LIST="`find ./data ../stk-assets/tracks ../stk-assets/karts \
-name 'achievements.xml' -or \
-name 'kart.xml' -or \
-name 'track.xml' -or \
-name 'scene.xml' -or \
-name '*.challenge' -or \
-name '*.grandprix' -or \
-name '*.stkgui' \
XML_FILE_LIST="`find ./data \
../stk-assets/tracks \
../stk-assets/karts \
../supertuxkart-assets/tracks \
../supertuxkart-assets/karts \
-name 'achievements.xml' -or \
-name 'kart.xml' -or \
-name 'track.xml' -or \
-name 'scene.xml' -or \
-name '*.challenge' -or \
-name '*.grandprix' -or \
-name '*.stkgui' | sort -n \
`"
ANGELSCRIPT_FILE_LIST="`find ./data ../stk-assets/tracks -name '*.as'`"
ANGELSCRIPT_FILE_LIST="`find ./data \
../stk-assets/tracks \
../supertuxkart-assets/tracks \
-name '*.as' | sort -n \
`"
echo "--------------------"
echo " Source Files :"

File diff suppressed because it is too large Load Diff

View File

@@ -55,7 +55,7 @@
-->
<item name="rubber-ball" icon="rubber_ball-icon.png"
model="rubber_ball.spm" speed="35.0"
scale="1 1 1" interval="1"
interval="1"
max-height="4.0" min-height="0"
fast-ping-distance="50"
early-target-factor="1"
@@ -84,7 +84,6 @@
is different. Typically, the higher the number of karts, the
stronger the difference in "powerup quality" between the first and
the last.
Each of those weight tags is stored into a WeightsData object.
At race time, a new WeightsData object is created from the list for
the current race type depending on number of karts in the race.
@@ -101,7 +100,6 @@
the first non-leader kart, and the last entry for the last
kart. So the 3rd till second-last entries are distributed
evenly instead of the 2nd till second-last).
For example, with 5 karts and 5 entries those points will
match positions 2, 3, 4. With 10 karts (and 5 entries), they
will correspond to 3,25 ; 5,5 ; 7,75. It is not an issue if
@@ -118,14 +116,12 @@
a triple item rather than a single one. The probability to get
an item is its weight divided by the sum of weights of all items
(single AND multi). It is recommended to keep that sum equal
to 200 to easily keep track of probabilities.
to 1000 to easily keep track of probabilities.
'Global' items which affect all karts (switch, parachute) should
be quite rare, since otherwise the item might be used
too often (compared with many items which will only
affect a karts or two) - especially with increasing number of
karts in a race.
The distribution should give more similar items to different ranks
when there are few karts, but have more important differences when
there are more karts. -->
@@ -135,70 +131,69 @@
<!-- The entry for '1' kart lists more than a single weight
because the others are used for interpolation when
there are two karts or more. -->
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="28 0 60 20 45 15 32 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="30 0 59 26 40 14 27 0 0 0"
multi =" 0 0 4 0 0 0 0 0 0 0" />
<weight single ="30 0 62 27 36 13 27 0 0 0"
multi =" 0 0 5 0 0 0 0 0 0 0" />
<weight single ="31 0 56 36 34 12 25 0 0 0"
multi =" 0 0 6 0 0 0 0 0 0 0" />
<weight single ="34 0 36 55 30 10 17 0 0 0"
multi =" 0 0 18 0 0 0 0 0 0 0" />
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="140 0 300 100 225 75 160 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="150 0 295 130 200 70 135 0 0 0"
multi =" 0 0 20 0 0 0 0 0 0 0" />
<weight single ="150 0 310 135 180 65 135 0 0 0"
multi =" 0 0 25 0 0 0 0 0 0 0" />
<weight single ="155 0 280 180 170 60 125 0 0 0"
multi =" 0 0 30 0 0 0 0 0 0 0" />
<weight single ="170 0 180 275 150 50 85 0 0 0"
multi =" 0 0 90 0 0 0 0 0 0 0" />
</weights>
<weights num-karts="5">
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="26 16 52 15 46 12 33 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="30 27 48 25 28 10 27 0 0 0"
multi =" 0 0 5 0 0 0 0 0 0 0" />
<weight single ="30 27 45 27 27 9 27 3 0 0"
multi =" 0 0 5 0 0 0 0 0 0 0" />
<weight single ="32 24 28 38 22 7 20 16 6 0"
multi =" 0 0 7 0 0 0 0 0 0 0" />
<weight single ="28 21 9 45 0 6 0 10 18 0"
multi =" 8 0 16 35 4 0 0 0 0 0" />
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="130 80 260 75 230 60 165 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="150 135 240 125 140 50 135 0 0 0"
multi =" 0 0 25 0 0 0 0 0 0 0" />
<weight single ="150 135 225 135 135 45 135 15 0 0"
multi =" 0 0 25 0 0 0 0 0 0 0" />
<weight single ="160 120 140 190 110 35 100 80 30 0"
multi =" 0 0 35 0 0 0 0 0 0 0" />
<weight single ="140 105 45 225 0 30 0 50 90 0"
multi =" 40 0 80 175 20 0 0 0 0 0" />
</weights>
<weights num-karts="9">
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="24 12 58 10 54 8 34 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="29 30 45 24 32 7 27 0 0 0"
multi =" 0 0 6 0 0 0 0 0 0 0" />
<weight single ="30 26 41 28 26 6 26 10 0 0"
multi =" 0 0 7 0 0 0 0 0 0 0" />
<weight single ="33 23 26 45 14 5 16 12 8 0"
multi =" 0 0 12 0 6 0 0 0 0 0" />
<weight single ="20 16 7 37 0 3 0 4 15 0"
multi ="18 0 18 58 4 0 0 0 0 0" />
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="120 60 290 50 270 40 170 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="145 150 225 120 160 35 135 0 0 0"
multi =" 0 0 30 0 0 0 0 0 0 0" />
<weight single ="150 130 205 140 130 30 130 50 0 0"
multi =" 0 0 35 0 0 0 0 0 0 0" />
<weight single ="165 115 130 225 70 25 80 60 40 0"
multi =" 0 0 60 0 30 0 0 0 0 0" />
<weight single ="100 80 35 185 0 15 0 20 75 0"
multi =" 90 0 90 290 20 0 0 0 0 0" />
</weights>
<weights num-karts="14">
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="22 8 64 5 60 6 35 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="28 31 48 22 34 4 27 0 0 0"
multi =" 0 0 6 0 0 0 0 0 0 0" />
<weight single ="30 25 42 29 29 3 24 10 0 0"
multi =" 0 0 8 0 0 0 0 0 0 0" />
<weight single ="27 21 23 44 12 3 14 8 6 0"
multi =" 8 0 16 8 10 0 0 0 0 0" />
<weight single ="18 14 3 35 0 0 0 0 10 0"
multi ="24 0 25 65 6 0 0 0 0 0" />
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="110 40 320 25 300 30 175 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="140 155 240 110 170 20 135 0 0 0"
multi =" 0 0 30 0 0 0 0 0 0 0" />
<weight single ="150 125 210 145 145 15 120 50 0 0"
multi =" 0 0 40 0 0 0 0 0 0 0" />
<weight single ="135 105 115 220 60 15 70 40 30 0"
multi =" 40 0 80 40 50 0 0 0 0 0" />
<weight single =" 90 70 15 175 0 0 0 0 50 0"
multi ="120 0 125 325 30 0 0 0 0 0" />
</weights>
<weights num-karts="20">
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="20 0 74 0 66 4 36 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="27 32 48 20 37 3 27 0 0 0"
multi =" 0 0 6 0 0 0 0 0 0 0" />
<weight single ="30 24 40 30 28 2 21 10 0 0"
multi =" 0 0 10 0 5 0 0 0 0 0" />
<weight single ="25 18 20 50 10 2 10 6 3 0"
multi ="10 0 20 10 16 0 0 0 0 0" />
<weight single ="15 12 0 25 0 0 0 0 7 0"
multi ="30 0 31 80 0 0 0 0 0 0" />
<!-- bubble cake bowl zipper plunger switch swattr rubber para anvil -->
<weight single ="100 0 370 0 330 20 180 0 0 0"
multi =" 0 0 0 0 0 0 0 0 0 0" />
<weight single ="135 160 240 100 185 15 135 0 0 0"
multi =" 0 0 30 0 0 0 0 0 0 0" />
<weight single ="150 120 200 150 140 10 105 50 0 0"
multi =" 0 0 50 0 25 0 0 0 0 0" />
<weight single ="125 90 100 250 50 10 50 30 15 0"
multi =" 50 0 100 50 80 0 0 0 0 0" />
<weight single =" 75 60 0 125 0 0 0 0 35 0"
multi ="150 0 155 400 0 0 0 0 0 0" />
</weights>
</race-weight-list>

View File

@@ -4,6 +4,7 @@ in float hue_change;
in vec3 normal;
in vec3 tangent;
in vec2 uv;
in vec4 world_position;
layout(location = 0) out vec4 o_diffuse_color;
layout(location = 1) out vec4 o_normal_color;
@@ -12,9 +13,17 @@ layout(location = 1) out vec4 o_normal_color;
#stk_include "utils/rgb_conversion.frag"
#stk_include "utils/sp_texture_sampling.frag"
uniform sampler2D g_detail_map;
void main()
{
// Triplanar detail map
vec2 xyuv = vec2(world_position.x, world_position.y);
float detail = texture(g_detail_map, uv * 32.0).r;
detail *= 2.5;
vec4 col = sampleTextureLayer0(uv);
col = (col - detail) + 0.5;
if (hue_change > 0.0)
{
float mask = col.a;

View File

@@ -1,3 +1,5 @@
uniform sampler2D road_masking;
in vec3 bitangent;
in vec4 color;
in float hue_change;
@@ -21,6 +23,7 @@ void main()
vec4 col = multi_sampleTextureLayer0(uv, camdist);
float mask = sampleTextureLayer4(uuv * 2.0).r;
mask += sampleTextureLayer4(uuv * 0.5).r;
//* (1.0 - color.g)
mask = mix(1.0, mask, color.r);
@@ -36,16 +39,16 @@ void main()
mask_2 = pow(mask_2, 1.5);
mask_2 *= pow(mask_3, 0.5);
float skidding_marks = sampleTextureLayer5(uv * 10.0).g;
float skidding_marks = texture(road_masking, uv * 10.0).g;
skidding_marks *= mask_2;
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), skidding_marks);
float skidding_marks_2 = sampleTextureLayer5(uv * 15.0).g;
float skidding_marks_2 = texture(road_masking, uv * 15.0).g;
skidding_marks_2 *= mask_2;
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), skidding_marks_2);
// Add some cracks
float cracks_marks = sampleTextureLayer5(uv * 11.0).b;
float cracks_marks = texture(road_masking, uv * 11.0).b;
float crack_mask = sampleTextureLayer4(uuv * 0.5).r;
cracks_marks *= crack_mask;
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), cracks_marks);

View File

@@ -37,6 +37,8 @@ out vec3 normal;
out vec2 uv;
out vec2 uv_two;
out vec4 color;
out vec4 world_position;
out float camdist;
out float hue_change;
@@ -106,7 +108,7 @@ void main()
skinned_normal = joint_matrix * idle_normal;
skinned_tangent = joint_matrix * idle_tangent;
vec4 world_position = getWorldPosition(i_origin, i_rotation, i_scale.xyz,
vec4 v_world_position = getWorldPosition(i_origin, i_rotation, i_scale.xyz,
skinned_position.xyz);
vec3 world_normal = rotateVector(i_rotation, skinned_normal.xyz);
vec3 world_tangent = rotateVector(i_rotation, skinned_tangent.xyz);
@@ -123,7 +125,8 @@ void main()
uv_two = i_uv_two;
color = i_color.zyxw;
camdist = length(u_view_matrix * world_position);
camdist = length(u_view_matrix * v_world_position);
hue_change = float(i_misc_data.y) * 0.01;
gl_Position = u_projection_view_matrix * world_position;
gl_Position = u_projection_view_matrix * v_world_position;
world_position = v_world_position;
}

View File

@@ -3,6 +3,10 @@
<first-pass vertex-shader="sp_pass.vert"
fragment-shader="sp_normal_map.frag"
skinned-mesh-shader="sp_skinning.vert">
<prefilled-textures>
<prefilled-texture name="g_detail_map" file="gfx_detailmap_a.png"
srgb="Y" sampler="trilinear"/>
</prefilled-textures>
</first-pass>
<shadow-pass vertex-shader="sp_shadow.vert"
fragment-shader="white.frag"

View File

@@ -2,15 +2,8 @@
<shader-info name="roadBlending" fallback-shader="solid" use-tangents="Y"/>
<first-pass vertex-shader="sp_pass.vert"
fragment-shader="sp_road_blending.frag">
<prefilled-textures>
<prefilled-texture name="road_masking" file="hd_roadMarking_a_mask.png" srgb="Y" sampler="trilinear"/>
</prefilled-textures>
</first-pass>
<!--
<shadow-pass vertex-shader="sp_shadow.vert"
fragment-shader="white.frag"
skinned-mesh-shader="sp_skinning_shadow.vert">
</shadow-pass>
<uniform-assigners>
<uniform-assigner name="layer"
function="shadowCascadeUniformAssigner"/>
</uniform-assigners>
-->
</spshader>

View File

@@ -109,6 +109,29 @@ vec4 sampleTextureLayer4(vec2 uv)
return texture(tex_layer_4, uv);
}
vec4 multi_sampleTextureLayer4(vec2 uv, float distance)
{
vec4 l_col = sampleTextureLayer4(uv * LOW_SAMPLING);
vec4 m_col = sampleTextureLayer4(uv * MEDIUM_SAMPLING);
vec4 h_col = sampleTextureLayer4(uv * HIGH_SAMPLING);
// From Low to medium
float factor = distance * 0.02;
factor = pow(factor, 2.5);
factor = clamp(factor, 0.0, 1.0);
vec4 f_col = mix(m_col, l_col, factor);
// From medium to high
factor = distance * 0.1;
factor = pow(factor, 2.5);
factor = clamp(factor, 0.0, 1.0);
f_col = mix(h_col, f_col, factor);
return f_col;
}
vec4 sampleTextureLayer5(vec2 uv)
{
return texture(tex_layer_5, uv);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -346,9 +346,6 @@ endcopy:
// and the epilogue below, the stack unwind works as it should.
// TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
"pushl %%ebp \n"
#ifndef __ANDROID__
".cfi_startproc \n"
#endif
".cfi_adjust_cfa_offset 4 \n"
".cfi_rel_offset ebp, 0 \n"
"movl %%esp, %%ebp \n"
@@ -395,9 +392,6 @@ endcopy:
"popl %%ebp \n"
".cfi_adjust_cfa_offset -4 \n"
".cfi_restore ebp \n"
#ifndef __ANDROID__
".cfi_endproc \n"
#endif
#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
@@ -474,9 +468,6 @@ endcopy:
// and the epilogue below, the stack unwind works as it should.
// TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
"pushl %%ebp \n"
#ifndef __ANDROID__
".cfi_startproc \n"
#endif
".cfi_adjust_cfa_offset 4 \n"
".cfi_rel_offset ebp, 0 \n"
"movl %%esp, %%ebp \n"
@@ -524,9 +515,6 @@ endcopy:
"popl %%ebp \n"
".cfi_adjust_cfa_offset -4 \n"
".cfi_restore ebp \n"
#ifndef __ANDROID__
".cfi_endproc \n"
#endif
#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
@@ -603,9 +591,6 @@ endcopy:
// and the epilogue below, the stack unwind works as it should.
// TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
"pushl %%ebp \n"
#ifndef __ANDROID__
".cfi_startproc \n"
#endif
".cfi_adjust_cfa_offset 4 \n"
".cfi_rel_offset ebp, 0 \n"
"movl %%esp, %%ebp \n"
@@ -653,9 +638,6 @@ endcopy:
"popl %%ebp \n"
".cfi_adjust_cfa_offset -4 \n"
".cfi_restore ebp \n"
#ifndef __ANDROID__
".cfi_endproc \n"
#endif
#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
@@ -741,9 +723,6 @@ endcopy:
// and the epilogue below, the stack unwind works as it should.
// TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
"pushl %%ebp \n"
#ifndef __ANDROID__
".cfi_startproc \n"
#endif
".cfi_adjust_cfa_offset 4 \n"
".cfi_rel_offset ebp, 0 \n"
"movl %%esp, %%ebp \n"
@@ -795,9 +774,6 @@ endcopy:
"popl %%ebp \n"
".cfi_adjust_cfa_offset -4 \n"
".cfi_restore ebp \n"
#ifndef __ANDROID__
".cfi_endproc \n"
#endif
#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
@@ -879,9 +855,6 @@ endcopy:
// and the epilogue below, the stack unwind works as it should.
// TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
"pushl %%ebp \n"
#ifndef __ANDROID__
".cfi_startproc \n"
#endif
".cfi_adjust_cfa_offset 4 \n"
".cfi_rel_offset ebp, 0 \n"
"movl %%esp, %%ebp \n"
@@ -930,9 +903,6 @@ endcopy:
"popl %%ebp \n"
".cfi_adjust_cfa_offset -4 \n"
".cfi_restore ebp \n"
#ifndef __ANDROID__
".cfi_endproc \n"
#endif
#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
@@ -1016,9 +986,6 @@ endcopy:
// and the epilogue below, the stack unwind works as it should.
// TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
"pushl %%ebp \n"
#ifndef __ANDROID__
".cfi_startproc \n"
#endif
".cfi_adjust_cfa_offset 4 \n"
".cfi_rel_offset ebp, 0 \n"
"movl %%esp, %%ebp \n"
@@ -1070,9 +1037,6 @@ endcopy:
"popl %%ebp \n"
".cfi_adjust_cfa_offset -4 \n"
".cfi_restore ebp \n"
#ifndef __ANDROID__
".cfi_endproc \n"
#endif
#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
@@ -1144,9 +1108,6 @@ endcopy:
// and the epilogue below, the stack unwind works as it should.
// TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
"pushl %%ebp \n"
#ifndef __ANDROID__
".cfi_startproc \n"
#endif
".cfi_adjust_cfa_offset 4 \n"
".cfi_rel_offset ebp, 0 \n"
"movl %%esp, %%ebp \n"
@@ -1191,9 +1152,6 @@ endcopy:
"popl %%ebp \n"
".cfi_adjust_cfa_offset -4 \n"
".cfi_restore ebp \n"
#ifndef __ANDROID__
".cfi_endproc \n"
#endif
#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
@@ -1281,9 +1239,6 @@ endcopy:
// and the epilogue below, the stack unwind works as it should.
// TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
"pushl %%ebp \n"
#ifndef __ANDROID__
".cfi_startproc \n"
#endif
".cfi_adjust_cfa_offset 4 \n"
".cfi_rel_offset ebp, 0 \n"
"movl %%esp, %%ebp \n"
@@ -1337,9 +1292,6 @@ endcopy:
"popl %%ebp \n"
".cfi_adjust_cfa_offset -4 \n"
".cfi_restore ebp \n"
#ifndef __ANDROID__
".cfi_endproc \n"
#endif
#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable
@@ -1434,9 +1386,6 @@ endcopy:
// and the epilogue below, the stack unwind works as it should.
// TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
"pushl %%ebp \n"
#ifndef __ANDROID__
".cfi_startproc \n"
#endif
".cfi_adjust_cfa_offset 4 \n"
".cfi_rel_offset ebp, 0 \n"
"movl %%esp, %%ebp \n"
@@ -1503,9 +1452,6 @@ endcopy:
"popl %%ebp \n"
".cfi_adjust_cfa_offset -4 \n"
".cfi_restore ebp \n"
#ifndef __ANDROID__
".cfi_endproc \n"
#endif
#endif
// Copy EAX:EDX to retQW. As the stack pointer has been
// restored it is now safe to access the local variable

View File

@@ -66,6 +66,10 @@ namespace scene
indices have changed. Otherwise, changes won't be updated
on the GPU in the next render cycle. */
virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) = 0;
/** This is used in server without graphics to free all mesh vertex buffer if
possible, for example: kart, attachment and power model (because they are not used in physics). */
virtual void freeMeshVertexBuffer() {}
};
} // end namespace scene

View File

@@ -33,6 +33,8 @@ bool CIrrDeviceAndroid::IsPaused = true;
bool CIrrDeviceAndroid::IsFocused = false;
bool CIrrDeviceAndroid::IsStarted = false;
AndroidApplicationInfo CIrrDeviceAndroid::ApplicationInfo;
// Execution of android_main() function is a kind of "onCreate" event, so this
// function should be used there to make sure that global window state variables
// have their default values on startup.
@@ -50,6 +52,7 @@ CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param)
Gyroscope(0),
AccelerometerActive(false),
GyroscopeActive(false),
TextInputEnabled(false),
IsMousePressed(false),
GamepadAxisX(0),
GamepadAxisY(0),
@@ -58,68 +61,82 @@ CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param)
#ifdef _DEBUG
setDebugName("CIrrDeviceAndroid");
#endif
Android = (android_app *)(param.PrivateData);
assert(Android != NULL);
Android->userData = this;
Android->onAppCmd = handleAndroidCommand;
Android->onAppCmdDirect = handleAndroidCommandDirect;
Android->onInputEvent = handleInput;
printConfig();
createKeyMap();
CursorControl = new CCursorControl();
Android = (android_app*)(param.PrivateData);
Close = Android->destroyRequested;
// It typically shouldn't happen, but just in case...
if (Close)
return;
SensorManager = ASensorManager_getInstance();
SensorEventQueue = ASensorManager_createEventQueue(SensorManager,
Android->looper, LOOPER_ID_USER, NULL, NULL);
ANativeActivity_setWindowFlags(Android->activity,
AWINDOW_FLAG_KEEP_SCREEN_ON |
AWINDOW_FLAG_FULLSCREEN, 0);
os::Printer::log("Waiting for Android activity window to be created.", ELL_DEBUG);
while (!IsStarted || !IsFocused || IsPaused)
if (Android == NULL && CreationParams.DriverType != video::EDT_NULL)
{
s32 events = 0;
android_poll_source* source = 0;
s32 id = ALooper_pollAll(-1, NULL, &events, (void**)&source);
if (id >=0 && source != NULL)
{
source->process(Android, source);
}
os::Printer::log("Irrlicht device can run only with NULL driver without android_app.", ELL_DEBUG);
return;
}
assert(Android->window);
os::Printer::log("Done", ELL_DEBUG);
ExposedVideoData.OGLESAndroid.Window = Android->window;
createVideoModeList();
if (Android != NULL)
{
Android->userData = this;
Android->onAppCmd = handleAndroidCommand;
Android->onAppCmdDirect = handleAndroidCommandDirect;
Android->onInputEvent = handleInput;
printConfig();
Close = Android->destroyRequested;
// It typically shouldn't happen, but just in case...
if (Close)
return;
SensorManager = ASensorManager_getInstance();
SensorEventQueue = ASensorManager_createEventQueue(SensorManager,
Android->looper, LOOPER_ID_USER, NULL, NULL);
ANativeActivity_setWindowFlags(Android->activity,
AWINDOW_FLAG_KEEP_SCREEN_ON |
AWINDOW_FLAG_FULLSCREEN, 0);
os::Printer::log("Waiting for Android activity window to be created.", ELL_DEBUG);
while (!IsStarted || !IsFocused || IsPaused)
{
s32 events = 0;
android_poll_source* source = 0;
s32 id = ALooper_pollAll(-1, NULL, &events, (void**)&source);
if (id >=0 && source != NULL)
{
source->process(Android, source);
}
}
assert(Android->window);
os::Printer::log("Done", ELL_DEBUG);
ExposedVideoData.OGLESAndroid.Window = Android->window;
createVideoModeList();
}
createDriver();
if (VideoDriver)
{
createGUIAndScene();
}
}
CIrrDeviceAndroid::~CIrrDeviceAndroid()
{
Android->userData = NULL;
Android->onAppCmd = NULL;
Android->onInputEvent = NULL;
if (Android)
{
Android->userData = NULL;
Android->onAppCmd = NULL;
Android->onInputEvent = NULL;
}
}
void CIrrDeviceAndroid::printConfig()
@@ -211,6 +228,9 @@ bool CIrrDeviceAndroid::run()
{
os::Timer::tick();
if (Android == NULL)
return !Close;
while (!Close)
{
s32 Events = 0;
@@ -372,8 +392,8 @@ void CIrrDeviceAndroid::handleAndroidCommandDirect(ANativeActivity* activity,
switch (cmd)
{
case APP_CMD_RESUME:
os::Printer::log("Android command direct APP_CMD_RESUME", ELL_DEBUG);
hideNavBar(activity);
os::Printer::log("Android command direct APP_CMD_RESUME", ELL_DEBUG);
hideNavBar(activity);
break;
default:
break;
@@ -684,14 +704,22 @@ s32 CIrrDeviceAndroid::handleKeyboard(AInputEvent* androidEvent)
if (event.KeyInput.Key > 0)
{
getKeyChar(event);
if (TextInputEnabled == true)
{
event.KeyInput.Char = getUnicodeChar(androidEvent);
}
if (event.KeyInput.Char == 0)
{
event.KeyInput.Char = getKeyChar(event);
}
}
// If button doesn't return key code, then at least use device-specific
// scan code, because it's better than nothing
if (event.KeyInput.Key == 0)
{
event.KeyInput.Key = (EKEY_CODE)scanCode;
event.KeyInput.Key = (EKEY_CODE)((int)IRR_KEY_CODES_COUNT + scanCode);
}
// Handle an event when back button in pressed just like an escape key
@@ -842,7 +870,7 @@ s32 CIrrDeviceAndroid::handleGamepad(AInputEvent* androidEvent)
if (event.KeyInput.Key == 0)
{
event.KeyInput.Key = (EKEY_CODE)scanCode;
event.KeyInput.Key = (EKEY_CODE)((int)IRR_KEY_CODES_COUNT + scanCode);
}
postEventFromUser(event);
@@ -935,14 +963,14 @@ void CIrrDeviceAndroid::createKeyMap()
KeyMap[AKEYCODE_DEL] = IRR_KEY_BACK;
KeyMap[AKEYCODE_GRAVE] = IRR_KEY_OEM_3;
KeyMap[AKEYCODE_MINUS] = IRR_KEY_MINUS;
KeyMap[AKEYCODE_EQUALS] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_LEFT_BRACKET] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_RIGHT_BRACKET] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BACKSLASH] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_SEMICOLON] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_APOSTROPHE] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_SLASH] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_AT] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_EQUALS] = IRR_KEY_PLUS;
KeyMap[AKEYCODE_LEFT_BRACKET] = IRR_KEY_OEM_4;
KeyMap[AKEYCODE_RIGHT_BRACKET] = IRR_KEY_OEM_6;
KeyMap[AKEYCODE_BACKSLASH] = IRR_KEY_OEM_5;
KeyMap[AKEYCODE_SEMICOLON] = IRR_KEY_OEM_1;
KeyMap[AKEYCODE_APOSTROPHE] = IRR_KEY_OEM_7;
KeyMap[AKEYCODE_SLASH] = IRR_KEY_OEM_2;
KeyMap[AKEYCODE_AT] = IRR_KEY_2;
KeyMap[AKEYCODE_NUM] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_HEADSETHOOK] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_FOCUS] = IRR_KEY_UNKNOWN;
@@ -985,8 +1013,8 @@ void CIrrDeviceAndroid::createKeyMap()
KeyMap[AKEYCODE_CTRL_RIGHT] = IRR_KEY_CONTROL;
KeyMap[AKEYCODE_CAPS_LOCK] = IRR_KEY_CAPITAL;
KeyMap[AKEYCODE_SCROLL_LOCK] = IRR_KEY_SCROLL;
KeyMap[AKEYCODE_META_LEFT] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_META_RIGHT] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_META_LEFT] = IRR_KEY_LWIN;
KeyMap[AKEYCODE_META_RIGHT] = IRR_KEY_RWIN;
KeyMap[AKEYCODE_FUNCTION] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_SYSRQ] = IRR_KEY_SNAPSHOT;
KeyMap[AKEYCODE_BREAK] = IRR_KEY_PAUSE;
@@ -1093,59 +1121,118 @@ void CIrrDeviceAndroid::createKeyMap()
KeyMap[AKEYCODE_MEDIA_AUDIO_TRACK] = IRR_KEY_UNKNOWN;
}
void CIrrDeviceAndroid::getKeyChar(SEvent& event)
wchar_t CIrrDeviceAndroid::getKeyChar(SEvent& event)
{
// Handle ASCII chars
event.KeyInput.Char = 0;
wchar_t key_char = 0;
// A-Z
if (event.KeyInput.SystemKeyCode > 28 && event.KeyInput.SystemKeyCode < 55)
{
if (event.KeyInput.Shift)
{
event.KeyInput.Char = event.KeyInput.SystemKeyCode + 36;
key_char = event.KeyInput.SystemKeyCode + 36;
}
else
{
event.KeyInput.Char = event.KeyInput.SystemKeyCode + 68;
key_char = event.KeyInput.SystemKeyCode + 68;
}
}
// 0-9
else if (event.KeyInput.SystemKeyCode > 6 && event.KeyInput.SystemKeyCode < 17)
{
event.KeyInput.Char = event.KeyInput.SystemKeyCode + 41;
key_char = event.KeyInput.SystemKeyCode + 41;
}
else if (event.KeyInput.SystemKeyCode == AKEYCODE_BACK)
{
event.KeyInput.Char = 8;
key_char = 8;
}
else if (event.KeyInput.SystemKeyCode == AKEYCODE_DEL)
{
event.KeyInput.Char = 8;
key_char = 8;
}
else if (event.KeyInput.SystemKeyCode == AKEYCODE_TAB)
{
event.KeyInput.Char = 9;
key_char = 9;
}
else if (event.KeyInput.SystemKeyCode == AKEYCODE_ENTER)
{
event.KeyInput.Char = 13;
key_char = 13;
}
else if (event.KeyInput.SystemKeyCode == AKEYCODE_SPACE)
{
event.KeyInput.Char = 32;
key_char = 32;
}
else if (event.KeyInput.SystemKeyCode == AKEYCODE_COMMA)
{
event.KeyInput.Char = 44;
key_char = 44;
}
else if (event.KeyInput.SystemKeyCode == AKEYCODE_PERIOD)
{
event.KeyInput.Char = 46;
key_char = 46;
}
return key_char;
}
wchar_t CIrrDeviceAndroid::getUnicodeChar(AInputEvent* event)
{
bool was_detached = false;
JNIEnv* env = NULL;
jint status = Android->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (status == JNI_EDETACHED)
{
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6;
args.name = "NativeThread";
args.group = NULL;
status = Android->activity->vm->AttachCurrentThread(&env, &args);
was_detached = true;
}
if (status != JNI_OK)
{
os::Printer::log("Cannot get unicode character.", ELL_DEBUG);
return 0;
}
jlong down_time = AKeyEvent_getDownTime(event);
jlong event_time = AKeyEvent_getEventTime(event);
jint action = AKeyEvent_getAction(event);
jint code = AKeyEvent_getKeyCode(event);
jint repeat = AKeyEvent_getRepeatCount(event);
jint meta_state = AKeyEvent_getMetaState(event);
jint device_id = AInputEvent_getDeviceId(event);
jint scan_code = AKeyEvent_getScanCode(event);
jint flags = AKeyEvent_getFlags(event);
jint source = AInputEvent_getSource(event);
jclass key_event = env->FindClass("android/view/KeyEvent");
jmethodID key_event_constructor = env->GetMethodID(key_event, "<init>",
"(JJIIIIIIII)V");
jobject key_event_obj = env->NewObject(key_event, key_event_constructor,
down_time, event_time, action, code,
repeat, meta_state, device_id,
scan_code, flags, source);
jmethodID get_unicode = env->GetMethodID(key_event, "getUnicodeChar", "(I)I");
wchar_t unicode_char = env->CallIntMethod(key_event_obj, get_unicode,
meta_state);
if (was_detached)
{
Android->activity->vm->DetachCurrentThread();
}
return unicode_char;
}
void CIrrDeviceAndroid::hideNavBar(ANativeActivity* activity)
@@ -1288,6 +1375,120 @@ int CIrrDeviceAndroid::getRotation()
return rotation;
}
void CIrrDeviceAndroid::readApplicationInfo(ANativeActivity* activity)
{
bool was_detached = false;
JNIEnv* env = NULL;
jint status = activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (status == JNI_EDETACHED)
{
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6;
args.name = "NativeThread";
args.group = NULL;
status = activity->vm->AttachCurrentThread(&env, &args);
was_detached = true;
}
if (status != JNI_OK)
{
os::Printer::log("Cannot get application info.", ELL_DEBUG);
return;
}
jobject activity_obj = activity->clazz;
jclass activity_class = env->GetObjectClass(activity_obj);
jmethodID get_package_manager = env->GetMethodID(activity_class,
"getPackageManager",
"()Landroid/content/pm/PackageManager;");
jobject package_manager_obj = env->CallObjectMethod(activity_obj,
get_package_manager);
jmethodID get_intent = env->GetMethodID(activity_class, "getIntent",
"()Landroid/content/Intent;");
jobject intent_obj = env->CallObjectMethod(activity_obj, get_intent);
jclass intent = env->FindClass("android/content/Intent");
jmethodID get_component = env->GetMethodID(intent, "getComponent",
"()Landroid/content/ComponentName;");
jobject component_name = env->CallObjectMethod(intent_obj, get_component);
jclass package_manager = env->FindClass("android/content/pm/PackageManager");
jfieldID get_meta_data_field = env->GetStaticFieldID(package_manager,
"GET_META_DATA", "I");
jint get_meta_data = env->GetStaticIntField(package_manager,
get_meta_data_field);
jmethodID get_activity_info = env->GetMethodID(package_manager,
"getActivityInfo",
"(Landroid/content/ComponentName;I)"
"Landroid/content/pm/ActivityInfo;");
jobject activity_info_obj = env->CallObjectMethod(package_manager_obj,
get_activity_info,
component_name,
get_meta_data);
jclass activity_info = env->FindClass("android/content/pm/ActivityInfo");
jfieldID application_info_field = env->GetFieldID(activity_info,
"applicationInfo",
"Landroid/content/pm/ApplicationInfo;");
jobject application_info_obj = env->GetObjectField(activity_info_obj,
application_info_field);
jclass application_info = env->FindClass("android/content/pm/ApplicationInfo");
jfieldID native_library_dir_field = env->GetFieldID(application_info,
"nativeLibraryDir",
"Ljava/lang/String;");
jstring native_library_dir_str = (jstring)env->GetObjectField(
application_info_obj,
native_library_dir_field);
const char* native_library_dir = env->GetStringUTFChars(
native_library_dir_str,
NULL);
jfieldID data_dir_field = env->GetFieldID(application_info, "dataDir",
"Ljava/lang/String;");
jstring data_dir_str = (jstring)env->GetObjectField(application_info_obj,
data_dir_field);
const char* data_dir = env->GetStringUTFChars(data_dir_str, NULL);
if (native_library_dir != NULL)
{
ApplicationInfo.native_lib_dir = native_library_dir;
}
if (data_dir != NULL)
{
ApplicationInfo.data_dir = data_dir;
}
ApplicationInfo.initialized = true;
if (was_detached)
{
activity->vm->DetachCurrentThread();
}
}
const AndroidApplicationInfo& CIrrDeviceAndroid::getApplicationInfo(
ANativeActivity* activity)
{
if (activity != NULL && ApplicationInfo.initialized == false)
{
readApplicationInfo(activity);
}
return ApplicationInfo;
}
DeviceOrientation CIrrDeviceAndroid::getDefaultOrientation()
{
int rotation = getRotation();

View File

@@ -30,6 +30,15 @@ namespace irr
ORIENTATION_LANDSCAPE
};
struct AndroidApplicationInfo
{
std::string native_lib_dir;
std::string data_dir;
bool initialized;
AndroidApplicationInfo() : initialized(false) {};
};
class CIrrDeviceAndroid : public CIrrDeviceStub, video::IImagePresenter
{
public:
@@ -64,6 +73,7 @@ namespace irr
virtual bool deactivateGyroscope();
virtual bool isGyroscopeActive();
virtual bool isGyroscopeAvailable();
virtual void setTextInputEnabled(bool enabled) {TextInputEnabled = enabled;}
class CCursorControl : public gui::ICursorControl
{
@@ -104,6 +114,8 @@ namespace irr
};
static void onCreate();
static const AndroidApplicationInfo& getApplicationInfo(
ANativeActivity* activity);
private:
android_app* Android;
@@ -113,6 +125,8 @@ namespace irr
const ASensor* Gyroscope;
bool AccelerometerActive;
bool GyroscopeActive;
bool TextInputEnabled;
static AndroidApplicationInfo ApplicationInfo;
static bool IsPaused;
static bool IsFocused;
@@ -141,8 +155,10 @@ namespace irr
void createDriver();
void createKeyMap();
void createVideoModeList();
void getKeyChar(SEvent& event);
wchar_t getKeyChar(SEvent& event);
wchar_t getUnicodeChar(AInputEvent* event);
static void hideNavBar(ANativeActivity* activity);
static void readApplicationInfo(ANativeActivity* activity);
int getRotation();
DeviceOrientation getDefaultOrientation();
video::SExposedVideoData& getExposedVideoData();

View File

@@ -2179,6 +2179,8 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()
XRRScreenResources* res = XRRGetScreenResources(display, DefaultRootWindow(display));
if (!res)
break;
const char* output_name = getenv("IRR_VIDEO_OUTPUT");
RROutput primary_id = XRRGetOutputPrimary(display, DefaultRootWindow(display));
@@ -2198,8 +2200,18 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()
continue;
}
if (res->outputs[i] == primary_id ||
output_id == 0 || crtc_tmp->x < crtc->x ||
bool is_primary = false;
if (output_name != NULL)
{
is_primary = (strcmp(output_name, output_tmp->name) == 0);
}
else
{
is_primary = (res->outputs[i] == primary_id);
}
if (is_primary || output_id == 0 || crtc_tmp->x < crtc->x ||
(crtc_tmp->x == crtc->x && crtc_tmp->y < crtc->y))
{
XRRFreeCrtcInfo(crtc);
@@ -2215,7 +2227,7 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()
XRRFreeOutputInfo(output_tmp);
}
if (res->outputs[i] == primary_id)
if (is_primary)
break;
}

View File

@@ -23,7 +23,7 @@ CSkinnedMesh::CSkinnedMesh()
LastAnimatedFrame(-1), SkinnedLastFrame(false),
InterpolationMode(EIM_LINEAR),
HasAnimation(false), PreparedForSkinning(false),
AnimateNormals(true), HardwareSkinning(false)
AnimateNormals(true), m_deleted_vertex_buffer(false)
{
#ifdef _DEBUG
setDebugName("CSkinnedMesh");
@@ -74,12 +74,8 @@ void CSkinnedMesh::setAnimationSpeed(f32 fps)
//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
{
const bool is_hw_skinning_before = HardwareSkinning;
if (is_hw_skinning_before)
{
HardwareSkinning = false;
LastAnimatedFrame = -1;
}
if (m_deleted_vertex_buffer)
return this;
//animate(frame,startFrameLoop, endFrameLoop);
if (frame==-1)
return this;
@@ -87,9 +83,6 @@ IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32
animateMesh((f32)frame, 1.0f);
skinMesh();
if (is_hw_skinning_before)
HardwareSkinning = true;
return this;
}
@@ -103,7 +96,7 @@ IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32
//! blend: {0-old position, 1-New position}
void CSkinnedMesh::animateMesh(f32 frame, f32 blend)
{
if (HardwareSkinning && LastAnimatedFrame==frame)
if (LastAnimatedFrame==frame)
{
SkinnedLastFrame=false;
return;
@@ -732,20 +725,6 @@ const core::array<CSkinnedMesh::SJoint*> &CSkinnedMesh::getAllJoints() const
return AllJoints;
}
//! (This feature is not implementated in irrlicht yet)
bool CSkinnedMesh::setHardwareSkinning(bool on)
{
if (HardwareSkinning!=on)
{
if (on)
toStaticPose();
HardwareSkinning=on;
}
return HardwareSkinning;
}
void CSkinnedMesh::toStaticPose()
{
for (u32 i=0; i<AllJoints.size(); ++i)
@@ -1154,7 +1133,7 @@ void CSkinnedMesh::finalize()
void CSkinnedMesh::updateBoundingBox(void)
{
if(HardwareSkinning || !SkinningBuffers)
if (!SkinningBuffers)
return;
core::array<SSkinMeshBuffer*> & buffer = *SkinningBuffers;
@@ -1397,6 +1376,27 @@ void CSkinnedMesh::addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes,
SkinnedLastFrame=false;
}
void CSkinnedMesh::freeMeshVertexBuffer()
{
if (m_deleted_vertex_buffer)
return;
for (u32 i=0; i<AllJoints.size(); ++i)
delete AllJoints[i];
for (u32 j=0; j<LocalBuffers.size(); ++j)
{
if (LocalBuffers[j])
{
LocalBuffers[j]->Vertices_Tangents.clear();
LocalBuffers[j]->Vertices_2TCoords.clear();
LocalBuffers[j]->Vertices_Standard.clear();
LocalBuffers[j]->Indices.clear();
}
}
AllJoints.clear();
m_deleted_vertex_buffer = true;
}
} // end namespace scene
} // end namespace irr

View File

@@ -117,7 +117,7 @@ namespace scene
virtual bool isStatic();
//! (This feature is not implemented in irrlicht yet)
virtual bool setHardwareSkinning(bool on);
virtual bool setHardwareSkinning(bool on) { return false; }
//Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_
//these functions will use the needed arrays, set values, etc to help the loaders
@@ -176,6 +176,8 @@ namespace scene
core::array<SJoint*> RootJoints;
virtual void freeMeshVertexBuffer();
private:
void toStaticPose();
@@ -222,7 +224,7 @@ private:
bool HasAnimation;
bool PreparedForSkinning;
bool AnimateNormals;
bool HardwareSkinning;
bool m_deleted_vertex_buffer;
};
} // end namespace scene

View File

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

View File

@@ -23,6 +23,7 @@
#include "audio/music_dummy.hpp"
#include "audio/music_ogg.hpp"
#include "config/user_config.hpp"
#include "io/file_manager.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
@@ -170,10 +171,15 @@ void MusicInformation::startMusic()
}
#ifdef ENABLE_SOUND
m_normal_music = new MusicOggStream(m_normal_loop_start);
#else
m_normal_music = new MusicDummy();
if (UserConfigParams::m_enable_sound)
{
m_normal_music = new MusicOggStream(m_normal_loop_start);
}
else
#endif
{
m_normal_music = new MusicDummy();
}
if (m_normal_music->load(m_normal_filename) == false)
{
@@ -201,10 +207,15 @@ void MusicInformation::startMusic()
}
#ifdef ENABLE_SOUND
m_fast_music = new MusicOggStream(m_fast_loop_start);
#else
m_fast_music = new MusicDummy();
if (UserConfigParams::m_enable_sound)
{
m_fast_music = new MusicOggStream(m_fast_loop_start);
}
else
#endif
{
m_fast_music = new MusicDummy();
}
if (m_fast_music->load(m_fast_filename) == false)
{

View File

@@ -50,43 +50,44 @@ MusicManager::MusicManager()
//FIXME: I'm not sure that this code goes here
#ifdef ENABLE_SOUND
if (UserConfigParams::m_enable_sound)
{
#if defined(__APPLE__) && !defined(NDEBUG)
// HACK: On OSX, when OpenAL is initialized, breaking in a debugger causes
// my iTunes music to stop too, which is highly annoying ;) so in debug
// mode, require a restart to enable sound
if (UserConfigParams::m_sfx || UserConfigParams::m_music)
{
// HACK: On OSX, when OpenAL is initialized, breaking in a debugger
// causes my iTunes music to stop too, which is highly annoying ;) so in
// debug mode, require a restart to enable sound
if (UserConfigParams::m_sfx || UserConfigParams::m_music)
{
#endif
ALCdevice* device = alcOpenDevice ( NULL ); //The default sound device
if( device == NULL )
{
Log::warn("MusicManager", "Could not open the default sound device.");
m_initialized = false;
}
else
{
ALCcontext* context = alcCreateContext( device, NULL );
if( context == NULL )
{
Log::warn("MusicManager", "Could not create a sound context.");
m_initialized = false;
}
else
{
alcMakeContextCurrent( context );
m_initialized = true;
}
}
ALCdevice* device = alcOpenDevice(NULL); //The default sound device
if (device == NULL)
{
Log::warn("MusicManager", "Could not open the default sound "
"device.");
m_initialized = false;
}
else
{
ALCcontext* context = alcCreateContext(device, NULL);
if (context == NULL)
{
Log::warn("MusicManager", "Could not create a sound "
"context.");
m_initialized = false;
}
else
{
alcMakeContextCurrent(context);
m_initialized = true;
}
}
#if defined(__APPLE__) && !defined(NDEBUG)
}
}
#endif
alGetError(); //Called here to clear any non-important errors found
alGetError(); //Called here to clear any non-important errors found
}
#endif
loadMusicInformation();

View File

@@ -97,24 +97,27 @@ bool SFXBuffer::load()
if (UserConfigParams::m_sfx == false) return false;
#ifdef ENABLE_SOUND
if (m_loaded) return false;
alGetError(); // clear errors from previously
alGenBuffers(1, &m_buffer);
if (!SFXManager::checkError("generating a buffer"))
if (UserConfigParams::m_enable_sound)
{
return false;
}
assert( alIsBuffer(m_buffer) );
if (!loadVorbisBuffer(m_file, m_buffer))
{
Log::error("SFXBuffer", "Could not load sound effect %s",
m_file.c_str());
// TODO: free al buffer here?
return false;
if (m_loaded) return false;
alGetError(); // clear errors from previously
alGenBuffers(1, &m_buffer);
if (!SFXManager::checkError("generating a buffer"))
{
return false;
}
assert(alIsBuffer(m_buffer));
if (!loadVorbisBuffer(m_file, m_buffer))
{
Log::error("SFXBuffer", "Could not load sound effect %s",
m_file.c_str());
// TODO: free al buffer here?
return false;
}
}
#endif
@@ -131,10 +134,13 @@ bool SFXBuffer::load()
void SFXBuffer::unload()
{
#ifdef ENABLE_SOUND
if (m_loaded)
if (UserConfigParams::m_enable_sound)
{
alDeleteBuffers(1, &m_buffer);
m_buffer = 0;
if (m_loaded)
{
alDeleteBuffers(1, &m_buffer);
m_buffer = 0;
}
}
#endif
m_loaded = false;
@@ -148,6 +154,9 @@ void SFXBuffer::unload()
bool SFXBuffer::loadVorbisBuffer(const std::string &name, ALuint buffer)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return false;
const int ogg_endianness = (IS_LITTLE_ENDIAN ? 0 : 1);

View File

@@ -98,32 +98,35 @@ SFXManager::SFXManager()
loadSfx();
#ifdef ENABLE_SOUND
pthread_cond_init(&m_cond_request, NULL);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
m_thread_id.setAtomic(new pthread_t());
// The thread is created even if there atm sfx are disabled
// (since the user might enable it later).
int error = pthread_create(m_thread_id.getData(), &attr,
&SFXManager::mainLoop, this);
if (error)
if (UserConfigParams::m_enable_sound)
{
m_thread_id.lock();
delete m_thread_id.getData();
m_thread_id.unlock();
m_thread_id.setAtomic(0);
Log::error("SFXManager", "Could not create thread, error=%d.",
errno);
pthread_cond_init(&m_cond_request, NULL);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
m_thread_id.setAtomic(new pthread_t());
// The thread is created even if there atm sfx are disabled
// (since the user might enable it later).
int error = pthread_create(m_thread_id.getData(), &attr,
&SFXManager::mainLoop, this);
if (error)
{
m_thread_id.lock();
delete m_thread_id.getData();
m_thread_id.unlock();
m_thread_id.setAtomic(0);
Log::error("SFXManager", "Could not create thread, error=%d.",
errno);
}
pthread_attr_destroy(&attr);
setMasterSFXVolume( UserConfigParams::m_sfx_volume );
m_sfx_commands.lock();
m_sfx_commands.getData().clear();
m_sfx_commands.unlock();
}
pthread_attr_destroy(&attr);
setMasterSFXVolume( UserConfigParams::m_sfx_volume );
m_sfx_commands.lock();
m_sfx_commands.getData().clear();
m_sfx_commands.unlock();
#endif
} // SoundManager
@@ -133,11 +136,14 @@ SFXManager::SFXManager()
SFXManager::~SFXManager()
{
#ifdef ENABLE_SOUND
m_thread_id.lock();
pthread_join(*m_thread_id.getData(), NULL);
delete m_thread_id.getData();
m_thread_id.unlock();
pthread_cond_destroy(&m_cond_request);
if (UserConfigParams::m_enable_sound)
{
m_thread_id.lock();
pthread_join(*m_thread_id.getData(), NULL);
delete m_thread_id.getData();
m_thread_id.unlock();
pthread_cond_destroy(&m_cond_request);
}
#endif
// ---- clear m_all_sfx
@@ -189,6 +195,9 @@ SFXManager::~SFXManager()
void SFXManager::queue(SFXCommands command, SFXBase *sfx)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
SFXCommand *sfx_command = new SFXCommand(command, sfx);
queueCommand(sfx_command);
#endif
@@ -205,6 +214,9 @@ void SFXManager::queue(SFXCommands command, SFXBase *sfx)
void SFXManager::queue(SFXCommands command, SFXBase *sfx, float f)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
SFXCommand *sfx_command = new SFXCommand(command, sfx, f);
queueCommand(sfx_command);
#endif
@@ -221,8 +233,11 @@ void SFXManager::queue(SFXCommands command, SFXBase *sfx, float f)
void SFXManager::queue(SFXCommands command, SFXBase *sfx, const Vec3 &p)
{
#ifdef ENABLE_SOUND
SFXCommand *sfx_command = new SFXCommand(command, sfx, p);
queueCommand(sfx_command);
if (!UserConfigParams::m_enable_sound)
return;
SFXCommand *sfx_command = new SFXCommand(command, sfx, p);
queueCommand(sfx_command);
#endif
} // queue (Vec3)
@@ -231,6 +246,9 @@ void SFXManager::queue(SFXCommands command, SFXBase *sfx, const Vec3 &p)
void SFXManager::queue(SFXCommands command, SFXBase *sfx, const Vec3 &p, SFXBuffer* buffer)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
SFXCommand *sfx_command = new SFXCommand(command, sfx, p);
sfx_command->m_buffer = buffer;
queueCommand(sfx_command);
@@ -250,6 +268,9 @@ void SFXManager::queue(SFXCommands command, SFXBase *sfx, float f,
const Vec3 &p)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
SFXCommand *sfx_command = new SFXCommand(command, sfx, f, p);
queueCommand(sfx_command);
#endif
@@ -262,6 +283,9 @@ void SFXManager::queue(SFXCommands command, SFXBase *sfx, float f,
void SFXManager::queue(SFXCommands command, MusicInformation *mi)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
SFXCommand *sfx_command = new SFXCommand(command, mi);
queueCommand(sfx_command);
#endif
@@ -275,6 +299,9 @@ void SFXManager::queue(SFXCommands command, MusicInformation *mi)
void SFXManager::queue(SFXCommands command, MusicInformation *mi, float f)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
SFXCommand *sfx_command = new SFXCommand(command, mi, f);
queueCommand(sfx_command);
#endif
@@ -288,6 +315,9 @@ void SFXManager::queue(SFXCommands command, MusicInformation *mi, float f)
void SFXManager::queueCommand(SFXCommand *command)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
m_sfx_commands.lock();
if(World::getWorld() &&
m_sfx_commands.getData().size() > 20*race_manager->getNumberOfKarts()+20 &&
@@ -321,12 +351,17 @@ void SFXManager::queueCommand(SFXCommand *command)
void SFXManager::stopThread()
{
#ifdef ENABLE_SOUND
queue(SFX_EXIT);
// Make sure the thread wakes up.
pthread_cond_signal(&m_cond_request);
#else
setCanBeDeleted();
if (UserConfigParams::m_enable_sound)
{
queue(SFX_EXIT);
// Make sure the thread wakes up.
pthread_cond_signal(&m_cond_request);
}
else
#endif
{
setCanBeDeleted();
}
} // stopThread
//----------------------------------------------------------------------------
@@ -338,6 +373,9 @@ void SFXManager::stopThread()
void* SFXManager::mainLoop(void *obj)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return NULL;
VS::setThreadName("SFXManager");
SFXManager *me = (SFXManager*)obj;
@@ -674,14 +712,24 @@ SFXBase* SFXManager::createSoundSource(SFXBuffer* buffer,
positional = buffer->isPositional();
}
SFXBase* sfx = NULL;
#ifdef ENABLE_SOUND
//assert( alIsBuffer(buffer->getBufferID()) ); crashes on server
SFXBase* sfx = new SFXOpenAL(buffer, positional, buffer->getGain(), owns_buffer);
#else
SFXBase* sfx = new DummySFX(buffer, positional, buffer->getGain());
if (owns_buffer)
delete buffer;
if (UserConfigParams::m_enable_sound)
{
//assert( alIsBuffer(buffer->getBufferID()) ); crashes on server
sfx = new SFXOpenAL(buffer, positional, buffer->getGain(), owns_buffer);
}
else
#endif
{
sfx = new DummySFX(buffer, positional, buffer->getGain());
if (owns_buffer)
{
delete buffer;
}
}
sfx->setMasterVolume(m_master_gain);
@@ -766,6 +814,9 @@ void SFXManager::deleteSFXMapping(const std::string &name)
void SFXManager::update()
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
queue(SFX_UPDATE, (SFXBase*)NULL);
// Wake up the sfx thread to handle all queued up audio commands.
pthread_cond_signal(&m_cond_request);
@@ -780,6 +831,9 @@ void SFXManager::update()
void SFXManager::reallyUpdateNow(SFXCommand *current)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
if (m_last_update_time < 0.0)
{
// first time
@@ -906,10 +960,13 @@ void SFXManager::reallyResumeAllNow()
bool SFXManager::checkError(const std::string &context)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return true;
// Check (and clear) the error flag
int error = alGetError();
if(error != AL_NO_ERROR)
if (error != AL_NO_ERROR)
{
Log::error("SFXManager", "SFXOpenAL OpenAL error while %s: %s",
context.c_str(), SFXManager::getErrorString(error).c_str());
@@ -958,6 +1015,9 @@ void SFXManager::setMasterSFXVolume(float gain)
const std::string SFXManager::getErrorString(int err)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return std::string("sound disabled");
switch(err)
{
case AL_NO_ERROR: return std::string("AL_NO_ERROR" );
@@ -968,9 +1028,9 @@ const std::string SFXManager::getErrorString(int err)
case AL_OUT_OF_MEMORY: return std::string("AL_OUT_OF_MEMORY" );
default: return std::string("UNKNOWN");
};
#else
return std::string("sound disabled");
#endif
return std::string("sound disabled");
} // getErrorString
//-----------------------------------------------------------------------------

View File

@@ -18,13 +18,13 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "utils/ptr_vector.hpp"
#include <vector>
// The order here is important. If all_params is declared later (e.g. after
// the #includes), all elements will be added to all_params, and then
// all_params will be initialised, i.e. cleared!
class UserConfigParam;
static PtrVector<UserConfigParam, REF> all_params;
static std::vector<UserConfigParam*> all_params;
// X-macros
#define PARAM_PREFIX
@@ -53,7 +53,9 @@ const int UserConfig::m_current_config_version = 8;
// ----------------------------------------------------------------------------
UserConfigParam::~UserConfigParam()
{
all_params.remove(this);
// Now we have server config param so we cannot do this anymore,
// esp all params are kept until the closing of stk anyway
//all_params.remove(this);
} // ~UserConfigParam
// ----------------------------------------------------------------------------
@@ -61,7 +63,7 @@ UserConfigParam::~UserConfigParam()
* \param stream the xml writer.
* \param level determines indentation level.
*/
void UserConfigParam::writeInner(std::ofstream& stream, int level) const
void UserConfigParam::writeInner(std::stringstream& stream, int level) const
{
std::string tab(level * 4,' ');
stream << " " << tab.c_str() << m_param_name.c_str() << "=\""
@@ -88,7 +90,7 @@ GroupUserConfigParam::GroupUserConfigParam(const char* group_name,
} // GroupUserConfigParam
// ----------------------------------------------------------------------------
void GroupUserConfigParam::write(std::ofstream& stream) const
void GroupUserConfigParam::write(std::stringstream& stream) const
{
const int attr_amount = (int)m_attributes.size();
@@ -118,7 +120,7 @@ void GroupUserConfigParam::write(std::ofstream& stream) const
} // write
// ----------------------------------------------------------------------------
void GroupUserConfigParam::writeInner(std::ofstream& stream, int level) const
void GroupUserConfigParam::writeInner(std::stringstream& stream, int level) const
{
std::string tab(level * 4,' ');
for(int i = 0; i < level; i++) tab =+ " ";
@@ -184,21 +186,14 @@ void GroupUserConfigParam::addChild(UserConfigParam* child)
// ----------------------------------------------------------------------------
template<typename T, typename U>
MapUserConfigParam<T, U>::MapUserConfigParam(const char* param_name,
const char* comment)
const char* comment, std::array<std::string, 3> key_names,
std::map<T, U> default_value)
{
m_param_name = param_name;
all_params.push_back(this);
if (comment != NULL) m_comment = comment;
} // MapUserConfigParam
// ----------------------------------------------------------------------------
template<typename T, typename U>
MapUserConfigParam<T, U>::MapUserConfigParam(const char* param_name,
const char* comment, std::map<T, U> default_value)
{
m_param_name = param_name;
all_params.push_back(this);
if (comment != NULL) m_comment = comment;
m_key_names = key_names;
m_elements = default_value;
} // MapUserConfigParam
@@ -217,28 +212,30 @@ MapUserConfigParam<T, U>::MapUserConfigParam(const char* param_name,
template<typename T, typename U>
MapUserConfigParam<T, U>::MapUserConfigParam(const char* param_name,
GroupUserConfigParam* group, const char* comment,
std::map<T, U> default_value)
std::array<std::string, 3> key_names, std::map<T, U> default_value)
{
m_param_name = param_name;
group->addChild(this);
if (comment != NULL) m_comment = comment;
m_key_names = key_names;
m_elements = default_value;
} // MapUserConfigParam
// ----------------------------------------------------------------------------
template<typename T, typename U>
void MapUserConfigParam<T, U>::write(std::ofstream& stream) const
void MapUserConfigParam<T, U>::write(std::stringstream& stream) const
{
// comment
if (m_comment.size() > 0) stream << " <!-- " << m_comment.c_str();
stream << " -->\n <" << m_param_name.c_str() << "\n";
stream << " -->\n <" << m_param_name.c_str() << ">\n";
for (const auto& kv : m_elements)
{
stream << " " << kv.first << "=\"" << kv.second << "\"\n";
stream << " <" << m_key_names[0] << " " << m_key_names[1] <<
"=\"" << kv.first << "\" " << m_key_names[2] << "=\"" <<
kv.second << "\"/>\n";
}
stream << " >\n";
stream << " </" << m_param_name.c_str() << ">\n\n";
} // write
@@ -249,10 +246,44 @@ void MapUserConfigParam<T, U>::findYourDataInAChildOf(const XMLNode* node)
const XMLNode* child = node->getNode(m_param_name);
if (child == NULL)
{
//Log::error("User Config", "Couldn't find parameter group %s", m_param_name.c_str());
Log::error("User Config", "Couldn't find parameter group %s",
m_param_name.c_str());
return;
}
child->get(&m_elements);
for (unsigned i = 0; i < child->getNumNodes(); i++)
{
const std::string& map_name = m_key_names[0];
const std::string& key_name = m_key_names[1];
const std::string& value_name = m_key_names[2];
const XMLNode* map = child->getNode(i);
if (map->getName() != map_name)
{
Log::error("User Config", "Invalid name %s",
map->getName().c_str());
continue;
}
T key;
std::string key_string;
if (!map->get(key_name, &key_string) ||
!StringUtils::fromString(key_string, key))
{
Log::error("User Config", "Invalid key name %s",
key_name.c_str());
continue;
}
U value;
std::string value_string;
if (!map->get(value_name, &value_string) ||
!StringUtils::fromString(value_string, value))
{
Log::error("User Config", "Invalid value name %s",
value_name.c_str());
continue;
}
m_elements[key] = value;
}
} // findYourDataInAChildOf
// ----------------------------------------------------------------------------
@@ -301,7 +332,7 @@ IntUserConfigParam::IntUserConfigParam(int default_value,
} // IntUserConfigParam
// ----------------------------------------------------------------------------
void IntUserConfigParam::write(std::ofstream& stream) const
void IntUserConfigParam::write(std::stringstream& stream) const
{
if(m_comment.size() > 0) stream << " <!-- " << m_comment.c_str()
<< " -->\n";
@@ -364,11 +395,11 @@ TimeUserConfigParam::TimeUserConfigParam(StkTime::TimeType default_value,
} // TimeUserConfigParam
// ----------------------------------------------------------------------------
void TimeUserConfigParam::write(std::ofstream& stream) const
void TimeUserConfigParam::write(std::stringstream& stream) const
{
if(m_comment.size() > 0) stream << " <!-- " << m_comment.c_str()
<< " -->\n";
std::ostringstream o;
std::stringstream o;
o<<m_value;
stream << " <" << m_param_name.c_str() << " value=\""
<< o.str().c_str() << "\" />\n\n";
@@ -381,7 +412,7 @@ irr::core::stringc TimeUserConfigParam::toString() const
// we can't use an irrlicht's stringw directly. Since it's only a
// number, we can use std::string, and convert to stringw
std::ostringstream o;
std::stringstream o;
o<<m_value;
return o.str().c_str();
} // toString
@@ -435,7 +466,7 @@ StringUserConfigParam::StringUserConfigParam(const char* default_value,
} // StringUserConfigParam
// ----------------------------------------------------------------------------
void StringUserConfigParam::write(std::ofstream& stream) const
void StringUserConfigParam::write(std::stringstream& stream) const
{
if(m_comment.size() > 0) stream << " <!-- " << m_comment.c_str()
<< " -->\n";
@@ -487,7 +518,7 @@ BoolUserConfigParam::BoolUserConfigParam(bool default_value,
// ----------------------------------------------------------------------------
void BoolUserConfigParam::write(std::ofstream& stream) const
void BoolUserConfigParam::write(std::stringstream& stream) const
{
if(m_comment.size() > 0) stream << " <!-- " << m_comment.c_str()
<< " -->\n";
@@ -572,7 +603,7 @@ FloatUserConfigParam::FloatUserConfigParam(float default_value,
} // FloatUserConfigParam
// ----------------------------------------------------------------------------
void FloatUserConfigParam::write(std::ofstream& stream) const
void FloatUserConfigParam::write(std::stringstream& stream) const
{
if(m_comment.size() > 0) stream << " <!-- " << m_comment.c_str()
<< " -->\n";
@@ -669,10 +700,9 @@ bool UserConfig::loadConfig()
// ---- Read parameters values (all parameter objects must have been created before this point if
// you want them automatically read from the config file)
const int paramAmount = all_params.size();
for(int i=0; i<paramAmount; i++)
for (unsigned i = 0; i < all_params.size(); i++)
{
all_params[i].findYourDataInAChildOf(root);
all_params[i]->findYourDataInAChildOf(root);
}
@@ -696,29 +726,27 @@ bool UserConfig::loadConfig()
void UserConfig::saveConfig()
{
const std::string filename = file_manager->getUserConfigFile(m_filename);
std::stringstream ss;
ss << "<?xml version=\"1.0\"?>\n";
ss << "<stkconfig version=\"" << m_current_config_version
<< "\" >\n\n";
for (unsigned i = 0; i < all_params.size(); i++)
{
all_params[i]->write(ss);
}
ss << "</stkconfig>\n";
try
{
std::ofstream configfile (filename.c_str(), std::ofstream::out);
configfile << "<?xml version=\"1.0\"?>\n";
configfile << "<stkconfig version=\"" << m_current_config_version
<< "\" >\n\n";
const int paramAmount = all_params.size();
for(int i=0; i<paramAmount; i++)
{
//Log::info("UserConfig", "Saving parameter %d to file", i);
all_params[i].write(configfile);
}
configfile << "</stkconfig>\n";
std::string s = ss.str();
std::ofstream configfile(filename.c_str(), std::ofstream::out);
configfile << ss.rdbuf();
configfile.close();
}
catch (std::runtime_error& e)
{
Log::error("UserConfig::saveConfig", "Failed to write config to %s, because %s",
filename.c_str(), e.what());
Log::error("UserConfig::saveConfig", "Failed to write config to %s, "
"because %s", filename.c_str(), e.what());
}
} // saveConfig

View File

@@ -37,11 +37,12 @@
cause an undefined game action now
6: Added stick configurations.
*/
#include <array>
#include <iterator>
#include <string>
#include <map>
#include <vector>
#include <fstream>
#include <sstream>
#include <irrString.h>
using irr::core::stringc;
@@ -69,8 +70,8 @@ protected:
std::string m_comment;
public:
virtual ~UserConfigParam();
virtual void write(std::ofstream & stream) const = 0;
virtual void writeInner(std::ofstream & stream, int level = 0) const;
virtual void write(std::stringstream & stream) const = 0;
virtual void writeInner(std::stringstream & stream, int level = 0) const;
virtual void findYourDataInAChildOf(const XMLNode* node) = 0;
virtual void findYourDataInAnAttributeOf(const XMLNode* node) = 0;
virtual irr::core::stringc toString() const = 0;
@@ -86,8 +87,8 @@ public:
GroupUserConfigParam(const char* param_name,
GroupUserConfigParam* group,
const char* comment = NULL);
void write(std::ofstream& stream) const;
void writeInner(std::ofstream& stream, int level = 0) const;
void write(std::stringstream& stream) const;
void writeInner(std::stringstream& stream, int level = 0) const;
void findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node);
@@ -99,26 +100,36 @@ public:
}; // GroupUserConfigParam
// ============================================================================
/** ATM only map with 1 key and 1 value is supported
*/
template<typename T, typename U>
class MapUserConfigParam : public UserConfigParam
{
protected:
std::array<std::string, 3> m_key_names;
std::map<T, U> m_elements;
MapUserConfigParam(const char* param_name,
const char* comment)
{
m_param_name = param_name;
if (comment != NULL)
m_comment = comment;
}
public:
MapUserConfigParam(const char* param_name,
const char* comment = NULL);
MapUserConfigParam(const char* param_name,
const char* comment,
std::array<std::string, 3> key_names,
std::map<T, U> default_value);
MapUserConfigParam(const char* param_name,
GroupUserConfigParam* group,
const char* comment = NULL);
MapUserConfigParam(const char* param_name,
GroupUserConfigParam* group,
const char* comment,
const char* comment, std::array<std::string, 3> key_names,
std::map<T, U> default_value);
void write(std::ofstream& stream) const;
void write(std::stringstream& stream) const;
void findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node);
@@ -152,14 +163,25 @@ public:
{
return m_elements[key];
}
U& at(const T key)
{
return m_elements.at(key);
}
}; // MapUserConfigParam
typedef MapUserConfigParam<uint32_t, uint32_t> UIntToUIntUserConfigParam;
typedef MapUserConfigParam<std::string, uint32_t> StringToUIntUserConfigParam;
// ============================================================================
class IntUserConfigParam : public UserConfigParam
{
protected:
int m_value;
int m_default_value;
IntUserConfigParam(const char* param_name, const char* comment)
{
m_param_name = param_name;
if (comment != NULL)
m_comment = comment;
}
public:
@@ -169,7 +191,7 @@ public:
GroupUserConfigParam* group,
const char* comment = NULL);
void write(std::ofstream& stream) const;
void write(std::stringstream& stream) const;
void findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node);
@@ -196,7 +218,7 @@ public:
TimeUserConfigParam(StkTime::TimeType default_value, const char* param_name,
GroupUserConfigParam* group, const char* comment=NULL);
void write(std::ofstream& stream) const;
void write(std::stringstream& stream) const;
void findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node);
@@ -212,18 +234,25 @@ public:
// ============================================================================
class StringUserConfigParam : public UserConfigParam
{
protected:
std::string m_value;
std::string m_default_value;
StringUserConfigParam(const char* param_name, const char* comment)
{
m_param_name = param_name;
if (comment != NULL)
m_comment = comment;
}
public:
StringUserConfigParam(const char* default_value, const char* param_name,
const char* comment = NULL);
const char* comment);
StringUserConfigParam(const char* default_value, const char* param_name,
GroupUserConfigParam* group,
const char* comment = NULL);
void write(std::ofstream& stream) const;
void write(std::stringstream& stream) const;
void findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node);
@@ -245,8 +274,15 @@ public:
// ============================================================================
class BoolUserConfigParam : public UserConfigParam
{
protected:
bool m_value;
bool m_default_value;
BoolUserConfigParam(const char* param_name, const char* comment)
{
m_param_name = param_name;
if (comment != NULL)
m_comment = comment;
}
public:
BoolUserConfigParam(bool default_value, const char* param_name,
@@ -254,7 +290,7 @@ public:
BoolUserConfigParam(bool default_value, const char* param_name,
GroupUserConfigParam* group,
const char* comment = NULL);
void write(std::ofstream& stream) const;
void write(std::stringstream& stream) const;
void findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node);
@@ -270,8 +306,15 @@ public:
// ============================================================================
class FloatUserConfigParam : public UserConfigParam
{
protected:
float m_value;
float m_default_value;
FloatUserConfigParam(const char* param_name, const char* comment)
{
m_param_name = param_name;
if (comment != NULL)
m_comment = comment;
}
public:
FloatUserConfigParam(float default_value, const char* param_name,
@@ -280,7 +323,7 @@ public:
GroupUserConfigParam* group,
const char* comment = NULL);
void write(std::ofstream& stream) const;
void write(std::stringstream& stream) const;
void findYourDataInAChildOf(const XMLNode* node);
void findYourDataInAnAttributeOf(const XMLNode* node);
@@ -464,7 +507,7 @@ namespace UserConfigParams
"A parameter that determines general accelerometer sensitivity."));
PARAM_PREFIX FloatUserConfigParam m_multitouch_scale
PARAM_DEFAULT( FloatUserConfigParam(1.1f, "multitouch_scale",
PARAM_DEFAULT( FloatUserConfigParam(1.2f, "multitouch_scale",
&m_multitouch_group,
"A parameter in range [0.5, 1.5] that determines the scale of the "
"multitouch interface."));
@@ -586,7 +629,7 @@ namespace UserConfigParams
PARAM_DEFAULT(BoolUserConfigParam(false, "hq_mipmap",
&m_video_group, "Generate mipmap for textures using "
"high quality method with SSE"));
// ---- Recording
PARAM_PREFIX GroupUserConfigParam m_recording_group
PARAM_DEFAULT(GroupUserConfigParam("Recording",
@@ -672,6 +715,8 @@ namespace UserConfigParams
PARAM_PREFIX bool m_race_now PARAM_DEFAULT( false );
PARAM_PREFIX bool m_enforce_current_player PARAM_DEFAULT( false );
PARAM_PREFIX bool m_enable_sound PARAM_DEFAULT( true );
/** True to test funky ambient/diffuse/specularity in RGB &
* all anisotropic */
@@ -681,21 +726,24 @@ namespace UserConfigParams
PARAM_PREFIX bool m_profiler_enabled PARAM_DEFAULT( false );
// ---- Networking
PARAM_PREFIX StringToUIntUserConfigParam m_stun_list
PARAM_DEFAULT(StringToUIntUserConfigParam("stun_list",
"The stun servers that will be used to know the public address,"
" LHS: server address, RHS: ping time.",
PARAM_PREFIX StringToUIntUserConfigParam m_stun_servers
PARAM_DEFAULT(StringToUIntUserConfigParam("stun-servers",
"The stun servers that will be used to know the public address with"
" port", {{ "stun-server", "address", "ping" }},
{
{ "numb.viagenie.ca", 0u },
{ "stun.12connect.com", 0u },
{ "stun.callwithus.com", 0u },
{ "stun.cope.es", 0u },
{ "stun.counterpath.net", 0u },
{ "stun.ekiga.net", 0u },
{ "stun.ivao.aero", 0u },
{ "stun.schlund.de", 0u },
{ "stun.stunprotocol.org", 0u },
{ "stun.voip.aebc.com", 0u }
{ "stun.12connect.com:3478", 0u },
{ "stun.callwithus.com:3478", 0u },
{ "stun.cope.es:3478", 0u },
{ "stun.counterpath.net:3478", 0u },
{ "stun.ekiga.net:3478", 0u },
{ "stun.ivao.aero:3478", 0u },
{ "stun.schlund.de:3478", 0u },
{ "stun.stunprotocol.org:3478", 0u },
{ "stun.l.google.com:19302", 0u },
{ "stun1.l.google.com:19302", 0u },
{ "stun2.l.google.com:19302", 0u },
{ "stun3.l.google.com:19302", 0u },
{ "stun4.l.google.com:19302", 0u }
}
));
@@ -716,50 +764,19 @@ namespace UserConfigParams
PARAM_DEFAULT(BoolUserConfigParam(false, "lobby-chat",
&m_network_group, "Enable chatting in networking lobby, if off than "
"no chat message will be displayed from any players."));
PARAM_PREFIX FloatUserConfigParam m_voting_timeout
PARAM_DEFAULT(FloatUserConfigParam(20.0f, "voting-timeout",
&m_network_group, "Timeout in seconds for voting tracks in server."));
PARAM_PREFIX FloatUserConfigParam m_validation_timeout
PARAM_DEFAULT(FloatUserConfigParam(20.0f, "validation-timeout",
&m_network_group, "Timeout in seconds for validation of clients."));
PARAM_PREFIX IntUserConfigParam m_server_max_players
PARAM_DEFAULT(IntUserConfigParam(8, "server-max-players",
&m_network_group, "Maximum number of players on the server."));
PARAM_PREFIX BoolUserConfigParam m_firewalled_server
PARAM_DEFAULT(BoolUserConfigParam(true, "firewalled-server",
&m_network_group, "Disable it to turn off all stun related code "
"in server, for official server hosting use only."));
PARAM_PREFIX FloatUserConfigParam m_start_game_counter
PARAM_DEFAULT(FloatUserConfigParam(30.0f, "start-game-counter",
&m_network_group, "Time to wait before entering kart selection screen "
"if satisfied start-game-threshold below for owner less or ranked "
"server."));
PARAM_PREFIX FloatUserConfigParam m_start_game_threshold
PARAM_DEFAULT(FloatUserConfigParam(0.7f, "start-game-threshold",
&m_network_group, "Only auto start kart selection when number of "
"connected player is larger than max player * this value, for "
"owner less or ranked server, after start-game-counter."));
PARAM_PREFIX StringToUIntUserConfigParam m_server_ban_list
PARAM_DEFAULT(StringToUIntUserConfigParam("server_ban_list",
"LHS: IP in x.x.x.x format, RHS: online id, if 0 than all players "
"from this IP will be banned.",
{ { "0.0.0.0", 0u } }
));
PARAM_PREFIX IntUserConfigParam m_max_ping
PARAM_DEFAULT(IntUserConfigParam(300, "max-ping",
&m_network_group, "Maximum ping allowed for a player (in ms)."));
PARAM_PREFIX IntUserConfigParam m_jitter_tolerance
PARAM_DEFAULT(IntUserConfigParam(100, "jitter-tolerance",
&m_network_group, "Tolerance of jitter in network allowed (in ms)."));
PARAM_PREFIX BoolUserConfigParam m_kick_high_ping_players
PARAM_DEFAULT(BoolUserConfigParam(false, "kick-high-ping-players",
&m_network_group, "Kick players whose ping is above max-ping."));
PARAM_PREFIX IntUserConfigParam m_max_players
PARAM_DEFAULT(IntUserConfigParam(8, "max-players",
&m_network_group, "Maximum number of players on the server "
"(for gui server creation."));
PARAM_PREFIX IntUserConfigParam m_timer_sync_difference_tolerance
PARAM_DEFAULT(IntUserConfigParam(5, "timer-sync-difference-tolerance",
&m_network_group, "Max time difference tolerance (in ms) to synchronize timer with server."));
// ---- Gamemode setup
PARAM_PREFIX UIntToUIntUserConfigParam m_num_karts_per_gamemode
PARAM_DEFAULT(UIntToUIntUserConfigParam("num_karts_per_gamemode",
PARAM_DEFAULT(UIntToUIntUserConfigParam("num-karts-per-gamemode",
"The Number of karts per gamemode.",
{{ "gamemode-list", "gamemode", "num-karts" }},
{
{ 0u, 4u },
{ 1002u, 5u },

View File

@@ -20,6 +20,7 @@
#include "font/font_manager.hpp"
#include "io/file_manager.hpp"
#include "modes/profile_world.hpp"
// ----------------------------------------------------------------------------
/** Constructor. Load all TTFs from a list.
@@ -28,6 +29,9 @@
FaceTTF::FaceTTF(const std::vector<std::string>& ttf_list)
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
for (const std::string& font : ttf_list)
{
FT_Face face = NULL;
@@ -46,6 +50,9 @@ FaceTTF::FaceTTF(const std::vector<std::string>& ttf_list)
FaceTTF::~FaceTTF()
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
for (unsigned int i = 0; i < m_faces.size(); i++)
{
font_manager->checkFTError(FT_Done_Face(m_faces[i]), "removing face");

View File

@@ -23,6 +23,7 @@
#include "font/digit_face.hpp"
#include "font/face_ttf.hpp"
#include "font/regular_face.hpp"
#include "modes/profile_world.hpp"
#include "utils/string_utils.hpp"
#include "utils/translation.hpp"
@@ -33,6 +34,10 @@ FontManager *font_manager = NULL;
FontManager::FontManager()
{
#ifndef SERVER_ONLY
m_ft_library = NULL;
if (ProfileWorld::isNoGraphics())
return;
checkFTError(FT_Init_FreeType(&m_ft_library), "loading freetype library");
#endif
} // FontManager
@@ -52,8 +57,10 @@ FontManager::~FontManager()
m_digit_ttf = NULL;
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
checkFTError(FT_Done_FreeType(m_ft_library), "removing freetype library");
m_ft_library = NULL;
#endif
} // ~FontManager

View File

@@ -77,6 +77,12 @@ void FontWithFace::init()
{
setDPI();
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
{
reset();
return;
}
// Get the max height for this face
assert(m_face_ttf->getTotalFaces() > 0);
FT_Face cur_face = m_face_ttf->getFace(0);
@@ -127,6 +133,9 @@ void FontWithFace::reset()
void FontWithFace::loadGlyphInfo(wchar_t c)
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
unsigned int font_number = 0;
unsigned int glyph_index = 0;
while (font_number < m_face_ttf->getTotalFaces())
@@ -145,6 +154,9 @@ void FontWithFace::loadGlyphInfo(wchar_t c)
void FontWithFace::createNewGlyphPage()
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
uint8_t* data = new uint8_t[getGlyphPageSize() * getGlyphPageSize() *
(CVS->isARBTextureSwizzleUsable() ? 1 : 4)]();
#else
@@ -173,6 +185,9 @@ void FontWithFace::createNewGlyphPage()
void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
assert(gi.glyph_index > 0);
assert(gi.font_number < m_face_ttf->getTotalFaces());
FT_Face cur_face = m_face_ttf->getFace(gi.font_number);
@@ -401,6 +416,8 @@ core::dimension2d<u32> FontWithFace::getDimension(const wchar_t* text,
#ifdef SERVER_ONLY
return core::dimension2d<u32>(1, 1);
#else
if (ProfileWorld::isNoGraphics())
return core::dimension2d<u32>(1, 1);
const float scale = font_settings ? font_settings->getScale() : 1.0f;
// Test if lazy load char is needed
@@ -494,6 +511,9 @@ void FontWithFace::render(const core::stringw& text,
FontCharCollector* char_collector)
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
const bool black_border = font_settings ?
font_settings->useBlackBorder() : false;
const bool rtl = font_settings ? font_settings->isRTL() : false;

View File

@@ -700,5 +700,14 @@ void GL32_draw2DRectangle(video::SColor color, const core::rect<s32>& position,
glGetError();
} // GL32_draw2DRectangle
void preloadShaders()
{
Primitive2DList::getInstance();
UniformColoredTextureRectShader::getInstance();
TextureRectShader::getInstance();
ColoredRectShader::getInstance();
ColoredTextureRectShader::getInstance();
} // preloadShaders
#endif // !SERVER_ONLY

View File

@@ -28,6 +28,8 @@
#include <SColor.h>
#include <SVertexIndex.h>
void preloadShaders();
void draw2DImageFromRTT(GLuint texture, size_t texture_w, size_t texture_h,
const irr::core::rect<irr::s32>& destRect,
const irr::core::rect<irr::s32>& sourceRect,

View File

@@ -248,7 +248,9 @@ void CameraNormal::update(float dt)
// If an explosion is happening, stop moving the camera,
// but keep it target on the kart.
if (dynamic_cast<ExplosionAnimation*>(m_kart->getKartAnimation()))
ExplosionAnimation* ea =
dynamic_cast<ExplosionAnimation*>(m_kart->getKartAnimation());
if (ea && !ea->hasResetAlready())
{
float above_kart, cam_angle, side_way, distance;
bool smoothing;

View File

@@ -134,6 +134,28 @@ CPUParticleManager::GLParticle::GLParticle(bool flips)
glBindVertexArray(0);
} // GLParticle
// ----------------------------------------------------------------------------
CPUParticleManager::CPUParticleManager()
{
assert(CVS->isGLSL());
const float vertices[] =
{
-0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 1.0f, 1.0f,
};
glGenBuffers(1, &m_particle_quad);
glBindBuffer(GL_ARRAY_BUFFER, m_particle_quad);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// For preloading shaders
ParticleRenderer::getInstance();
AlphaTestParticleRenderer::getInstance();
} // CPUParticleManager
// ----------------------------------------------------------------------------
void CPUParticleManager::addBillboardNode(scene::IBillboardSceneNode* node)
{

View File

@@ -116,21 +116,7 @@ private:
public:
// ------------------------------------------------------------------------
CPUParticleManager()
{
const float vertices[] =
{
-0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 1.0f, 1.0f,
};
glGenBuffers(1, &m_particle_quad);
glBindBuffer(GL_ARRAY_BUFFER, m_particle_quad);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
CPUParticleManager();
// ------------------------------------------------------------------------
~CPUParticleManager()
{

View File

@@ -638,8 +638,11 @@ void IrrDriver::initDevice()
#endif
#ifndef SERVER_ONLY
if(CVS->isGLSL())
if (CVS->isGLSL())
{
m_renderer = new ShaderBasedRenderer();
preloadShaders();
}
else
m_renderer = new FixedPipelineRenderer();
#endif
@@ -795,6 +798,9 @@ void IrrDriver::getOpenGLData(std::string *vendor, std::string *renderer,
std::string *version)
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
*vendor = (char*)glGetString(GL_VENDOR );
*renderer = (char*)glGetString(GL_RENDERER);
*version = (char*)glGetString(GL_VERSION );
@@ -1847,22 +1853,6 @@ void IrrDriver::doScreenShot()
*/
void IrrDriver::update(float dt)
{
// User aborted (e.g. closed window)
// =================================
if (!m_device->run())
{
// Don't bother cleaning up GUI, has no use and may result in crashes
//GUIEngine::cleanUp();
//GUIEngine::deallocate();
main_loop->abort();
return;
}
// If we quit via the menu the m_device->run() does not return true.
// To avoid any other calls, we return here.
if(main_loop->isAborted())
return;
// If the resolution should be switched, do it now. This will delete the
// old device and create a new one.
if (m_resolution_changing!=RES_CHANGE_NONE)

View File

@@ -758,6 +758,9 @@ PostProcessing::PostProcessing()
STKTexManager::getInstance()->addTexture(m_areamap);
areamap->drop();
// For preloading shaders
MotionBlurShader::getInstance();
LightningShader::getInstance();
} // PostProcessing
// ----------------------------------------------------------------------------

View File

@@ -32,6 +32,7 @@
#include "karts/kart_properties.hpp"
#include "karts/max_speed.hpp"
#include "modes/world.hpp"
#include "network/rewind_manager.hpp"
#include "tracks/quad.hpp"
#include "utils/constants.hpp"
#include "utils/mini_glm.hpp"
@@ -825,12 +826,28 @@ void SlipStream::update(int ticks)
m_slipstream_time = 0.0f;
m_bonus_active = true;
float speed_increase = kp->getSlipstreamMaxSpeedIncrease();
float add_power = kp->getSlipstreamAddPower();
int duration = stk_config->time2Ticks(m_bonus_time);
int fade_out = kp->getSlipstreamFadeOutTicks();
m_kart->instantSpeedIncrease(MaxSpeed::MS_INCREASE_SLIPSTREAM,
kp->getSlipstreamMaxSpeedIncrease(),
kp->getSlipstreamMaxSpeedIncrease(),
kp->getSlipstreamAddPower(),
stk_config->time2Ticks(m_bonus_time), fade_out);
m_kart->instantSpeedIncrease(
MaxSpeed::MS_INCREASE_SLIPSTREAM, speed_increase,
speed_increase, add_power, duration, fade_out);
if (RewindManager::get()->useLocalEvent())
{
AbstractKart* kart = m_kart;
RewindManager::get()->addRewindInfoEventFunction(new
RewindInfoEventFunction(
World::getWorld()->getTicksSinceStart(),
[](){},
[kart, speed_increase, add_power, duration, fade_out]()
{
kart->instantSpeedIncrease(
MaxSpeed::MS_INCREASE_SLIPSTREAM, speed_increase,
speed_increase, add_power, duration, fade_out);
}));
}
}
if(!is_sstreaming)

View File

@@ -127,7 +127,7 @@ void SPMeshBuffer::uploadGLMesh()
{
m_textures[i][j] = SPTextureManager::get()->getTexture
(m_shaders[0]->hasTextureLayer(j) ?
std::get<2>(m_stk_material[i])->getSamplerPath(j) : "",
std::get<2>(m_stk_material[i])->getSamplerPath(j) : "",
j == 0 ? std::get<2>(m_stk_material[i]) : NULL,
m_shaders[0]->isSrgbForTextureLayer(j),
std::get<2>(m_stk_material[i])->getContainerId());
@@ -469,10 +469,22 @@ void SPMeshBuffer::reloadTextureCompare()
void SPMeshBuffer::setSTKMaterial(Material* m)
{
m_stk_material[0] = std::make_tuple(0u, getIndexCount(), m);
m_shaders[0] = SPShaderManager::get()->getSPShader(
std::get<2>(m_stk_material[0])->getShaderName());
m_shaders[1] = SPShaderManager::get()->getSPShader(
std::get<2>(m_stk_material[0])->getShaderName() + "_skinned");
const std::string shader_name =
std::get<2>(m_stk_material[0])->getShaderName();
const std::string skinned_shader_name =
std::get<2>(m_stk_material[0])->getShaderName() + "_skinned";
m_shaders[0] = SPShaderManager::get()->getSPShader(shader_name);
if (!m_shaders[0])
{
Log::warn("SPMeshBuffer", "%s shader is missing, fallback to solid",
shader_name.c_str());
m_shaders[0] = SPShaderManager::get()->getSPShader("solid");
}
m_shaders[1] = SPShaderManager::get()->getSPShader(skinned_shader_name);
if (!m_shaders[1])
m_shaders[1] = SPShaderManager::get()->getSPShader("solid_skinned");
} // setSTKMaterial
}

View File

@@ -21,6 +21,7 @@
#include "config/user_config.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/modaldialog.hpp"
#include "guiengine/screen_keyboard.hpp"
#include "guiengine/screen.hpp"
#include "input/device_manager.hpp"
@@ -49,6 +50,7 @@ void AbstractStateManager::enterGameState()
{
// you need to close any dialog before calling this
assert(!ModalDialog::isADialogActive());
assert(!ScreenKeyboard::isActive());
if (getCurrentScreen() != NULL) getCurrentScreen()->tearDown();
m_menu_stack.clear();
@@ -90,6 +92,7 @@ void AbstractStateManager::pushMenu(Screen* screen)
// you need to close any dialog before calling this
assert(!ModalDialog::isADialogActive());
assert(!ScreenKeyboard::isActive());
if (UserConfigParams::logGUI())
{
@@ -122,6 +125,7 @@ void AbstractStateManager::pushScreen(Screen* screen)
{
// you need to close any dialog before calling this
assert(!ModalDialog::isADialogActive());
assert(!ScreenKeyboard::isActive());
if (UserConfigParams::logGUI())
{
@@ -146,6 +150,7 @@ void AbstractStateManager::replaceTopMostScreen(Screen* screen, GUIEngine::GameS
//assert(m_game_mode != GAME);
// you need to close any dialog before calling this
assert(!ModalDialog::isADialogActive());
assert(!ScreenKeyboard::isActive());
if (!screen->isLoaded()) screen->loadFromFile();
std::string name = screen->getName();
@@ -179,6 +184,7 @@ void AbstractStateManager::reshowTopMostMenu()
assert(m_game_mode != GAME);
// you need to close any dialog before calling this
assert(!ModalDialog::isADialogActive());
assert(!ScreenKeyboard::isActive());
// Send tear-down event to previous menu
if (m_menu_stack.size() > 0)
@@ -243,6 +249,7 @@ void AbstractStateManager::resetAndGoToScreen(Screen* screen)
{
// you need to close any dialog before calling this
assert(!ModalDialog::isADialogActive());
assert(!ScreenKeyboard::isActive());
std::string name = screen->getName();
@@ -271,6 +278,7 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[])
assert(screens[0] != NULL);
// you need to close any dialog before calling this
assert(!ModalDialog::isADialogActive());
assert(!ScreenKeyboard::isActive());
if (m_game_mode != GAME) getCurrentScreen()->tearDown();
m_menu_stack.clear();

View File

@@ -30,6 +30,7 @@
#include "guiengine/widget.hpp"
#include "guiengine/widgets/list_widget.hpp"
#include "guiengine/widgets/ribbon_widget.hpp"
#include "guiengine/widgets/spinner_widget.hpp"
#include "input/input_manager.hpp"
#include "modes/demo_world.hpp"
#include "modes/world.hpp"
@@ -488,6 +489,16 @@ void EventHandler::navigate(const NavigationDirection nav, const int playerID)
sendEventToUser(ribbon, ribbon->m_properties[PROP_ID], playerID);
}
}
// For spinners, select the most intuitive button
// based on where the navigation came from
// Right if coming from right by a left press
// Left for all other directions
if (closest_widget->getType() == WTYPE_SPINNER)
{
SpinnerWidget* spinner = dynamic_cast<SpinnerWidget*>(closest_widget);
spinner->setSelectedButton(nav == NAV_LEFT);
}
}
return;
@@ -724,6 +735,7 @@ EventPropagation EventHandler::onWidgetActivated(GUIEngine::Widget* w, const int
Widget* parent = w->m_event_handler;
//FIXME : sendEventToUser do the same screen keyboard and modal dialog checks, so they are done twice
if (ScreenKeyboard::isActive())
{
if (ScreenKeyboard::getCurrent()->processEvent(w->m_properties[PROP_ID]) == EVENT_BLOCK)
@@ -743,6 +755,13 @@ EventPropagation EventHandler::onWidgetActivated(GUIEngine::Widget* w, const int
//Log::info("EventHandler", "Widget activated: %s", w->m_properties[PROP_ID].c_str());
// For spinners, also trigger activation
if (w->getType() == WTYPE_SPINNER)
{
SpinnerWidget* spinner = dynamic_cast<SpinnerWidget*>(w);
spinner->activateSelectedButton();
}
if (w->m_event_handler != NULL)
{
/* Find all parents. Stop looping if a widget event handler's is itself, to not fall
@@ -802,7 +821,10 @@ EventPropagation EventHandler::onGUIEvent(const SEvent& event)
return EVENT_BLOCK;
}
w->onClick();
EventPropagation result = w->onClick();
if (result == EVENT_BLOCK)
return result;
// These events are only triggered by mouse (or so I hope)
// The player that owns the mouser receives "game master" priviledges

View File

@@ -24,6 +24,7 @@
#include "guiengine/engine.hpp"
#include "guiengine/scalable_font.hpp"
#include "guiengine/skin.hpp"
#include "modes/profile_world.hpp"
#include "utils/synchronised.hpp"
#include "utils/translation.hpp"
@@ -292,8 +293,12 @@ void updatePosition()
*/
void add(MessageType mt, const irr::core::stringw &message)
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
Message *m = new TextMessage(mt, message);
privateAdd(m);
#endif
} // add
// ----------------------------------------------------------------------------
@@ -305,6 +310,10 @@ void add(MessageType mt, const irr::core::stringw &message)
*/
void update(float dt)
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
if (!g_container)
g_container = new SkinWidgetContainer();
@@ -325,7 +334,7 @@ void update(float dt)
current->remove();
}
g_all_messages.unlock();
#endif
} // update
// ----------------------------------------------------------------------------
@@ -337,7 +346,12 @@ void update(float dt)
*/
void showProgressBar(int progress, const wchar_t* msg)
{
#ifndef SERVER_ONLY
if (ProfileWorld::isNoGraphics())
return;
g_progress_bar_msg.setProgress(progress, msg);
#endif
} // showProgressBar
} // namespace GUIEngine

View File

@@ -25,6 +25,7 @@
#include "guiengine/modaldialog.hpp"
#include "guiengine/widget.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "states_screens/state_manager.hpp"
#include <irrlicht.h>
@@ -90,7 +91,8 @@ Screen::~Screen()
*/
void Screen::init()
{
if(m_pause_race && World::getWorld())
if (m_pause_race && World::getWorld() &&
!NetworkConfig::get()->isNetworking())
World::getWorld()->schedulePause(World::IN_GAME_MENU_PHASE);
} // init
@@ -111,7 +113,8 @@ void Screen::push()
*/
void Screen::tearDown()
{
if(m_pause_race && World::getWorld())
if (m_pause_race && World::getWorld() &&
!NetworkConfig::get()->isNetworking())
World::getWorld()->scheduleUnpause();
} // tearDown

View File

@@ -1410,20 +1410,29 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget,
void Skin::drawSpinnerChild(const core::recti &rect, Widget* widget,
const bool pressed, bool focused)
{
if (!widget->isVisible()) return;
if (!widget->isVisible() || widget->m_deactivated) return;
if (!widget->m_deactivated && pressed)
int areas = 0;
bool right;
if (widget->m_properties[PROP_ID] == "left")
{
Widget* spinner = widget->m_event_handler;
int areas = 0;
areas = BoxRenderParams::LEFT;
right = false;
}
else if (widget->m_properties[PROP_ID] == "right")
{
areas = BoxRenderParams::RIGHT;
right = true;
}
else
return;
if (widget->m_properties[PROP_ID] == "left")
areas = BoxRenderParams::LEFT;
else if (widget->m_properties[PROP_ID] == "right")
areas = BoxRenderParams::RIGHT;
else
return;
SpinnerWidget* spinner = dynamic_cast<SpinnerWidget*>(widget->m_event_handler);
bool spinner_focused = spinner->isFocusedForPlayer(PLAYER_ID_GAME_MASTER);
if (pressed || (spinner->isRightButtonSelected() == right && spinner_focused))
{
core::recti rect2(spinner->m_x, spinner->m_y,
spinner->m_x + spinner->m_w,
spinner->m_y + spinner->m_h );
@@ -1434,7 +1443,7 @@ void Skin::drawSpinnerChild(const core::recti &rect, Widget* widget,
widget->m_deactivated);
}
}
} // drawSpinnerChild
// ----------------------------------------------------------------------------
/**

View File

@@ -674,7 +674,7 @@ namespace GUIEngine
bool ok() const { return (m_magic_number == 0xCAFEC001); }
/** Gets called when the widget is active and got clicked. (Only works for button widgets for now.) */
virtual void onClick() { }
virtual EventPropagation onClick() { return EVENT_LET; }
virtual irr::core::dimension2di getDimension() const { return irr::core::dimension2di(m_w, m_h); }
};

View File

@@ -120,6 +120,14 @@ CGUIEditBox::~CGUIEditBox()
dl->setIMEEnable(false);
}
#endif
#ifdef ANDROID
if (irr_driver->getDevice()->getType() == irr::EIDT_ANDROID)
{
CIrrDeviceAndroid* dl = dynamic_cast<CIrrDeviceAndroid*>(
irr_driver->getDevice());
dl->setTextInputEnabled(false);
}
#endif
#endif
}
@@ -268,11 +276,19 @@ bool CGUIEditBox::OnEvent(const SEvent& event)
irr_driver->getDevice());
dl->setIMEEnable(false);
}
#endif
#ifdef ANDROID
if (irr_driver->getDevice()->getType() == irr::EIDT_ANDROID)
{
CIrrDeviceAndroid* dl = dynamic_cast<CIrrDeviceAndroid*>(
irr_driver->getDevice());
dl->setTextInputEnabled(false);
}
#endif
}
#ifdef _IRR_COMPILE_WITH_X11_DEVICE_
else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
{
#ifdef _IRR_COMPILE_WITH_X11_DEVICE_
if (irr_driver->getDevice()->getType() == irr::EIDT_X11)
{
CIrrDeviceLinux* dl = dynamic_cast<CIrrDeviceLinux*>(
@@ -280,8 +296,16 @@ bool CGUIEditBox::OnEvent(const SEvent& event)
dl->setIMEEnable(true);
dl->setIMELocation(calculateICPos());
}
}
#endif
#ifdef ANDROID
if (irr_driver->getDevice()->getType() == irr::EIDT_ANDROID)
{
CIrrDeviceAndroid* dl = dynamic_cast<CIrrDeviceAndroid*>(
irr_driver->getDevice());
dl->setTextInputEnabled(true);
}
#endif
}
break;
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
case EET_IMPUT_METHOD_EVENT:

View File

@@ -572,7 +572,11 @@ void CGUISTKListBox::draw()
Items[i].m_contents[x].m_center, true, &clientClip);
}
//Position back to inital pos
textRect.UpperLeftCorner.X -= ItemsIconWidth+6;
if (IconBank && (Items[i].m_contents[x].m_icon > -1))
textRect.UpperLeftCorner.X -= ItemsIconWidth;
textRect.UpperLeftCorner.X -= 6;
//Calculate new beginning
textRect.UpperLeftCorner.X += Items[i].m_contents[x].m_proportion * part_size;
}
@@ -780,4 +784,3 @@ void CGUISTKListBox::setDrawBackground(bool draw)
} // end namespace gui
} // end namespace irr

View File

@@ -54,11 +54,11 @@ void ListWidget::setIcons(STKModifiedSpriteBank* icons, int size)
m_use_icons = (icons != NULL);
m_icons = icons;
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
if (m_use_icons)
{
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
list->setSpriteBank(m_icons);
// determine needed height
@@ -83,6 +83,10 @@ void ListWidget::setIcons(STKModifiedSpriteBank* icons, int size)
list->setItemHeight( item_height );
}
}
else
{
list->setSpriteBank(NULL);
}
}
@@ -145,7 +149,8 @@ void ListWidget::createHeader()
}
int x = m_x;
for (unsigned int n=0; n<m_header.size(); n++)
int scrollbar_width = GUIEngine::getSkin()->getSize(EGDS_SCROLLBAR_SIZE);
for (unsigned int n=0; n<m_header.size()+1; n++)
{
std::ostringstream name;
name << m_properties[PROP_ID];
@@ -160,12 +165,22 @@ void ListWidget::createHeader()
header->m_h = header_height;
header->m_x = x;
header->m_w = (int)(m_w * float(m_header[n].m_proportion)
/float(proportion_total));
if (n == m_header.size())
{
header->m_w = scrollbar_width;
header->setActive(false);
}
else
{
int header_width = m_w - scrollbar_width;
header->m_w = (int)(header_width * float(m_header[n].m_proportion)
/float(proportion_total));
}
x += header->m_w;
header->setText( m_header[n].m_text );
if (n < m_header.size())
header->setText( m_header[n].m_text );
header->m_properties[PROP_ID] = name.str();
header->add();

View File

@@ -112,10 +112,12 @@ void RatingBarWidget::setStepValuesByMouse(const core::position2di & mouse_posit
}
}
void RatingBarWidget::onClick()
EventPropagation RatingBarWidget::onClick()
{
if(m_allow_voting)
m_rating = m_hover_rating;
return EVENT_LET;
}

View File

@@ -73,7 +73,7 @@ namespace GUIEngine
void setStepValuesByMouse(const core::position2di & mouse_position, const core::recti & stars_rect);
virtual void onClick();
virtual EventPropagation onClick();
void allowVoting() { m_allow_voting = true; }
};

View File

@@ -779,6 +779,14 @@ EventPropagation RibbonWidget::mouseHovered(Widget* child,
return EVENT_BLOCK;
} // mouseHovered
EventPropagation RibbonWidget::onClick()
{
if (m_ribbon_type == RIBBON_TOOLBAR)
return EVENT_BLOCK;
return EVENT_LET;
}
// ----------------------------------------------------------------------------
const std::string& RibbonWidget::getSelectionIDString(const int playerID)
{

View File

@@ -92,6 +92,8 @@ namespace GUIEngine
virtual EventPropagation focused(const int playerID) OVERRIDE;
virtual void unfocused(const int playerID, Widget* new_focus) OVERRIDE;
virtual EventPropagation onClick() OVERRIDE;
PtrVector<irr::gui::IGUIStaticText, REF> m_labels;
IRibbonListener* m_listener;

View File

@@ -49,6 +49,7 @@ SpinnerWidget::SpinnerWidget(const bool gauge) : Widget(WTYPE_SPINNER)
m_spinner_widget_player_id=-1;
m_min = 0;
m_max = 999;
m_right_selected = false;
}
// -----------------------------------------------------------------------------
@@ -230,45 +231,65 @@ void SpinnerWidget::move(const int x, const int y, const int w, const int h)
EventPropagation SpinnerWidget::rightPressed(const int playerID)
{
//Log::info("SpinnerWidget", "Right pressed");
// if widget is deactivated, do nothing
if (m_deactivated) return EVENT_BLOCK;
//Log::info("SpinnerWidget", "Right pressed");
if (m_value+1 <= m_max)
{
setValue(m_value+1);
}
else if (m_wrap_around)
{
setValue(m_min);
}
// if right arrow is selected, let event handler move to next widget
if (m_right_selected)
return EVENT_BLOCK;
else
setSelectedButton(/* right*/ true);
//GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID );
return EVENT_LET;
}
return EVENT_BLOCK_BUT_HANDLED;
} // rightPressed
// -----------------------------------------------------------------------------
EventPropagation SpinnerWidget::leftPressed(const int playerID)
{
//Log::info("SpinnerWidget", "Left pressed");
// if widget is deactivated, do nothing
if (m_deactivated) return EVENT_BLOCK;
//Log::info("SpinnerWidget", "Left pressed");
if (m_value-1 >= m_min)
{
setValue(m_value-1);
}
else if (m_wrap_around)
{
setValue(m_max);
}
//GUIEngine::transmitEvent( this, m_properties[PROP_ID], playerID );
// if right arrow is selected, select left arrow
if (m_right_selected)
setSelectedButton(/* right*/ false);
// if left arrow is selected, let navigation move to next widget
else
return EVENT_BLOCK;
return EVENT_LET;
}
return EVENT_BLOCK_BUT_HANDLED;
} // leftPressed
void SpinnerWidget::activateSelectedButton()
{
if (m_right_selected)
{
if (m_value+1 <= m_max)
{
setValue(m_value+1);
}
else if (m_wrap_around)
{
setValue(m_min);
}
}
else // left button active
{
if (m_value-1 >= m_min)
{
setValue(m_value-1);
}
else if (m_wrap_around)
{
setValue(m_max);
}
}
} // activateSelectedButton
// -----------------------------------------------------------------------------
@@ -283,11 +304,13 @@ EventPropagation SpinnerWidget::transmitEvent(Widget* w,
if (originator == "left")
{
leftPressed(playerID);
m_right_selected = false;
activateSelectedButton();
}
else if (originator == "right")
{
rightPressed(playerID);
m_right_selected = true;
activateSelectedButton();
}
else if (originator == "spinnerbody" || originator == m_properties[PROP_ID])
{
@@ -434,13 +457,13 @@ void SpinnerWidget::setCustomText(const core::stringw& text)
// -----------------------------------------------------------------------------
void SpinnerWidget::onClick()
EventPropagation SpinnerWidget::onClick()
{
if (m_children[1].m_deactivated ||
m_children[1].m_properties[PROP_ID] != "spinnerbody" ||
!isGauge())
{
return;
return EVENT_LET;
}
const core::position2di mouse_position
@@ -464,6 +487,8 @@ void SpinnerWidget::onClick()
setValue(new_value);
}
return EVENT_LET;
}
// -----------------------------------------------------------------------------

View File

@@ -76,6 +76,9 @@ namespace GUIEngine
/** \brief Whether to wrap back to the first value when going "beyond" the last value */
bool m_wrap_around;
/** \brief Whether the right or left arrow is the currently selected one */
bool m_right_selected;
/** \brief Keeps track of the custom text in spinner (a text which isn't related to a value)
* to remember it and set it back (example : when we deactivate the widget)
*/
@@ -93,7 +96,7 @@ namespace GUIEngine
virtual EventPropagation leftPressed(const int playerID);
/** \brief implementing method from base class Widget */
virtual void onClick();
virtual EventPropagation onClick();
/** 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 */
@@ -124,6 +127,11 @@ namespace GUIEngine
int getSpinnerWidgetPlayerID() {return m_spinner_widget_player_id; }
void unsetUseBackgroundColor() {m_use_background_color=false; }
void activateSelectedButton();
void setSelectedButton(bool right) {m_right_selected = right; }
bool isRightButtonSelected() {return m_right_selected; }
void setListener(ISpinnerConfirmListener* listener) { m_listener = listener; }

View File

@@ -100,20 +100,6 @@ irr::core::stringw Binding::getAsString() const
switch(m_id)
{
#if defined(WIN32) || (defined(__linux__) && !defined(ANDROID))
// Windows codes certain special keys, which have atm no defined
// value in irr::IRR_KEY_*. So for now hardcode the values.
// FIXME: what happens with international keyboards? E.g. A [
// might be an Umlaut on a German keyboard. How do we get
// the character to display in this case??
case 186: s=";"; break;
case 191: s="/"; break;
case 192: s="`"; break;
case 219: s="["; break;
case 220: s="\\"; break;
case 221: s="]"; break;
case 222: s="'"; break;
#endif
//I18N: input configuration screen: mouse button
case irr::IRR_KEY_LBUTTON : s = _C("input_key", "Left Mouse Button"); break;
//I18N: input configuration screen: mouse button
@@ -327,6 +313,20 @@ irr::core::stringw Binding::getAsString() const
case irr::IRR_KEY_PA1 : s = _C("input_key", "Pa1"); break;
//I18N: input configuration screen: keyboard key
case irr::IRR_KEY_OEM_CLEAR : s = _C("input_key", "Oem Clear"); break;
//I18N: input configuration screen: keyboard key
case irr::IRR_KEY_OEM_1 : s = ";"; break;
//I18N: input configuration screen: keyboard key
case irr::IRR_KEY_OEM_2 : s = "/"; break;
//I18N: input configuration screen: keyboard key
case irr::IRR_KEY_OEM_3 : s = "`"; break;
//I18N: input configuration screen: keyboard key
case irr::IRR_KEY_OEM_4 : s = "["; break;
//I18N: input configuration screen: keyboard key
case irr::IRR_KEY_OEM_5 : s = "\\"; break;
//I18N: input configuration screen: keyboard key
case irr::IRR_KEY_OEM_6 : s = "]"; break;
//I18N: input configuration screen: keyboard key
case irr::IRR_KEY_OEM_7 : s = "'"; break;
// for azerty layout
case irr::IRR_KEY_AMPERSAND : s = "&"; break;

View File

@@ -396,7 +396,7 @@ void InputManager::handleStaticAction(int key, int value)
{
AbstractKart* kart = world->getLocalPlayerKart(0);
if(control_is_pressed && race_manager->getMinorMode()!=
RaceManager::MINOR_MODE_3_STRIKES)
RaceManager::MINOR_MODE_BATTLE)
kart->setPowerup(PowerupManager::POWERUP_RUBBERBALL,
10000);
else

View File

@@ -28,6 +28,8 @@
#ifdef ANDROID
#include <android/asset_manager.h>
#include <sys/statfs.h>
#include "../../../lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h"
#endif
//-----------------------------------------------------------------------------
@@ -49,6 +51,9 @@ void AssetsAndroid::init()
#ifdef ANDROID
if (m_file_manager == NULL)
return;
if (!global_android_app)
return;
bool needs_extract_data = false;
const std::string version = std::string("supertuxkart.") + STK_VERSION;
@@ -339,6 +344,9 @@ void AssetsAndroid::extractData()
bool AssetsAndroid::extractDir(std::string dir_name)
{
#ifdef ANDROID
if (!global_android_app)
return false;
AAssetManager* amgr = global_android_app->activity->assetManager;
Log::info("AssetsAndroid", "Extracting %s directory",
@@ -482,7 +490,7 @@ void AssetsAndroid::removeData()
if (file == m_stk_dir + "/.nomedia")
continue;
Log::info("AssetsAndroid", "Deleting file: %s\n", file.c_str());
Log::info("AssetsAndroid", "Deleting file: %s", file.c_str());
if (m_file_manager->isDirectory(file))
{
@@ -493,6 +501,20 @@ void AssetsAndroid::removeData()
m_file_manager->removeFile(file);
}
}
std::string data_path = getDataPath();
if (!data_path.empty())
{
const std::string child_path = data_path + "/files/libchildprocess.so";
if (m_file_manager->fileExists(child_path))
{
Log::info("AssetsAndroid", "Deleting old libchildprocess: %s",
child_path.c_str());
m_file_manager->removeFile(child_path);
}
}
#endif
}
@@ -581,3 +603,31 @@ std::string AssetsAndroid::getPreferredPath(const std::vector<std::string>&
}
//-----------------------------------------------------------------------------
/** Get a path for internal data directory
* \return Path for internal data directory or empty string when failed
*/
std::string AssetsAndroid::getDataPath()
{
#ifdef ANDROID
std::string data_path = "/data/data/" ANDROID_PACKAGE_NAME;
if (access(data_path.c_str(), R_OK) != 0)
{
Log::warn("AssetsAndroid", "Cannot use standard data dir");
AndroidApplicationInfo application_info =
CIrrDeviceAndroid::getApplicationInfo(global_android_app->activity);
data_path = application_info.data_dir;
}
if (access(data_path.c_str(), R_OK) != 0)
{
data_path = "";
}
return data_path;
#endif
return "";
}

View File

@@ -42,6 +42,7 @@ public:
~AssetsAndroid() {};
void init();
static std::string getDataPath();
};

View File

@@ -198,7 +198,8 @@ public:
void redirectOutput();
bool fileIsNewer(const std::string& f1, const std::string& f2) const;
// ------------------------------------------------------------------------
const std::string& getUserConfigDir() const { return m_user_config_dir; }
// ------------------------------------------------------------------------
/** Returns the irrlicht file system. */
irr::io::IFileSystem* getFileSystem() { return m_file_system; }

View File

@@ -98,27 +98,6 @@ public:
int getHPR(core::vector3df *value) const;
int getHPR(Vec3 *value) const;
template<typename T, typename U>
int get(std::map<T, U>* out_map) const
{
using namespace StringUtils;
for (auto& p : m_attributes)
{
T val_1;
if (!fromString(p.first, val_1))
{
return 0;
}
U val_2;
if (!fromString(wideToUtf8(p.second), val_2))
{
return 0;
}
(*out_map)[val_1] = val_2;
}
return (int)m_attributes.size();
}
bool hasChildNamed(const char* name) const;
/** Handy functions to test the bit pattern returned by get(vector3df*).*/

View File

@@ -35,7 +35,6 @@
#include "karts/controller/controller.hpp"
#include "karts/explosion_animation.hpp"
#include "karts/kart_properties.hpp"
#include "modes/three_strikes_battle.hpp"
#include "modes/world.hpp"
#include "network/rewind_manager.hpp"
#include "physics/triangle_mesh.hpp"
@@ -309,7 +308,7 @@ void Attachment::rewindTo(BareNetworkString *buffer)
if (m_type == new_type || m_type == ATTACH_NOTHING)
{
setTicksLeft(ticks_left);
if (m_type != new_type)
if (m_type != new_type && new_type != ATTACH_SWATTER)
m_type = new_type;
return;
}
@@ -343,10 +342,11 @@ void Attachment::hitBanana(ItemState *item_state)
bool add_a_new_item = true;
if (dynamic_cast<ThreeStrikesBattle*>(World::getWorld()) != NULL)
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_BATTLE)
{
World::getWorld()->kartHit(m_kart->getWorldKartId());
ExplosionAnimation::create(m_kart);
if (m_kart->getKartAnimation() == NULL)
ExplosionAnimation::create(m_kart);
return;
}
@@ -607,7 +607,8 @@ void Attachment::update(int ticks)
m_bubble_explode_sound->play();
}
ItemManager::get()->dropNewItem(Item::ITEM_BUBBLEGUM, m_kart);
if (!m_kart->isGhostKart())
ItemManager::get()->dropNewItem(Item::ITEM_BUBBLEGUM, m_kart);
}
break;
} // switch

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