Conflicts:
	data/achievements.xml
This commit is contained in:
Csaba Molnar 2014-03-22 00:52:33 +01:00
commit 3a5812dd6c
67 changed files with 2526 additions and 1500 deletions

View File

@ -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:

View File

@ -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)

Binary file not shown.

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View 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>

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
data/gui/gp_copy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
data/gui/gp_edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
data/gui/gp_edit_track.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
data/gui/gp_new.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
data/gui/gp_remove.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
data/gui/gp_rename.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
data/gui/gp_save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

35
data/gui/gpedit.stkgui Normal file
View 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
View 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>

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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).

View File

@ -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)

View File

@ -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
}

View File

@ -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)

View File

@ -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
{

View File

@ -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
{

View File

@ -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());

View File

@ -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;
}
}

View File

@ -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);
}*/
}

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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" );

View File

@ -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();

View File

@ -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);
}
// -----------------------------------------------------------------------------

View File

@ -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__)

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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 &&

View File

@ -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());

View File

@ -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

View File

@ -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();

View File

@ -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]);

View File

@ -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) */

View File

@ -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());
}
}

View File

@ -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;

View 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);
}
}

View 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

View File

@ -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;

View File

@ -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);

View 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));
}

View 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

View 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();
}
}

View 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

View 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();
}

View 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

View File

@ -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
// ----------------------------------------------------------------------------

View File

@ -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;