Merge branch 'master' of https://github.com/supertuxkart/stk-code
Conflicts: data/achievements.xml
11
.travis.yml
@ -6,9 +6,7 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
#- clang
|
||||
git:
|
||||
submodules: false
|
||||
# - clang
|
||||
#branches:
|
||||
# only:
|
||||
# - master
|
||||
@ -16,10 +14,13 @@ before_install:
|
||||
# UPDATE REPOS
|
||||
- sudo apt-get update -qq
|
||||
# INSTALL DEPENDENCIES
|
||||
- sudo apt-get install autoconf automake build-essential cmake libogg-dev libvorbis-dev libopenal-dev libxxf86vm-dev libgl1-mesa-dev libglu1-mesa-dev libcurl4-openssl-dev libfribidi-dev libbluetooth-dev
|
||||
- sudo apt-get install build-essential cmake libogg-dev libvorbis-dev libopenal-dev libxxf86vm-dev libgl1-mesa-dev libglu1-mesa-dev libcurl4-openssl-dev libfribidi-dev libbluetooth-dev
|
||||
script:
|
||||
# BUILD COMMANDS
|
||||
- ./tools/build-linux-travis.sh
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake .. -DCMAKE_BUILD_TYPE=Debug
|
||||
- make VERBOSE=1 -j 4
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
|
@ -3,7 +3,7 @@ project(SuperTuxKart)
|
||||
set(PROJECT_VERSION "0.8.1")
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.1)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
|
||||
|
||||
include(BuildTypeSTKRelease)
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
|
BIN
data/CREDITS
@ -29,4 +29,19 @@
|
||||
title="Skid-row" description="Make 5 skidding in a single lap">
|
||||
<skidding goal="5"/>
|
||||
</achievement>
|
||||
<achievement id="6" check-type="all-at-least" reset-type="never"
|
||||
title="Gold driver" description="Win in all single player modes, against at least 3 opponents.">
|
||||
<standard goal="1"/>
|
||||
<std_timetrial goal="1"/>
|
||||
<follow_leader goal="1"/>
|
||||
<opponents goal="3"/>
|
||||
</achievement>
|
||||
<achievement id="7" check-type="all-at-least" reset-type="race"
|
||||
title="Powerup Love" description="Use 10 or more powerups in a race">
|
||||
<poweruplover goal="10"/>
|
||||
</achievement>
|
||||
<achievement id="8" check-type="all-at-least" reset-type="never"
|
||||
title="Unstoppable" description="Win 5 single races in a row">
|
||||
<wins goal="5"/>
|
||||
</achievement>
|
||||
</achievements>
|
BIN
data/gui/down.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
54
data/gui/edit_track.stkgui
Normal file
@ -0,0 +1,54 @@
|
||||
<stkgui>
|
||||
|
||||
<div x="2%" y="1%" width="96%" height="98%" layout="vertical-row" padding="10">
|
||||
|
||||
<header id="selected_track" width="80%" height="30"
|
||||
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>
|
||||
|
||||
<!-- Populated dynamically at runtime -->
|
||||
<tabs width="100%" height="30" id="trackgroups"> </tabs>
|
||||
|
||||
<spacer height="50" />
|
||||
|
||||
<!-- Laps and reverse -->
|
||||
<div width="100%" height="100" layout="horizontal-row" align="center">
|
||||
|
||||
<spacer proportion="1" />
|
||||
|
||||
<label id="laps_label" text_align="left"
|
||||
I18N="In the edit track screen" text="Number of laps:" />
|
||||
<spacer width="20" />
|
||||
<spinner id="laps" proportion="1" width="100" min_value="1"
|
||||
max_value="99" wrap_around="false" />
|
||||
|
||||
<spacer proportion="1" />
|
||||
|
||||
<label id="reverse_label" text_align="left"
|
||||
I18N="In the edit track screen" text="Reverse:" />
|
||||
<spacer width="20" />
|
||||
<checkbox id="reverse" />
|
||||
|
||||
<spacer proportion="1" />
|
||||
</div>
|
||||
|
||||
<!-- Dialog buttons -->
|
||||
<div width="100%" height="60" layout="horizontal-row">
|
||||
<spacer proportion="2" />
|
||||
<button id="ok" text="OK" proportion="1" />
|
||||
<spacer proportion="1" />
|
||||
<button id="cancel" text="Cancel" proportion="1" />
|
||||
<spacer proportion="2" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</stkgui>
|
21
data/gui/enter_gp_name_dialog.stkgui
Normal file
@ -0,0 +1,21 @@
|
||||
<stkgui>
|
||||
|
||||
<div x="2%" y="10%" width="96%" height="80%" layout="vertical-row" >
|
||||
|
||||
<label id="title" width="100%" text_align="center" word_wrap="true"
|
||||
I18N="In the 'add new grand prix' dialog"
|
||||
text="Please enter the name of the grand prix" proportion="1" />
|
||||
|
||||
<spacer height="25" width="10" />
|
||||
|
||||
<textbox id="textfield" width="75%" I18N="In the 'add new grand prix' dialog" align="center"/>
|
||||
|
||||
<spacer height="20" width="20" />
|
||||
|
||||
<button id="cancel" I18N="When configuring input" text="Press ESC to cancel" align="center"/>
|
||||
|
||||
<spacer height="15" width="20" />
|
||||
|
||||
</div>
|
||||
|
||||
</stkgui>
|
BIN
data/gui/gp_add_track.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
data/gui/gp_copy.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
data/gui/gp_edit.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
data/gui/gp_edit_track.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
data/gui/gp_new.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
data/gui/gp_remove.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
data/gui/gp_remove_track.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
data/gui/gp_rename.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
data/gui/gp_save.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
35
data/gui/gpedit.stkgui
Normal file
@ -0,0 +1,35 @@
|
||||
<stkgui>
|
||||
|
||||
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png" />
|
||||
|
||||
<div x="2%" y="1%" width="96%" height="98%" layout="vertical-row">
|
||||
|
||||
<header id="title" width="80%" I18N="Title in edit grand prix screen"
|
||||
text="Edit Grand Prix" align="center" text_align="center" />
|
||||
|
||||
<spacer width="100%" height="2%" />
|
||||
|
||||
<box proportion="5" width="98%" align="center" layout="vertical-row" padding="6">
|
||||
<list id="tracks" x="0" y="0" width="100%" height="100%" keep_selection="true" />
|
||||
</box>
|
||||
|
||||
<spacer width="100%" height="2%" />
|
||||
|
||||
<buttonbar proportion="1" id="menu" height="135" width="100%" align="center">
|
||||
<icon-button id="up" width="128" height="128" icon="gui/up.png"
|
||||
I18N="Menu item" text="Move up" />
|
||||
<icon-button id="down" width="128" height="128" icon="gui/down.png"
|
||||
I18N="Menu item" text="Move down" />
|
||||
<icon-button id="add" width="128" height="128" icon="gui/gp_add_track.png"
|
||||
I18N="Menu item" text="Add" />
|
||||
<icon-button id="edit" width="128" height="128" icon="gui/gp_edit_track.png"
|
||||
I18N="Menu item" text="Edit" />
|
||||
<icon-button id="remove" width="128" height="128" icon="gui/gp_remove_track.png"
|
||||
I18N="Menu item" text="Remove" />
|
||||
<icon-button id="save" width="128" height="128" icon="gui/gp_save.png"
|
||||
I18N="Menu item" text="Save" />
|
||||
</buttonbar>
|
||||
|
||||
</div>
|
||||
|
||||
</stkgui>
|
45
data/gui/gpeditor.stkgui
Normal file
@ -0,0 +1,45 @@
|
||||
<stkgui>
|
||||
|
||||
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
|
||||
|
||||
<div x="2%" y="1%" width="96%" height="98%" layout="vertical-row" >
|
||||
|
||||
<header width="80%" I18N="Title in grand prix editor screen" text="Grand Prix editor"
|
||||
align="center" text_align="center" />
|
||||
|
||||
<spacer height="20" />
|
||||
|
||||
<box proportion="4" 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" />
|
||||
</box>
|
||||
|
||||
<spacer height="10" />
|
||||
|
||||
<box proportion="2" width="100%" layout="vertical-row">
|
||||
<label id="gpname" text_align="center" width="100%"
|
||||
I18N="In the grand prix editor screen" text="" />
|
||||
<ribbon_grid id="tracks" proportion="1" width="100%" square_items="true"
|
||||
label_location="each" align="left" max_rows="1"
|
||||
child_width="160" child_height="120" />
|
||||
</box>
|
||||
|
||||
<spacer height="20" />
|
||||
|
||||
<buttonbar proportion="1" 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"
|
||||
I18N="Menu item" text="Copy" />
|
||||
<icon-button id="edit" width="128" height="128" icon="gui/gp_edit.png"
|
||||
I18N="Menu item" text="Edit" />
|
||||
<icon-button id="remove" width="128" height="128" icon="gui/gp_remove.png"
|
||||
I18N="Menu item" text="Remove" />
|
||||
<icon-button id="rename" width="128" height="128" icon="gui/gp_rename.png"
|
||||
I18N="Menu item" text="Rename" />
|
||||
</buttonbar>
|
||||
|
||||
</div>
|
||||
|
||||
</stkgui>
|
@ -35,13 +35,15 @@
|
||||
|
||||
<spacer width="10" height="10" />
|
||||
|
||||
<buttonbar id="menu_bottomrow" x="0" y="0" width="30%" height="100%" align="center">
|
||||
<buttonbar id="menu_bottomrow" x="0" y="0" width="38%" height="100%" align="center">
|
||||
<icon-button id="options" width="64" height="64" icon="gui/main_options.png" extend_label="50"
|
||||
I18N="Main menu button" text="Options" label_location="hover"/>
|
||||
<icon-button id="help" width="64" height="64" icon="gui/main_help.png" extend_label="50"
|
||||
I18N="Main menu button" text="Help" label_location="hover"/>
|
||||
<icon-button id="startTutorial" width="64" height="64" icon="gui/tutorial.png" extend_label="150"
|
||||
I18N="Main menu button" text="Tutorial" label_location="hover"/>
|
||||
<icon-button id="gpEditor" width="64" height="64" icon="gui/gpeditor.png" extend_label="150"
|
||||
I18N="Main menu button" text="Grand Prix Editor" label_location="hover"/>
|
||||
<icon-button id="about" width="64" height="64" icon="gui/main_about.png" extend_label="50"
|
||||
I18N="Main menu button" text="About" label_location="hover"/>
|
||||
<icon-button id="quit" width="64" height="64" icon="gui/main_quit.png" extend_label="50"
|
||||
|
BIN
data/gui/up.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
@ -2,6 +2,7 @@ uniform sampler2D tex;
|
||||
|
||||
#if __VERSION__ >= 130
|
||||
in vec2 uv;
|
||||
in vec4 color;
|
||||
out vec4 FragColor;
|
||||
#else
|
||||
varying vec2 uv;
|
||||
@ -11,5 +12,5 @@ varying vec2 uv;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = texture(tex, uv);
|
||||
FragColor = texture(tex, uv) * color;
|
||||
}
|
||||
|
@ -4,7 +4,9 @@ uniform mat4 TextureMatrix;
|
||||
#if __VERSION__ >= 130
|
||||
in vec3 Position;
|
||||
in vec2 Texcoord;
|
||||
in vec4 Color;
|
||||
out vec2 uv;
|
||||
out vec4 color;
|
||||
#else
|
||||
attribute vec3 Position;
|
||||
attribute vec2 Texcoord;
|
||||
@ -16,4 +18,5 @@ void main()
|
||||
{
|
||||
uv = (TextureMatrix * vec4(Texcoord, 1., 1.)).xy;
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(Position, 1.);
|
||||
color = Color;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ uniform vec2 screen;
|
||||
|
||||
#if __VERSION__ >= 130
|
||||
in vec2 uv;
|
||||
in vec4 color;
|
||||
out vec4 FragColor;
|
||||
#else
|
||||
varying vec2 uv;
|
||||
@ -20,7 +21,7 @@ varying vec2 uv;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture(tex, uv);
|
||||
vec4 diffusecolor = texture(tex, uv) * color;
|
||||
vec3 tmp = vec3(gl_FragCoord.xy / screen, gl_FragCoord.z);
|
||||
tmp = 2. * tmp - 1.;
|
||||
|
||||
@ -33,5 +34,5 @@ void main()
|
||||
|
||||
fog = min(fog, fogmax);
|
||||
|
||||
FragColor = vec4(vec4(col, 0.) * fog + color *(1. - fog));
|
||||
FragColor = vec4(vec4(col, 0.) * fog + diffusecolor *(1. - fog));
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
# CMakeLists.txt for Irrlicht in STK
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/jpeglib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/libpng
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/zlib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/bzip2)
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/jpeglib"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/libpng"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/zlib"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/bzip2")
|
||||
|
||||
if(APPLE)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/MacOSX ${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht)
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht/MacOSX" "${CMAKE_CURRENT_SOURCE_DIR}/source/Irrlicht")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch i386")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch i386 -F/Library/Frameworks")
|
||||
endif()
|
||||
|
@ -2,6 +2,16 @@
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.1)
|
||||
|
||||
# libbluetooth is required on Unix platforms
|
||||
if(UNIX)
|
||||
include(FindPkgConfig)
|
||||
pkg_check_modules(BLUETOOTH bluez)
|
||||
if(NOT BLUETOOTH_FOUND)
|
||||
message(FATAL_ERROR "Bluetooth library not found. "
|
||||
"Either install libbluetooth or disable wiiuse support with -DUSE_WIIUSE=0")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(WIIUSE_SOURCES
|
||||
classic.c
|
||||
dynamics.c
|
||||
|
@ -227,6 +227,7 @@ src/states_screens/dialogs/addons_loading.cpp
|
||||
src/states_screens/dialogs/change_password_dialog.cpp
|
||||
src/states_screens/dialogs/confirm_resolution_dialog.cpp
|
||||
src/states_screens/dialogs/custom_video_settings.cpp
|
||||
src/states_screens/dialogs/enter_gp_name_dialog.cpp
|
||||
src/states_screens/dialogs/enter_player_name_dialog.cpp
|
||||
src/states_screens/dialogs/gp_info_dialog.cpp
|
||||
src/states_screens/dialogs/message_dialog.cpp
|
||||
@ -243,7 +244,10 @@ src/states_screens/dialogs/tutorial_message_dialog.cpp
|
||||
src/states_screens/dialogs/user_info_dialog.cpp
|
||||
src/states_screens/dialogs/vote_dialog.cpp
|
||||
src/states_screens/easter_egg_screen.cpp
|
||||
src/states_screens/edit_gp_screen.cpp
|
||||
src/states_screens/edit_track_screen.cpp
|
||||
src/states_screens/feature_unlocked.cpp
|
||||
src/states_screens/grand_prix_editor_screen.cpp
|
||||
src/states_screens/grand_prix_lose.cpp
|
||||
src/states_screens/grand_prix_win.cpp
|
||||
src/states_screens/guest_login_screen.cpp
|
||||
@ -563,6 +567,7 @@ src/states_screens/dialogs/addons_loading.hpp
|
||||
src/states_screens/dialogs/change_password_dialog.hpp
|
||||
src/states_screens/dialogs/confirm_resolution_dialog.hpp
|
||||
src/states_screens/dialogs/custom_video_settings.hpp
|
||||
src/states_screens/dialogs/enter_gp_name_dialog.hpp
|
||||
src/states_screens/dialogs/enter_player_name_dialog.hpp
|
||||
src/states_screens/dialogs/gp_info_dialog.hpp
|
||||
src/states_screens/dialogs/message_dialog.hpp
|
||||
@ -579,7 +584,10 @@ src/states_screens/dialogs/tutorial_message_dialog.hpp
|
||||
src/states_screens/dialogs/user_info_dialog.hpp
|
||||
src/states_screens/dialogs/vote_dialog.hpp
|
||||
src/states_screens/easter_egg_screen.hpp
|
||||
src/states_screens/edit_gp_screen.hpp
|
||||
src/states_screens/edit_track_screen.hpp
|
||||
src/states_screens/feature_unlocked.hpp
|
||||
src/states_screens/grand_prix_editor_screen.hpp
|
||||
src/states_screens/grand_prix_lose.hpp
|
||||
src/states_screens/grand_prix_win.hpp
|
||||
src/states_screens/guest_login_screen.hpp
|
||||
|
@ -36,18 +36,21 @@ class Achievement;
|
||||
/** This is the base class for storing the definition of an achievement, e.g.
|
||||
* title, description (which is common for all achievements), but also how
|
||||
* to achieve this achievement.
|
||||
* \ingroup achievements
|
||||
*/
|
||||
* \ingroup achievements
|
||||
*/
|
||||
class AchievementInfo
|
||||
{
|
||||
public:
|
||||
/** Some handy names for the various achievements. */
|
||||
enum { ACHIEVE_COLUMBUS = 1,
|
||||
ACHIEVE_FIRST = ACHIEVE_COLUMBUS,
|
||||
ACHIEVE_STRIKE = 2,
|
||||
ACHIEVE_ARCH_ENEMY = 3,
|
||||
ACHIEVE_MARATHONER = 4,
|
||||
ACHIEVE_SKIDDING = 5
|
||||
enum { ACHIEVE_COLUMBUS = 1,
|
||||
ACHIEVE_FIRST = ACHIEVE_COLUMBUS,
|
||||
ACHIEVE_STRIKE = 2,
|
||||
ACHIEVE_ARCH_ENEMY = 3,
|
||||
ACHIEVE_MARATHONER = 4,
|
||||
ACHIEVE_SKIDDING = 5,
|
||||
ACHIEVE_GOLD_DRIVER = 6,
|
||||
ACHIEVE_POWERUP_LOVER = 7,
|
||||
ACHIEVE_UNSTOPPABLE = 8
|
||||
};
|
||||
/** Achievement check type:
|
||||
* ALL_AT_LEAST: All goal values must be reached (or exceeded).
|
||||
|
@ -314,16 +314,6 @@ SFXBase* SFXManager::createSoundSource(SFXBuffer* buffer,
|
||||
return sfx;
|
||||
} // createSoundSource
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void SFXManager::dump()
|
||||
{
|
||||
for(int n=0; n<(int)m_all_sfx.size(); n++)
|
||||
{
|
||||
Log::debug("SFXManager", "Sound %i : %s \n", n, m_all_sfx[n]->getBuffer()->getFileName().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
SFXBase* SFXManager::createSoundSource(const std::string &name,
|
||||
const bool addToSFXList)
|
||||
|
@ -64,8 +64,10 @@ PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
||||
static bool is_gl_init = false;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef WIN32
|
||||
#define ARB_DEBUG_OUTPUT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ARB_DEBUG_OUTPUT
|
||||
static void
|
||||
@ -200,7 +202,7 @@ void initGL()
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ARB_DEBUG_OUTPUT
|
||||
glDebugMessageCallbackARB((GLDEBUGPROCARB)debugCallback, NULL);
|
||||
glDebugMessageCallbackARB((GLDEBUGPROCARB)debugCallback, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -743,50 +743,11 @@ void IrrDriver::renderGlow(video::SOverrideMaterial &overridemat,
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#define MAXLIGHT 16 // to be adjusted in pointlight.frag too
|
||||
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN2(a, b) ((a) > (b) ? (b) : (a))
|
||||
static LightShader::PointLightInfo PointLightsInfo[MAXLIGHT];
|
||||
|
||||
|
||||
static GLuint pointlightvbo = 0;
|
||||
static GLuint pointlightsvao = 0;
|
||||
|
||||
struct PointLightInfo
|
||||
{
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
float energy;
|
||||
float red;
|
||||
float green;
|
||||
float blue;
|
||||
float padding;
|
||||
};
|
||||
|
||||
void createPointLightVAO()
|
||||
{
|
||||
glGenVertexArrays(1, &pointlightsvao);
|
||||
glBindVertexArray(pointlightsvao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, SharedObject::billboardvbo);
|
||||
glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Corner);
|
||||
glVertexAttribPointer(MeshShader::PointLightShader::attrib_Corner, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
||||
|
||||
glGenBuffers(1, &pointlightvbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, pointlightvbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, MAXLIGHT * sizeof(PointLightInfo), 0, GL_DYNAMIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Position);
|
||||
glVertexAttribPointer(MeshShader::PointLightShader::attrib_Position, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), 0);
|
||||
glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Energy);
|
||||
glVertexAttribPointer(MeshShader::PointLightShader::attrib_Energy, 1, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(3 * sizeof(float)));
|
||||
glEnableVertexAttribArray(MeshShader::PointLightShader::attrib_Color);
|
||||
glVertexAttribPointer(MeshShader::PointLightShader::attrib_Color, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(4 * sizeof(float)));
|
||||
|
||||
glVertexAttribDivisor(MeshShader::PointLightShader::attrib_Position, 1);
|
||||
glVertexAttribDivisor(MeshShader::PointLightShader::attrib_Energy, 1);
|
||||
glVertexAttribDivisor(MeshShader::PointLightShader::attrib_Color, 1);
|
||||
}
|
||||
|
||||
static void renderPointLights()
|
||||
static void renderPointLights(unsigned count)
|
||||
{
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
@ -794,23 +755,18 @@ static void renderPointLights()
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glUseProgram(MeshShader::PointLightShader::Program);
|
||||
glBindVertexArray(pointlightsvao);
|
||||
glUseProgram(LightShader::PointLightShader::Program);
|
||||
glBindVertexArray(LightShader::PointLightShader::vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, LightShader::PointLightShader::vbo);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(LightShader::PointLightInfo), PointLightsInfo);
|
||||
|
||||
setTexture(0, getTextureGLuint(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST);
|
||||
setTexture(1, getDepthTexture(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST);
|
||||
MeshShader::PointLightShader::setUniforms(irr_driver->getViewMatrix(), irr_driver->getProjMatrix(), irr_driver->getInvProjMatrix(), core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height), 200, 0, 1);
|
||||
LightShader::PointLightShader::setUniforms(irr_driver->getViewMatrix(), irr_driver->getProjMatrix(), irr_driver->getInvProjMatrix(), core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height), 200, 0, 1);
|
||||
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, MAXLIGHT);
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, count);
|
||||
}
|
||||
|
||||
PointLightInfo PointLightsInfo[MAXLIGHT];
|
||||
|
||||
void IrrDriver::renderLights(const core::aabbox3df& cambox,
|
||||
scene::ICameraSceneNode * const camnode,
|
||||
video::SOverrideMaterial &overridemat,
|
||||
@ -848,7 +804,7 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox,
|
||||
const core::vector3df &lightpos = (m_lights[i]->getAbsolutePosition() - campos);
|
||||
unsigned idx = (unsigned)(lightpos.getLength() / 10);
|
||||
if (idx > 14)
|
||||
continue;
|
||||
idx = 14;
|
||||
BucketedLN[idx].push_back(m_lights[i]);
|
||||
}
|
||||
|
||||
@ -895,17 +851,7 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox,
|
||||
|
||||
lightnum++;
|
||||
|
||||
// Fill lights
|
||||
for (; lightnum < MAXLIGHT; lightnum++) {
|
||||
PointLightsInfo[lightnum].energy = 0;
|
||||
}
|
||||
|
||||
if (!pointlightsvao)
|
||||
createPointLightVAO();
|
||||
glBindVertexArray(pointlightsvao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, pointlightvbo);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, MAXLIGHT * sizeof(PointLightInfo), PointLightsInfo);
|
||||
renderPointLights();
|
||||
renderPointLights(MIN2(lightnum, MAXLIGHT));
|
||||
if (SkyboxCubeMap)
|
||||
m_post_processing->renderDiffuseEnvMap(blueSHCoeff, greenSHCoeff, redSHCoeff);
|
||||
// Handle SSAO
|
||||
@ -992,9 +938,6 @@ static void createcubevao()
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * 6 * sizeof(int), indices, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN2(a, b) ((a) > (b) ? (b) : (a))
|
||||
|
||||
static void getXYZ(GLenum face, float i, float j, float &x, float &y, float &z)
|
||||
{
|
||||
switch (face)
|
||||
|
@ -270,7 +270,7 @@ void Shaders::loadShaders()
|
||||
MeshShader::TransparentShader::init();
|
||||
MeshShader::TransparentFogShader::init();
|
||||
MeshShader::BillboardShader::init();
|
||||
MeshShader::PointLightShader::init();
|
||||
LightShader::PointLightShader::init();
|
||||
MeshShader::DisplaceShader::init();
|
||||
MeshShader::DisplaceMaskShader::init();
|
||||
MeshShader::ShadowShader::init();
|
||||
@ -873,6 +873,7 @@ namespace MeshShader
|
||||
GLuint TransparentShader::Program;
|
||||
GLuint TransparentShader::attrib_position;
|
||||
GLuint TransparentShader::attrib_texcoord;
|
||||
GLuint TransparentShader::attrib_color;
|
||||
GLuint TransparentShader::uniform_MVP;
|
||||
GLuint TransparentShader::uniform_TM;
|
||||
GLuint TransparentShader::uniform_tex;
|
||||
@ -882,6 +883,7 @@ namespace MeshShader
|
||||
Program = LoadProgram(file_manager->getAsset("shaders/transparent.vert").c_str(), file_manager->getAsset("shaders/transparent.frag").c_str());
|
||||
attrib_position = glGetAttribLocation(Program, "Position");
|
||||
attrib_texcoord = glGetAttribLocation(Program, "Texcoord");
|
||||
attrib_color = glGetAttribLocation(Program, "Color");
|
||||
uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix");
|
||||
uniform_TM = glGetUniformLocation(Program, "TextureMatrix");
|
||||
uniform_tex = glGetUniformLocation(Program, "tex");
|
||||
@ -897,6 +899,7 @@ namespace MeshShader
|
||||
GLuint TransparentFogShader::Program;
|
||||
GLuint TransparentFogShader::attrib_position;
|
||||
GLuint TransparentFogShader::attrib_texcoord;
|
||||
GLuint TransparentFogShader::attrib_color;
|
||||
GLuint TransparentFogShader::uniform_MVP;
|
||||
GLuint TransparentFogShader::uniform_TM;
|
||||
GLuint TransparentFogShader::uniform_tex;
|
||||
@ -914,6 +917,7 @@ namespace MeshShader
|
||||
Program = LoadProgram(file_manager->getAsset("shaders/transparent.vert").c_str(), file_manager->getAsset("shaders/transparentfog.frag").c_str());
|
||||
attrib_position = glGetAttribLocation(Program, "Position");
|
||||
attrib_texcoord = glGetAttribLocation(Program, "Texcoord");
|
||||
attrib_color = glGetAttribLocation(Program, "Color");
|
||||
uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix");
|
||||
uniform_TM = glGetUniformLocation(Program, "TextureMatrix");
|
||||
uniform_tex = glGetUniformLocation(Program, "tex");
|
||||
@ -942,47 +946,6 @@ namespace MeshShader
|
||||
glUniform1i(uniform_tex, TU_tex);
|
||||
}
|
||||
|
||||
GLuint PointLightShader::Program;
|
||||
GLuint PointLightShader::attrib_Position;
|
||||
GLuint PointLightShader::attrib_Color;
|
||||
GLuint PointLightShader::attrib_Energy;
|
||||
GLuint PointLightShader::attrib_Corner;
|
||||
GLuint PointLightShader::uniform_ntex;
|
||||
GLuint PointLightShader::uniform_dtex;
|
||||
GLuint PointLightShader::uniform_spec;
|
||||
GLuint PointLightShader::uniform_screen;
|
||||
GLuint PointLightShader::uniform_invproj;
|
||||
GLuint PointLightShader::uniform_VM;
|
||||
GLuint PointLightShader::uniform_PM;
|
||||
|
||||
void PointLightShader::init()
|
||||
{
|
||||
Program = LoadProgram(file_manager->getAsset("shaders/pointlight.vert").c_str(), file_manager->getAsset("shaders/pointlight.frag").c_str());
|
||||
attrib_Position = glGetAttribLocation(Program, "Position");
|
||||
attrib_Color = glGetAttribLocation(Program, "Color");
|
||||
attrib_Energy = glGetAttribLocation(Program, "Energy");
|
||||
attrib_Corner = glGetAttribLocation(Program, "Corner");
|
||||
uniform_ntex = glGetUniformLocation(Program, "ntex");
|
||||
uniform_dtex = glGetUniformLocation(Program, "dtex");
|
||||
uniform_spec = glGetUniformLocation(Program, "spec");
|
||||
uniform_invproj = glGetUniformLocation(Program, "invproj");
|
||||
uniform_screen = glGetUniformLocation(Program, "screen");
|
||||
uniform_VM = glGetUniformLocation(Program, "ViewMatrix");
|
||||
uniform_PM = glGetUniformLocation(Program, "ProjectionMatrix");
|
||||
}
|
||||
|
||||
void PointLightShader::setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 &InvProjMatrix, const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex)
|
||||
{
|
||||
glUniform1f(uniform_spec, 200);
|
||||
glUniform2f(uniform_screen, screen.X, screen.Y);
|
||||
glUniformMatrix4fv(uniform_invproj, 1, GL_FALSE, InvProjMatrix.pointer());
|
||||
glUniformMatrix4fv(uniform_VM, 1, GL_FALSE, ViewMatrix.pointer());
|
||||
glUniformMatrix4fv(uniform_PM, 1, GL_FALSE, ProjMatrix.pointer());
|
||||
|
||||
glUniform1i(uniform_ntex, TU_ntex);
|
||||
glUniform1i(uniform_dtex, TU_dtex);
|
||||
}
|
||||
|
||||
GLuint BillboardShader::Program;
|
||||
GLuint BillboardShader::attrib_corner;
|
||||
GLuint BillboardShader::attrib_texcoord;
|
||||
@ -1190,6 +1153,76 @@ namespace MeshShader
|
||||
}
|
||||
}
|
||||
|
||||
namespace LightShader
|
||||
{
|
||||
|
||||
GLuint PointLightShader::Program;
|
||||
GLuint PointLightShader::attrib_Position;
|
||||
GLuint PointLightShader::attrib_Color;
|
||||
GLuint PointLightShader::attrib_Energy;
|
||||
GLuint PointLightShader::attrib_Corner;
|
||||
GLuint PointLightShader::uniform_ntex;
|
||||
GLuint PointLightShader::uniform_dtex;
|
||||
GLuint PointLightShader::uniform_spec;
|
||||
GLuint PointLightShader::uniform_screen;
|
||||
GLuint PointLightShader::uniform_invproj;
|
||||
GLuint PointLightShader::uniform_VM;
|
||||
GLuint PointLightShader::uniform_PM;
|
||||
GLuint PointLightShader::vbo;
|
||||
GLuint PointLightShader::vao;
|
||||
|
||||
void PointLightShader::init()
|
||||
{
|
||||
Program = LoadProgram(file_manager->getAsset("shaders/pointlight.vert").c_str(), file_manager->getAsset("shaders/pointlight.frag").c_str());
|
||||
attrib_Position = glGetAttribLocation(Program, "Position");
|
||||
attrib_Color = glGetAttribLocation(Program, "Color");
|
||||
attrib_Energy = glGetAttribLocation(Program, "Energy");
|
||||
attrib_Corner = glGetAttribLocation(Program, "Corner");
|
||||
uniform_ntex = glGetUniformLocation(Program, "ntex");
|
||||
uniform_dtex = glGetUniformLocation(Program, "dtex");
|
||||
uniform_spec = glGetUniformLocation(Program, "spec");
|
||||
uniform_invproj = glGetUniformLocation(Program, "invproj");
|
||||
uniform_screen = glGetUniformLocation(Program, "screen");
|
||||
uniform_VM = glGetUniformLocation(Program, "ViewMatrix");
|
||||
uniform_PM = glGetUniformLocation(Program, "ProjectionMatrix");
|
||||
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, SharedObject::billboardvbo);
|
||||
glEnableVertexAttribArray(attrib_Corner);
|
||||
glVertexAttribPointer(attrib_Corner, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
||||
|
||||
glGenBuffers(1, &vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, MAXLIGHT * sizeof(PointLightInfo), 0, GL_DYNAMIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(attrib_Position);
|
||||
glVertexAttribPointer(attrib_Position, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), 0);
|
||||
glEnableVertexAttribArray(attrib_Energy);
|
||||
glVertexAttribPointer(attrib_Energy, 1, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(3 * sizeof(float)));
|
||||
glEnableVertexAttribArray(attrib_Color);
|
||||
glVertexAttribPointer(attrib_Color, 3, GL_FLOAT, GL_FALSE, sizeof(PointLightInfo), (GLvoid*)(4 * sizeof(float)));
|
||||
|
||||
glVertexAttribDivisor(attrib_Position, 1);
|
||||
glVertexAttribDivisor(attrib_Energy, 1);
|
||||
glVertexAttribDivisor(attrib_Color, 1);
|
||||
}
|
||||
|
||||
void PointLightShader::setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 &InvProjMatrix, const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex)
|
||||
{
|
||||
glUniform1f(uniform_spec, 200);
|
||||
glUniform2f(uniform_screen, screen.X, screen.Y);
|
||||
glUniformMatrix4fv(uniform_invproj, 1, GL_FALSE, InvProjMatrix.pointer());
|
||||
glUniformMatrix4fv(uniform_VM, 1, GL_FALSE, ViewMatrix.pointer());
|
||||
glUniformMatrix4fv(uniform_PM, 1, GL_FALSE, ProjMatrix.pointer());
|
||||
|
||||
glUniform1i(uniform_ntex, TU_ntex);
|
||||
glUniform1i(uniform_dtex, TU_dtex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace ParticleShader
|
||||
{
|
||||
|
@ -210,7 +210,7 @@ class TransparentShader
|
||||
{
|
||||
public:
|
||||
static GLuint Program;
|
||||
static GLuint attrib_position, attrib_texcoord;
|
||||
static GLuint attrib_position, attrib_texcoord, attrib_color;
|
||||
static GLuint uniform_MVP, uniform_TM, uniform_tex;
|
||||
|
||||
static void init();
|
||||
@ -221,25 +221,13 @@ class TransparentFogShader
|
||||
{
|
||||
public:
|
||||
static GLuint Program;
|
||||
static GLuint attrib_position, attrib_texcoord;
|
||||
static GLuint attrib_position, attrib_texcoord, attrib_color;
|
||||
static GLuint uniform_MVP, uniform_TM, uniform_tex, uniform_fogmax, uniform_startH, uniform_endH, uniform_start, uniform_end, uniform_col, uniform_screen, uniform_ipvmat;
|
||||
|
||||
static void init();
|
||||
static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix, const core::matrix4 &ipvmat, float fogmax, float startH, float endH, float start, float end, const core::vector3df &col, const core::vector3df &campos, unsigned TU_tex);
|
||||
};
|
||||
|
||||
class PointLightShader
|
||||
{
|
||||
public:
|
||||
static GLuint Program;
|
||||
static GLuint attrib_Position, attrib_Energy, attrib_Color;
|
||||
static GLuint attrib_Corner;
|
||||
static GLuint uniform_ntex, uniform_dtex, uniform_spec, uniform_screen, uniform_invproj, uniform_VM, uniform_PM;
|
||||
|
||||
static void init();
|
||||
static void setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 &InvProjMatrix, const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex);
|
||||
};
|
||||
|
||||
class BillboardShader
|
||||
{
|
||||
public:
|
||||
@ -331,6 +319,38 @@ public:
|
||||
|
||||
}
|
||||
|
||||
#define MAXLIGHT 16
|
||||
|
||||
namespace LightShader
|
||||
{
|
||||
struct PointLightInfo
|
||||
{
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
float energy;
|
||||
float red;
|
||||
float green;
|
||||
float blue;
|
||||
float padding;
|
||||
};
|
||||
|
||||
|
||||
class PointLightShader
|
||||
{
|
||||
public:
|
||||
static GLuint Program;
|
||||
static GLuint attrib_Position, attrib_Energy, attrib_Color;
|
||||
static GLuint attrib_Corner;
|
||||
static GLuint uniform_ntex, uniform_dtex, uniform_spec, uniform_screen, uniform_invproj, uniform_VM, uniform_PM;
|
||||
static GLuint vbo;
|
||||
static GLuint vao;
|
||||
|
||||
static void init();
|
||||
static void setUniforms(const core::matrix4 &ViewMatrix, const core::matrix4 &ProjMatrix, const core::matrix4 &InvProjMatrix, const core::vector2df &screen, unsigned spec, unsigned TU_ntex, unsigned TU_dtex);
|
||||
};
|
||||
}
|
||||
|
||||
namespace ParticleShader
|
||||
{
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/skidding.hpp"
|
||||
#include "physics/btKart.hpp"
|
||||
#include "graphics/stkmeshscenenode.hpp"
|
||||
|
||||
#include <IMeshSceneNode.h>
|
||||
#include <SMesh.h>
|
||||
@ -134,6 +135,8 @@ void SkidMarks::update(float dt, bool force_skid_marks,
|
||||
// (till these skid mark quads are deleted)
|
||||
m_left[m_current]->setHardwareMappingHint(scene::EHM_STATIC);
|
||||
m_right[m_current]->setHardwareMappingHint(scene::EHM_STATIC);
|
||||
if (STKMeshSceneNode* stkm = dynamic_cast<STKMeshSceneNode*>(m_nodes[m_current]))
|
||||
stkm->setReloadEachFrame(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -188,6 +191,8 @@ void SkidMarks::update(float dt, bool force_skid_marks,
|
||||
m_material, m_avoid_z_fighting, custom_color);
|
||||
new_mesh->addMeshBuffer(smq_right);
|
||||
scene::IMeshSceneNode *new_node = irr_driver->addMesh(new_mesh);
|
||||
if (STKMeshSceneNode* stkm = dynamic_cast<STKMeshSceneNode*>(new_node))
|
||||
stkm->setReloadEachFrame(true);
|
||||
#ifdef DEBUG
|
||||
std::string debug_name = m_kart.getIdent()+" (skid-mark)";
|
||||
new_node->setName(debug_name.c_str());
|
||||
|
@ -171,11 +171,13 @@ void STKAnimatedMesh::render()
|
||||
computeMVP(ModelViewProjectionMatrix);
|
||||
computeTIMV(TransposeInverseModelView);
|
||||
|
||||
glUseProgram(MeshShader::ObjectPass1Shader::Program);
|
||||
if (!GeometricMesh[FPSM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::ObjectPass1Shader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++)
|
||||
drawSolidPass1(*GeometricMesh[FPSM_DEFAULT][i], FPSM_DEFAULT);
|
||||
|
||||
glUseProgram(MeshShader::ObjectRefPass1Shader::Program);
|
||||
if (!GeometricMesh[FPSM_ALPHA_REF_TEXTURE].empty())
|
||||
glUseProgram(MeshShader::ObjectRefPass1Shader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_ALPHA_REF_TEXTURE].size(); i++)
|
||||
drawSolidPass1(*GeometricMesh[FPSM_ALPHA_REF_TEXTURE][i], FPSM_ALPHA_REF_TEXTURE);
|
||||
|
||||
@ -184,36 +186,43 @@ void STKAnimatedMesh::render()
|
||||
|
||||
if (irr_driver->getPhase() == SOLID_LIT_PASS)
|
||||
{
|
||||
glUseProgram(MeshShader::ObjectPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_DEFAULT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_DEFAULT][i], SM_DEFAULT);
|
||||
if (!ShadedMesh[SM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::ObjectPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_DEFAULT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_DEFAULT][i], SM_DEFAULT);
|
||||
|
||||
glUseProgram(MeshShader::ObjectRefPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_ALPHA_REF_TEXTURE].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_ALPHA_REF_TEXTURE][i], SM_ALPHA_REF_TEXTURE);
|
||||
if (!ShadedMesh[SM_ALPHA_REF_TEXTURE].empty())
|
||||
glUseProgram(MeshShader::ObjectRefPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_ALPHA_REF_TEXTURE].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_ALPHA_REF_TEXTURE][i], SM_ALPHA_REF_TEXTURE);
|
||||
|
||||
glUseProgram(MeshShader::ObjectRimLimitShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_RIMLIT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_RIMLIT][i], SM_RIMLIT);
|
||||
if (!ShadedMesh[SM_RIMLIT].empty())
|
||||
glUseProgram(MeshShader::ObjectRimLimitShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_RIMLIT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_RIMLIT][i], SM_RIMLIT);
|
||||
|
||||
glUseProgram(MeshShader::ObjectUnlitShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_UNLIT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_UNLIT][i], SM_UNLIT);
|
||||
if (!ShadedMesh[SM_UNLIT].empty())
|
||||
glUseProgram(MeshShader::ObjectUnlitShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_UNLIT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_UNLIT][i], SM_UNLIT);
|
||||
|
||||
glUseProgram(MeshShader::DetailledObjectPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_DETAILS].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_DETAILS][i], SM_DETAILS);
|
||||
if (!ShadedMesh[SM_DETAILS].empty())
|
||||
glUseProgram(MeshShader::DetailledObjectPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_DETAILS].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_DETAILS][i], SM_DETAILS);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
if (irr_driver->getPhase() == SHADOW_PASS)
|
||||
{
|
||||
glUseProgram(MeshShader::ShadowShader::Program);
|
||||
if (!GeometricMesh[FPSM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::ShadowShader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++)
|
||||
drawShadow(*GeometricMesh[FPSM_DEFAULT][i]);
|
||||
|
||||
glUseProgram(MeshShader::RefShadowShader::Program);
|
||||
if (!GeometricMesh[FPSM_ALPHA_REF_TEXTURE].empty())
|
||||
glUseProgram(MeshShader::RefShadowShader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_ALPHA_REF_TEXTURE].size(); i++)
|
||||
drawShadowRef(*GeometricMesh[FPSM_ALPHA_REF_TEXTURE][i]);
|
||||
return;
|
||||
@ -223,13 +232,25 @@ void STKAnimatedMesh::render()
|
||||
{
|
||||
computeMVP(ModelViewProjectionMatrix);
|
||||
|
||||
glUseProgram(MeshShader::BubbleShader::Program);
|
||||
if (!TransparentMesh[TM_BUBBLE].empty())
|
||||
glUseProgram(MeshShader::BubbleShader::Program);
|
||||
for (unsigned i = 0; i < TransparentMesh[TM_BUBBLE].size(); i++)
|
||||
drawBubble(*TransparentMesh[TM_BUBBLE][i], ModelViewProjectionMatrix);
|
||||
|
||||
glUseProgram(MeshShader::TransparentShader::Program);
|
||||
for (unsigned i = 0; i < TransparentMesh[TM_DEFAULT].size(); i++)
|
||||
drawTransparentObject(*TransparentMesh[TM_DEFAULT][i], ModelViewProjectionMatrix, (*TransparentMesh[TM_DEFAULT][i]).TextureMatrix);
|
||||
if (World::getWorld()->getTrack()->isFogEnabled())
|
||||
{
|
||||
if (!TransparentMesh[TM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::TransparentFogShader::Program);
|
||||
for (unsigned i = 0; i < TransparentMesh[TM_DEFAULT].size(); i++)
|
||||
drawTransparentFogObject(*TransparentMesh[TM_DEFAULT][i], ModelViewProjectionMatrix, (*TransparentMesh[TM_DEFAULT][i]).TextureMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TransparentMesh[TM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::TransparentShader::Program);
|
||||
for (unsigned i = 0; i < TransparentMesh[TM_DEFAULT].size(); i++)
|
||||
drawTransparentObject(*TransparentMesh[TM_DEFAULT][i], ModelViewProjectionMatrix, (*TransparentMesh[TM_DEFAULT][i]).TextureMatrix);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -401,6 +401,8 @@ void drawObjectRefPass2(const GLMesh &mesh, const core::matrix4 &ModelViewProjec
|
||||
glDrawElements(ptype, count, itype, 0);
|
||||
}
|
||||
|
||||
static video::ITexture *CausticTex = 0;
|
||||
|
||||
void drawCaustics(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, core::vector2df dir, core::vector2df dir2)
|
||||
{
|
||||
irr_driver->IncreaseObjectCount();
|
||||
@ -419,7 +421,9 @@ void drawCaustics(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionM
|
||||
GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
|
||||
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
|
||||
}
|
||||
setTexture(MeshShader::CausticsShader::TU_caustictex, getTextureGLuint(irr_driver->getTexture(file_manager->getAsset("textures/caustics.png").c_str())), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
|
||||
if (!CausticTex)
|
||||
CausticTex = irr_driver->getTexture(file_manager->getAsset("textures/caustics.png").c_str());
|
||||
setTexture(MeshShader::CausticsShader::TU_caustictex, getTextureGLuint(CausticTex), GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true);
|
||||
|
||||
MeshShader::CausticsShader::setUniforms(ModelViewProjectionMatrix, dir, dir2, core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height));
|
||||
|
||||
@ -814,20 +818,18 @@ void initvaostate(GLMesh &mesh, TransparentMaterial TranspMat)
|
||||
MeshShader::BubbleShader::attrib_position, MeshShader::BubbleShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride);
|
||||
break;
|
||||
case TM_DEFAULT:
|
||||
mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer,
|
||||
MeshShader::TransparentShader::attrib_position, MeshShader::TransparentShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride);
|
||||
if (World::getWorld()->getTrack()->isFogEnabled())
|
||||
mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer,
|
||||
MeshShader::TransparentFogShader::attrib_position, MeshShader::TransparentFogShader::attrib_texcoord, -1, -1, -1, -1, MeshShader::TransparentFogShader::attrib_color, mesh.Stride);
|
||||
|
||||
else
|
||||
mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer,
|
||||
MeshShader::TransparentShader::attrib_position, MeshShader::TransparentShader::attrib_texcoord, -1, -1, -1, -1, MeshShader::TransparentShader::attrib_color, mesh.Stride);
|
||||
break;
|
||||
}
|
||||
mesh.vao_glow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::ColorizeShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride);
|
||||
mesh.vao_displace_mask_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::DisplaceShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride);
|
||||
if (mesh.Stride >= 44)
|
||||
mesh.vao_displace_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::DisplaceShader::attrib_position, MeshShader::DisplaceShader::attrib_texcoord, MeshShader::DisplaceShader::attrib_second_texcoord, -1, -1, -1, -1, mesh.Stride);
|
||||
|
||||
/*
|
||||
else if (World::getWorld()->getTrack()->isFogEnabled())
|
||||
{
|
||||
mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer,
|
||||
MeshShader::TransparentFogShader::attrib_position, MeshShader::TransparentFogShader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,15 @@ STKMeshSceneNode::STKMeshSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent,
|
||||
const irr::core::vector3df& scale) :
|
||||
CMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale)
|
||||
{
|
||||
reload_each_frame = false;
|
||||
createGLMeshes();
|
||||
}
|
||||
|
||||
void STKMeshSceneNode::setReloadEachFrame(bool val)
|
||||
{
|
||||
reload_each_frame = val;
|
||||
}
|
||||
|
||||
void STKMeshSceneNode::createGLMeshes()
|
||||
{
|
||||
for (u32 i = 0; i<Mesh->getMeshBufferCount(); ++i)
|
||||
@ -137,6 +143,8 @@ void STKMeshSceneNode::drawGlow(const GLMesh &mesh)
|
||||
glDrawElements(ptype, count, itype, 0);
|
||||
}
|
||||
|
||||
static video::ITexture *displaceTex = 0;
|
||||
|
||||
void STKMeshSceneNode::drawDisplace(const GLMesh &mesh)
|
||||
{
|
||||
DisplaceProvider * const cb = (DisplaceProvider *)irr_driver->getCallback(ES_DISPLACE);
|
||||
@ -161,8 +169,10 @@ void STKMeshSceneNode::drawDisplace(const GLMesh &mesh)
|
||||
glDrawElements(ptype, count, itype, 0);
|
||||
|
||||
// Render the effect
|
||||
if (!displaceTex)
|
||||
displaceTex = irr_driver->getTexture(FileManager::TEXTURE, "displace.png");
|
||||
irr_driver->getVideoDriver()->setRenderTarget(irr_driver->getRTT(RTT_DISPLACE), false, false);
|
||||
setTexture(0, getTextureGLuint(irr_driver->getTexture(FileManager::TEXTURE, "displace.png")), GL_LINEAR, GL_LINEAR, true);
|
||||
setTexture(0, getTextureGLuint(displaceTex), GL_LINEAR, GL_LINEAR, true);
|
||||
setTexture(1, getTextureGLuint(irr_driver->getRTT(RTT_TMP4)), GL_LINEAR, GL_LINEAR, true);
|
||||
setTexture(2, getTextureGLuint(irr_driver->getRTT(RTT_COLOR)), GL_LINEAR, GL_LINEAR, true);
|
||||
glUseProgram(MeshShader::DisplaceShader::Program);
|
||||
@ -270,6 +280,41 @@ void STKMeshSceneNode::drawSolidPass2(const GLMesh &mesh, ShadedMaterial type)
|
||||
}
|
||||
}
|
||||
|
||||
void STKMeshSceneNode::updatevbo()
|
||||
{
|
||||
for (unsigned i = 0; i < Mesh->getMeshBufferCount(); ++i)
|
||||
{
|
||||
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
|
||||
if (!mb)
|
||||
continue;
|
||||
GLMesh &mesh = GLmeshes[i];
|
||||
glBindVertexArray(0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vertex_buffer);
|
||||
const void* vertices = mb->getVertices();
|
||||
const u32 vertexCount = mb->getVertexCount();
|
||||
const c8* vbuf = static_cast<const c8*>(vertices);
|
||||
glBufferData(GL_ARRAY_BUFFER, vertexCount * mesh.Stride, vbuf, GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.index_buffer);
|
||||
const void* indices = mb->getIndices();
|
||||
mesh.IndexCount = mb->getIndexCount();
|
||||
GLenum indexSize;
|
||||
switch (mb->getIndexType())
|
||||
{
|
||||
case irr::video::EIT_16BIT:
|
||||
indexSize = sizeof(u16);
|
||||
break;
|
||||
case irr::video::EIT_32BIT:
|
||||
indexSize = sizeof(u32);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Wrong index size");
|
||||
}
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.IndexCount * indexSize, indices, GL_STATIC_DRAW);
|
||||
}
|
||||
}
|
||||
|
||||
void STKMeshSceneNode::render()
|
||||
{
|
||||
irr::video::IVideoDriver* driver = irr_driver->getVideoDriver();
|
||||
@ -277,6 +322,9 @@ void STKMeshSceneNode::render()
|
||||
if (!Mesh || !driver)
|
||||
return;
|
||||
|
||||
if (reload_each_frame)
|
||||
updatevbo();
|
||||
|
||||
bool isTransparentPass =
|
||||
SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT;
|
||||
|
||||
@ -297,82 +345,113 @@ void STKMeshSceneNode::render()
|
||||
|
||||
if (irr_driver->getPhase() == SOLID_NORMAL_AND_DEPTH_PASS)
|
||||
{
|
||||
if (reload_each_frame)
|
||||
glDisable(GL_CULL_FACE);
|
||||
computeMVP(ModelViewProjectionMatrix);
|
||||
computeTIMV(TransposeInverseModelView);
|
||||
|
||||
glUseProgram(MeshShader::ObjectPass1Shader::Program);
|
||||
if (!GeometricMesh[FPSM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::ObjectPass1Shader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++)
|
||||
drawSolidPass1(*GeometricMesh[FPSM_DEFAULT][i], FPSM_DEFAULT);
|
||||
|
||||
glUseProgram(MeshShader::ObjectRefPass1Shader::Program);
|
||||
if (!GeometricMesh[FPSM_ALPHA_REF_TEXTURE].empty())
|
||||
glUseProgram(MeshShader::ObjectRefPass1Shader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_ALPHA_REF_TEXTURE].size(); i++)
|
||||
drawSolidPass1(*GeometricMesh[FPSM_ALPHA_REF_TEXTURE][i], FPSM_ALPHA_REF_TEXTURE);
|
||||
|
||||
glUseProgram(MeshShader::NormalMapShader::Program);
|
||||
if (!GeometricMesh[FPSM_NORMAL_MAP].empty())
|
||||
glUseProgram(MeshShader::NormalMapShader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_NORMAL_MAP].size(); i++)
|
||||
drawSolidPass1(*GeometricMesh[FPSM_NORMAL_MAP][i], FPSM_NORMAL_MAP);
|
||||
|
||||
glUseProgram(MeshShader::GrassPass1Shader::Program);
|
||||
if (!GeometricMesh[FPSM_GRASS].empty())
|
||||
glUseProgram(MeshShader::GrassPass1Shader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_GRASS].size(); i++)
|
||||
drawSolidPass1(*GeometricMesh[FPSM_GRASS][i], FPSM_GRASS);
|
||||
|
||||
if (reload_each_frame)
|
||||
glEnable(GL_CULL_FACE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (irr_driver->getPhase() == SOLID_LIT_PASS)
|
||||
{
|
||||
glUseProgram(MeshShader::ObjectPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_DEFAULT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_DEFAULT][i], SM_DEFAULT);
|
||||
if (reload_each_frame)
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glUseProgram(MeshShader::ObjectRefPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_ALPHA_REF_TEXTURE].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_ALPHA_REF_TEXTURE][i], SM_ALPHA_REF_TEXTURE);
|
||||
if (!ShadedMesh[SM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::ObjectPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_DEFAULT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_DEFAULT][i], SM_DEFAULT);
|
||||
|
||||
glUseProgram(MeshShader::ObjectRimLimitShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_RIMLIT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_RIMLIT][i], SM_RIMLIT);
|
||||
if (!ShadedMesh[SM_ALPHA_REF_TEXTURE].empty())
|
||||
glUseProgram(MeshShader::ObjectRefPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_ALPHA_REF_TEXTURE].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_ALPHA_REF_TEXTURE][i], SM_ALPHA_REF_TEXTURE);
|
||||
|
||||
glUseProgram(MeshShader::SphereMapShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_SPHEREMAP].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_SPHEREMAP][i], SM_SPHEREMAP);
|
||||
if (!ShadedMesh[SM_RIMLIT].empty())
|
||||
glUseProgram(MeshShader::ObjectRimLimitShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_RIMLIT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_RIMLIT][i], SM_RIMLIT);
|
||||
|
||||
glUseProgram(MeshShader::SplattingShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_SPLATTING].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_SPLATTING][i], SM_SPLATTING);
|
||||
if (!ShadedMesh[SM_SPHEREMAP].empty())
|
||||
glUseProgram(MeshShader::SphereMapShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_SPHEREMAP].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_SPHEREMAP][i], SM_SPHEREMAP);
|
||||
|
||||
glUseProgram(MeshShader::GrassPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_GRASS].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_GRASS][i], SM_GRASS);
|
||||
if (!ShadedMesh[SM_SPLATTING].empty())
|
||||
glUseProgram(MeshShader::SplattingShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_SPLATTING].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_SPLATTING][i], SM_SPLATTING);
|
||||
|
||||
glUseProgram(MeshShader::ObjectUnlitShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_UNLIT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_UNLIT][i], SM_UNLIT);
|
||||
if (!ShadedMesh[SM_GRASS].empty())
|
||||
glUseProgram(MeshShader::GrassPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_GRASS].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_GRASS][i], SM_GRASS);
|
||||
|
||||
glUseProgram(MeshShader::CausticsShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_CAUSTICS].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_CAUSTICS][i], SM_CAUSTICS);
|
||||
if (!ShadedMesh[SM_UNLIT].empty())
|
||||
glUseProgram(MeshShader::ObjectUnlitShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_UNLIT].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_UNLIT][i], SM_UNLIT);
|
||||
|
||||
glUseProgram(MeshShader::DetailledObjectPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_DETAILS].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_DETAILS][i], SM_DETAILS);
|
||||
if (!ShadedMesh[SM_CAUSTICS].empty())
|
||||
glUseProgram(MeshShader::CausticsShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_CAUSTICS].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_CAUSTICS][i], SM_CAUSTICS);
|
||||
|
||||
glUseProgram(MeshShader::UntexturedObjectShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_UNTEXTURED].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_UNTEXTURED][i], SM_UNTEXTURED);
|
||||
if (!ShadedMesh[SM_DETAILS].empty())
|
||||
glUseProgram(MeshShader::DetailledObjectPass2Shader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_DETAILS].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_DETAILS][i], SM_DETAILS);
|
||||
|
||||
return;
|
||||
if (!ShadedMesh[SM_UNTEXTURED].empty())
|
||||
glUseProgram(MeshShader::UntexturedObjectShader::Program);
|
||||
for (unsigned i = 0; i < ShadedMesh[SM_UNTEXTURED].size(); i++)
|
||||
drawSolidPass2(*ShadedMesh[SM_UNTEXTURED][i], SM_UNTEXTURED);
|
||||
|
||||
if (reload_each_frame)
|
||||
glEnable(GL_CULL_FACE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (irr_driver->getPhase() == SHADOW_PASS)
|
||||
{
|
||||
glUseProgram(MeshShader::ShadowShader::Program);
|
||||
if (reload_each_frame)
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if (!GeometricMesh[FPSM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::ShadowShader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++)
|
||||
drawShadow(*GeometricMesh[FPSM_DEFAULT][i]);
|
||||
|
||||
glUseProgram(MeshShader::RefShadowShader::Program);
|
||||
if (!GeometricMesh[FPSM_ALPHA_REF_TEXTURE].empty())
|
||||
glUseProgram(MeshShader::RefShadowShader::Program);
|
||||
for (unsigned i = 0; i < GeometricMesh[FPSM_ALPHA_REF_TEXTURE].size(); i++)
|
||||
drawShadowRef(*GeometricMesh[FPSM_ALPHA_REF_TEXTURE][i]);
|
||||
|
||||
if (reload_each_frame)
|
||||
glEnable(GL_CULL_FACE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -392,13 +471,25 @@ void STKMeshSceneNode::render()
|
||||
{
|
||||
computeMVP(ModelViewProjectionMatrix);
|
||||
|
||||
glUseProgram(MeshShader::BubbleShader::Program);
|
||||
if (!TransparentMesh[TM_BUBBLE].empty())
|
||||
glUseProgram(MeshShader::BubbleShader::Program);
|
||||
for (unsigned i = 0; i < TransparentMesh[TM_BUBBLE].size(); i++)
|
||||
drawBubble(*TransparentMesh[TM_BUBBLE][i], ModelViewProjectionMatrix);
|
||||
|
||||
glUseProgram(MeshShader::TransparentShader::Program);
|
||||
for (unsigned i = 0; i < TransparentMesh[TM_DEFAULT].size(); i++)
|
||||
drawTransparentObject(*TransparentMesh[TM_DEFAULT][i], ModelViewProjectionMatrix, (*TransparentMesh[TM_DEFAULT][i]).TextureMatrix);
|
||||
if (World::getWorld()->getTrack()->isFogEnabled())
|
||||
{
|
||||
if (!TransparentMesh[TM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::TransparentFogShader::Program);
|
||||
for (unsigned i = 0; i < TransparentMesh[TM_DEFAULT].size(); i++)
|
||||
drawTransparentFogObject(*TransparentMesh[TM_DEFAULT][i], ModelViewProjectionMatrix, (*TransparentMesh[TM_DEFAULT][i]).TextureMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TransparentMesh[TM_DEFAULT].empty())
|
||||
glUseProgram(MeshShader::TransparentShader::Program);
|
||||
for (unsigned i = 0; i < TransparentMesh[TM_DEFAULT].size(); i++)
|
||||
drawTransparentObject(*TransparentMesh[TM_DEFAULT][i], ModelViewProjectionMatrix, (*TransparentMesh[TM_DEFAULT][i]).TextureMatrix);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -23,15 +23,17 @@ protected:
|
||||
void createGLMeshes();
|
||||
void cleanGLMeshes();
|
||||
void setFirstTimeMaterial();
|
||||
void updatevbo();
|
||||
bool isMaterialInitialized;
|
||||
bool reload_each_frame;
|
||||
public:
|
||||
void setReloadEachFrame(bool);
|
||||
STKMeshSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id,
|
||||
const irr::core::vector3df& position = irr::core::vector3df(0, 0, 0),
|
||||
const irr::core::vector3df& rotation = irr::core::vector3df(0, 0, 0),
|
||||
const irr::core::vector3df& scale = irr::core::vector3df(1.0f, 1.0f, 1.0f));
|
||||
virtual void render();
|
||||
virtual void setMesh(irr::scene::IMesh* mesh);
|
||||
void MovingTexture(unsigned, unsigned);
|
||||
~STKMeshSceneNode();
|
||||
};
|
||||
|
||||
|
@ -26,6 +26,7 @@ STKModifiedSpriteBank::STKModifiedSpriteBank(IGUIEnvironment* env) :
|
||||
#endif
|
||||
|
||||
m_scale = 1.0f;
|
||||
m_height = 0;
|
||||
|
||||
if (Environment)
|
||||
{
|
||||
@ -62,8 +63,8 @@ core::array< core::rect<s32> >& STKModifiedSpriteBank::getPositions()
|
||||
|
||||
for (int n=0; n<(int)Rectangles.size(); n++)
|
||||
{
|
||||
const int h = (int)(Rectangles[n].getHeight()*m_scale);
|
||||
const int w = (int)(Rectangles[n].getWidth() *m_scale);
|
||||
const int h = getScaledHeight(Rectangles[n].getHeight());
|
||||
const int w = getScaledWidth(Rectangles[n].getWidth());
|
||||
copy.push_back( core::rect<s32>(Rectangles[n].UpperLeftCorner,
|
||||
core::dimension2d<s32>(w,h) )
|
||||
);
|
||||
@ -203,8 +204,8 @@ void STKModifiedSpriteBank::draw2DSprite(u32 index,
|
||||
const core::dimension2d<s32>& dim = r.getSize();
|
||||
|
||||
core::rect<s32> dest( pos,
|
||||
core::dimension2d<s32>((int)(dim.Width*m_scale),
|
||||
(int)(dim.Height*m_scale)) );
|
||||
core::dimension2d<s32>(getScaledWidth(dim.Width),
|
||||
getScaledHeight(dim.Height)));
|
||||
if (center)
|
||||
{
|
||||
dest -= dest.getSize() / 2;
|
||||
@ -295,6 +296,30 @@ void STKModifiedSpriteBank::draw2DSpriteBatch(const core::array<u32>& indices,
|
||||
}
|
||||
} // draw2DSpriteBatch
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void STKModifiedSpriteBank::scaleToHeight(int height)
|
||||
{
|
||||
m_height = height;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
s32 STKModifiedSpriteBank::getScaledWidth(s32 width) const
|
||||
{
|
||||
if (m_height == 0)
|
||||
return (s32)((float)width * m_scale);
|
||||
else
|
||||
return m_height;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
s32 STKModifiedSpriteBank::getScaledHeight(s32 height) const
|
||||
{
|
||||
if (m_height == 0)
|
||||
return (s32)((float)height * m_scale);
|
||||
else
|
||||
return m_height;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
} // namespace gui
|
||||
} // namespace irr
|
||||
|
@ -67,12 +67,15 @@ public:
|
||||
m_scale = scale;
|
||||
}
|
||||
|
||||
void scaleToHeight(int height);
|
||||
|
||||
protected:
|
||||
|
||||
// this object was getting access after being freed, I wanna see when/why
|
||||
unsigned int m_magic_number;
|
||||
|
||||
float m_scale;
|
||||
int m_height;
|
||||
|
||||
struct SDrawBatch
|
||||
{
|
||||
@ -91,6 +94,8 @@ protected:
|
||||
IGUIEnvironment* Environment;
|
||||
video::IVideoDriver* Driver;
|
||||
|
||||
s32 getScaledWidth(s32 width) const;
|
||||
s32 getScaledHeight(s32 height) const;
|
||||
};
|
||||
|
||||
} // end namespace gui
|
||||
|
@ -486,6 +486,14 @@ namespace GUIEngine
|
||||
Used on divs, indicate by how many pixels to pad contents
|
||||
|
||||
|
||||
\n
|
||||
\subsection prop20 PROP_KEEP_SELECTION
|
||||
<em> Name in XML files: </em> \c "keep_selection"
|
||||
|
||||
Used on lists, indicates that the list should keep showing the selected item
|
||||
even when it doesn't have the focus
|
||||
|
||||
|
||||
\n
|
||||
<HR>
|
||||
\section code Using the engine in code
|
||||
@ -723,20 +731,6 @@ namespace GUIEngine
|
||||
|
||||
std::vector<MenuMessage> gui_messages;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
Screen* getScreenNamed(const char* name)
|
||||
{
|
||||
const int screenCount = g_loaded_screens.size();
|
||||
for (int n=0; n<screenCount; n++)
|
||||
{
|
||||
if (g_loaded_screens[n].getName() == name)
|
||||
{
|
||||
return g_loaded_screens.get(n);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
} // getScreenNamed
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void showMessage(const wchar_t* message, const float time)
|
||||
{
|
||||
@ -803,7 +797,8 @@ namespace GUIEngine
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
int getLargeFontHeight()
|
||||
{
|
||||
{
|
||||
|
||||
return Private::large_font_height;
|
||||
} // getSmallFontHeight
|
||||
|
||||
|
@ -221,6 +221,7 @@ if(prop_name != NULL) widget.m_properties[prop_flag] = core::stringc(prop_name).
|
||||
READ_PROPERTY(max_rows, PROP_MAX_ROWS);
|
||||
READ_PROPERTY(wrap_around, PROP_WRAP_AROUND);
|
||||
READ_PROPERTY(padding, PROP_DIV_PADDING);
|
||||
READ_PROPERTY(keep_selection, PROP_KEEP_SELECTION);
|
||||
#undef READ_PROPERTY
|
||||
|
||||
const wchar_t* text = xml->getAttributeValue( L"text" );
|
||||
|
@ -103,7 +103,8 @@ namespace GUIEngine
|
||||
PROP_LABELS_LOCATION,
|
||||
PROP_MAX_ROWS,
|
||||
PROP_WRAP_AROUND,
|
||||
PROP_DIV_PADDING
|
||||
PROP_DIV_PADDING,
|
||||
PROP_KEEP_SELECTION,
|
||||
};
|
||||
|
||||
bool isWithinATextBox();
|
||||
|
@ -299,7 +299,8 @@ void ListWidget::unfocused(const int playerID, Widget* new_focus)
|
||||
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
|
||||
|
||||
// remove selection when leaving list
|
||||
if (list != NULL) list->setSelected(-1);
|
||||
if (list != NULL && m_properties[PROP_KEEP_SELECTION] != "true")
|
||||
list->setSelected(-1);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -192,6 +192,7 @@ FileManager::FileManager()
|
||||
checkAndCreateConfigDir();
|
||||
checkAndCreateAddonsDir();
|
||||
checkAndCreateScreenshotDir();
|
||||
checkAndCreateGPDir();
|
||||
|
||||
#ifdef WIN32
|
||||
redirectOutput();
|
||||
@ -209,6 +210,8 @@ FileManager::FileManager()
|
||||
m_addons_dir.c_str());
|
||||
Log::info("[FileManager]", "Screenshots will be stored in '%s'.",
|
||||
m_screenshot_dir.c_str());
|
||||
Log::info("[FileManager]", "User-defined grand prix will be stored in '%s'.",
|
||||
m_gp_dir.c_str());
|
||||
|
||||
/** Now search for the path to all needed subdirectories. */
|
||||
// ==========================================================
|
||||
@ -576,6 +579,14 @@ std::string FileManager::getScreenshotDir() const
|
||||
return m_screenshot_dir;
|
||||
} // getScreenshotDir
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the directory in which user-defined grand prix should be stored.
|
||||
*/
|
||||
std::string FileManager::getGPDir() const
|
||||
{
|
||||
return m_gp_dir;
|
||||
} // getGPDir
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the full path of a texture file name by searching in all
|
||||
* directories currently in the texture search path. The difference to
|
||||
@ -824,6 +835,32 @@ void FileManager::checkAndCreateScreenshotDir()
|
||||
|
||||
} // checkAndCreateScreenshotDir
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Creates the directories for user-defined grand prix. This will set m_gp_dir
|
||||
* with the appropriate path.
|
||||
*/
|
||||
void FileManager::checkAndCreateGPDir()
|
||||
{
|
||||
#if defined(WIN32) || defined(__CYGWIN__)
|
||||
m_gp_dir = m_user_config_dir + "grandprix/";
|
||||
#elif defined(__APPLE__)
|
||||
m_gp_dir = getenv("HOME");
|
||||
m_gp_dir += "/Library/Application Support/SuperTuxKart/grandprix/";
|
||||
#else
|
||||
m_gp_dir = checkAndCreateLinuxDir("XDG_DATA_HOME", "supertuxkart",
|
||||
".local/share", ".supertuxkart");
|
||||
m_gp_dir += "grandprix/";
|
||||
#endif
|
||||
|
||||
if(!checkAndCreateDirectory(m_gp_dir))
|
||||
{
|
||||
Log::error("FileManager", "Can not create user-defined grand prix directory '%s', "
|
||||
"falling back to '.'.", m_gp_dir.c_str());
|
||||
m_gp_dir = ".";
|
||||
}
|
||||
|
||||
} // checkAndCreateGPDir
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#if !defined(WIN32) && !defined(__CYGWIN__) && !defined(__APPLE__)
|
||||
|
||||
|
@ -72,6 +72,9 @@ private:
|
||||
/** Directory to store screenshots in. */
|
||||
std::string m_screenshot_dir;
|
||||
|
||||
/** Directory where user-defined grand prix are stored. */
|
||||
std::string m_gp_dir;
|
||||
|
||||
std::vector<std::string>
|
||||
m_texture_search_path,
|
||||
m_model_search_path,
|
||||
@ -88,6 +91,7 @@ private:
|
||||
bool isDirectory(const std::string &path) const;
|
||||
void checkAndCreateAddonsDir();
|
||||
void checkAndCreateScreenshotDir();
|
||||
void checkAndCreateGPDir();
|
||||
#if !defined(WIN32) && !defined(__CYGWIN__) && !defined(__APPLE__)
|
||||
std::string checkAndCreateLinuxDir(const char *env_name,
|
||||
const char *dir_name,
|
||||
@ -106,6 +110,7 @@ public:
|
||||
XMLNode *createXMLTreeFromString(const std::string & content);
|
||||
|
||||
std::string getScreenshotDir() const;
|
||||
std::string getGPDir() const;
|
||||
bool checkAndCreateDirectoryP(const std::string &path);
|
||||
const std::string &getAddonsDir() const;
|
||||
std::string getAddonsFile(const std::string &name);
|
||||
|
@ -18,6 +18,9 @@
|
||||
|
||||
#include "items/powerup.hpp"
|
||||
|
||||
#include "achievements/achievement_info.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
|
||||
#include "audio/sfx_base.hpp"
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "config/stk_config.hpp"
|
||||
@ -170,6 +173,14 @@ void Powerup::adjustSound()
|
||||
*/
|
||||
void Powerup::use()
|
||||
{
|
||||
// The player gets an achievement point for using a powerup
|
||||
StateManager::ActivePlayer * player = m_owner->getController()->getPlayer();
|
||||
if (m_type != PowerupManager::POWERUP_NOTHING &&
|
||||
player != NULL && player->getConstProfile() == PlayerManager::get()->getCurrentPlayer())
|
||||
{
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_POWERUP_LOVER, "poweruplover");
|
||||
}
|
||||
|
||||
// Play custom kart sound when collectible is used //TODO: what about the bubble gum?
|
||||
if (m_type != PowerupManager::POWERUP_NOTHING &&
|
||||
m_type != PowerupManager::POWERUP_SWATTER &&
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
#include "graphics/stkmeshscenenode.hpp"
|
||||
#include "items/plunger.hpp"
|
||||
#include "items/projectile_manager.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
@ -71,6 +72,8 @@ RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart)
|
||||
updatePosition();
|
||||
m_node = irr_driver->addMesh(m_mesh);
|
||||
irr_driver->applyObjectPassShader(m_node);
|
||||
if (STKMeshSceneNode *stkm = dynamic_cast<STKMeshSceneNode *>(m_node))
|
||||
stkm->setReloadEachFrame(true);
|
||||
#ifdef DEBUG
|
||||
std::string debug_name = m_owner->getIdent()+" (rubber-band)";
|
||||
m_node->setName(debug_name.c_str());
|
||||
|
@ -560,9 +560,17 @@ void KartProperties::getAllData(const XMLNode * root)
|
||||
else if (s == "small") m_engine_sfx_type = "engine_small";
|
||||
else
|
||||
{
|
||||
Log::warn("[KartProperties]", "Kart '%s' has invalid engine '%s'.",
|
||||
m_name.c_str(), s.c_str());
|
||||
m_engine_sfx_type = "engine_small";
|
||||
if (sfx_manager->soundExist(s))
|
||||
{
|
||||
m_engine_sfx_type = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("[KartProperties]",
|
||||
"Kart '%s' has an invalid engine '%s'.",
|
||||
m_name.c_str(), s.c_str());
|
||||
m_engine_sfx_type = "engine_small";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WILL_BE_ENABLED_ONCE_DONE_PROPERLY
|
||||
|
@ -445,6 +445,7 @@ void World::terminateRace()
|
||||
&best_player);
|
||||
}
|
||||
|
||||
// Check achievements
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_COLUMBUS,
|
||||
getTrack()->getIdent(), 1);
|
||||
if (raceHasLaps())
|
||||
@ -452,6 +453,64 @@ void World::terminateRace()
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_MARATHONER,
|
||||
"laps", race_manager->getNumLaps());
|
||||
}
|
||||
|
||||
Achievement *achiev = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER);
|
||||
if (achiev)
|
||||
{
|
||||
std::string mode_name = getIdent(); // Get the race mode name
|
||||
int winner_position = 1;
|
||||
int opponents = achiev->getInfo()->getGoalValue("opponents"); // Get the required opponents number
|
||||
if (mode_name == IDENT_FTL)
|
||||
{
|
||||
winner_position = 2;
|
||||
opponents++;
|
||||
}
|
||||
for(unsigned int i = 0; i < kart_amount; i++)
|
||||
{
|
||||
// Retrieve the current player
|
||||
StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer();
|
||||
if (p && p->getConstProfile() == PlayerManager::get()->getCurrentPlayer())
|
||||
{
|
||||
// Check if the player has won
|
||||
if (m_karts[i]->getPosition() == winner_position && kart_amount > opponents )
|
||||
{
|
||||
// Update the achievement
|
||||
mode_name = StringUtils::toLowerCase(mode_name);
|
||||
if (achiev->getValue("opponents") <= 0)
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER,
|
||||
"opponents", opponents);
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER,
|
||||
mode_name, 1);
|
||||
}
|
||||
}
|
||||
} // for i < kart_amount
|
||||
} // if (achiev)
|
||||
|
||||
Achievement *win = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_UNSTOPPABLE);
|
||||
//if achivement has been unlocked
|
||||
if (win->getValue("wins") < 5 )
|
||||
{
|
||||
for(unsigned int i = 0; i < kart_amount; i++)
|
||||
{
|
||||
// Retrieve the current player
|
||||
StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer();
|
||||
if (p && p->getConstProfile() == PlayerManager::get()->getCurrentPlayer())
|
||||
{
|
||||
// Check if the player has won
|
||||
if (m_karts[i]->getPosition() == 1 )
|
||||
{
|
||||
// Increase number of consecutive wins
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_UNSTOPPABLE,
|
||||
"wins", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Set number of consecutive wins to 0
|
||||
win->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PlayerManager::get()->getCurrentPlayer()->raceFinished();
|
||||
|
||||
if (m_race_gui) m_race_gui->clearAllMessages();
|
||||
|
@ -23,37 +23,62 @@
|
||||
#include "challenges/unlock_manager.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "io/utf_writer.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
GrandPrixData::GrandPrixData(const std::string filename)
|
||||
{
|
||||
load_from_file(file_manager->getAsset(FileManager::GRANDPRIX, filename),
|
||||
filename);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GrandPrixData::GrandPrixData(const std::string dir, const std::string filename)
|
||||
{
|
||||
assert(dir[dir.size() - 1] == '/');
|
||||
load_from_file(dir + filename, filename);
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::load_from_file(const std::string fullpath,
|
||||
const std::string filename)
|
||||
GrandPrixData::GrandPrixData(const std::string& filename) throw(std::logic_error)
|
||||
{
|
||||
m_filename = filename;
|
||||
m_id = StringUtils::getBasename(StringUtils::removeExtension(filename));
|
||||
m_editable = (filename.find(file_manager->getGPDir(), 0) == 0);
|
||||
reload();
|
||||
}
|
||||
|
||||
XMLNode * root = file_manager->createXMLTree(fullpath);
|
||||
if (!root)
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::setId(const std::string& id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::setName(const irr::core::stringw& name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::setFilename(const std::string& filename)
|
||||
{
|
||||
m_filename = filename;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::setEditable(const bool editable)
|
||||
{
|
||||
m_editable = editable;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::reload()
|
||||
{
|
||||
m_tracks.clear();
|
||||
m_laps.clear();
|
||||
m_reversed.clear();
|
||||
|
||||
std::auto_ptr<XMLNode> root(file_manager->createXMLTree(m_filename));
|
||||
if (root.get() == NULL)
|
||||
{
|
||||
Log::error("GrandPrixData","Error while trying to read grandprix file "
|
||||
"'%s'", fullpath.c_str());
|
||||
Log::error("GrandPrixData","Error while trying to read grandprix file '%s'",
|
||||
m_filename.c_str());
|
||||
throw std::logic_error("File not found");
|
||||
}
|
||||
|
||||
@ -61,24 +86,18 @@ void GrandPrixData::load_from_file(const std::string fullpath,
|
||||
|
||||
if (root->getName() == "supertuxkart_grand_prix")
|
||||
{
|
||||
std::string temp_name;
|
||||
if (root->get("name", &temp_name) == 0)
|
||||
if (root->get("name", &m_name) == 0)
|
||||
{
|
||||
Log::error("GrandPrixData", "Error while trying to read grandprix "
|
||||
"file '%s' : missing 'name' attribute\n",
|
||||
fullpath.c_str());
|
||||
delete root;
|
||||
Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : "
|
||||
"missing 'name' attribute\n", m_filename.c_str());
|
||||
throw std::logic_error("File contents are incomplete or corrupt");
|
||||
}
|
||||
m_name = temp_name.c_str();
|
||||
foundName = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("GrandPrixData", "Error while trying to read grandprix file "
|
||||
"'%s' : Root node has an unexpected name\n",
|
||||
fullpath.c_str());
|
||||
delete root;
|
||||
Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : "
|
||||
"Root node has an unexpected name\n", m_filename.c_str());
|
||||
throw std::logic_error("File contents are incomplete or corrupt");
|
||||
}
|
||||
|
||||
@ -95,20 +114,17 @@ void GrandPrixData::load_from_file(const std::string fullpath,
|
||||
int numLaps;
|
||||
bool reversed = false;
|
||||
|
||||
const int idFound = node->get("id", &trackID);
|
||||
const int lapFound = node->get("laps", &numLaps);
|
||||
const int idFound = node->get("id", &trackID );
|
||||
const int lapFound = node->get("laps", &numLaps );
|
||||
// Will stay false if not found
|
||||
node->get("reverse", &reversed );
|
||||
|
||||
if (!idFound || !lapFound)
|
||||
{
|
||||
Log::error("GrandPrixData", "Error while trying to read "
|
||||
"grandprix file '%s' : <track> tag does not have "
|
||||
"idi and laps reverse attributes. \n",
|
||||
fullpath.c_str());
|
||||
delete root;
|
||||
throw std::logic_error("File contents are incomplete or "
|
||||
"corrupt");
|
||||
Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : "
|
||||
"<track> tag does not have idi and laps reverse attributes. \n",
|
||||
m_filename.c_str());
|
||||
throw std::logic_error("File contents are incomplete or corrupt");
|
||||
}
|
||||
|
||||
// Make sure the track really is reversible
|
||||
@ -127,27 +143,58 @@ void GrandPrixData::load_from_file(const std::string fullpath,
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("Unknown node in Grand Prix XML file: %s/n",
|
||||
node->getName().c_str());
|
||||
delete root;
|
||||
std::cerr << "Unknown node in Grand Prix XML file : " << node->getName().c_str() << std::endl;
|
||||
throw std::runtime_error("Unknown node in sfx XML file");
|
||||
}
|
||||
}// end for
|
||||
|
||||
delete root;
|
||||
}// nend for
|
||||
|
||||
// sanity checks
|
||||
if (!foundName)
|
||||
{
|
||||
Log::error("GrandPrixData", "Error while trying to read grandprix file "
|
||||
"'%s' : missing 'name' attribute\n", fullpath.c_str());
|
||||
Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : "
|
||||
"missing 'name' attribute\n", m_filename.c_str());
|
||||
throw std::logic_error("File contents are incomplete or corrupt");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GrandPrixData::writeToFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
UTFWriter file(m_filename.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
file << L"\n<supertuxkart_grand_prix name=\"" << m_name << L"\">\n\n";
|
||||
for (unsigned int i = 0; i < m_tracks.size(); i++)
|
||||
{
|
||||
file <<
|
||||
L"\t<track id=\"" << m_tracks[i] <<
|
||||
L"\" laps=\"" << m_laps[i] <<
|
||||
L"\" reverse=\"" << (m_reversed[i] ? L"true" : L"false") <<
|
||||
L"\" />\n";
|
||||
}
|
||||
file << L"\n</supertuxkart_grand_prix>\n";
|
||||
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
Log::error("GrandPrixData", "Failed to write '%s'; cause: %s\n",
|
||||
m_filename.c_str(), e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GrandPrixData::checkConsistency(bool chatty) const
|
||||
{
|
||||
for(unsigned int i=0; i<m_tracks.size(); i++)
|
||||
for (unsigned int i = 0; i<m_tracks.size(); i++)
|
||||
{
|
||||
Track* t = track_manager->getTrack(m_tracks[i]);
|
||||
|
||||
@ -166,6 +213,7 @@ bool GrandPrixData::checkConsistency(bool chatty) const
|
||||
return true;
|
||||
} // checkConsistency
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns true if the track is available. This is used to test if Fort Magma
|
||||
* is available (this way FortMagma is not used in the last Grand Prix in
|
||||
@ -182,7 +230,7 @@ bool GrandPrixData::isTrackAvailable(const std::string &id) const
|
||||
void GrandPrixData::getLaps(std::vector<int> *laps) const
|
||||
{
|
||||
laps->clear();
|
||||
for(unsigned int i=0; i< m_tracks.size(); i++)
|
||||
for (unsigned int i = 0; i< m_tracks.size(); i++)
|
||||
if(isTrackAvailable(m_tracks[i]))
|
||||
laps->push_back(m_laps[i]);
|
||||
} // getLaps
|
||||
@ -191,16 +239,129 @@ void GrandPrixData::getLaps(std::vector<int> *laps) const
|
||||
void GrandPrixData::getReverse(std::vector<bool> *reverse) const
|
||||
{
|
||||
reverse->clear();
|
||||
for(unsigned int i=0; i< m_tracks.size(); i++)
|
||||
for (unsigned int i = 0; i< m_tracks.size(); i++)
|
||||
if(isTrackAvailable(m_tracks[i]))
|
||||
reverse->push_back(m_reversed[i]);
|
||||
} // getReverse
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GrandPrixData::isEditable() const
|
||||
{
|
||||
return m_editable;
|
||||
} // isEditable
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
unsigned int GrandPrixData::getNumberOfTracks() const
|
||||
{
|
||||
return m_tracks.size();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
irr::core::stringw GrandPrixData::getTrackName(const unsigned int track) const
|
||||
{
|
||||
assert(track < getNumberOfTracks());
|
||||
Track* t = track_manager->getTrack(m_tracks[track]);
|
||||
assert(t != NULL);
|
||||
return t->getName();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
const std::string& GrandPrixData::getTrackId(const unsigned int track) const
|
||||
{
|
||||
assert(track < getNumberOfTracks());
|
||||
return m_tracks[track];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
unsigned int GrandPrixData::getLaps(const unsigned int track) const
|
||||
{
|
||||
assert(track < getNumberOfTracks());
|
||||
return m_laps[track];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GrandPrixData::getReverse(const unsigned int track) const
|
||||
{
|
||||
assert(track < getNumberOfTracks());
|
||||
return m_reversed[track];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::moveUp(const unsigned int track)
|
||||
{
|
||||
assert (track > 0 && track < getNumberOfTracks());
|
||||
|
||||
std::swap(m_tracks[track], m_tracks[track - 1]);
|
||||
std::swap(m_laps[track], m_laps[track - 1]);
|
||||
m_reversed.swap(m_reversed[track], m_reversed[track - 1]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::moveDown(const unsigned int track)
|
||||
{
|
||||
assert (track < (getNumberOfTracks() - 1));
|
||||
|
||||
std::swap(m_tracks[track], m_tracks[track + 1]);
|
||||
std::swap(m_laps[track], m_laps[track + 1]);
|
||||
m_reversed.swap(m_reversed[track], m_reversed[track + 1]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::addTrack(Track* track, unsigned int laps, bool reverse,
|
||||
int position)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = getNumberOfTracks();
|
||||
assert (track != NULL);
|
||||
assert (laps > 0);
|
||||
assert (position >= -1 && position < n);
|
||||
|
||||
if (position < 0 || position == (n - 1) || m_tracks.empty())
|
||||
{
|
||||
//Append new track to the end of the list
|
||||
m_tracks.push_back(track->getIdent());
|
||||
m_laps.push_back(laps);
|
||||
m_reversed.push_back(reverse);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Insert new track right after the specified position. Caution:
|
||||
//std::vector inserts elements _before_ the specified position
|
||||
m_tracks.insert(m_tracks.begin() + position + 1, track->getIdent());
|
||||
m_laps.insert(m_laps.begin() + position + 1, laps);
|
||||
m_reversed.insert(m_reversed.begin() + position + 1, reverse);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::editTrack(unsigned int t, Track* track,
|
||||
unsigned int laps, bool reverse)
|
||||
{
|
||||
assert (t < getNumberOfTracks());
|
||||
assert (track != NULL);
|
||||
assert (laps > 0);
|
||||
|
||||
m_tracks[t] = track->getIdent();
|
||||
m_laps[t] = laps;
|
||||
m_reversed[t] = reverse;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixData::remove(const unsigned int track)
|
||||
{
|
||||
assert (track < getNumberOfTracks());
|
||||
|
||||
m_tracks.erase(m_tracks.begin() + track);
|
||||
m_laps.erase(m_laps.begin() + track);
|
||||
m_reversed.erase(m_reversed.begin() + track);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
const std::vector<std::string>& GrandPrixData::getTrackNames() const
|
||||
{
|
||||
m_really_available_tracks.clear();
|
||||
for(unsigned int i=0; i< m_tracks.size(); i++)
|
||||
for (unsigned int i = 0; i < m_tracks.size(); i++)
|
||||
{
|
||||
if(isTrackAvailable(m_tracks[i]))
|
||||
m_really_available_tracks.push_back(m_tracks[i]);
|
||||
|
@ -27,7 +27,8 @@
|
||||
#include <stdexcept>
|
||||
|
||||
#include "utils/translation.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
|
||||
class Track;
|
||||
|
||||
/** Simple class that hold the data relevant to a 'grand_prix', aka. a number
|
||||
* of races that has to be completed one after the other
|
||||
@ -65,28 +66,49 @@ private:
|
||||
/** Whether the track in question should be done in reverse mode */
|
||||
std::vector<bool> m_reversed;
|
||||
|
||||
void load_from_file(const std::string fullpath, const std::string filename);
|
||||
/** Wether the user can edit this grand prix or not */
|
||||
bool m_editable;
|
||||
|
||||
bool isTrackAvailable(const std::string &id) const;
|
||||
|
||||
public:
|
||||
|
||||
/** Load the GrandPrixData from the given filename */
|
||||
#if (defined(WIN32) || defined(_WIN32)) && !defined(__MINGW32__)
|
||||
#pragma warning(disable:4290)
|
||||
#endif
|
||||
GrandPrixData () {}; // empty for initialising
|
||||
GrandPrixData(const std::string filename);
|
||||
GrandPrixData (const std::string dir, const std::string filename);
|
||||
GrandPrixData (const std::string& filename) throw(std::logic_error);
|
||||
GrandPrixData () {}; // empty for initialising
|
||||
|
||||
void setId(const std::string& id);
|
||||
void setName(const irr::core::stringw& name);
|
||||
void setFilename(const std::string& filename);
|
||||
void setEditable(const bool editable);
|
||||
void reload();
|
||||
bool writeToFile();
|
||||
|
||||
bool checkConsistency(bool chatty=true) const;
|
||||
bool checkConsistency(bool chatty=true) const;
|
||||
const std::vector<std::string>& getTrackNames() const;
|
||||
void getLaps(std::vector<int> *laps) const;
|
||||
void getReverse(std::vector<bool> *reverse) const;
|
||||
void getLaps(std::vector<int> *laps) const;
|
||||
void getReverse(std::vector<bool> *reverse) const;
|
||||
bool isEditable() const;
|
||||
unsigned int getNumberOfTracks() const;
|
||||
const std::string& getTrackId(const unsigned int track) const;
|
||||
irr::core::stringw getTrackName(const unsigned int track) const;
|
||||
unsigned int getLaps(const unsigned int track) const;
|
||||
bool getReverse(const unsigned int track) const;
|
||||
void moveUp(const unsigned int track);
|
||||
void moveDown(const unsigned int track);
|
||||
void addTrack(Track* track, unsigned int laps,
|
||||
bool reverse, int position=-1);
|
||||
void editTrack(unsigned int t, Track* track,
|
||||
unsigned int laps, bool reverse);
|
||||
void remove(const unsigned int track);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** @return the (potentially translated) user-visible name of the Grand
|
||||
* Prix (apply fribidi as needed) */
|
||||
const irr::core::stringw getName() const { return _LTR(m_name.c_str()); }
|
||||
irr::core::stringw getName() const { return _LTR(m_name.c_str()); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** @return the internal name identifier of the Grand Prix (not translated) */
|
||||
|
@ -18,66 +18,126 @@
|
||||
|
||||
#include "race/grand_prix_manager.hpp"
|
||||
|
||||
#include <set>
|
||||
#include "config/user_config.hpp"
|
||||
#include "grand_prix_data.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
GrandPrixManager *grand_prix_manager = NULL;
|
||||
|
||||
const char* GrandPrixManager::SUFFIX = ".grandprix";
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixManager::loadFiles()
|
||||
{
|
||||
std::set<std::string> dirs;
|
||||
|
||||
//Add all the directories to a set to avoid duplicates
|
||||
dirs.insert(file_manager->getAsset(FileManager::GRANDPRIX, ""));
|
||||
dirs.insert(file_manager->getGPDir());
|
||||
dirs.insert(UserConfigParams::m_additional_gp_directory);
|
||||
|
||||
for (std::set<std::string>::const_iterator it = dirs.begin(); it != dirs.end(); ++it)
|
||||
{
|
||||
std::string dir = *it;
|
||||
if (!dir.empty() && dir[dir.size() - 1] == '/')
|
||||
loadDir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixManager::loadDir(const std::string& dir)
|
||||
{
|
||||
Log::info("GrandPrixManager", "Loading Grand Prix files from %s", dir.c_str());
|
||||
assert(!dir.empty() && dir[dir.size() - 1] == '/');
|
||||
|
||||
// Findout which grand prixs are available and load them
|
||||
std::set<std::string> result;
|
||||
file_manager->listFiles(result, dir);
|
||||
for(std::set<std::string>::iterator i = result.begin(); i != result.end(); i++)
|
||||
{
|
||||
if (StringUtils::hasSuffix(*i, SUFFIX))
|
||||
load(dir + *i);
|
||||
} // for i
|
||||
} // loadDir
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixManager::load(const std::string& filename)
|
||||
{
|
||||
GrandPrixData* gp;
|
||||
|
||||
try
|
||||
{
|
||||
gp = new GrandPrixData(filename);
|
||||
m_gp_data.push_back(gp);
|
||||
Log::debug("GrandPrixManager", "Grand Prix '%s' loaded from %s",
|
||||
gp->getId().c_str(), filename.c_str());
|
||||
}
|
||||
catch (std::logic_error& er)
|
||||
{
|
||||
Log::error("GrandPrixManager", "Ignoring GP %s (%s)\n",
|
||||
filename.c_str(), er.what());
|
||||
}
|
||||
} // load
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixManager::reload()
|
||||
{
|
||||
for(unsigned int i=0; i<m_gp_data.size(); i++)
|
||||
delete m_gp_data[i];
|
||||
m_gp_data.clear();
|
||||
|
||||
loadFiles();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
std::string GrandPrixManager::generateId()
|
||||
{
|
||||
std::stringstream s;
|
||||
|
||||
do
|
||||
{
|
||||
s.clear();
|
||||
s << "usr_gp_" << ((rand() % 90000000) + 10000000);
|
||||
} while (existsId(s.str()));
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GrandPrixManager::existsId(const std::string& id) const
|
||||
{
|
||||
bool exists;
|
||||
|
||||
exists = false;
|
||||
for (unsigned int i = 0; !exists && i < m_gp_data.size(); i++)
|
||||
exists = (m_gp_data[i]->getId() == id);
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool GrandPrixManager::existsName(const irr::core::stringw& name) const
|
||||
{
|
||||
bool exists;
|
||||
|
||||
exists = false;
|
||||
for (unsigned int i = 0; !exists && i < m_gp_data.size(); i++)
|
||||
exists = (m_gp_data[i]->getName() == name);
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GrandPrixManager::GrandPrixManager()
|
||||
{
|
||||
// Findout which grand prixs are available and load them
|
||||
// Grand Prix in the standart directory
|
||||
std::set<std::string> result;
|
||||
std::string gp_dir = file_manager->getAsset(FileManager::GRANDPRIX, "");
|
||||
file_manager->listFiles(result, gp_dir);
|
||||
for(std::set<std::string>::iterator i = result.begin();
|
||||
i != result.end() ; i++)
|
||||
{
|
||||
if (StringUtils::hasSuffix(*i, ".grandprix"))
|
||||
{
|
||||
try
|
||||
{
|
||||
m_gp_data.push_back(new GrandPrixData(*i));
|
||||
Log::debug("GrandPrixManager", "Grand Prix %s loaded.",
|
||||
i->c_str());
|
||||
}
|
||||
catch (std::logic_error& e)
|
||||
{
|
||||
Log::error("GrandPrixManager", "Ignoring GP %s ( %s ) \n",
|
||||
i->c_str(), e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load additional Grand Prix
|
||||
const std::string dir = UserConfigParams::m_additional_gp_directory;
|
||||
if(dir != "") {
|
||||
Log::info("GrandPrixManager", "Loading additional Grand Prix from "
|
||||
"%s ...", dir.c_str());
|
||||
file_manager->listFiles(result, dir);
|
||||
for(std::set<std::string>::iterator i = result.begin();
|
||||
i != result.end() ; i++)
|
||||
{
|
||||
if (StringUtils::hasSuffix(*i, ".grandprix"))
|
||||
{
|
||||
try
|
||||
{
|
||||
m_gp_data.push_back(new GrandPrixData(dir, *i));
|
||||
Log::debug("GrandPrixManager", "Grand Prix %s loaded from "
|
||||
"%s", i->c_str(),
|
||||
dir.c_str());
|
||||
}
|
||||
catch (std::logic_error& e)
|
||||
{
|
||||
Log::error("GrandPrixManager", "Ignoring GP %s ( %s ) \n",
|
||||
i->c_str(), e.what());
|
||||
}
|
||||
}
|
||||
} // end for
|
||||
} // end if
|
||||
loadFiles();
|
||||
} // GrandPrixManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GrandPrixManager::~GrandPrixManager()
|
||||
{
|
||||
@ -87,15 +147,21 @@ GrandPrixManager::~GrandPrixManager()
|
||||
} // for i
|
||||
|
||||
} // ~GrandPrixManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
const GrandPrixData* GrandPrixManager::getGrandPrix(const std::string& s) const
|
||||
{
|
||||
for(unsigned int i=0; i<m_gp_data.size(); i++)
|
||||
if(m_gp_data[i]->getId() == s)
|
||||
return m_gp_data[i];
|
||||
|
||||
return NULL;
|
||||
return editGrandPrix(s);
|
||||
} // getGrandPrix
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GrandPrixData* GrandPrixManager::editGrandPrix(const std::string& s) const
|
||||
{
|
||||
for(unsigned int i=0; i<m_gp_data.size(); i++)
|
||||
if(m_gp_data[i]->getId()==s) return m_gp_data[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixManager::checkConsistency()
|
||||
{
|
||||
@ -104,9 +170,64 @@ void GrandPrixManager::checkConsistency()
|
||||
if(!m_gp_data[i]->checkConsistency())
|
||||
{
|
||||
// delete this GP, since a track is missing
|
||||
m_gp_data.erase(m_gp_data.begin()+i);
|
||||
delete *(m_gp_data.erase(m_gp_data.begin()+i));
|
||||
i--;
|
||||
}
|
||||
}
|
||||
} // checkConsistency
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GrandPrixData* GrandPrixManager::createNew(const irr::core::stringw& newName)
|
||||
{
|
||||
if (existsName(newName))
|
||||
return NULL;
|
||||
|
||||
std::string newID = generateId();
|
||||
|
||||
GrandPrixData* gp = new GrandPrixData;
|
||||
gp->setId(newID);
|
||||
gp->setName(newName);
|
||||
gp->setFilename(file_manager->getGPDir() + newID + SUFFIX);
|
||||
gp->setEditable(true);
|
||||
gp->writeToFile();
|
||||
m_gp_data.push_back(gp);
|
||||
|
||||
return gp;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GrandPrixData* GrandPrixManager::copy(const std::string& id,
|
||||
const irr::core::stringw& newName)
|
||||
{
|
||||
if (existsName(newName))
|
||||
return NULL;
|
||||
|
||||
std::string newID = generateId();
|
||||
|
||||
GrandPrixData* gp = new GrandPrixData(*getGrandPrix(id));
|
||||
gp->setId(newID);
|
||||
gp->setName(newName);
|
||||
gp->setFilename(file_manager->getGPDir() + newID + SUFFIX);
|
||||
gp->setEditable(true);
|
||||
gp->writeToFile();
|
||||
m_gp_data.push_back(gp);
|
||||
|
||||
return gp;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixManager::remove(const std::string& id)
|
||||
{
|
||||
const GrandPrixData* gp = getGrandPrix(id);
|
||||
assert(gp != NULL);
|
||||
|
||||
if (gp->isEditable())
|
||||
{
|
||||
file_manager->removeFile(gp->getFilename());
|
||||
reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::warn("GrandPrixManager", "Grand Prix '%s' cannot be removed\n", gp->getId().c_str());
|
||||
}
|
||||
}
|
||||
|
@ -30,16 +30,31 @@
|
||||
class GrandPrixManager
|
||||
{
|
||||
private:
|
||||
static const char* SUFFIX;
|
||||
|
||||
void loadFiles();
|
||||
void loadDir(const std::string& dir);
|
||||
void load(const std::string &filename);
|
||||
|
||||
std::string generateId();
|
||||
|
||||
bool existsId(const std::string& id) const;
|
||||
bool existsName(const irr::core::stringw& name) const;
|
||||
|
||||
std::vector<GrandPrixData*> m_gp_data;
|
||||
public:
|
||||
GrandPrixManager();
|
||||
~GrandPrixManager();
|
||||
void load(const std::string &filename);
|
||||
const GrandPrixData* getGrandPrix(int i) const { return m_gp_data[i]; }
|
||||
void reload();
|
||||
const GrandPrixData* getGrandPrix(const int i) const { return m_gp_data[i]; }
|
||||
const GrandPrixData* getGrandPrix(const std::string& s) const;
|
||||
GrandPrixData* editGrandPrix(const std::string& s) const;
|
||||
unsigned int getNumberOfGrandPrix() const { return m_gp_data.size(); }
|
||||
void checkConsistency();
|
||||
|
||||
GrandPrixData* createNew(const irr::core::stringw& newName);
|
||||
GrandPrixData* copy(const std::string& id, const irr::core::stringw& newName);
|
||||
void remove(const std::string& id);
|
||||
}; // GrandPrixManager
|
||||
|
||||
extern GrandPrixManager *grand_prix_manager;
|
||||
|
137
src/states_screens/dialogs/enter_gp_name_dialog.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014 Marc Coll
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "states_screens/dialogs/enter_gp_name_dialog.hpp"
|
||||
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/widgets/button_widget.hpp"
|
||||
#include "guiengine/widgets/label_widget.hpp"
|
||||
#include "guiengine/widgets/text_box_widget.hpp"
|
||||
#include "race/grand_prix_manager.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
#include <IGUIEnvironment.h>
|
||||
|
||||
|
||||
using namespace GUIEngine;
|
||||
using namespace irr::core;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
EnterGPNameDialog::EnterGPNameDialog(INewGPListener* listener,
|
||||
const float w, const float h)
|
||||
: ModalDialog(w, h), m_listener(listener), m_self_destroy(false)
|
||||
{
|
||||
assert(listener != NULL);
|
||||
loadFromFile("enter_gp_name_dialog.stkgui");
|
||||
|
||||
TextBoxWidget* textCtrl = getWidget<TextBoxWidget>("textfield");
|
||||
assert(textCtrl != NULL);
|
||||
textCtrl->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
EnterGPNameDialog::~EnterGPNameDialog()
|
||||
{
|
||||
// FIXME: what is this code for?
|
||||
TextBoxWidget* textCtrl = getWidget<TextBoxWidget>("textfield");
|
||||
textCtrl->getIrrlichtElement()->remove();
|
||||
textCtrl->clearListeners();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
GUIEngine::EventPropagation EnterGPNameDialog::processEvent(const std::string& eventSource)
|
||||
{
|
||||
if (eventSource == "cancel")
|
||||
{
|
||||
dismiss();
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
return GUIEngine::EVENT_LET;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EnterGPNameDialog::onEnterPressedInternal()
|
||||
{
|
||||
//Cancel button pressed
|
||||
ButtonWidget* cancelButton = getWidget<ButtonWidget>("cancel");
|
||||
if (GUIEngine::isFocusedForPlayer(cancelButton, PLAYER_ID_GAME_MASTER))
|
||||
{
|
||||
std::string fakeEvent = "cancel";
|
||||
processEvent(fakeEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
//Otherwise, see if we can accept the new name
|
||||
TextBoxWidget* textCtrl = getWidget<TextBoxWidget>("textfield");
|
||||
assert(textCtrl != NULL);
|
||||
stringw name = textCtrl->getText().trim();
|
||||
if (name.size() > 0)
|
||||
{
|
||||
// check for duplicate names
|
||||
for (int i = 0; i < grand_prix_manager->getNumberOfGrandPrix(); i++)
|
||||
{
|
||||
const GrandPrixData* gp = grand_prix_manager->getGrandPrix(i);
|
||||
if (gp->getName() == name)
|
||||
{
|
||||
LabelWidget* label = getWidget<LabelWidget>("title");
|
||||
assert(label != NULL);
|
||||
label->setText(_("Another grand prix with this name already exists."), false);
|
||||
sfx_manager->quickSound("anvil");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// It's unsafe to delete from inside the event handler so we do it
|
||||
// in onUpdate (which checks for m_self_destroy)
|
||||
m_self_destroy = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LabelWidget* label = getWidget<LabelWidget>("title");
|
||||
assert(label != NULL);
|
||||
label->setText(_("Cannot add a grand prix with this name"), false);
|
||||
sfx_manager->quickSound("anvil");
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EnterGPNameDialog::onUpdate(float dt)
|
||||
{
|
||||
// It's unsafe to delete from inside the event handler so we do it here
|
||||
if (m_self_destroy)
|
||||
{
|
||||
TextBoxWidget* textCtrl = getWidget<TextBoxWidget>("textfield");
|
||||
stringw name = textCtrl->getText().trim();
|
||||
|
||||
// irrLicht is too stupid to remove focus from deleted widgets
|
||||
// so do it by hand
|
||||
GUIEngine::getGUIEnv()->removeFocus( textCtrl->getIrrlichtElement() );
|
||||
GUIEngine::getGUIEnv()->removeFocus( m_irrlicht_window );
|
||||
|
||||
// we will destroy the dialog before notifying the listener to be safer.
|
||||
// but in order not to crash we must make a local copy of the listern
|
||||
// otherwise we will crash
|
||||
INewGPListener* listener = m_listener;
|
||||
|
||||
ModalDialog::dismiss();
|
||||
|
||||
if (listener != NULL)
|
||||
listener->onNewGPWithName(name);
|
||||
}
|
||||
}
|
70
src/states_screens/dialogs/enter_gp_name_dialog.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014 Marc Coll
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
#ifndef HEADER_ENTER_GP_NAME_DIALOG_HPP
|
||||
#define HEADER_ENTER_GP_NAME_DIALOG_HPP
|
||||
|
||||
#include "guiengine/modaldialog.hpp"
|
||||
|
||||
#include <irrString.h>
|
||||
|
||||
|
||||
namespace GUIEngine
|
||||
{
|
||||
class TextBoxWidget;
|
||||
class ButtonWidget;
|
||||
class LabelWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Dialog that allows the player to enter the name for a new grand prix
|
||||
* \ingroup states_screens
|
||||
*/
|
||||
class EnterGPNameDialog : public GUIEngine::ModalDialog
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
class INewGPListener
|
||||
{
|
||||
public:
|
||||
virtual void onNewGPWithName(const irr::core::stringw& newName) = 0;
|
||||
virtual ~INewGPListener(){}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
INewGPListener* m_listener;
|
||||
bool m_self_destroy;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a modal dialog with given percentage of screen width and height
|
||||
*/
|
||||
EnterGPNameDialog(INewGPListener* listener, const float percentWidth,
|
||||
const float percentHeight);
|
||||
~EnterGPNameDialog();
|
||||
|
||||
void onEnterPressedInternal();
|
||||
GUIEngine::EventPropagation processEvent(const std::string& eventSource);
|
||||
|
||||
virtual void onUpdate(float dt);
|
||||
};
|
||||
|
||||
#endif
|
@ -278,6 +278,24 @@ void UserInfoDialog::declineFriendRequest()
|
||||
|
||||
} // declineFriendRequest
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Removes an existing friend.
|
||||
*/
|
||||
void UserInfoDialog::removeExistingFriend()
|
||||
{
|
||||
CurrentUser::get()->requestRemoveFriend(m_profile->getID());
|
||||
|
||||
} // removeExistingFriend
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Removes a pending friend request.
|
||||
*/
|
||||
void UserInfoDialog::removePendingFriend()
|
||||
{
|
||||
CurrentUser::get()->requestCancelFriend(m_profile->getID());
|
||||
|
||||
} // removePendingFriend
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
GUIEngine::EventPropagation UserInfoDialog::processEvent(const std::string& eventSource)
|
||||
{
|
||||
@ -304,10 +322,12 @@ GUIEngine::EventPropagation UserInfoDialog::processEvent(const std::string& even
|
||||
}
|
||||
else if(selection == m_remove_widget->m_properties[PROP_ID])
|
||||
{
|
||||
if(m_profile->getRelationInfo()->isPending())
|
||||
CurrentUser::get()->requestCancelFriend(m_profile->getID());
|
||||
if (m_profile->getRelationInfo() &&
|
||||
m_profile->getRelationInfo()->isPending() )
|
||||
removePendingFriend();
|
||||
else
|
||||
CurrentUser::get()->requestRemoveFriend(m_profile->getID());
|
||||
removeExistingFriend();
|
||||
|
||||
m_processing = true;
|
||||
m_options_widget->setDeactivated();
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
|
@ -63,6 +63,8 @@ private:
|
||||
void sendFriendRequest();
|
||||
void acceptFriendRequest();
|
||||
void declineFriendRequest();
|
||||
void removeExistingFriend();
|
||||
void removePendingFriend();
|
||||
|
||||
public:
|
||||
UserInfoDialog(uint32_t showing_id, const core::stringw info = "", bool error = false, bool from_queue = false);
|
||||
|
334
src/states_screens/edit_gp_screen.cpp
Normal file
@ -0,0 +1,334 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014 Marc Coll
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "states_screens/edit_gp_screen.hpp"
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "guiengine/CGUISpriteBank.h"
|
||||
#include "guiengine/widgets/dynamic_ribbon_widget.hpp"
|
||||
#include "guiengine/widgets/icon_button_widget.hpp"
|
||||
#include "guiengine/widgets/label_widget.hpp"
|
||||
#include "guiengine/widgets/list_widget.hpp"
|
||||
#include "race/grand_prix_data.hpp"
|
||||
#include "states_screens/edit_track_screen.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
|
||||
|
||||
using namespace GUIEngine;
|
||||
|
||||
DEFINE_SCREEN_SINGLETON( EditGPScreen );
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
EditGPScreen::EditGPScreen()
|
||||
: Screen("gpedit.stkgui"), m_gp(NULL), m_list(NULL), m_icon_bank(NULL),
|
||||
m_selected(-1), m_modified(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
EditGPScreen::~EditGPScreen()
|
||||
{
|
||||
delete m_icon_bank;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::setSelectedGP(GrandPrixData* gp)
|
||||
{
|
||||
assert(gp != NULL);
|
||||
m_gp = gp;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::loadedFromFile()
|
||||
{
|
||||
if (m_icon_bank == NULL)
|
||||
m_icon_bank = new irr::gui::STKModifiedSpriteBank(GUIEngine::getGUIEnv());
|
||||
|
||||
m_list = getWidget<ListWidget>("tracks");
|
||||
assert(m_list != NULL);
|
||||
m_list->addColumn(_("Track"), 3);
|
||||
m_list->addColumn(_("Laps"), 1);
|
||||
m_list->addColumn(_("Reversed"), 1);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||
const int playerID)
|
||||
{
|
||||
setSelected(m_list->getSelectionID());
|
||||
|
||||
if (name == "tracks")
|
||||
{
|
||||
m_action = "edit";
|
||||
edit();
|
||||
}
|
||||
else if (name == "menu")
|
||||
{
|
||||
RibbonWidget* menu = getWidget<RibbonWidget>("menu");
|
||||
assert(menu != NULL);
|
||||
m_action = menu->getSelectionIDString(PLAYER_ID_GAME_MASTER);
|
||||
|
||||
if (m_action == "up")
|
||||
{
|
||||
if (canMoveUp())
|
||||
{
|
||||
m_gp->moveUp(m_selected--);
|
||||
loadList(m_selected);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
else if (m_action == "down")
|
||||
{
|
||||
if (canMoveDown())
|
||||
{
|
||||
m_gp->moveDown(m_selected++);
|
||||
loadList(m_selected);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
else if (m_action == "add" || m_action == "edit")
|
||||
{
|
||||
if (m_action == "edit")
|
||||
{
|
||||
edit();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditTrackScreen* edit = EditTrackScreen::getInstance();
|
||||
assert(edit != NULL);
|
||||
//By default, 3 laps and no reversing
|
||||
edit->setSelection(NULL, 3, false);
|
||||
StateManager::get()->pushScreen(edit);
|
||||
}
|
||||
}
|
||||
else if (m_action == "remove")
|
||||
{
|
||||
if (m_selected >= 0 && m_selected < m_list->getItemCount())
|
||||
{
|
||||
new MessageDialog(
|
||||
_("Are you sure you want to remove '%s'?",
|
||||
m_gp->getTrackName(m_selected).c_str()),
|
||||
MessageDialog::MESSAGE_DIALOG_CONFIRM,
|
||||
this, false);
|
||||
}
|
||||
}
|
||||
else if (m_action == "save")
|
||||
{
|
||||
save();
|
||||
}
|
||||
}
|
||||
else if (name == "back")
|
||||
{
|
||||
if (m_modified)
|
||||
{
|
||||
m_action = "back";
|
||||
new MessageDialog(
|
||||
_("Do you want to save your changes?"),
|
||||
MessageDialog::MESSAGE_DIALOG_CONFIRM,
|
||||
this, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::init()
|
||||
{
|
||||
if (m_action.empty())
|
||||
{
|
||||
LabelWidget* header = getWidget<LabelWidget>("title");
|
||||
assert(header != NULL);
|
||||
header->setText(m_gp->getName(), true);
|
||||
|
||||
IconButtonWidget* button = getWidget<IconButtonWidget>("save");
|
||||
assert(button != NULL);
|
||||
button->setDeactivated();
|
||||
|
||||
loadList(0);
|
||||
setModified(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditTrackScreen* edit = EditTrackScreen::getInstance();
|
||||
assert(edit != NULL);
|
||||
|
||||
if (edit->getResult())
|
||||
{
|
||||
if (m_action == "add")
|
||||
{
|
||||
m_gp->addTrack(edit->getTrack(), edit->getLaps(), edit->getReverse(),
|
||||
m_selected);
|
||||
setSelected(m_selected + 1);
|
||||
}
|
||||
else if (m_action == "edit")
|
||||
{
|
||||
m_gp->editTrack(m_selected, edit->getTrack(), edit->getLaps(),
|
||||
edit->getReverse());
|
||||
}
|
||||
setModified(true);
|
||||
}
|
||||
loadList(m_selected);
|
||||
m_action.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::onConfirm()
|
||||
{
|
||||
ModalDialog::dismiss();
|
||||
if (m_action == "remove")
|
||||
{
|
||||
m_gp->remove(m_selected);
|
||||
setSelected(m_selected >= m_gp->getNumberOfTracks() ?
|
||||
m_gp->getNumberOfTracks() - 1 : m_selected);
|
||||
loadList(m_selected);
|
||||
setModified(true);
|
||||
}
|
||||
else if (m_action == "back")
|
||||
{
|
||||
save();
|
||||
back();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::onCancel()
|
||||
{
|
||||
ModalDialog::dismiss();
|
||||
if (m_action == "back")
|
||||
back();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::loadList(const int selected)
|
||||
{
|
||||
m_list->clear();
|
||||
m_icons.clear();
|
||||
m_icon_bank->clear();
|
||||
m_icon_bank->scaleToHeight (64);
|
||||
m_list->setIcons(m_icon_bank, 64);
|
||||
|
||||
for (unsigned int i = 0; i < m_gp->getNumberOfTracks(); i++)
|
||||
{
|
||||
std::vector<GUIEngine::ListWidget::ListCell> row;
|
||||
|
||||
Track* t = track_manager->getTrack(m_gp->getTrackId(i));
|
||||
assert(t != NULL);
|
||||
video::ITexture* screenShot = irr_driver->getTexture(t->getScreenshotFile());
|
||||
assert(screenShot != NULL);
|
||||
m_icons.push_back(m_icon_bank->addTextureAsSprite(screenShot));
|
||||
|
||||
row.push_back(GUIEngine::ListWidget::ListCell(
|
||||
_LTR(m_gp->getTrackName(i).c_str()), m_icons[i], 3, false));
|
||||
row.push_back(GUIEngine::ListWidget::ListCell(
|
||||
StringUtils::toWString<unsigned int>(m_gp->getLaps(i)), -1, 1, true));
|
||||
row.push_back(GUIEngine::ListWidget::ListCell(
|
||||
m_gp->getReverse(i) ? _("Yes") : _("No"), -1, 1, true));
|
||||
|
||||
m_list->addItem(m_gp->getId(), row);
|
||||
}
|
||||
m_list->setIcons(m_icon_bank);
|
||||
|
||||
if (selected < m_list->getItemCount())
|
||||
{
|
||||
m_list->setSelectionID(selected);
|
||||
setSelected(selected);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::setModified(const bool modified)
|
||||
{
|
||||
m_modified = modified;
|
||||
|
||||
IconButtonWidget* save_button = getWidget<IconButtonWidget>("save");
|
||||
assert(save_button != NULL);
|
||||
if (modified)
|
||||
save_button->setActivated();
|
||||
else
|
||||
save_button->setDeactivated();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::setSelected(const int selected)
|
||||
{
|
||||
IconButtonWidget* button_up = getWidget<IconButtonWidget>("up");
|
||||
assert(button_up != NULL);
|
||||
IconButtonWidget* button_down = getWidget<IconButtonWidget>("down");
|
||||
assert(button_down != NULL);
|
||||
|
||||
m_selected = selected;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::edit()
|
||||
{
|
||||
EditTrackScreen* edit_screen = EditTrackScreen::getInstance();
|
||||
assert(edit_screen != NULL);
|
||||
|
||||
if (m_selected >= 0 && m_selected < m_list->getItemCount())
|
||||
{
|
||||
edit_screen->setSelection(track_manager->getTrack(
|
||||
m_gp->getTrackId(m_selected)),
|
||||
m_gp->getLaps(m_selected),
|
||||
m_gp->getReverse(m_selected));
|
||||
StateManager::get()->pushScreen(edit_screen);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
bool EditGPScreen::save()
|
||||
{
|
||||
if (m_gp->writeToFile())
|
||||
{
|
||||
setModified(false);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
new MessageDialog(
|
||||
_("An error occurred while trying to save your grand prix"),
|
||||
MessageDialog::MESSAGE_DIALOG_OK, NULL, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditGPScreen::back ()
|
||||
{
|
||||
m_action.clear();
|
||||
m_modified = false;
|
||||
StateManager::get()->popMenu();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
bool EditGPScreen::canMoveUp() const
|
||||
{
|
||||
return (m_selected > 0 && m_selected < m_list->getItemCount());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
bool EditGPScreen::canMoveDown() const
|
||||
{
|
||||
return (m_selected >= 0 && m_selected < (m_list->getItemCount() - 1));
|
||||
}
|
85
src/states_screens/edit_gp_screen.hpp
Normal file
@ -0,0 +1,85 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014 Marc Coll
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_EDIT_GP_SCREEN_HPP
|
||||
#define HEADER_EDIT_GP_SCREEN_HPP
|
||||
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "guiengine/widgets/list_widget.hpp"
|
||||
#include "states_screens/dialogs/message_dialog.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace GUIEngine { class Widget; }
|
||||
namespace irr { namespace gui { class STKModifiedSpriteBank; } }
|
||||
|
||||
class GrandPrixData;
|
||||
|
||||
/**
|
||||
* \brief screen where the user can edit a grand prix
|
||||
* \ingroup states_screens
|
||||
*/
|
||||
class EditGPScreen :
|
||||
public GUIEngine::Screen,
|
||||
public GUIEngine::ScreenSingleton<EditGPScreen>,
|
||||
public MessageDialog::IConfirmDialogListener
|
||||
{
|
||||
friend class GUIEngine::ScreenSingleton<EditGPScreen>;
|
||||
|
||||
EditGPScreen();
|
||||
|
||||
void onConfirm();
|
||||
void onCancel();
|
||||
|
||||
void loadList(const int selected);
|
||||
void setModified(const bool modified);
|
||||
void setSelected(const int selected);
|
||||
void edit();
|
||||
bool save();
|
||||
void back();
|
||||
|
||||
bool canMoveUp() const;
|
||||
bool canMoveDown() const;
|
||||
|
||||
GrandPrixData* m_gp;
|
||||
GUIEngine::ListWidget* m_list;
|
||||
irr::gui::STKModifiedSpriteBank* m_icon_bank;
|
||||
std::vector<int> m_icons;
|
||||
int m_selected;
|
||||
bool m_modified;
|
||||
|
||||
std::string m_action;
|
||||
|
||||
public:
|
||||
|
||||
~EditGPScreen();
|
||||
|
||||
void setSelectedGP(GrandPrixData* gp);
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void loadedFromFile() OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||
const int playerID) OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void init() OVERRIDE;
|
||||
};
|
||||
|
||||
#endif
|
240
src/states_screens/edit_track_screen.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014 Marc Coll
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "states_screens/edit_track_screen.hpp"
|
||||
|
||||
#include "guiengine/widgets/button_widget.hpp"
|
||||
#include "guiengine/widgets/check_box_widget.hpp"
|
||||
#include "guiengine/widgets/dynamic_ribbon_widget.hpp"
|
||||
#include "guiengine/widgets/label_widget.hpp"
|
||||
#include "guiengine/widgets/ribbon_widget.hpp"
|
||||
#include "guiengine/widgets/spinner_widget.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
|
||||
|
||||
using namespace GUIEngine;
|
||||
using namespace irr::core;
|
||||
|
||||
const char* EditTrackScreen::ALL_TRACKS_GROUP_ID = "all";
|
||||
|
||||
DEFINE_SCREEN_SINGLETON( EditTrackScreen );
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
EditTrackScreen::EditTrackScreen()
|
||||
: Screen("edit_track.stkgui"), m_track_group(ALL_TRACKS_GROUP_ID),
|
||||
m_track(NULL), m_laps(0), m_reverse(false), m_result(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
EditTrackScreen::~EditTrackScreen()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditTrackScreen::setSelection(Track* track, unsigned int laps, bool reverse)
|
||||
{
|
||||
assert(laps > 0);
|
||||
m_track = track;
|
||||
m_laps = laps;
|
||||
m_reverse = reverse;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
Track* EditTrackScreen::getTrack() const
|
||||
{
|
||||
return m_track;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
unsigned int EditTrackScreen::getLaps() const
|
||||
{
|
||||
return m_laps;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
bool EditTrackScreen::getReverse() const
|
||||
{
|
||||
return m_reverse;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
bool EditTrackScreen::getResult() const
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditTrackScreen::loadedFromFile()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditTrackScreen::eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||
const int playerID)
|
||||
{
|
||||
if (name == "ok")
|
||||
{
|
||||
m_result = true;
|
||||
StateManager::get()->popMenu();
|
||||
}
|
||||
else if (name == "cancel")
|
||||
{
|
||||
m_result = false;
|
||||
StateManager::get()->popMenu();
|
||||
}
|
||||
else if (name == "tracks")
|
||||
{
|
||||
DynamicRibbonWidget* tracks = getWidget<DynamicRibbonWidget>("tracks");
|
||||
assert(tracks != NULL);
|
||||
selectTrack(tracks->getSelectionIDString(PLAYER_ID_GAME_MASTER));
|
||||
}
|
||||
else if (name == "trackgroups")
|
||||
{
|
||||
RibbonWidget* tabs = getWidget<RibbonWidget>("trackgroups");
|
||||
assert(tabs != NULL);
|
||||
m_track_group = tabs->getSelectionIDString(PLAYER_ID_GAME_MASTER);
|
||||
loadTrackList();
|
||||
}
|
||||
else if (name == "laps")
|
||||
{
|
||||
SpinnerWidget* laps = getWidget<SpinnerWidget>("laps");
|
||||
assert(laps != NULL);
|
||||
m_laps = laps->getValue();
|
||||
}
|
||||
else if (name == "reverse")
|
||||
{
|
||||
CheckBoxWidget* reverse = getWidget<CheckBoxWidget>("reverse");
|
||||
assert(reverse != NULL);
|
||||
m_reverse = reverse->getState();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditTrackScreen::beforeAddingWidget()
|
||||
{
|
||||
RibbonWidget* tabs = getWidget<RibbonWidget>("trackgroups");
|
||||
assert (tabs != NULL);
|
||||
|
||||
tabs->clearAllChildren();
|
||||
|
||||
const std::vector<std::string>& groups = track_manager->getAllTrackGroups();
|
||||
if (groups.size() > 1)
|
||||
{
|
||||
tabs->addTextChild(_("All"), ALL_TRACKS_GROUP_ID);
|
||||
for (unsigned int i = 0; i < groups.size(); i++)
|
||||
tabs->addTextChild(_(groups[i].c_str()), groups[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditTrackScreen::init()
|
||||
{
|
||||
RibbonWidget* tabs = getWidget<RibbonWidget>("trackgroups");
|
||||
assert (tabs != NULL);
|
||||
SpinnerWidget* laps = getWidget<SpinnerWidget>("laps");
|
||||
assert(laps != NULL);
|
||||
CheckBoxWidget* reverse = getWidget<CheckBoxWidget>("reverse");
|
||||
assert(reverse != NULL);
|
||||
|
||||
if (m_track_group.empty())
|
||||
tabs->select (ALL_TRACKS_GROUP_ID, PLAYER_ID_GAME_MASTER);
|
||||
else
|
||||
tabs->select (m_track_group, PLAYER_ID_GAME_MASTER);
|
||||
laps->setValue(m_laps);
|
||||
reverse->setState(m_reverse);
|
||||
|
||||
loadTrackList();
|
||||
if (m_track == NULL)
|
||||
selectTrack("");
|
||||
else
|
||||
selectTrack(m_track->getIdent());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditTrackScreen::loadTrackList()
|
||||
{
|
||||
bool belongsToGroup;
|
||||
|
||||
DynamicRibbonWidget* tracks_widget = getWidget<DynamicRibbonWidget>("tracks");
|
||||
assert(tracks_widget != NULL);
|
||||
|
||||
tracks_widget->clearItems();
|
||||
|
||||
for (unsigned int i = 0; i < track_manager->getNumberOfTracks(); i++)
|
||||
{
|
||||
Track* t = track_manager->getTrack(i);
|
||||
const std::vector<std::string>& groups = t->getGroups();
|
||||
belongsToGroup = (m_track_group.empty() || m_track_group == ALL_TRACKS_GROUP_ID ||
|
||||
std::find(groups.begin(), groups.end(), m_track_group) != groups.end());
|
||||
if (!t->isArena() && !t->isSoccer() && !t->isInternal() && belongsToGroup)
|
||||
{
|
||||
tracks_widget->addItem(translations->fribidize(t->getName()), t->getIdent(),
|
||||
t->getScreenshotFile(), 0, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE );
|
||||
}
|
||||
}
|
||||
|
||||
tracks_widget->updateItemDisplay();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditTrackScreen::selectTrack(const std::string& id)
|
||||
{
|
||||
DynamicRibbonWidget* tracks = getWidget<DynamicRibbonWidget>("tracks");
|
||||
assert(tracks != NULL);
|
||||
LabelWidget* selected_track = getWidget<LabelWidget>("selected_track");
|
||||
assert(selected_track != NULL);
|
||||
SpinnerWidget* laps = getWidget<SpinnerWidget>("laps");
|
||||
assert(laps != NULL);
|
||||
LabelWidget* label_reverse = getWidget<LabelWidget>("reverse_label");
|
||||
assert(label_reverse != NULL);
|
||||
CheckBoxWidget* reverse = getWidget<CheckBoxWidget>("reverse");
|
||||
assert(reverse != NULL);
|
||||
ButtonWidget* ok_button = getWidget<ButtonWidget>("ok");
|
||||
assert(ok_button != NULL);
|
||||
|
||||
m_track = track_manager->getTrack(id);
|
||||
if (m_track != NULL)
|
||||
{
|
||||
tracks->setSelection(m_track->getIdent(), PLAYER_ID_GAME_MASTER, true);
|
||||
selected_track->setText(m_track->getName(), true);
|
||||
|
||||
laps->setValue(m_laps);
|
||||
|
||||
reverse->setVisible(m_track->reverseAvailable());
|
||||
label_reverse->setVisible(m_track->reverseAvailable());
|
||||
|
||||
ok_button->setActivated();
|
||||
}
|
||||
else
|
||||
{
|
||||
tracks->setSelection("", PLAYER_ID_GAME_MASTER, true);
|
||||
selected_track->setText(_("Select a track"), true);
|
||||
|
||||
laps->setValue(3);
|
||||
|
||||
reverse->setVisible(true);
|
||||
reverse->setState(false);
|
||||
|
||||
ok_button->setDeactivated();
|
||||
}
|
||||
}
|
78
src/states_screens/edit_track_screen.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014 Marc Coll
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_EDIT_TRACK_SCREEN_HPP
|
||||
#define HEADER_EDIT_TRACK_SCREEN_HPP
|
||||
|
||||
#include "guiengine/screen.hpp"
|
||||
|
||||
|
||||
namespace GUIEngine { class Widget; }
|
||||
|
||||
namespace irr { namespace gui { class STKModifiedSpriteBank; } }
|
||||
|
||||
class Track;
|
||||
|
||||
/**
|
||||
* \brief screen where the user can edit the details of a track inside a grand prix
|
||||
* \ingroup states_screens
|
||||
*/
|
||||
class EditTrackScreen :
|
||||
public GUIEngine::Screen,
|
||||
public GUIEngine::ScreenSingleton<EditTrackScreen>
|
||||
{
|
||||
friend class GUIEngine::ScreenSingleton<EditTrackScreen>;
|
||||
|
||||
static const char* ALL_TRACKS_GROUP_ID;
|
||||
|
||||
EditTrackScreen();
|
||||
|
||||
void loadTrackList();
|
||||
void selectTrack(const std::string& id);
|
||||
|
||||
std::string m_track_group;
|
||||
|
||||
Track* m_track;
|
||||
unsigned int m_laps;
|
||||
bool m_reverse;
|
||||
bool m_result;
|
||||
|
||||
public:
|
||||
|
||||
~EditTrackScreen();
|
||||
|
||||
void setSelection(Track* track, unsigned int laps, bool reverse);
|
||||
Track* getTrack() const;
|
||||
unsigned int getLaps() const;
|
||||
bool getReverse() const;
|
||||
bool getResult() const;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void beforeAddingWidget() OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void loadedFromFile() OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||
const int playerID) OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void init() OVERRIDE;
|
||||
};
|
||||
|
||||
#endif
|
286
src/states_screens/grand_prix_editor_screen.cpp
Normal file
@ -0,0 +1,286 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014 Marc Coll
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "states_screens/grand_prix_editor_screen.hpp"
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "guiengine/widget.hpp"
|
||||
#include "guiengine/widgets/label_widget.hpp"
|
||||
#include "guiengine/widgets/dynamic_ribbon_widget.hpp"
|
||||
#include "guiengine/widgets/icon_button_widget.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "race/grand_prix_data.hpp"
|
||||
#include "race/grand_prix_manager.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "states_screens/edit_gp_screen.hpp"
|
||||
#include "states_screens/dialogs/enter_gp_name_dialog.hpp"
|
||||
#include "states_screens/dialogs/gp_info_dialog.hpp"
|
||||
#include "states_screens/dialogs/track_info_dialog.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
|
||||
using namespace GUIEngine;
|
||||
using namespace irr::core;
|
||||
|
||||
DEFINE_SCREEN_SINGLETON( GrandPrixEditorScreen );
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
GrandPrixEditorScreen::GrandPrixEditorScreen()
|
||||
: Screen("gpeditor.stkgui"), m_selection(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GrandPrixEditorScreen::loadedFromFile()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GrandPrixEditorScreen::eventCallback(Widget* widget, const std::string& name, const int playerID)
|
||||
{
|
||||
DynamicRibbonWidget* gplist_widget = getWidget<DynamicRibbonWidget>("gplist");
|
||||
assert (gplist_widget != NULL);
|
||||
std::string selected = gplist_widget->getSelectionIDString(PLAYER_ID_GAME_MASTER);
|
||||
if (!selected.empty())
|
||||
setSelection (grand_prix_manager->getGrandPrix(selected));
|
||||
|
||||
if (name == "menu")
|
||||
{
|
||||
RibbonWidget* menu = getWidget<RibbonWidget>("menu");
|
||||
assert(menu != NULL);
|
||||
m_action = menu->getSelectionIDString(PLAYER_ID_GAME_MASTER);
|
||||
|
||||
if (m_action == "new" || m_action == "copy")
|
||||
{
|
||||
new EnterGPNameDialog(this, 0.5f, 0.4f);
|
||||
}
|
||||
else if (m_action == "edit")
|
||||
{
|
||||
if (m_selection->isEditable())
|
||||
{
|
||||
showEditScreen(m_selection);
|
||||
}
|
||||
else
|
||||
{
|
||||
new MessageDialog(
|
||||
_("You can't edit the '%s' grand prix.\nYou might want to copy it first",
|
||||
m_selection->getName().c_str()),
|
||||
MessageDialog::MESSAGE_DIALOG_OK, NULL, false);
|
||||
}
|
||||
}
|
||||
else if (m_action == "remove")
|
||||
{
|
||||
if (m_selection->isEditable())
|
||||
{
|
||||
new MessageDialog(
|
||||
_("Are you sure you want to remove '%s'?", m_selection->getName().c_str()),
|
||||
MessageDialog::MESSAGE_DIALOG_CONFIRM,
|
||||
this, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
new MessageDialog(
|
||||
_("You can't remove '%s'.", m_selection->getName().c_str()),
|
||||
MessageDialog::MESSAGE_DIALOG_OK, NULL, false);
|
||||
}
|
||||
}
|
||||
else if (m_action == "rename")
|
||||
{
|
||||
if (m_selection->isEditable())
|
||||
{
|
||||
new EnterGPNameDialog(this, 0.5f, 0.4f);
|
||||
}
|
||||
else
|
||||
{
|
||||
new MessageDialog(
|
||||
_("You can't rename '%s'.", m_selection->getName().c_str()),
|
||||
MessageDialog::MESSAGE_DIALOG_OK, NULL, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (name == "back")
|
||||
{
|
||||
StateManager::get()->escapePressed();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GrandPrixEditorScreen::init()
|
||||
{
|
||||
if (grand_prix_manager->getNumberOfGrandPrix() > 0)
|
||||
{
|
||||
if (m_selection == NULL)
|
||||
{
|
||||
loadGPList();
|
||||
setSelection (grand_prix_manager->getGrandPrix(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string id = m_selection->getId();
|
||||
grand_prix_manager->reload();
|
||||
loadGPList();
|
||||
m_selection = grand_prix_manager->editGrandPrix(id);
|
||||
m_selection->reload();
|
||||
setSelection (m_selection);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loadGPList();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GrandPrixEditorScreen::setSelection (const GrandPrixData* gpdata)
|
||||
{
|
||||
LabelWidget* gpname_widget = getWidget<LabelWidget>("gpname");
|
||||
assert(gpname_widget != NULL);
|
||||
DynamicRibbonWidget* gplist_widget = getWidget<DynamicRibbonWidget>("gplist");
|
||||
assert (gplist_widget != NULL);
|
||||
|
||||
m_selection = grand_prix_manager->editGrandPrix(gpdata->getId());
|
||||
gpname_widget->setText (gpdata->getName(), true);
|
||||
gplist_widget->setSelection(m_selection->getId(), PLAYER_ID_GAME_MASTER, true);
|
||||
loadTrackList (gpdata->getId());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GrandPrixEditorScreen::loadTrackList (const std::string& gpname)
|
||||
{
|
||||
if (gpname.empty())
|
||||
return;
|
||||
|
||||
DynamicRibbonWidget* tracks_widget = getWidget<DynamicRibbonWidget>("tracks");
|
||||
assert(tracks_widget != NULL);
|
||||
|
||||
const GrandPrixData* gp = grand_prix_manager->getGrandPrix(gpname);
|
||||
const std::vector<std::string>& tracks = gp->getTrackNames();
|
||||
|
||||
tracks_widget->clearItems();
|
||||
tracks_widget->setItemCountHint(tracks.size());
|
||||
for (unsigned int t = 0; t < tracks.size(); t++)
|
||||
{
|
||||
Track* curr = track_manager->getTrack(tracks[t]);
|
||||
if (curr == NULL)
|
||||
{
|
||||
Log::warn("GrandPrixEditor",
|
||||
"Grand Prix '%s' refers to track '%s', which does not exist\n",
|
||||
gp->getId().c_str(), tracks[t].c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
tracks_widget->addItem(
|
||||
StringUtils::toWString(t + 1) + ". " + translations->fribidize(curr->getName()),
|
||||
curr->getIdent(), curr->getScreenshotFile(), 0,
|
||||
IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE );
|
||||
}
|
||||
}
|
||||
|
||||
tracks_widget->updateItemDisplay();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GrandPrixEditorScreen::loadGPList()
|
||||
{
|
||||
DynamicRibbonWidget* gplist_widget = getWidget<DynamicRibbonWidget>("gplist");
|
||||
assert(gplist_widget != NULL);
|
||||
|
||||
// Reset GP list everytime (accounts for locking changes, etc.)
|
||||
gplist_widget->clearItems();
|
||||
|
||||
// Build GP list
|
||||
for (unsigned int i = 0; i < grand_prix_manager->getNumberOfGrandPrix(); i++)
|
||||
{
|
||||
const GrandPrixData* gp = grand_prix_manager->getGrandPrix(i);
|
||||
const std::vector<std::string>& tracks = gp->getTrackNames();
|
||||
|
||||
std::vector<std::string> sshot_files;
|
||||
for (unsigned int t=0; t<tracks.size(); t++)
|
||||
{
|
||||
Track* track = track_manager->getTrack(tracks[t]);
|
||||
if (track == NULL)
|
||||
{
|
||||
Log::warn("GrandPrixEditor",
|
||||
"Grand Prix '%s' refers to track '%s', which does not exist\n",
|
||||
gp->getId().c_str(), tracks[t].c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
sshot_files.push_back(track->getScreenshotFile());
|
||||
}
|
||||
}
|
||||
if (sshot_files.size() == 0)
|
||||
{
|
||||
Log::warn("GrandPrixEditor",
|
||||
"Grand Prix '%s' does not contain any valid track\n",
|
||||
gp->getId().c_str());
|
||||
sshot_files.push_back("gui/main_help.png");
|
||||
}
|
||||
|
||||
gplist_widget->addAnimatedItem(translations->fribidize(gp->getName()), gp->getId(),
|
||||
sshot_files, 2.0f, 0, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE );
|
||||
}
|
||||
|
||||
gplist_widget->updateItemDisplay();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GrandPrixEditorScreen::showEditScreen(GrandPrixData* gp)
|
||||
{
|
||||
assert(gp != NULL);
|
||||
EditGPScreen* edit = EditGPScreen::getInstance();
|
||||
edit->setSelectedGP(gp);
|
||||
StateManager::get()->pushScreen(edit);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GrandPrixEditorScreen::onNewGPWithName(const stringw& newName)
|
||||
{
|
||||
if (m_action == "copy")
|
||||
{
|
||||
setSelection(grand_prix_manager->copy(m_selection->getId(), newName));
|
||||
}
|
||||
else if (m_action == "rename")
|
||||
{
|
||||
m_selection->setName(newName);
|
||||
m_selection->writeToFile();
|
||||
}
|
||||
else if (m_action == "new")
|
||||
{
|
||||
setSelection(grand_prix_manager->createNew(newName));
|
||||
}
|
||||
|
||||
loadGPList();
|
||||
if (m_action != "rename")
|
||||
showEditScreen(m_selection);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GrandPrixEditorScreen::onConfirm()
|
||||
{
|
||||
if (m_action == "remove")
|
||||
{
|
||||
grand_prix_manager->remove(m_selection->getId());
|
||||
loadGPList();
|
||||
if (grand_prix_manager->getNumberOfGrandPrix() > 0)
|
||||
setSelection (grand_prix_manager->getGrandPrix(0));
|
||||
}
|
||||
ModalDialog::dismiss();
|
||||
}
|
68
src/states_screens/grand_prix_editor_screen.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014 Marc Coll
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_GRAND_PRIX_EDITOR_SCREEN_HPP
|
||||
#define HEADER_GRAND_PRIX_EDITOR_SCREEN_HPP
|
||||
|
||||
#include "dialogs/enter_gp_name_dialog.hpp"
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "states_screens/dialogs/message_dialog.hpp"
|
||||
|
||||
|
||||
namespace GUIEngine { class Widget; }
|
||||
|
||||
class GrandPrixData;
|
||||
|
||||
/**
|
||||
* \brief screen where the user can edit his own grand prix
|
||||
* \ingroup states_screens
|
||||
*/
|
||||
class GrandPrixEditorScreen :
|
||||
public GUIEngine::Screen,
|
||||
public GUIEngine::ScreenSingleton<GrandPrixEditorScreen>,
|
||||
public EnterGPNameDialog::INewGPListener,
|
||||
public MessageDialog::IConfirmDialogListener
|
||||
{
|
||||
friend class GUIEngine::ScreenSingleton<GrandPrixEditorScreen>;
|
||||
|
||||
GrandPrixEditorScreen();
|
||||
|
||||
void setSelection(const GrandPrixData* gpdata);
|
||||
void loadGPList();
|
||||
void loadTrackList(const std::string& gpname);
|
||||
void showEditScreen(GrandPrixData* gp);
|
||||
|
||||
void onNewGPWithName(const irr::core::stringw& newName);
|
||||
void onConfirm();
|
||||
|
||||
GrandPrixData* m_selection;
|
||||
std::string m_action;
|
||||
|
||||
public:
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void loadedFromFile() OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||
const int playerID) OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void init() OVERRIDE;
|
||||
};
|
||||
|
||||
#endif
|
@ -39,6 +39,7 @@
|
||||
#include "online/request_manager.hpp"
|
||||
#include "states_screens/addons_screen.hpp"
|
||||
#include "states_screens/credits.hpp"
|
||||
#include "states_screens/grand_prix_editor_screen.hpp"
|
||||
#include "states_screens/help_screen_1.hpp"
|
||||
#include "states_screens/login_screen.hpp"
|
||||
#include "states_screens/offline_kart_selection.hpp"
|
||||
@ -424,6 +425,10 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name,
|
||||
}
|
||||
StateManager::get()->pushScreen(AddonsScreen::getInstance());
|
||||
}
|
||||
else if (selection == "gpEditor")
|
||||
{
|
||||
StateManager::get()->pushScreen(GrandPrixEditorScreen::getInstance());
|
||||
}
|
||||
} // eventCallback
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -726,6 +726,16 @@ void TrackObjectPresentationActionTrigger::onTriggerItemApproached(Item* who)
|
||||
new TutorialMessageDialog(_("Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!", fire),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_backgiftboxes")
|
||||
{
|
||||
m_action_active = false;
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw fire = config->getBindingAsString(PA_FIRE);
|
||||
|
||||
new TutorialMessageDialog(_("Press <B> to look behind, to fire the weapon with <%s> while pressing <B> to to fire behind!", fire),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_nitro_collect")
|
||||
{
|
||||
m_action_active = false;
|
||||
|