Merge branch 'master' into kart-properties
This commit is contained in:
commit
b51eadae28
@ -20,7 +20,7 @@ option(USE_FRIBIDI "Support for right-to-left languages" ON)
|
||||
option(CHECK_ASSETS "Check if assets are installed in ../stk-assets" ON)
|
||||
option(USE_SYSTEM_ANGELSCRIPT "Use system angelscript instead of built-in angelscript. If you enable this option, make sure to use a compatible version." OFF)
|
||||
|
||||
if(MSVC)
|
||||
if(MSVC AND (MSVC_VERSION LESS 1900))
|
||||
# Normally hide the option to build wiiuse on VS, since it depends
|
||||
# on the installation of the Windows DDK (Driver Developer Kit),
|
||||
# which also needs an absolute path :(
|
||||
@ -211,6 +211,11 @@ if(WIN32)
|
||||
|
||||
# And shut up about unsafe stuff
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
# Avoid timespec structure redeclaration on Visual Studio 2015
|
||||
if (MSVC_VERSION EQUAL 1900)
|
||||
add_definitions(-DHAVE_STRUCT_TIMESPEC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
|
@ -52,7 +52,7 @@
|
||||
chassis-angular-damping="0"
|
||||
downward-impulse-factor="5"
|
||||
track-connection-accel="2"
|
||||
smooth-flying-impulse="25" />
|
||||
smooth-flying-impulse="250" />
|
||||
|
||||
<!-- Turning
|
||||
radius: The turn radius of the kart at
|
||||
|
@ -2,6 +2,8 @@ uniform sampler2D tex_128;
|
||||
uniform sampler2D tex_256;
|
||||
uniform sampler2D tex_512;
|
||||
|
||||
uniform sampler2D tex_dust;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
@ -10,5 +12,13 @@ void main()
|
||||
vec4 col = .125 * texture(tex_128, uv);
|
||||
col += .25 * texture(tex_256, uv);
|
||||
col += .5 * texture(tex_512, uv);
|
||||
|
||||
/* Lens dust effect ---- */
|
||||
vec4 col2 = texture(tex_128, uv);
|
||||
col2 += col2;
|
||||
col2 += col2;
|
||||
//float dustMask = max(col2.r,max(col2.g,col2.b));
|
||||
col += texture(tex_dust, uv) * col2;
|
||||
|
||||
FragColor = vec4(col.xyz, 1.);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
uniform int dt;
|
||||
uniform mat4 previous_frame_sourcematrix;
|
||||
uniform mat4 sourcematrix;
|
||||
uniform int level;
|
||||
uniform float size_increase_factor;
|
||||
@ -32,31 +33,48 @@ out float new_size;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
float updated_lifetime = lifetime + (float(dt)/lifetime_initial);
|
||||
if (updated_lifetime > 1.)
|
||||
{
|
||||
if (gl_VertexID < level)
|
||||
float updated_lifetime = lifetime + (float(dt)/lifetime_initial);
|
||||
if (updated_lifetime > 1.)
|
||||
{
|
||||
float dt_from_last_frame = fract(updated_lifetime) * lifetime_initial;
|
||||
vec4 updated_initialposition = sourcematrix * vec4(particle_position_initial, 1.0);
|
||||
vec4 updated_initial_velocity = sourcematrix * vec4(particle_position_initial + particle_velocity_initial, 1.0) - updated_initialposition;
|
||||
new_particle_position = updated_initialposition.xyz + updated_initial_velocity.xyz * float(dt_from_last_frame);
|
||||
new_particle_velocity = updated_initial_velocity.xyz;
|
||||
new_lifetime = fract(updated_lifetime);
|
||||
new_size = mix(size_initial, size_initial * size_increase_factor, fract(updated_lifetime));
|
||||
if (gl_VertexID < level)
|
||||
{
|
||||
float dt_from_last_frame = fract(updated_lifetime) * lifetime_initial;
|
||||
float coeff = dt_from_last_frame / dt;
|
||||
|
||||
vec4 previous_frame_position = previous_frame_sourcematrix * vec4(particle_position_initial, 1.0);
|
||||
vec4 current_frame_position = sourcematrix * vec4(particle_position_initial, 1.0);
|
||||
|
||||
vec4 updated_initialposition = mix(current_frame_position,
|
||||
previous_frame_position,
|
||||
coeff);
|
||||
|
||||
vec4 updated_initial_velocity = mix(sourcematrix * vec4(particle_velocity_initial, 0.0),
|
||||
previous_frame_sourcematrix * vec4(particle_velocity_initial, 0.0),
|
||||
coeff);
|
||||
//+ (current_frame_position - previous_frame_position) / dt;
|
||||
//To be accurate, emitter speed should be added.
|
||||
//But the simple formula ( (current_frame_position - previous_frame_position) / dt ) with a constant speed
|
||||
//between 2 frames creates visual artifacts when the framerate is low, and a more accurate formula would need
|
||||
//more complex computations.
|
||||
|
||||
new_particle_position = updated_initialposition.xyz + dt_from_last_frame * updated_initial_velocity.xyz;
|
||||
new_particle_velocity = updated_initial_velocity.xyz;
|
||||
|
||||
new_lifetime = fract(updated_lifetime);
|
||||
new_size = mix(size_initial, size_initial * size_increase_factor, fract(updated_lifetime));
|
||||
}
|
||||
else
|
||||
{
|
||||
new_lifetime = fract(updated_lifetime);
|
||||
new_size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_lifetime = fract(updated_lifetime);
|
||||
new_size = 0;
|
||||
new_particle_position = particle_position + particle_velocity.xyz * float(dt);
|
||||
new_particle_velocity = particle_velocity;
|
||||
new_lifetime = updated_lifetime;
|
||||
new_size = (size == 0) ? 0. : mix(size_initial, size_initial * size_increase_factor, updated_lifetime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_particle_position = particle_position + particle_velocity.xyz * float(dt);
|
||||
new_particle_velocity = particle_velocity;
|
||||
new_lifetime = updated_lifetime;
|
||||
new_size = (size == 0) ? 0. : mix(size_initial, size_initial * size_increase_factor, updated_lifetime);
|
||||
}
|
||||
gl_Position = vec4(0.);
|
||||
gl_Position = vec4(0.);
|
||||
}
|
||||
|
2
data/supertuxkart.git
Normal file
2
data/supertuxkart.git
Normal file
@ -0,0 +1,2 @@
|
||||
This file is only here to help STK finding the right directory,
|
||||
and to avoid problems with other directories called 'data'.
|
@ -584,8 +584,8 @@ BEGIN_AS_NAMESPACE
|
||||
template<typename T>
|
||||
asUINT asGetTypeTraits()
|
||||
{
|
||||
#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS)
|
||||
// MSVC & XCode/Clang
|
||||
#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5)
|
||||
// MSVC & XCode/Clang, and gnuc 5+
|
||||
// C++11 compliant code
|
||||
bool hasConstructor = std::is_default_constructible<T>::value && !std::is_trivially_default_constructible<T>::value;
|
||||
bool hasDestructor = std::is_destructible<T>::value && !std::is_trivially_destructible<T>::value;
|
||||
|
@ -61,7 +61,7 @@ namespace scene
|
||||
|
||||
//! Get the name of the bone
|
||||
/** \deprecated Use getName instead. This method may be removed by Irrlicht 1.9 */
|
||||
_IRR_DEPRECATED_ virtual const c8* getBoneName() const { return getName(); }
|
||||
//~ _IRR_DEPRECATED_ virtual const c8* getBoneName() const { return getName(); }
|
||||
|
||||
//! Get the index of the bone
|
||||
virtual u32 getBoneIndex() const = 0;
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include "IVideoDriver.h"
|
||||
#include "rect.h"
|
||||
|
||||
#define CJK_START 12287
|
||||
#define CJK_END 40960
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace gui
|
||||
@ -360,6 +363,20 @@ void CGUIStaticText::breakText()
|
||||
{
|
||||
// part of a word
|
||||
word += c;
|
||||
|
||||
//Check for CJK, show them first if out of range of displaying area
|
||||
if (Text[i] > CJK_START && Text[i] < CJK_END)
|
||||
{
|
||||
const s32 cjklgth = font->getDimension(word.c_str()).Width;
|
||||
if (cjklgth > (elWidth - 23))
|
||||
{
|
||||
BrokenText.push_back(line);
|
||||
length = cjklgth;
|
||||
line = word;
|
||||
word = L"";
|
||||
whitespace = L"";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( isWhitespace || i == (size-1))
|
||||
|
@ -2081,11 +2081,13 @@ void CIrrDeviceLinux::pollJoysticks()
|
||||
for (u32 j= 0; j< ActiveJoysticks.size(); ++j)
|
||||
{
|
||||
JoystickInfo & info = ActiveJoysticks[j];
|
||||
bool event_received = false;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
struct joystick js;
|
||||
if (read(info.fd, &js, sizeof(js)) == sizeof(js))
|
||||
{
|
||||
event_received = true;
|
||||
info.persistentData.JoystickEvent.ButtonStates = js.b1 | (js.b2 << 1); /* should be a two-bit field */
|
||||
info.persistentData.JoystickEvent.Axis[0] = js.x; /* X axis */
|
||||
info.persistentData.JoystickEvent.Axis[1] = js.y; /* Y axis */
|
||||
@ -2098,14 +2100,23 @@ void CIrrDeviceLinux::pollJoysticks()
|
||||
{
|
||||
case JS_EVENT_BUTTON:
|
||||
if (event.value)
|
||||
info.persistentData.JoystickEvent.ButtonStates |= (1 << event.number);
|
||||
{
|
||||
event_received = true;
|
||||
info.persistentData.JoystickEvent.ButtonStates |= (1 << event.number);
|
||||
}
|
||||
else
|
||||
info.persistentData.JoystickEvent.ButtonStates &= ~(1 << event.number);
|
||||
{
|
||||
event_received = true;
|
||||
info.persistentData.JoystickEvent.ButtonStates &= ~(1 << event.number);
|
||||
}
|
||||
break;
|
||||
|
||||
case JS_EVENT_AXIS:
|
||||
if (event.number < SEvent::SJoystickEvent::NUMBER_OF_AXES)
|
||||
{
|
||||
event_received = true;
|
||||
info.persistentData.JoystickEvent.Axis[event.number] = event.value;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2116,6 +2127,13 @@ void CIrrDeviceLinux::pollJoysticks()
|
||||
|
||||
// Send an irrlicht joystick event once per ::run() even if no new data were received.
|
||||
(void)postEventFromUser(info.persistentData);
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_X11_
|
||||
if (event_received)
|
||||
{
|
||||
XResetScreenSaver(display);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
|
||||
}
|
||||
|
@ -978,7 +978,8 @@ SFXBase* SFXManager::quickSound(const std::string &sound_type)
|
||||
else
|
||||
{
|
||||
SFXBase *base_sound = sound->second;
|
||||
base_sound->play();
|
||||
if (base_sound->getStatus() != SFXBase::SFX_PLAYING)
|
||||
base_sound->play();
|
||||
return base_sound;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ ChallengeData::ChallengeData(const std::string& filename)
|
||||
|
||||
// we are using auto_ptr to make sure the XML node is released when leaving
|
||||
// the scope
|
||||
std::auto_ptr<XMLNode> root(new XMLNode( filename ));
|
||||
std::unique_ptr<XMLNode> root(new XMLNode( filename ));
|
||||
|
||||
if(root.get() == NULL || root->getName()!="challenge")
|
||||
{
|
||||
|
@ -173,9 +173,10 @@ void SavedGrandPrix::loadKarts(std::vector<RaceManager::KartStatus> & kart_list)
|
||||
{
|
||||
if(kart_list[x].m_local_player_id == m_karts[i].m_local_player_id)
|
||||
{
|
||||
if(kp) kart_list[x].m_ident = m_karts[i].m_ident;
|
||||
kart_list[x].m_score = m_karts[i].m_score;
|
||||
kart_list[x].m_overall_time = m_karts[i].m_overall_time;
|
||||
} // if kart_list[x].m_local_player_id == m_karts[i].,_local
|
||||
} // if kart_list[x].m_local_player_id == m_karts[i].local
|
||||
} // for x
|
||||
} // if m_local_player_id == -1
|
||||
} // for i
|
||||
|
@ -1,444 +0,0 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "graphics/IBL.hpp"
|
||||
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/gl_headers.hpp"
|
||||
#include "graphics/shaders.hpp"
|
||||
#include "graphics/shared_gpu_objects.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
|
||||
|
||||
class SpecularIBLGenerator : public TextureShader<SpecularIBLGenerator, 1,
|
||||
core::matrix4, float >
|
||||
{
|
||||
public:
|
||||
GLuint m_tu_samples;
|
||||
SpecularIBLGenerator()
|
||||
{
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
|
||||
GL_FRAGMENT_SHADER, "importance_sampling_specular.frag");
|
||||
assignUniforms("PermutationMatrix", "ViewportSize");
|
||||
m_tu_samples = 1;
|
||||
assignSamplerNames(0, "tex", ST_TRILINEAR_CUBEMAP);
|
||||
assignTextureUnit(m_tu_samples, "samples");
|
||||
}
|
||||
|
||||
}; // SpecularIBLGenerator
|
||||
|
||||
// ============================================================================
|
||||
static void getXYZ(GLenum face, float i, float j, float &x, float &y, float &z)
|
||||
{
|
||||
switch (face)
|
||||
{
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
x = 1.;
|
||||
y = -i;
|
||||
z = -j;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
x = -1.;
|
||||
y = -i;
|
||||
z = j;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
x = j;
|
||||
y = 1.;
|
||||
z = i;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
x = j;
|
||||
y = -1;
|
||||
z = -i;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
x = j;
|
||||
y = -i;
|
||||
z = 1;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
x = -j;
|
||||
y = -i;
|
||||
z = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
float norm = sqrt(x * x + y * y + z * z);
|
||||
x /= norm, y /= norm, z /= norm;
|
||||
return;
|
||||
} // getXYZ
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static void getYml(GLenum face, size_t edge_size,
|
||||
float *Y00,
|
||||
float *Y1minus1, float *Y10, float *Y11,
|
||||
float *Y2minus2, float *Y2minus1, float *Y20, float *Y21, float *Y22)
|
||||
{
|
||||
#pragma omp parallel for
|
||||
for (int i = 0; i < int(edge_size); i++)
|
||||
{
|
||||
for (unsigned j = 0; j < edge_size; j++)
|
||||
{
|
||||
float x, y, z;
|
||||
float fi = float(i), fj = float(j);
|
||||
fi /= edge_size, fj /= edge_size;
|
||||
fi = 2 * fi - 1, fj = 2 * fj - 1;
|
||||
getXYZ(face, fi, fj, x, y, z);
|
||||
|
||||
// constant part of Ylm
|
||||
float c00 = 0.282095f;
|
||||
float c1minus1 = 0.488603f;
|
||||
float c10 = 0.488603f;
|
||||
float c11 = 0.488603f;
|
||||
float c2minus2 = 1.092548f;
|
||||
float c2minus1 = 1.092548f;
|
||||
float c21 = 1.092548f;
|
||||
float c20 = 0.315392f;
|
||||
float c22 = 0.546274f;
|
||||
|
||||
size_t idx = i * edge_size + j;
|
||||
|
||||
Y00[idx] = c00;
|
||||
Y1minus1[idx] = c1minus1 * y;
|
||||
Y10[idx] = c10 * z;
|
||||
Y11[idx] = c11 * x;
|
||||
Y2minus2[idx] = c2minus2 * x * y;
|
||||
Y2minus1[idx] = c2minus1 * y * z;
|
||||
Y21[idx] = c21 * x * z;
|
||||
Y20[idx] = c20 * (3 * z * z - 1);
|
||||
Y22[idx] = c22 * (x * x - y * y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static void projectSH(Color *cubemap_face[6], size_t edge_size, float *Y00[],
|
||||
float *Y1minus1[], float *Y10[], float *Y11[],
|
||||
float *Y2minus2[], float *Y2minus1[], float * Y20[],
|
||||
float *Y21[], float *Y22[], float *blue_sh_coeff,
|
||||
float *green_sh_coeff, float *red_sh_coeff)
|
||||
{
|
||||
for (unsigned i = 0; i < 9; i++)
|
||||
{
|
||||
blue_sh_coeff[i] = 0;
|
||||
green_sh_coeff[i] = 0;
|
||||
red_sh_coeff[i] = 0;
|
||||
}
|
||||
|
||||
float wh = float(edge_size * edge_size);
|
||||
float b0 = 0., b1 = 0., b2 = 0., b3 = 0., b4 = 0., b5 = 0., b6 = 0., b7 = 0., b8 = 0.;
|
||||
float r0 = 0., r1 = 0., r2 = 0., r3 = 0., r4 = 0., r5 = 0., r6 = 0., r7 = 0., r8 = 0.;
|
||||
float g0 = 0., g1 = 0., g2 = 0., g3 = 0., g4 = 0., g5 = 0., g6 = 0., g7 = 0., g8 = 0.;
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
#pragma omp parallel for reduction(+ : b0, b1, b2, b3, b4, b5, b6, b7, b8, \
|
||||
r0, r1, r2, r3, r4, r5, r6, r7, r8, \
|
||||
g0, g1, g2, g3, g4, g5, g6, g7, g8)
|
||||
for (int i = 0; i < int(edge_size); i++)
|
||||
{
|
||||
for (unsigned j = 0; j < edge_size; j++)
|
||||
{
|
||||
int idx = i * edge_size + j;
|
||||
float fi = float(i), fj = float(j);
|
||||
fi /= edge_size, fj /= edge_size;
|
||||
fi = 2 * fi - 1, fj = 2 * fj - 1;
|
||||
|
||||
|
||||
float d = sqrt(fi * fi + fj * fj + 1);
|
||||
|
||||
// Constant obtained by projecting unprojected ref values
|
||||
float solidangle = 2.75f / (wh * pow(d, 1.5f));
|
||||
// pow(., 2.2) to convert from srgb
|
||||
float b = cubemap_face[face][edge_size * i + j].Blue;
|
||||
float g = cubemap_face[face][edge_size * i + j].Green;
|
||||
float r = cubemap_face[face][edge_size * i + j].Red;
|
||||
|
||||
b0 += b * Y00[face][idx] * solidangle;
|
||||
b1 += b * Y1minus1[face][idx] * solidangle;
|
||||
b2 += b * Y10[face][idx] * solidangle;
|
||||
b3 += b * Y11[face][idx] * solidangle;
|
||||
b4 += b * Y2minus2[face][idx] * solidangle;
|
||||
b5 += b * Y2minus1[face][idx] * solidangle;
|
||||
b6 += b * Y20[face][idx] * solidangle;
|
||||
b7 += b * Y21[face][idx] * solidangle;
|
||||
b8 += b * Y22[face][idx] * solidangle;
|
||||
|
||||
g0 += g * Y00[face][idx] * solidangle;
|
||||
g1 += g * Y1minus1[face][idx] * solidangle;
|
||||
g2 += g * Y10[face][idx] * solidangle;
|
||||
g3 += g * Y11[face][idx] * solidangle;
|
||||
g4 += g * Y2minus2[face][idx] * solidangle;
|
||||
g5 += g * Y2minus1[face][idx] * solidangle;
|
||||
g6 += g * Y20[face][idx] * solidangle;
|
||||
g7 += g * Y21[face][idx] * solidangle;
|
||||
g8 += g * Y22[face][idx] * solidangle;
|
||||
|
||||
|
||||
r0 += r * Y00[face][idx] * solidangle;
|
||||
r1 += r * Y1minus1[face][idx] * solidangle;
|
||||
r2 += r * Y10[face][idx] * solidangle;
|
||||
r3 += r * Y11[face][idx] * solidangle;
|
||||
r4 += r * Y2minus2[face][idx] * solidangle;
|
||||
r5 += r * Y2minus1[face][idx] * solidangle;
|
||||
r6 += r * Y20[face][idx] * solidangle;
|
||||
r7 += r * Y21[face][idx] * solidangle;
|
||||
r8 += r * Y22[face][idx] * solidangle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blue_sh_coeff[0] = b0;
|
||||
blue_sh_coeff[1] = b1;
|
||||
blue_sh_coeff[2] = b2;
|
||||
blue_sh_coeff[3] = b3;
|
||||
blue_sh_coeff[4] = b4;
|
||||
blue_sh_coeff[5] = b5;
|
||||
blue_sh_coeff[6] = b6;
|
||||
blue_sh_coeff[7] = b7;
|
||||
blue_sh_coeff[8] = b8;
|
||||
|
||||
red_sh_coeff[0] = r0;
|
||||
red_sh_coeff[1] = r1;
|
||||
red_sh_coeff[2] = r2;
|
||||
red_sh_coeff[3] = r3;
|
||||
red_sh_coeff[4] = r4;
|
||||
red_sh_coeff[5] = r5;
|
||||
red_sh_coeff[6] = r6;
|
||||
red_sh_coeff[7] = r7;
|
||||
red_sh_coeff[8] = r8;
|
||||
|
||||
green_sh_coeff[0] = g0;
|
||||
green_sh_coeff[1] = g1;
|
||||
green_sh_coeff[2] = g2;
|
||||
green_sh_coeff[3] = g3;
|
||||
green_sh_coeff[4] = g4;
|
||||
green_sh_coeff[5] = g5;
|
||||
green_sh_coeff[6] = g6;
|
||||
green_sh_coeff[7] = g7;
|
||||
green_sh_coeff[8] = g8;
|
||||
} // projectSH
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Generate the 9 first SH coefficients for each color channel
|
||||
* using the cubemap provided by CubemapFace.
|
||||
* \param textures sequence of 6 square textures.
|
||||
* \param row/columns count of textures.
|
||||
*/
|
||||
void generateSphericalHarmonics(Color *cubemap_face[6], size_t edge_size,
|
||||
float *blue_sh_coeff, float *green_sh_coeff,
|
||||
float *red_sh_coeff)
|
||||
{
|
||||
float *Y00[6];
|
||||
float *Y1minus1[6];
|
||||
float *Y10[6];
|
||||
float *Y11[6];
|
||||
float *Y2minus2[6];
|
||||
float *Y2minus1[6];
|
||||
float *Y20[6];
|
||||
float *Y21[6];
|
||||
float *Y22[6];
|
||||
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
Y00[face] = new float[edge_size * edge_size];
|
||||
Y1minus1[face] = new float[edge_size * edge_size];
|
||||
Y10[face] = new float[edge_size * edge_size];
|
||||
Y11[face] = new float[edge_size * edge_size];
|
||||
Y2minus2[face] = new float[edge_size * edge_size];
|
||||
Y2minus1[face] = new float[edge_size * edge_size];
|
||||
Y20[face] = new float[edge_size * edge_size];
|
||||
Y21[face] = new float[edge_size * edge_size];
|
||||
Y22[face] = new float[edge_size * edge_size];
|
||||
|
||||
getYml(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, edge_size, Y00[face],
|
||||
Y1minus1[face], Y10[face], Y11[face], Y2minus2[face],
|
||||
Y2minus1[face], Y20[face], Y21[face], Y22[face]);
|
||||
}
|
||||
|
||||
projectSH(cubemap_face, edge_size, Y00, Y1minus1, Y10, Y11, Y2minus2,
|
||||
Y2minus1, Y20, Y21, Y22, blue_sh_coeff, green_sh_coeff,
|
||||
red_sh_coeff);
|
||||
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
delete[] Y00[face];
|
||||
delete[] Y1minus1[face];
|
||||
delete[] Y10[face];
|
||||
delete[] Y11[face];
|
||||
delete[] Y2minus2[face];
|
||||
delete[] Y2minus1[face];
|
||||
delete[] Y20[face];
|
||||
delete[] Y21[face];
|
||||
delete[] Y22[face];
|
||||
}
|
||||
} // generateSphericalHarmonics
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// From http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
|
||||
/** Returns the index-th pair from Hammersley set of pseudo random set.
|
||||
Hammersley set is a uniform distribution between 0 and 1 for 2 components.
|
||||
We use the natural indexation on the set to avoid storing the whole set.
|
||||
\param index of the pair
|
||||
\param size of the set. */
|
||||
std::pair<float, float> getHammersleySequence(int index, int samples)
|
||||
{
|
||||
float InvertedBinaryRepresentation = 0.;
|
||||
for (size_t i = 0; i < 32; i++)
|
||||
{
|
||||
InvertedBinaryRepresentation += ((index >> i) & 0x1)
|
||||
* powf(.5, (float) (i + 1.));
|
||||
}
|
||||
return std::make_pair(float(index) / float(samples),
|
||||
InvertedBinaryRepresentation);
|
||||
} // HammersleySequence
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns a pseudo random (theta, phi) generated from a probability density
|
||||
* function modeled after Phong function.
|
||||
* \param a pseudo random float pair from a uniform density function between
|
||||
* 0 and 1.
|
||||
* \param exponent from the Phong formula.
|
||||
*/
|
||||
std::pair<float, float> getImportanceSamplingPhong(std::pair<float, float> Seeds,
|
||||
float exponent)
|
||||
{
|
||||
return std::make_pair(acosf(powf(Seeds.first, 1.f / (exponent + 1.f))),
|
||||
2.f * 3.14f * Seeds.second);
|
||||
} // getImportanceSamplingPhong
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static core::matrix4 getPermutationMatrix(size_t indexX, float valX,
|
||||
size_t indexY, float valY,
|
||||
size_t indexZ, float valZ)
|
||||
{
|
||||
core::matrix4 result_mat;
|
||||
float *M = result_mat.pointer();
|
||||
memset(M, 0, 16 * sizeof(float));
|
||||
assert(indexX < 4);
|
||||
assert(indexY < 4);
|
||||
assert(indexZ < 4);
|
||||
M[indexX] = valX;
|
||||
M[4 + indexY] = valY;
|
||||
M[8 + indexZ] = valZ;
|
||||
return result_mat;
|
||||
} // getPermutationMatrix
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GLuint generateSpecularCubemap(GLuint probe)
|
||||
{
|
||||
GLuint cubemap_texture;
|
||||
|
||||
glGenTextures(1, &cubemap_texture);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap_texture);
|
||||
size_t cubemap_size = 256;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA16F,
|
||||
cubemap_size, cubemap_size, 0, GL_BGRA, GL_FLOAT, 0);
|
||||
}
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
|
||||
if (!CVS->isDefferedEnabled())
|
||||
return cubemap_texture;
|
||||
|
||||
GLuint fbo;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glViewport(0, 0, cubemap_size, cubemap_size);
|
||||
GLenum bufs[] = { GL_COLOR_ATTACHMENT0 };
|
||||
glDrawBuffers(1, bufs);
|
||||
SpecularIBLGenerator::getInstance()->use();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
core::matrix4 M[6] = {
|
||||
getPermutationMatrix(2, -1., 1, -1., 0, 1.),
|
||||
getPermutationMatrix(2, 1., 1, -1., 0, -1.),
|
||||
getPermutationMatrix(0, 1., 2, 1., 1, 1.),
|
||||
getPermutationMatrix(0, 1., 2, -1., 1, -1.),
|
||||
getPermutationMatrix(0, 1., 1, -1., 2, 1.),
|
||||
getPermutationMatrix(0, -1., 1, -1., 2, -1.),
|
||||
};
|
||||
|
||||
for (unsigned level = 0; level < 8; level++)
|
||||
{
|
||||
// Blinn Phong can be approximated by Phong with 4x the specular
|
||||
// coefficient
|
||||
// See http://seblagarde.wordpress.com/2012/03/29/relationship-between-phong-and-blinn-lighting-model/
|
||||
// NOTE : Removed because it makes too sharp reflexion
|
||||
float roughness = (8 - level) * pow(2.f, 10.f) / 8.f;
|
||||
float viewportSize = float(1 << (8 - level));
|
||||
|
||||
float *tmp = new float[2048];
|
||||
for (unsigned i = 0; i < 1024; i++)
|
||||
{
|
||||
std::pair<float, float> sample =
|
||||
getImportanceSamplingPhong(getHammersleySequence(i, 1024),
|
||||
roughness);
|
||||
tmp[2 * i] = sample.first;
|
||||
tmp[2 * i + 1] = sample.second;
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
glActiveTexture(GL_TEXTURE0 +
|
||||
SpecularIBLGenerator::getInstance()->m_tu_samples);
|
||||
GLuint sampleTex, sampleBuffer;
|
||||
glGenBuffers(1, &sampleBuffer);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, sampleBuffer);
|
||||
glBufferData(GL_TEXTURE_BUFFER, 2048 * sizeof(float), tmp,
|
||||
GL_STATIC_DRAW);
|
||||
glGenTextures(1, &sampleTex);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, sampleTex);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32F, sampleBuffer);
|
||||
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
|
||||
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
|
||||
cubemap_texture, level);
|
||||
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
assert(status == GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
SpecularIBLGenerator::getInstance()->setTextureUnits(probe);
|
||||
SpecularIBLGenerator::getInstance()->setUniforms(M[face],
|
||||
viewportSize);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
}
|
||||
glActiveTexture( GL_TEXTURE0
|
||||
+ SpecularIBLGenerator::getInstance()->m_tu_samples);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
|
||||
delete[] tmp;
|
||||
glDeleteTextures(1, &sampleTex);
|
||||
glDeleteBuffers(1, &sampleBuffer);
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
return cubemap_texture;
|
||||
} // generateSpecularCubemap
|
@ -1,35 +0,0 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef IBL_HPP
|
||||
#define IBL_HPP
|
||||
|
||||
#include "gl_headers.hpp"
|
||||
|
||||
struct Color
|
||||
{
|
||||
float Red;
|
||||
float Green;
|
||||
float Blue;
|
||||
};
|
||||
|
||||
void generateSphericalHarmonics(Color *CubemapFace[6], size_t edge_size,
|
||||
float *blue_sh_coeff, float *green_sh_coeff,
|
||||
float *red_sh_coeff);
|
||||
|
||||
GLuint generateSpecularCubemap(GLuint probe);
|
||||
#endif
|
@ -37,7 +37,7 @@
|
||||
/** Transform feedback shader that simulates the particles on GPU.
|
||||
*/
|
||||
class PointEmitterShader : public Shader
|
||||
< PointEmitterShader, core::matrix4, int, int, float >
|
||||
< PointEmitterShader, core::matrix4, core::matrix4, int, int, float >
|
||||
{
|
||||
public:
|
||||
PointEmitterShader()
|
||||
@ -45,7 +45,8 @@ public:
|
||||
const char *varyings[] = { "new_particle_position", "new_lifetime",
|
||||
"new_particle_velocity", "new_size" };
|
||||
loadTFBProgram("pointemitter.vert", varyings, 4);
|
||||
assignUniforms("sourcematrix", "dt", "level", "size_increase_factor");
|
||||
assignUniforms("previous_frame_sourcematrix", "sourcematrix",
|
||||
"dt", "level", "size_increase_factor");
|
||||
} // PointEmitterShader
|
||||
|
||||
}; // PointEmitterShader
|
||||
@ -262,7 +263,7 @@ void ParticleSystemProxy::generateParticlesFromPointEmitter(scene::IParticlePoin
|
||||
ParticleParams[i].PositionZ = 0;
|
||||
// Initial lifetime is >1
|
||||
InitialValues[i].Lifetime = 2.;
|
||||
|
||||
|
||||
memcpy(&(InitialValues[i].PositionX), &(ParticleParams[i].PositionX), 3 * sizeof(float));
|
||||
|
||||
generateLifetimeSizeDirection(emitter, ParticleParams[i].Lifetime, ParticleParams[i].Size,
|
||||
@ -466,11 +467,11 @@ void ParticleSystemProxy::CommonSimulationVAO(GLuint position_vbo, GLuint initia
|
||||
}
|
||||
|
||||
void ParticleSystemProxy::simulate()
|
||||
{
|
||||
{
|
||||
int timediff = int(GUIEngine::getLatestDt() * 1000.f);
|
||||
int active_count = getEmitter()->getMaxLifeTime() * getEmitter()->getMaxParticlesPerSecond() / 1000;
|
||||
core::matrix4 matrix = getAbsoluteTransformation();
|
||||
|
||||
|
||||
glEnable(GL_RASTERIZER_DISCARD);
|
||||
if (has_height_map)
|
||||
{
|
||||
@ -482,9 +483,10 @@ void ParticleSystemProxy::simulate()
|
||||
else
|
||||
{
|
||||
PointEmitterShader::getInstance()->use();
|
||||
PointEmitterShader::getInstance()->setUniforms(matrix, timediff, active_count, size_increase_factor);
|
||||
PointEmitterShader::getInstance()->setUniforms(m_previous_frame_matrix, matrix, timediff, active_count, size_increase_factor);
|
||||
}
|
||||
|
||||
m_previous_frame_matrix = matrix;
|
||||
|
||||
glBindVertexArray(current_simulation_vao);
|
||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfb_buffers[1]);
|
||||
|
||||
@ -617,8 +619,14 @@ void ParticleSystemProxy::render() {
|
||||
return;
|
||||
}
|
||||
if (m_first_execution)
|
||||
{
|
||||
generateVAOs();
|
||||
m_first_execution = false;
|
||||
simulate();
|
||||
draw();
|
||||
m_previous_frame_matrix = getAbsoluteTransformation();
|
||||
m_first_execution = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
simulate();
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
@ -40,9 +40,12 @@ protected:
|
||||
float m_color_to[3];
|
||||
bool m_first_execution;
|
||||
bool m_randomize_initial_y;
|
||||
|
||||
|
||||
GLuint texture;
|
||||
|
||||
|
||||
/** Previous frame particles emitter source matrix */
|
||||
core::matrix4 m_previous_frame_matrix;
|
||||
|
||||
/** Current count of particles. */
|
||||
unsigned m_count;
|
||||
/** Previous count - for error handling only. */
|
||||
|
@ -121,10 +121,13 @@ IrrDriver::IrrDriver()
|
||||
m_rtts = NULL;
|
||||
m_post_processing = NULL;
|
||||
m_wind = new Wind();
|
||||
m_skybox = NULL;
|
||||
m_spherical_harmonics = NULL;
|
||||
|
||||
m_mipviz = m_wireframe = m_normals = m_ssaoviz = false;
|
||||
m_lightviz = m_shadowviz = m_distortviz = m_rsm = m_rh = m_gi = false;
|
||||
m_boundingboxesviz = false;
|
||||
SkyboxCubeMap = m_last_light_bucket_distance = 0;
|
||||
m_last_light_bucket_distance = 0;
|
||||
memset(object_count, 0, sizeof(object_count));
|
||||
} // IrrDriver
|
||||
|
||||
@ -156,6 +159,7 @@ IrrDriver::~IrrDriver()
|
||||
m_shadow_matrices = NULL;
|
||||
Shaders::destroy();
|
||||
delete m_wind;
|
||||
delete m_spherical_harmonics;
|
||||
} // ~IrrDriver
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -504,6 +508,7 @@ void IrrDriver::initDevice()
|
||||
|
||||
CVS->init();
|
||||
|
||||
m_spherical_harmonics = new SphericalHarmonics(m_scene_manager->getAmbientLight().toSColor());
|
||||
|
||||
if (UserConfigParams::m_shadows_resolution != 0 &&
|
||||
(UserConfigParams::m_shadows_resolution < 512 ||
|
||||
@ -1359,14 +1364,16 @@ scene::ISceneNode *IrrDriver::addSkyDome(video::ITexture *texture,
|
||||
* \param back: Texture for the back plane of the box.
|
||||
*/
|
||||
scene::ISceneNode *IrrDriver::addSkyBox(const std::vector<video::ITexture*> &texture,
|
||||
const std::vector<video::ITexture*> &sphericalHarmonics)
|
||||
const std::vector<video::ITexture*> &spherical_harmonics_textures)
|
||||
{
|
||||
assert(texture.size() == 6);
|
||||
SkyboxTextures = texture;
|
||||
SphericalHarmonicsTextures = sphericalHarmonics;
|
||||
SkyboxCubeMap = 0;
|
||||
SkyboxSpecularProbe = 0;
|
||||
m_skybox_ready = false;
|
||||
|
||||
m_skybox = new Skybox(texture);
|
||||
if(spherical_harmonics_textures.size() == 6)
|
||||
{
|
||||
m_spherical_harmonics->setTextures(spherical_harmonics_textures);
|
||||
}
|
||||
|
||||
return m_scene_manager->addSkyBoxSceneNode(texture[0], texture[1],
|
||||
texture[2], texture[3],
|
||||
texture[4], texture[5]);
|
||||
@ -1374,16 +1381,8 @@ scene::ISceneNode *IrrDriver::addSkyBox(const std::vector<video::ITexture*> &tex
|
||||
|
||||
void IrrDriver::suppressSkyBox()
|
||||
{
|
||||
SkyboxTextures.clear();
|
||||
SphericalHarmonicsTextures.clear();
|
||||
m_skybox_ready = false;
|
||||
if ((SkyboxCubeMap) && (!ProfileWorld::isNoGraphics()))
|
||||
{
|
||||
glDeleteTextures(1, &SkyboxCubeMap);
|
||||
glDeleteTextures(1, &SkyboxSpecularProbe);
|
||||
}
|
||||
SkyboxCubeMap = 0;
|
||||
SkyboxSpecularProbe = 0;
|
||||
delete m_skybox;
|
||||
m_skybox = NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1763,7 +1762,7 @@ void IrrDriver::onUnloadWorld()
|
||||
void IrrDriver::setAmbientLight(const video::SColorf &light)
|
||||
{
|
||||
m_scene_manager->setAmbientLight(light);
|
||||
m_skybox_ready = false;
|
||||
m_spherical_harmonics->setAmbientLight(light.toSColor());
|
||||
} // setAmbientLight
|
||||
|
||||
video::SColorf IrrDriver::getAmbientLight() const
|
||||
@ -2345,7 +2344,7 @@ void IrrDriver::RTTProvider::setupRTTScene(PtrVector<scene::IMesh, REF>& mesh,
|
||||
}
|
||||
|
||||
irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 35, 35, 35) );
|
||||
|
||||
|
||||
const core::vector3df &spot_pos = core::vector3df(0, 30, 40);
|
||||
m_light = irr_driver->getSceneManager()
|
||||
->addLightSceneNode(NULL, spot_pos, video::SColorf(1.0f,1.0f,1.0f),
|
||||
|
@ -36,8 +36,10 @@
|
||||
#include <SColor.h>
|
||||
#include "IrrlichtDevice.h"
|
||||
#include "ISkinnedMesh.h"
|
||||
#include "graphics/wind.hpp"
|
||||
#include "graphics/gl_headers.hpp"
|
||||
#include "graphics/skybox.hpp"
|
||||
#include "graphics/sphericalHarmonics.hpp"
|
||||
#include "graphics/wind.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "utils/aligned_array.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
@ -214,14 +216,9 @@ private:
|
||||
/** Matrixes used in several places stored here to avoid recomputation. */
|
||||
core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_InvProjViewMatrix;
|
||||
|
||||
std::vector<video::ITexture *> SkyboxTextures;
|
||||
std::vector<video::ITexture *> SphericalHarmonicsTextures;
|
||||
bool m_skybox_ready;
|
||||
Skybox *m_skybox;
|
||||
SphericalHarmonics *m_spherical_harmonics;
|
||||
|
||||
public:
|
||||
float blueSHCoeff[9];
|
||||
float greenSHCoeff[9];
|
||||
float redSHCoeff[9];
|
||||
private:
|
||||
|
||||
/** Keep a trace of the origin file name of a texture. */
|
||||
@ -238,8 +235,6 @@ private:
|
||||
ShadowMatrices *m_shadow_matrices;
|
||||
|
||||
public:
|
||||
GLuint SkyboxCubeMap;
|
||||
GLuint SkyboxSpecularProbe;
|
||||
/** A simple class to store video resolutions. */
|
||||
class VideoMode
|
||||
{
|
||||
@ -348,8 +343,6 @@ public:
|
||||
void getOpenGLData(std::string *vendor, std::string *renderer,
|
||||
std::string *version);
|
||||
|
||||
void prepareSkybox();
|
||||
void generateDiffuseCoefficients();
|
||||
void renderSkybox(const scene::ICameraSceneNode *camera);
|
||||
void setPhase(STKRenderingPass);
|
||||
STKRenderingPass getPhase() const;
|
||||
@ -407,7 +400,7 @@ public:
|
||||
int vert_res, float texture_percent,
|
||||
float sphere_percent);
|
||||
scene::ISceneNode *addSkyBox(const std::vector<video::ITexture*> &texture_names,
|
||||
const std::vector<video::ITexture*> &sphericalHarmonics);
|
||||
const std::vector<video::ITexture*> &spherical_harmonics_textures);
|
||||
void suppressSkyBox();
|
||||
void removeNode(scene::ISceneNode *node);
|
||||
void removeMeshFromCache(scene::IMesh *mesh);
|
||||
@ -531,6 +524,12 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
inline core::vector3df getWind() {return m_wind->getWind();}
|
||||
// -----------------------------------------------------------------------
|
||||
/** Returns a pointer to the skybox. */
|
||||
inline Skybox *getSkybox() {return m_skybox;}
|
||||
// -----------------------------------------------------------------------
|
||||
/** Returns a pointer to spherical harmonics. */
|
||||
inline SphericalHarmonics *getSphericalHarmonics() {return m_spherical_harmonics;}
|
||||
// -----------------------------------------------------------------------
|
||||
const core::vector3df& getSunDirection() const { return m_sun_direction; };
|
||||
// -----------------------------------------------------------------------
|
||||
void setSunDirection(const core::vector3df &SunPos)
|
||||
@ -766,6 +765,7 @@ public:
|
||||
size_t width, size_t height);
|
||||
void uploadLightingData();
|
||||
|
||||
|
||||
// --------------------- OLD RTT --------------------
|
||||
/**
|
||||
* THIS IS THE OLD OPENGL 1 RTT PROVIDER, USE THE SHADER-BASED
|
||||
|
@ -84,21 +84,19 @@ Material::Material(const XMLNode *node, bool deprecated)
|
||||
|
||||
|
||||
std::string s;
|
||||
//node->get("adjust-image", &s );
|
||||
//if(s=="premultiply")
|
||||
// m_adjust_image = ADJ_PREMUL;
|
||||
//else if (s=="divide")
|
||||
// m_adjust_image = ADJ_DIV;
|
||||
//else if (s=="" || s=="none")
|
||||
// m_adjust_image = ADJ_NONE;
|
||||
//else
|
||||
// Log::warn("material",
|
||||
// "Incorrect adjust-image specification: '%s' - ignored.",
|
||||
// s.c_str());
|
||||
|
||||
node->get("high-adhesion", &m_high_tire_adhesion);
|
||||
node->get("reset", &m_drive_reset );
|
||||
|
||||
node->get("high-adhesion", &m_high_tire_adhesion );
|
||||
node->get("reset", &m_drive_reset );
|
||||
s = "";
|
||||
node->get("mirror-axis", &s);
|
||||
if (s == "u")
|
||||
s = "U";
|
||||
else if (s == "v")
|
||||
s = "V";
|
||||
if (s != "U" && s != "V")
|
||||
m_mirror_axis_when_reverse = ' ';
|
||||
else
|
||||
m_mirror_axis_when_reverse = s[0];
|
||||
// backwards compatibility
|
||||
bool crash_reset = false;
|
||||
node->get("crash-reset", &crash_reset );
|
||||
@ -433,6 +431,7 @@ void Material::init()
|
||||
m_surface = false;
|
||||
m_ignore = false;
|
||||
m_drive_reset = false;
|
||||
m_mirror_axis_when_reverse = ' ';
|
||||
m_collision_reaction = NORMAL;
|
||||
m_disable_z_write = false;
|
||||
m_water_shader_speed_1 = 6.6667f;
|
||||
|
@ -156,6 +156,11 @@ private:
|
||||
|
||||
bool m_fog;
|
||||
|
||||
/** Either ' ' (no mirroring), 'U' or 'V' if a texture needs to be
|
||||
* mirrored when driving in reverse. Typically used for arrows indicating
|
||||
* the direction. */
|
||||
char m_mirror_axis_when_reverse;
|
||||
|
||||
ParticleKind* m_particles_effects[EMIT_KINDS_COUNT];
|
||||
|
||||
/** For normal maps */
|
||||
@ -373,6 +378,9 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
ShaderType getShaderType() const { return m_shader_type; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** True if this texture should have the U coordinates mirrored. */
|
||||
char getMirrorAxisInReverse() const { return m_mirror_axis_when_reverse; }
|
||||
// ------------------------------------------------------------------------
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -332,25 +332,32 @@ public:
|
||||
} // render
|
||||
}; // BloomShader
|
||||
|
||||
static video::ITexture *lensDustTex = 0;
|
||||
|
||||
// ============================================================================
|
||||
class BloomBlendShader : public TextureShader<BloomBlendShader, 3>
|
||||
class BloomBlendShader : public TextureShader<BloomBlendShader, 4>
|
||||
{
|
||||
public:
|
||||
BloomBlendShader()
|
||||
{
|
||||
if (!lensDustTex)
|
||||
lensDustTex = irr_driver->getTexture(FileManager::TEXTURE, "gfx_lensDust_a.png");
|
||||
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
|
||||
GL_FRAGMENT_SHADER, "bloomblend.frag");
|
||||
assignUniforms();
|
||||
assignSamplerNames(0, "tex_128", ST_BILINEAR_FILTERED,
|
||||
1, "tex_256", ST_BILINEAR_FILTERED,
|
||||
2, "tex_512", ST_BILINEAR_FILTERED);
|
||||
2, "tex_512", ST_BILINEAR_FILTERED,
|
||||
3, "tex_dust", ST_BILINEAR_FILTERED);
|
||||
} // BloomBlendShader
|
||||
// ------------------------------------------------------------------------
|
||||
void render()
|
||||
{
|
||||
setTextureUnits(irr_driver->getRenderTargetTexture(RTT_BLOOM_128),
|
||||
irr_driver->getRenderTargetTexture(RTT_BLOOM_256),
|
||||
irr_driver->getRenderTargetTexture(RTT_BLOOM_512));
|
||||
irr_driver->getRenderTargetTexture(RTT_BLOOM_512),
|
||||
getTextureGLuint(lensDustTex));
|
||||
drawFullScreenEffect();
|
||||
} // render
|
||||
}; // BloomBlendShader
|
||||
@ -987,8 +994,7 @@ static void renderBloom(GLuint in)
|
||||
} // renderBloom
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void PostProcessing::renderEnvMap(const float *bSHCoeff, const float *gSHCoeff,
|
||||
const float *rSHCoeff, GLuint skybox)
|
||||
void PostProcessing::renderEnvMap(GLuint skybox)
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
|
@ -79,8 +79,7 @@ public:
|
||||
const video::SColorf &col);
|
||||
|
||||
void renderSSAO();
|
||||
void renderEnvMap(const float *bSHCoeff, const float *gSHCoeff,
|
||||
const float *rSHCoeff, unsigned skycubemap);
|
||||
void renderEnvMap(unsigned skycubemap);
|
||||
void renderRHDebug(unsigned SHR, unsigned SHG, unsigned SHB,
|
||||
const core::matrix4 &rh_matrix,
|
||||
const core::vector3df &rh_extend);
|
||||
|
@ -186,15 +186,9 @@ void IrrDriver::renderGLSL(float dt)
|
||||
|
||||
const core::recti &viewport = camera->getViewport();
|
||||
|
||||
if (World::getWorld() && World::getWorld()->getTrack()->hasShadows() && !SphericalHarmonicsTextures.empty())
|
||||
if (World::getWorld() && World::getWorld()->getTrack()->hasShadows() && m_spherical_harmonics->has6Textures())
|
||||
irr_driver->getSceneManager()->setAmbientLight(SColor(0, 0, 0, 0));
|
||||
|
||||
// TODO: put this outside of the rendering loop
|
||||
if (!m_skybox_ready)
|
||||
{
|
||||
prepareSkybox();
|
||||
m_skybox_ready = true;
|
||||
}
|
||||
if (!CVS->isDefferedEnabled())
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
@ -623,6 +617,17 @@ void IrrDriver::renderFixed(float dt)
|
||||
m_video_driver->endScene();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void IrrDriver::renderSkybox(const scene::ICameraSceneNode *camera)
|
||||
{
|
||||
if(m_skybox)
|
||||
{
|
||||
m_skybox->render(camera);
|
||||
}
|
||||
} // renderSkybox
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void IrrDriver::renderParticles()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,333 +0,0 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2014-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "central_settings.hpp"
|
||||
#include "graphics/IBL.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/shaders.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "utils/profiler.hpp"
|
||||
|
||||
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN2(a, b) ((a) > (b) ? (b) : (a))
|
||||
|
||||
class SkyboxShader : public TextureShader<SkyboxShader,1>
|
||||
{
|
||||
private:
|
||||
GLuint m_vao;
|
||||
|
||||
public:
|
||||
SkyboxShader()
|
||||
{
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "sky.vert",
|
||||
GL_FRAGMENT_SHADER, "sky.frag");
|
||||
assignUniforms();
|
||||
assignSamplerNames(0, "tex", ST_TRILINEAR_CUBEMAP);
|
||||
|
||||
glGenVertexArrays(1, &m_vao);
|
||||
glBindVertexArray(m_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, SharedGPUObjects::getSkyTriVBO());
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
|
||||
glBindVertexArray(0);
|
||||
} // SkyboxShader
|
||||
// ------------------------------------------------------------------------
|
||||
void bindVertexArray()
|
||||
{
|
||||
glBindVertexArray(m_vao);
|
||||
} // bindVertexArray
|
||||
}; // SkyboxShader
|
||||
|
||||
// ============================================================================
|
||||
//***************************************************************************
|
||||
// Currently unused functions, they will be used later so please DON'T remove
|
||||
//***************************************************************************
|
||||
/*static float getTexelValue(unsigned i, unsigned j, size_t width, size_t height,
|
||||
float *Coeff, float *Y00, float *Y1minus1,
|
||||
float *Y10, float *Y11, float *Y2minus2,
|
||||
float * Y2minus1, float * Y20, float *Y21,
|
||||
float *Y22)
|
||||
{
|
||||
float solidangle = 1.;
|
||||
size_t idx = i * height + j;
|
||||
float reconstructedVal = Y00[idx] * Coeff[0];
|
||||
reconstructedVal += Y1minus1[i * height + j] * Coeff[1]
|
||||
+ Y10[i * height + j] * Coeff[2]
|
||||
+ Y11[i * height + j] * Coeff[3];
|
||||
reconstructedVal += Y2minus2[idx] * Coeff[4]
|
||||
+ Y2minus1[idx] * Coeff[5] + Y20[idx] * Coeff[6]
|
||||
+ Y21[idx] * Coeff[7] + Y22[idx] * Coeff[8];
|
||||
reconstructedVal /= solidangle;
|
||||
return MAX2(255.0f * reconstructedVal, 0.f);
|
||||
}*/ // getTexelValue
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/*static void unprojectSH(float *output[], size_t width, size_t height,
|
||||
float *Y00[], float *Y1minus1[], float *Y10[],
|
||||
float *Y11[], float *Y2minus2[], float *Y2minus1[],
|
||||
float * Y20[], float *Y21[], float *Y22[],
|
||||
float *blueSHCoeff, float *greenSHCoeff,
|
||||
float *redSHCoeff)
|
||||
{
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
for (unsigned i = 0; i < width; i++)
|
||||
{
|
||||
for (unsigned j = 0; j < height; j++)
|
||||
{
|
||||
float fi = float(i), fj = float(j);
|
||||
fi /= width, fj /= height;
|
||||
fi = 2 * fi - 1, fj = 2 * fj - 1;
|
||||
|
||||
output[face][4 * height * i + 4 * j + 2] =
|
||||
getTexelValue(i, j, width, height, redSHCoeff, Y00[face],
|
||||
Y1minus1[face], Y10[face], Y11[face],
|
||||
Y2minus2[face], Y2minus1[face], Y20[face],
|
||||
Y21[face], Y22[face]);
|
||||
output[face][4 * height * i + 4 * j + 1] =
|
||||
getTexelValue(i, j, width, height, greenSHCoeff, Y00[face],
|
||||
Y1minus1[face], Y10[face], Y11[face],
|
||||
Y2minus2[face], Y2minus1[face], Y20[face],
|
||||
Y21[face], Y22[face]);
|
||||
output[face][4 * height * i + 4 * j] =
|
||||
getTexelValue(i, j, width, height, blueSHCoeff, Y00[face],
|
||||
Y1minus1[face], Y10[face], Y11[face],
|
||||
Y2minus2[face], Y2minus1[face], Y20[face],
|
||||
Y21[face], Y22[face]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/ // unprojectSH
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/*static void displayCoeff(float *SHCoeff)
|
||||
{
|
||||
printf("L00:%f\n", SHCoeff[0]);
|
||||
printf("L1-1:%f, L10:%f, L11:%f\n", SHCoeff[1], SHCoeff[2], SHCoeff[3]);
|
||||
printf("L2-2:%f, L2-1:%f, L20:%f, L21:%f, L22:%f\n",
|
||||
SHCoeff[4], SHCoeff[5], SHCoeff[6], SHCoeff[7], SHCoeff[8]);
|
||||
}*/ // displayCoeff
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void swapPixels(char *old_img, char *new_img, unsigned stride, unsigned old_i,
|
||||
unsigned old_j, unsigned new_i, unsigned new_j)
|
||||
{
|
||||
new_img[4 * (stride * new_i + new_j)] = old_img[4 * (stride * old_i + old_j)];
|
||||
new_img[4 * (stride * new_i + new_j) + 1] = old_img[4 * (stride * old_i + old_j) + 1];
|
||||
new_img[4 * (stride * new_i + new_j) + 2] = old_img[4 * (stride * old_i + old_j) + 2];
|
||||
new_img[4 * (stride * new_i + new_j) + 3] = old_img[4 * (stride * old_i + old_j) + 3];
|
||||
} // swapPixels
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Generate an opengl cubemap texture from 6 2d textures.
|
||||
Out of legacy the sequence of textures maps to :
|
||||
- 1st texture maps to GL_TEXTURE_CUBE_MAP_POSITIVE_Y
|
||||
- 2nd texture maps to GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
|
||||
- 3rd texture maps to GL_TEXTURE_CUBE_MAP_POSITIVE_X
|
||||
- 4th texture maps to GL_TEXTURE_CUBE_MAP_NEGATIVE_X
|
||||
- 5th texture maps to GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
|
||||
- 6th texture maps to GL_TEXTURE_CUBE_MAP_POSITIVE_Z
|
||||
* \param textures sequence of 6 textures.
|
||||
*/
|
||||
GLuint generateCubeMapFromTextures(const std::vector<video::ITexture *> &textures)
|
||||
{
|
||||
assert(textures.size() == 6);
|
||||
|
||||
GLuint result;
|
||||
glGenTextures(1, &result);
|
||||
|
||||
unsigned size = 0;
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
size = MAX2(size, textures[i]->getSize().Width);
|
||||
size = MAX2(size, textures[i]->getSize().Height);
|
||||
}
|
||||
|
||||
const unsigned texture_permutation[] = { 2, 3, 0, 1, 5, 4 };
|
||||
char *rgba[6];
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
rgba[i] = new char[size * size * 4];
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
unsigned idx = texture_permutation[i];
|
||||
|
||||
video::IImage* image = irr_driver->getVideoDriver()
|
||||
->createImageFromData(textures[idx]->getColorFormat(),
|
||||
textures[idx]->getSize(),
|
||||
textures[idx]->lock(), false );
|
||||
textures[idx]->unlock();
|
||||
|
||||
image->copyToScaling(rgba[i], size, size);
|
||||
image->drop();
|
||||
|
||||
if (i == 2 || i == 3)
|
||||
{
|
||||
char *tmp = new char[size * size * 4];
|
||||
memcpy(tmp, rgba[i], size * size * 4);
|
||||
for (unsigned x = 0; x < size; x++)
|
||||
{
|
||||
for (unsigned y = 0; y < size; y++)
|
||||
{
|
||||
swapPixels(tmp, rgba[i], size, x, y, (size - y - 1), x);
|
||||
}
|
||||
}
|
||||
delete[] tmp;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, result);
|
||||
if (CVS->isTextureCompressionEnabled())
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
|
||||
GL_COMPRESSED_SRGB_ALPHA, size, size, 0, GL_BGRA,
|
||||
GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
|
||||
GL_SRGB_ALPHA, size, size, 0, GL_BGRA,
|
||||
GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]);
|
||||
}
|
||||
}
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
delete[] rgba[i];
|
||||
return result;
|
||||
} // generateCubeMapFromTextures
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void IrrDriver::prepareSkybox()
|
||||
{
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
|
||||
generateDiffuseCoefficients();
|
||||
if (!SkyboxTextures.empty())
|
||||
{
|
||||
SkyboxCubeMap = generateCubeMapFromTextures(SkyboxTextures);
|
||||
SkyboxSpecularProbe = generateSpecularCubemap(SkyboxCubeMap);
|
||||
}
|
||||
} // prepareSkybox
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void IrrDriver::generateDiffuseCoefficients()
|
||||
{
|
||||
const unsigned texture_permutation[] = { 2, 3, 0, 1, 5, 4 };
|
||||
|
||||
unsigned sh_w = 0, sh_h = 0;
|
||||
unsigned char *sh_rgba[6];
|
||||
|
||||
if (SphericalHarmonicsTextures.size() == 6)
|
||||
{
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
sh_w = MAX2(sh_w, SphericalHarmonicsTextures[i]->getSize().Width);
|
||||
sh_h = MAX2(sh_h, SphericalHarmonicsTextures[i]->getSize().Height);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
sh_rgba[i] = new unsigned char[sh_w * sh_h * 4];
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
unsigned idx = texture_permutation[i];
|
||||
|
||||
video::IImage* image = getVideoDriver()->createImageFromData(
|
||||
SphericalHarmonicsTextures[idx]->getColorFormat(),
|
||||
SphericalHarmonicsTextures[idx]->getSize(),
|
||||
SphericalHarmonicsTextures[idx]->lock(),
|
||||
false
|
||||
);
|
||||
SphericalHarmonicsTextures[idx]->unlock();
|
||||
|
||||
image->copyToScaling(sh_rgba[i], sh_w, sh_h);
|
||||
delete image;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_w = 16;
|
||||
sh_h = 16;
|
||||
|
||||
video::SColor ambient = m_scene_manager->getAmbientLight().toSColor();
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
sh_rgba[i] = new unsigned char[sh_w * sh_h * 4];
|
||||
|
||||
for (unsigned j = 0; j < sh_w * sh_h * 4; j += 4)
|
||||
{
|
||||
sh_rgba[i][j] = ambient.getBlue();
|
||||
sh_rgba[i][j + 1] = ambient.getGreen();
|
||||
sh_rgba[i][j + 2] = ambient.getRed();
|
||||
sh_rgba[i][j + 3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to float texture
|
||||
Color *FloatTexCube[6];
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
FloatTexCube[i] = new Color[sh_w * sh_h];
|
||||
for (unsigned j = 0; j < sh_w * sh_h; j++)
|
||||
{
|
||||
FloatTexCube[i][j].Blue = powf(float(0xFF & sh_rgba[i][4 * j]) / 255.f, 2.2f);
|
||||
FloatTexCube[i][j].Green = powf(float(0xFF & sh_rgba[i][4 * j + 1]) / 255.f, 2.2f);
|
||||
FloatTexCube[i][j].Red = powf(float(0xFF & sh_rgba[i][4 * j + 2]) / 255.f, 2.2f);
|
||||
}
|
||||
}
|
||||
|
||||
generateSphericalHarmonics(FloatTexCube, sh_w, blueSHCoeff, greenSHCoeff, redSHCoeff);
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
delete[] sh_rgba[i];
|
||||
delete[] FloatTexCube[i];
|
||||
}
|
||||
|
||||
if (SphericalHarmonicsTextures.size() != 6)
|
||||
{
|
||||
// Diffuse env map is x 0.25, compensate
|
||||
for (unsigned i = 0; i < 9; i++)
|
||||
{
|
||||
blueSHCoeff[i] *= 4;
|
||||
greenSHCoeff[i] *= 4;
|
||||
redSHCoeff[i] *= 4;
|
||||
}
|
||||
}
|
||||
} // generateDiffuseCoefficients
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void IrrDriver::renderSkybox(const scene::ICameraSceneNode *camera)
|
||||
{
|
||||
if (SkyboxTextures.empty())
|
||||
return;
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
assert(SkyboxTextures.size() == 6);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
SkyboxShader::getInstance()->use();
|
||||
SkyboxShader::getInstance()->bindVertexArray();
|
||||
SkyboxShader::getInstance()->setUniforms();
|
||||
|
||||
SkyboxShader::getInstance()->setTextureUnits(SkyboxCubeMap);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindVertexArray(0);
|
||||
} // renderSkybox
|
@ -56,7 +56,6 @@ RTT::RTT(size_t width, size_t height)
|
||||
m_RH_FBO = NULL;
|
||||
m_RSM = NULL;
|
||||
m_RH_FBO = NULL;
|
||||
m_diffuse_coefficients_calculated = false;
|
||||
using namespace video;
|
||||
using namespace core;
|
||||
|
||||
@ -296,11 +295,6 @@ void RTT::prepareRender(scene::ICameraSceneNode* camera)
|
||||
irr_driver->setRTT(this);
|
||||
irr_driver->getSceneManager()->setActiveCamera(camera);
|
||||
|
||||
if (!m_diffuse_coefficients_calculated)
|
||||
{
|
||||
irr_driver->generateDiffuseCoefficients();
|
||||
m_diffuse_coefficients_calculated = true;
|
||||
}
|
||||
}
|
||||
|
||||
FrameBuffer* RTT::render(scene::ICameraSceneNode* camera, float dt)
|
||||
@ -310,8 +304,6 @@ FrameBuffer* RTT::render(scene::ICameraSceneNode* camera, float dt)
|
||||
irr_driver->getSceneManager()->setActiveCamera(camera);
|
||||
|
||||
std::vector<IrrDriver::GlowData> glows;
|
||||
// TODO: put this outside of the rendering loop
|
||||
//irr_driver->generateDiffuseCoefficients();
|
||||
irr_driver->computeMatrixesAndCameras(camera, m_width, m_height);
|
||||
unsigned plc = irr_driver->updateLightsInfo(camera, dt);
|
||||
irr_driver->uploadLightingData();
|
||||
|
@ -62,8 +62,6 @@ private:
|
||||
int m_width;
|
||||
int m_height;
|
||||
|
||||
bool m_diffuse_coefficients_calculated;
|
||||
|
||||
unsigned shadowColorTex, shadowDepthTex;
|
||||
unsigned RSM_Color, RSM_Normal, RSM_Depth;
|
||||
unsigned RH_Red, RH_Green, RH_Blue;
|
||||
|
@ -174,13 +174,16 @@ void ShaderBase::bypassUBO() const
|
||||
irr_driver->getCurrentScreenSize().Y);
|
||||
|
||||
GLint bLmn = glGetUniformLocation(m_program, "blueLmn[0]");
|
||||
glUniform1fv(bLmn, 9, irr_driver->blueSHCoeff);
|
||||
const float* blue_SH_coeff = irr_driver->getSphericalHarmonics()->getBlueSHCoeff();
|
||||
glUniform1fv(bLmn, 9, blue_SH_coeff);
|
||||
|
||||
GLint gLmn = glGetUniformLocation(m_program, "greenLmn[0]");
|
||||
glUniform1fv(gLmn, 9, irr_driver->greenSHCoeff);
|
||||
const float* green_SH_coeff = irr_driver->getSphericalHarmonics()->getGreenSHCoeff();
|
||||
glUniform1fv(gLmn, 9, green_SH_coeff);
|
||||
|
||||
GLint rLmn = glGetUniformLocation(m_program, "redLmn[0]");
|
||||
glUniform1fv(rLmn, 9, irr_driver->redSHCoeff);
|
||||
const float* red_SH_coeff = irr_driver->getSphericalHarmonics()->getRedSHCoeff();
|
||||
glUniform1fv(rLmn, 9, red_SH_coeff);
|
||||
|
||||
GLint sun_dir = glGetUniformLocation(m_program, "sun_direction");
|
||||
const core::vector3df &sd = irr_driver->getSunDirection();
|
||||
|
357
src/graphics/skybox.cpp
Normal file
357
src/graphics/skybox.cpp
Normal file
@ -0,0 +1,357 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
#include "graphics/skybox.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/shaders.hpp"
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
using namespace irr;
|
||||
|
||||
|
||||
class SkyboxShader : public TextureShader<SkyboxShader,1>
|
||||
{
|
||||
private:
|
||||
GLuint m_vao;
|
||||
|
||||
public:
|
||||
SkyboxShader()
|
||||
{
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "sky.vert",
|
||||
GL_FRAGMENT_SHADER, "sky.frag");
|
||||
assignUniforms();
|
||||
assignSamplerNames(0, "tex", ST_TRILINEAR_CUBEMAP);
|
||||
|
||||
glGenVertexArrays(1, &m_vao);
|
||||
glBindVertexArray(m_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, SharedGPUObjects::getSkyTriVBO());
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
|
||||
glBindVertexArray(0);
|
||||
} // SkyboxShader
|
||||
// ------------------------------------------------------------------------
|
||||
void bindVertexArray()
|
||||
{
|
||||
glBindVertexArray(m_vao);
|
||||
} // bindVertexArray
|
||||
}; // SkyboxShader
|
||||
|
||||
|
||||
class SpecularIBLGenerator : public TextureShader<SpecularIBLGenerator, 1,
|
||||
core::matrix4, float >
|
||||
{
|
||||
public:
|
||||
GLuint m_tu_samples;
|
||||
SpecularIBLGenerator()
|
||||
{
|
||||
loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert",
|
||||
GL_FRAGMENT_SHADER, "importance_sampling_specular.frag");
|
||||
assignUniforms("PermutationMatrix", "ViewportSize");
|
||||
m_tu_samples = 1;
|
||||
assignSamplerNames(0, "tex", ST_TRILINEAR_CUBEMAP);
|
||||
assignTextureUnit(m_tu_samples, "samples");
|
||||
}
|
||||
|
||||
}; // SpecularIBLGenerator
|
||||
|
||||
|
||||
namespace {
|
||||
// ----------------------------------------------------------------------------
|
||||
void swapPixels(char *old_img, char *new_img, unsigned stride, unsigned old_i,
|
||||
unsigned old_j, unsigned new_i, unsigned new_j)
|
||||
{
|
||||
new_img[4 * (stride * new_i + new_j)] = old_img[4 * (stride * old_i + old_j)];
|
||||
new_img[4 * (stride * new_i + new_j) + 1] = old_img[4 * (stride * old_i + old_j) + 1];
|
||||
new_img[4 * (stride * new_i + new_j) + 2] = old_img[4 * (stride * old_i + old_j) + 2];
|
||||
new_img[4 * (stride * new_i + new_j) + 3] = old_img[4 * (stride * old_i + old_j) + 3];
|
||||
} // swapPixels
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// From http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
|
||||
/** Returns the index-th pair from Hammersley set of pseudo random set.
|
||||
Hammersley set is a uniform distribution between 0 and 1 for 2 components.
|
||||
We use the natural indexation on the set to avoid storing the whole set.
|
||||
\param index of the pair
|
||||
\param size of the set. */
|
||||
std::pair<float, float> getHammersleySequence(int index, int samples)
|
||||
{
|
||||
float InvertedBinaryRepresentation = 0.;
|
||||
for (size_t i = 0; i < 32; i++)
|
||||
{
|
||||
InvertedBinaryRepresentation += ((index >> i) & 0x1)
|
||||
* powf(.5, (float) (i + 1.));
|
||||
}
|
||||
return std::make_pair(float(index) / float(samples),
|
||||
InvertedBinaryRepresentation);
|
||||
} // HammersleySequence
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns a pseudo random (theta, phi) generated from a probability density
|
||||
* function modeled after Phong function.
|
||||
* \param a pseudo random float pair from a uniform density function between
|
||||
* 0 and 1.
|
||||
* \param exponent from the Phong formula.
|
||||
*/
|
||||
std::pair<float, float> getImportanceSamplingPhong(std::pair<float, float> Seeds,
|
||||
float exponent)
|
||||
{
|
||||
return std::make_pair(acosf(powf(Seeds.first, 1.f / (exponent + 1.f))),
|
||||
2.f * 3.14f * Seeds.second);
|
||||
} // getImportanceSamplingPhong
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static core::matrix4 getPermutationMatrix(size_t indexX, float valX,
|
||||
size_t indexY, float valY,
|
||||
size_t indexZ, float valZ)
|
||||
{
|
||||
core::matrix4 result_mat;
|
||||
float *M = result_mat.pointer();
|
||||
memset(M, 0, 16 * sizeof(float));
|
||||
assert(indexX < 4);
|
||||
assert(indexY < 4);
|
||||
assert(indexZ < 4);
|
||||
M[indexX] = valX;
|
||||
M[4 + indexY] = valY;
|
||||
M[8 + indexZ] = valZ;
|
||||
return result_mat;
|
||||
} // getPermutationMatrix
|
||||
|
||||
} //namespace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Generate an opengl cubemap texture from 6 2d textures */
|
||||
void Skybox::generateCubeMapFromTextures()
|
||||
{
|
||||
assert(m_skybox_textures.size() == 6);
|
||||
|
||||
glGenTextures(1, &m_cube_map);
|
||||
|
||||
unsigned size = 0;
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
size = std::max(size, m_skybox_textures[i]->getSize().Width);
|
||||
size = std::max(size, m_skybox_textures[i]->getSize().Height);
|
||||
}
|
||||
|
||||
const unsigned texture_permutation[] = { 2, 3, 0, 1, 5, 4 };
|
||||
char *rgba[6];
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
rgba[i] = new char[size * size * 4];
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
unsigned idx = texture_permutation[i];
|
||||
|
||||
video::IImage* image = irr_driver->getVideoDriver()
|
||||
->createImageFromData(m_skybox_textures[idx]->getColorFormat(),
|
||||
m_skybox_textures[idx]->getSize(),
|
||||
m_skybox_textures[idx]->lock(), false );
|
||||
m_skybox_textures[idx]->unlock();
|
||||
|
||||
image->copyToScaling(rgba[i], size, size);
|
||||
image->drop();
|
||||
|
||||
if (i == 2 || i == 3)
|
||||
{
|
||||
char *tmp = new char[size * size * 4];
|
||||
memcpy(tmp, rgba[i], size * size * 4);
|
||||
for (unsigned x = 0; x < size; x++)
|
||||
{
|
||||
for (unsigned y = 0; y < size; y++)
|
||||
{
|
||||
swapPixels(tmp, rgba[i], size, x, y, (size - y - 1), x);
|
||||
}
|
||||
}
|
||||
delete[] tmp;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_cube_map);
|
||||
if (CVS->isTextureCompressionEnabled())
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
|
||||
GL_COMPRESSED_SRGB_ALPHA, size, size, 0, GL_BGRA,
|
||||
GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
|
||||
GL_SRGB_ALPHA, size, size, 0, GL_BGRA,
|
||||
GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]);
|
||||
}
|
||||
}
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
delete[] rgba[i];
|
||||
} // generateCubeMapFromTextures
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Skybox::generateSpecularCubemap()
|
||||
{
|
||||
glGenTextures(1, &m_specular_probe);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_specular_probe);
|
||||
size_t cubemap_size = 256;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA16F,
|
||||
cubemap_size, cubemap_size, 0, GL_BGRA, GL_FLOAT, 0);
|
||||
}
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
|
||||
if (!CVS->isDefferedEnabled())
|
||||
return;
|
||||
|
||||
GLuint fbo;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glViewport(0, 0, cubemap_size, cubemap_size);
|
||||
GLenum bufs[] = { GL_COLOR_ATTACHMENT0 };
|
||||
glDrawBuffers(1, bufs);
|
||||
SpecularIBLGenerator::getInstance()->use();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
core::matrix4 M[6] = {
|
||||
getPermutationMatrix(2, -1., 1, -1., 0, 1.),
|
||||
getPermutationMatrix(2, 1., 1, -1., 0, -1.),
|
||||
getPermutationMatrix(0, 1., 2, 1., 1, 1.),
|
||||
getPermutationMatrix(0, 1., 2, -1., 1, -1.),
|
||||
getPermutationMatrix(0, 1., 1, -1., 2, 1.),
|
||||
getPermutationMatrix(0, -1., 1, -1., 2, -1.),
|
||||
};
|
||||
|
||||
for (unsigned level = 0; level < 8; level++)
|
||||
{
|
||||
// Blinn Phong can be approximated by Phong with 4x the specular
|
||||
// coefficient
|
||||
// See http://seblagarde.wordpress.com/2012/03/29/relationship-between-phong-and-blinn-lighting-model/
|
||||
// NOTE : Removed because it makes too sharp reflexion
|
||||
float roughness = (8 - level) * pow(2.f, 10.f) / 8.f;
|
||||
float viewportSize = float(1 << (8 - level));
|
||||
|
||||
float *tmp = new float[2048];
|
||||
for (unsigned i = 0; i < 1024; i++)
|
||||
{
|
||||
std::pair<float, float> sample =
|
||||
getImportanceSamplingPhong(getHammersleySequence(i, 1024),
|
||||
roughness);
|
||||
tmp[2 * i] = sample.first;
|
||||
tmp[2 * i + 1] = sample.second;
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
glActiveTexture(GL_TEXTURE0 +
|
||||
SpecularIBLGenerator::getInstance()->m_tu_samples);
|
||||
GLuint sampleTex, sampleBuffer;
|
||||
glGenBuffers(1, &sampleBuffer);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, sampleBuffer);
|
||||
glBufferData(GL_TEXTURE_BUFFER, 2048 * sizeof(float), tmp,
|
||||
GL_STATIC_DRAW);
|
||||
glGenTextures(1, &sampleTex);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, sampleTex);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32F, sampleBuffer);
|
||||
glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO());
|
||||
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
|
||||
m_specular_probe, level);
|
||||
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
assert(status == GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
SpecularIBLGenerator::getInstance()->setTextureUnits(m_cube_map);
|
||||
SpecularIBLGenerator::getInstance()->setUniforms(M[face],
|
||||
viewportSize);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
}
|
||||
glActiveTexture( GL_TEXTURE0
|
||||
+ SpecularIBLGenerator::getInstance()->m_tu_samples);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
|
||||
delete[] tmp;
|
||||
glDeleteTextures(1, &sampleTex);
|
||||
glDeleteBuffers(1, &sampleBuffer);
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
} // generateSpecularCubemap
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Generate a skybox from 6 2d textures.
|
||||
Out of legacy the sequence of textures maps to:
|
||||
- 1st texture maps to GL_TEXTURE_CUBE_MAP_POSITIVE_Y
|
||||
- 2nd texture maps to GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
|
||||
- 3rd texture maps to GL_TEXTURE_CUBE_MAP_POSITIVE_X
|
||||
- 4th texture maps to GL_TEXTURE_CUBE_MAP_NEGATIVE_X
|
||||
- 5th texture maps to GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
|
||||
- 6th texture maps to GL_TEXTURE_CUBE_MAP_POSITIVE_Z
|
||||
* \param skybox_textures sequence of 6 textures.
|
||||
*/
|
||||
Skybox::Skybox(const std::vector<video::ITexture *> &skybox_textures)
|
||||
{
|
||||
m_skybox_textures = skybox_textures;
|
||||
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
|
||||
if (!skybox_textures.empty())
|
||||
{
|
||||
generateCubeMapFromTextures();
|
||||
generateSpecularCubemap();
|
||||
}
|
||||
}
|
||||
|
||||
Skybox::~Skybox()
|
||||
{
|
||||
glDeleteTextures(1, &m_cube_map);
|
||||
glDeleteTextures(1, &m_specular_probe);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Skybox::render(const scene::ICameraSceneNode *camera) const
|
||||
{
|
||||
if (m_skybox_textures.empty())
|
||||
return;
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
assert(m_skybox_textures.size() == 6);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
SkyboxShader::getInstance()->use();
|
||||
SkyboxShader::getInstance()->bindVertexArray();
|
||||
SkyboxShader::getInstance()->setUniforms();
|
||||
|
||||
SkyboxShader::getInstance()->setTextureUnits(m_cube_map);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindVertexArray(0);
|
||||
} // renderSkybox
|
||||
|
||||
|
55
src/graphics/skybox.hpp
Normal file
55
src/graphics/skybox.hpp
Normal file
@ -0,0 +1,55 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
#ifndef HEADER_SKYBOX_HPP
|
||||
#define HEADER_SKYBOX_HPP
|
||||
|
||||
#include "graphics/gl_headers.hpp"
|
||||
#include <ICameraSceneNode.h>
|
||||
#include <ITexture.h>
|
||||
#include <IVideoDriver.h>
|
||||
#include <vector>
|
||||
|
||||
class Skybox
|
||||
{
|
||||
private:
|
||||
/** The 6 skybox textures */
|
||||
std::vector<irr::video::ITexture *> m_skybox_textures;
|
||||
|
||||
/** The skybox texture id */
|
||||
GLuint m_cube_map;
|
||||
|
||||
/** The specular probe texture id */
|
||||
GLuint m_specular_probe;
|
||||
|
||||
|
||||
void generateCubeMapFromTextures ();
|
||||
void generateSpecularCubemap ();
|
||||
|
||||
public:
|
||||
Skybox(const std::vector<irr::video::ITexture *> &skybox_textures);
|
||||
~Skybox();
|
||||
|
||||
void render(const irr::scene::ICameraSceneNode *camera) const;
|
||||
|
||||
inline GLuint getSpecularProbe() const {return m_specular_probe; }
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif //HEADER_SKYBOX_HPP
|
521
src/graphics/sphericalHarmonics.cpp
Normal file
521
src/graphics/sphericalHarmonics.cpp
Normal file
@ -0,0 +1,521 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/sphericalHarmonics.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <irrlicht.h>
|
||||
|
||||
using namespace irr;
|
||||
|
||||
namespace
|
||||
{
|
||||
/** Convert an unsigned char cubemap texture to a float texture
|
||||
* \param sh_rgba The 6 faces of the cubemap texture
|
||||
* \param sh_w Texture width
|
||||
* \param sh_h Texture height
|
||||
* \param[out] float_tex_cube The converted float cubemap texture
|
||||
*/
|
||||
void convertToFloatTexture(unsigned char *sh_rgba[6], unsigned sh_w, unsigned sh_h, Color *float_tex_cube[6])
|
||||
{
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
float_tex_cube[i] = new Color[sh_w * sh_h];
|
||||
for (unsigned j = 0; j < sh_w * sh_h; j++)
|
||||
{
|
||||
float_tex_cube[i][j].Blue = powf(float(0xFF & sh_rgba[i][4 * j]) / 255.f, 2.2f);
|
||||
float_tex_cube[i][j].Green = powf(float(0xFF & sh_rgba[i][4 * j + 1]) / 255.f, 2.2f);
|
||||
float_tex_cube[i][j].Red = powf(float(0xFF & sh_rgba[i][4 * j + 2]) / 255.f, 2.2f);
|
||||
}
|
||||
}
|
||||
} //convertToFloatTexture
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Print the nine first spherical harmonics coefficients
|
||||
* \param SH_coeff The nine spherical harmonics coefficients
|
||||
*/
|
||||
void displayCoeff(float *SH_coeff)
|
||||
{
|
||||
Log::debug("SphericalHarmonics", "L00:%f", SH_coeff[0]);
|
||||
Log::debug("SphericalHarmonics", "L1-1:%f, L10:%f, L11:%f",
|
||||
SH_coeff[1], SH_coeff[2], SH_coeff[3]);
|
||||
Log::debug("SphericalHarmonics", "L2-2:%f, L2-1:%f, L20:%f, L21:%f, L22:%f",
|
||||
SH_coeff[4], SH_coeff[5], SH_coeff[6], SH_coeff[7], SH_coeff[8]);
|
||||
} // displayCoeff
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Compute the value of the (i,j) texel of the environment map
|
||||
* from the spherical harmonics coefficients
|
||||
* \param i The texel line
|
||||
* \param j The texel column
|
||||
* \param width The texture width
|
||||
* \param height The texture height
|
||||
* \param Coeff The 9 first SH coefficients for a color channel (blue, green or red)
|
||||
* \param Yml The sphericals harmonics functions values on each texel of the cubemap
|
||||
*/
|
||||
float getTexelValue(unsigned i, unsigned j, size_t width, size_t height,
|
||||
float *Coeff, float *Y00, float *Y1minus1,
|
||||
float *Y10, float *Y11, float *Y2minus2,
|
||||
float * Y2minus1, float * Y20, float *Y21,
|
||||
float *Y22)
|
||||
{
|
||||
float solidangle = 1.;
|
||||
size_t idx = i * height + j;
|
||||
float reconstructedVal = Y00[idx] * Coeff[0];
|
||||
reconstructedVal += Y1minus1[i * height + j] * Coeff[1]
|
||||
+ Y10[i * height + j] * Coeff[2]
|
||||
+ Y11[i * height + j] * Coeff[3];
|
||||
reconstructedVal += Y2minus2[idx] * Coeff[4]
|
||||
+ Y2minus1[idx] * Coeff[5] + Y20[idx] * Coeff[6]
|
||||
+ Y21[idx] * Coeff[7] + Y22[idx] * Coeff[8];
|
||||
reconstructedVal /= solidangle;
|
||||
return std::max(255.0f * reconstructedVal, 0.f);
|
||||
} // getTexelValue
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return a normalized vector aiming at a texel on a cubemap
|
||||
* \param face The face of the cubemap
|
||||
* \param j The texel line in the face
|
||||
* \param j The texel column in the face
|
||||
* \param x The x vector component
|
||||
* \param y The y vector component
|
||||
* \param z The z vector component
|
||||
*/
|
||||
void getXYZ(GLenum face, float i, float j, float &x, float &y, float &z)
|
||||
{
|
||||
switch (face)
|
||||
{
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
x = 1.;
|
||||
y = -i;
|
||||
z = -j;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
x = -1.;
|
||||
y = -i;
|
||||
z = j;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
x = j;
|
||||
y = 1.;
|
||||
z = i;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
x = j;
|
||||
y = -1;
|
||||
z = -i;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
x = j;
|
||||
y = -i;
|
||||
z = 1;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
x = -j;
|
||||
y = -i;
|
||||
z = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
float norm = sqrt(x * x + y * y + z * z);
|
||||
x /= norm, y /= norm, z /= norm;
|
||||
return;
|
||||
} // getXYZ
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Compute the value of the spherical harmonics basis functions (Yml)
|
||||
* on each texel of a cubemap face
|
||||
* \param face Face of the cubemap
|
||||
* \param edge_size Size of the cubemap face
|
||||
* \param[out] Yml The sphericals harmonics functions values on each texel of the cubemap
|
||||
*/
|
||||
void getYml(GLenum face, size_t edge_size,
|
||||
float *Y00,
|
||||
float *Y1minus1, float *Y10, float *Y11,
|
||||
float *Y2minus2, float *Y2minus1, float *Y20, float *Y21, float *Y22)
|
||||
{
|
||||
#pragma omp parallel for
|
||||
for (int i = 0; i < int(edge_size); i++)
|
||||
{
|
||||
for (unsigned j = 0; j < edge_size; j++)
|
||||
{
|
||||
float x, y, z;
|
||||
float fi = float(i), fj = float(j);
|
||||
fi /= edge_size, fj /= edge_size;
|
||||
fi = 2 * fi - 1, fj = 2 * fj - 1;
|
||||
getXYZ(face, fi, fj, x, y, z);
|
||||
|
||||
// constant part of Ylm
|
||||
float c00 = 0.282095f;
|
||||
float c1minus1 = 0.488603f;
|
||||
float c10 = 0.488603f;
|
||||
float c11 = 0.488603f;
|
||||
float c2minus2 = 1.092548f;
|
||||
float c2minus1 = 1.092548f;
|
||||
float c21 = 1.092548f;
|
||||
float c20 = 0.315392f;
|
||||
float c22 = 0.546274f;
|
||||
|
||||
size_t idx = i * edge_size + j;
|
||||
|
||||
Y00[idx] = c00;
|
||||
Y1minus1[idx] = c1minus1 * y;
|
||||
Y10[idx] = c10 * z;
|
||||
Y11[idx] = c11 * x;
|
||||
Y2minus2[idx] = c2minus2 * x * y;
|
||||
Y2minus1[idx] = c2minus1 * y * z;
|
||||
Y21[idx] = c21 * x * z;
|
||||
Y20[idx] = c20 * (3 * z * z - 1);
|
||||
Y22[idx] = c22 * (x * x - y * y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Compute m_red_SH_coeff, m_green_SH_coeff and m_blue_SH_coeff from Yml values
|
||||
* \param cubemap_face The 6 cubemap faces (float textures)
|
||||
* \param edge_size Size of the cubemap face
|
||||
* \param Yml The sphericals harmonics functions values on each texel of the cubemap
|
||||
*/
|
||||
void SphericalHarmonics::projectSH(Color *cubemap_face[6], size_t edge_size,
|
||||
float *Y00[],
|
||||
float *Y1minus1[], float *Y10[], float *Y11[],
|
||||
float *Y2minus2[], float *Y2minus1[], float * Y20[],
|
||||
float *Y21[], float *Y22[])
|
||||
{
|
||||
for (unsigned i = 0; i < 9; i++)
|
||||
{
|
||||
m_blue_SH_coeff[i] = 0;
|
||||
m_green_SH_coeff[i] = 0;
|
||||
m_red_SH_coeff[i] = 0;
|
||||
}
|
||||
|
||||
float wh = float(edge_size * edge_size);
|
||||
float b0 = 0., b1 = 0., b2 = 0., b3 = 0., b4 = 0., b5 = 0., b6 = 0., b7 = 0., b8 = 0.;
|
||||
float r0 = 0., r1 = 0., r2 = 0., r3 = 0., r4 = 0., r5 = 0., r6 = 0., r7 = 0., r8 = 0.;
|
||||
float g0 = 0., g1 = 0., g2 = 0., g3 = 0., g4 = 0., g5 = 0., g6 = 0., g7 = 0., g8 = 0.;
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
#pragma omp parallel for reduction(+ : b0, b1, b2, b3, b4, b5, b6, b7, b8, \
|
||||
r0, r1, r2, r3, r4, r5, r6, r7, r8, \
|
||||
g0, g1, g2, g3, g4, g5, g6, g7, g8)
|
||||
for (int i = 0; i < int(edge_size); i++)
|
||||
{
|
||||
for (unsigned j = 0; j < edge_size; j++)
|
||||
{
|
||||
int idx = i * edge_size + j;
|
||||
float fi = float(i), fj = float(j);
|
||||
fi /= edge_size, fj /= edge_size;
|
||||
fi = 2 * fi - 1, fj = 2 * fj - 1;
|
||||
|
||||
|
||||
float d = sqrt(fi * fi + fj * fj + 1);
|
||||
|
||||
// Constant obtained by projecting unprojected ref values
|
||||
float solidangle = 2.75f / (wh * pow(d, 1.5f));
|
||||
// pow(., 2.2) to convert from srgb
|
||||
float b = cubemap_face[face][edge_size * i + j].Blue;
|
||||
float g = cubemap_face[face][edge_size * i + j].Green;
|
||||
float r = cubemap_face[face][edge_size * i + j].Red;
|
||||
|
||||
b0 += b * Y00[face][idx] * solidangle;
|
||||
b1 += b * Y1minus1[face][idx] * solidangle;
|
||||
b2 += b * Y10[face][idx] * solidangle;
|
||||
b3 += b * Y11[face][idx] * solidangle;
|
||||
b4 += b * Y2minus2[face][idx] * solidangle;
|
||||
b5 += b * Y2minus1[face][idx] * solidangle;
|
||||
b6 += b * Y20[face][idx] * solidangle;
|
||||
b7 += b * Y21[face][idx] * solidangle;
|
||||
b8 += b * Y22[face][idx] * solidangle;
|
||||
|
||||
g0 += g * Y00[face][idx] * solidangle;
|
||||
g1 += g * Y1minus1[face][idx] * solidangle;
|
||||
g2 += g * Y10[face][idx] * solidangle;
|
||||
g3 += g * Y11[face][idx] * solidangle;
|
||||
g4 += g * Y2minus2[face][idx] * solidangle;
|
||||
g5 += g * Y2minus1[face][idx] * solidangle;
|
||||
g6 += g * Y20[face][idx] * solidangle;
|
||||
g7 += g * Y21[face][idx] * solidangle;
|
||||
g8 += g * Y22[face][idx] * solidangle;
|
||||
|
||||
|
||||
r0 += r * Y00[face][idx] * solidangle;
|
||||
r1 += r * Y1minus1[face][idx] * solidangle;
|
||||
r2 += r * Y10[face][idx] * solidangle;
|
||||
r3 += r * Y11[face][idx] * solidangle;
|
||||
r4 += r * Y2minus2[face][idx] * solidangle;
|
||||
r5 += r * Y2minus1[face][idx] * solidangle;
|
||||
r6 += r * Y20[face][idx] * solidangle;
|
||||
r7 += r * Y21[face][idx] * solidangle;
|
||||
r8 += r * Y22[face][idx] * solidangle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_blue_SH_coeff[0] = b0;
|
||||
m_blue_SH_coeff[1] = b1;
|
||||
m_blue_SH_coeff[2] = b2;
|
||||
m_blue_SH_coeff[3] = b3;
|
||||
m_blue_SH_coeff[4] = b4;
|
||||
m_blue_SH_coeff[5] = b5;
|
||||
m_blue_SH_coeff[6] = b6;
|
||||
m_blue_SH_coeff[7] = b7;
|
||||
m_blue_SH_coeff[8] = b8;
|
||||
|
||||
m_red_SH_coeff[0] = r0;
|
||||
m_red_SH_coeff[1] = r1;
|
||||
m_red_SH_coeff[2] = r2;
|
||||
m_red_SH_coeff[3] = r3;
|
||||
m_red_SH_coeff[4] = r4;
|
||||
m_red_SH_coeff[5] = r5;
|
||||
m_red_SH_coeff[6] = r6;
|
||||
m_red_SH_coeff[7] = r7;
|
||||
m_red_SH_coeff[8] = r8;
|
||||
|
||||
m_green_SH_coeff[0] = g0;
|
||||
m_green_SH_coeff[1] = g1;
|
||||
m_green_SH_coeff[2] = g2;
|
||||
m_green_SH_coeff[3] = g3;
|
||||
m_green_SH_coeff[4] = g4;
|
||||
m_green_SH_coeff[5] = g5;
|
||||
m_green_SH_coeff[6] = g6;
|
||||
m_green_SH_coeff[7] = g7;
|
||||
m_green_SH_coeff[8] = g8;
|
||||
} // projectSH
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Generate the 9 first SH coefficients for each color channel
|
||||
* using the cubemap provided by CubemapFace.
|
||||
* \param cubemap_face The 6 cubemap faces (float textures)
|
||||
* \param edge_size Size of the cubemap face
|
||||
*/
|
||||
void SphericalHarmonics::generateSphericalHarmonics(Color *cubemap_face[6], size_t edge_size)
|
||||
{
|
||||
float *Y00[6];
|
||||
float *Y1minus1[6];
|
||||
float *Y10[6];
|
||||
float *Y11[6];
|
||||
float *Y2minus2[6];
|
||||
float *Y2minus1[6];
|
||||
float *Y20[6];
|
||||
float *Y21[6];
|
||||
float *Y22[6];
|
||||
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
Y00[face] = new float[edge_size * edge_size];
|
||||
Y1minus1[face] = new float[edge_size * edge_size];
|
||||
Y10[face] = new float[edge_size * edge_size];
|
||||
Y11[face] = new float[edge_size * edge_size];
|
||||
Y2minus2[face] = new float[edge_size * edge_size];
|
||||
Y2minus1[face] = new float[edge_size * edge_size];
|
||||
Y20[face] = new float[edge_size * edge_size];
|
||||
Y21[face] = new float[edge_size * edge_size];
|
||||
Y22[face] = new float[edge_size * edge_size];
|
||||
|
||||
getYml(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, edge_size, Y00[face],
|
||||
Y1minus1[face], Y10[face], Y11[face], Y2minus2[face],
|
||||
Y2minus1[face], Y20[face], Y21[face], Y22[face]);
|
||||
}
|
||||
|
||||
projectSH(cubemap_face, edge_size, Y00, Y1minus1, Y10, Y11, Y2minus2,
|
||||
Y2minus1, Y20, Y21, Y22);
|
||||
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
delete[] Y00[face];
|
||||
delete[] Y1minus1[face];
|
||||
delete[] Y10[face];
|
||||
delete[] Y11[face];
|
||||
delete[] Y2minus2[face];
|
||||
delete[] Y2minus1[face];
|
||||
delete[] Y20[face];
|
||||
delete[] Y21[face];
|
||||
delete[] Y22[face];
|
||||
}
|
||||
} // generateSphericalHarmonics
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
SphericalHarmonics::SphericalHarmonics(const std::vector<video::ITexture *> &spherical_harmonics_textures)
|
||||
{
|
||||
setTextures(spherical_harmonics_textures);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** When spherical harmonics textures are not defined, SH coefficents are computed
|
||||
* from ambient light
|
||||
*/
|
||||
SphericalHarmonics::SphericalHarmonics(const video::SColor &ambient)
|
||||
{
|
||||
//make sure m_ambient and ambient are not equal
|
||||
m_ambient = (ambient==0) ? 1 : 0;
|
||||
setAmbientLight(ambient);
|
||||
}
|
||||
|
||||
/** Compute spherical harmonics coefficients from 6 textures */
|
||||
void SphericalHarmonics::setTextures(const std::vector<video::ITexture *> &spherical_harmonics_textures)
|
||||
{
|
||||
assert(spherical_harmonics_textures.size() == 6);
|
||||
|
||||
m_spherical_harmonics_textures = spherical_harmonics_textures;
|
||||
|
||||
const unsigned texture_permutation[] = { 2, 3, 0, 1, 5, 4 };
|
||||
unsigned char *sh_rgba[6];
|
||||
unsigned sh_w = 0, sh_h = 0;
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
sh_w = std::max(sh_w, m_spherical_harmonics_textures[i]->getSize().Width);
|
||||
sh_h = std::max(sh_h, m_spherical_harmonics_textures[i]->getSize().Height);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
sh_rgba[i] = new unsigned char[sh_w * sh_h * 4];
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
unsigned idx = texture_permutation[i];
|
||||
|
||||
video::IImage* image = irr_driver->getVideoDriver()->createImageFromData(
|
||||
m_spherical_harmonics_textures[idx]->getColorFormat(),
|
||||
m_spherical_harmonics_textures[idx]->getSize(),
|
||||
m_spherical_harmonics_textures[idx]->lock(),
|
||||
false
|
||||
);
|
||||
m_spherical_harmonics_textures[idx]->unlock();
|
||||
|
||||
image->copyToScaling(sh_rgba[i], sh_w, sh_h);
|
||||
delete image;
|
||||
} //for (unsigned i = 0; i < 6; i++)
|
||||
|
||||
Color *float_tex_cube[6];
|
||||
convertToFloatTexture(sh_rgba, sh_w, sh_h, float_tex_cube);
|
||||
generateSphericalHarmonics(float_tex_cube, sh_w);
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
delete[] sh_rgba[i];
|
||||
delete[] float_tex_cube[i];
|
||||
}
|
||||
} //setSphericalHarmonicsTextures
|
||||
|
||||
/** Compute spherical harmonics coefficients from ambient light */
|
||||
void SphericalHarmonics::setAmbientLight(const video::SColor &ambient)
|
||||
{
|
||||
//do not recompute SH coefficients if we already use the same ambient light
|
||||
if((m_spherical_harmonics_textures.size() != 6) && (ambient == m_ambient))
|
||||
return;
|
||||
|
||||
m_spherical_harmonics_textures.clear();
|
||||
m_ambient = ambient;
|
||||
|
||||
unsigned char *sh_rgba[6];
|
||||
unsigned sh_w = 16;
|
||||
unsigned sh_h = 16;
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
sh_rgba[i] = new unsigned char[sh_w * sh_h * 4];
|
||||
|
||||
for (unsigned j = 0; j < sh_w * sh_h * 4; j += 4)
|
||||
{
|
||||
sh_rgba[i][j] = ambient.getBlue();
|
||||
sh_rgba[i][j + 1] = ambient.getGreen();
|
||||
sh_rgba[i][j + 2] = ambient.getRed();
|
||||
sh_rgba[i][j + 3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
Color *float_tex_cube[6];
|
||||
convertToFloatTexture(sh_rgba, sh_w, sh_h, float_tex_cube);
|
||||
generateSphericalHarmonics(float_tex_cube, sh_w);
|
||||
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
{
|
||||
delete[] sh_rgba[i];
|
||||
delete[] float_tex_cube[i];
|
||||
}
|
||||
|
||||
// Diffuse env map is x 0.25, compensate
|
||||
for (unsigned i = 0; i < 9; i++)
|
||||
{
|
||||
m_blue_SH_coeff[i] *= 4;
|
||||
m_green_SH_coeff[i] *= 4;
|
||||
m_red_SH_coeff[i] *= 4;
|
||||
}
|
||||
} //setAmbientLight
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Print spherical harmonics coefficients (debug) */
|
||||
void SphericalHarmonics::printCoeff() {
|
||||
Log::debug("SphericalHarmonics", "Blue_SH:");
|
||||
displayCoeff(m_blue_SH_coeff);
|
||||
Log::debug("SphericalHarmonics", "Green_SH:");
|
||||
displayCoeff(m_green_SH_coeff);
|
||||
Log::debug("SphericalHarmonics", "Red_SH:");
|
||||
displayCoeff(m_red_SH_coeff);
|
||||
} //printCoeff
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Compute the the environment map from the spherical harmonics coefficients
|
||||
* \param width The texture width
|
||||
* \param height The texture height
|
||||
* \param Yml The sphericals harmonics functions values
|
||||
* \param[out] output The environment map texels values
|
||||
*/
|
||||
void SphericalHarmonics::unprojectSH(size_t width, size_t height,
|
||||
float *Y00[], float *Y1minus1[], float *Y10[],
|
||||
float *Y11[], float *Y2minus2[], float *Y2minus1[],
|
||||
float *Y20[], float *Y21[], float *Y22[],
|
||||
float *output[])
|
||||
{
|
||||
for (unsigned face = 0; face < 6; face++)
|
||||
{
|
||||
for (unsigned i = 0; i < width; i++)
|
||||
{
|
||||
for (unsigned j = 0; j < height; j++)
|
||||
{
|
||||
float fi = float(i), fj = float(j);
|
||||
fi /= width, fj /= height;
|
||||
fi = 2 * fi - 1, fj = 2 * fj - 1;
|
||||
|
||||
output[face][4 * height * i + 4 * j + 2] =
|
||||
getTexelValue(i, j, width, height, m_red_SH_coeff, Y00[face],
|
||||
Y1minus1[face], Y10[face], Y11[face],
|
||||
Y2minus2[face], Y2minus1[face], Y20[face],
|
||||
Y21[face], Y22[face]);
|
||||
output[face][4 * height * i + 4 * j + 1] =
|
||||
getTexelValue(i, j, width, height, m_green_SH_coeff, Y00[face],
|
||||
Y1minus1[face], Y10[face], Y11[face],
|
||||
Y2minus2[face], Y2minus1[face], Y20[face],
|
||||
Y21[face], Y22[face]);
|
||||
output[face][4 * height * i + 4 * j] =
|
||||
getTexelValue(i, j, width, height, m_blue_SH_coeff, Y00[face],
|
||||
Y1minus1[face], Y10[face], Y11[face],
|
||||
Y2minus2[face], Y2minus1[face], Y20[face],
|
||||
Y21[face], Y22[face]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // unprojectSH
|
||||
|
77
src/graphics/sphericalHarmonics.hpp
Normal file
77
src/graphics/sphericalHarmonics.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
#ifndef HEADER_SPHERICAL_HARMONICS_HPP
|
||||
#define HEADER_SPHERICAL_HARMONICS_HPP
|
||||
|
||||
#include <ITexture.h>
|
||||
#include <vector>
|
||||
|
||||
struct Color
|
||||
{
|
||||
float Red;
|
||||
float Green;
|
||||
float Blue;
|
||||
};
|
||||
|
||||
|
||||
class SphericalHarmonics
|
||||
{
|
||||
private:
|
||||
/** The 6 spherical harmonics textures */
|
||||
std::vector<irr::video::ITexture *> m_spherical_harmonics_textures;
|
||||
|
||||
/** Ambient light is used for tracks without spherical harmonics textures */
|
||||
irr::video::SColor m_ambient;
|
||||
|
||||
/** The spherical harmonics coefficients */
|
||||
float m_blue_SH_coeff[9];
|
||||
float m_green_SH_coeff[9];
|
||||
float m_red_SH_coeff[9];
|
||||
|
||||
|
||||
void projectSH(Color *cubemap_face[6], size_t edge_size, float *Y00[],
|
||||
float *Y1minus1[], float *Y10[], float *Y11[],
|
||||
float *Y2minus2[], float *Y2minus1[], float * Y20[],
|
||||
float *Y21[], float *Y22[]);
|
||||
|
||||
void generateSphericalHarmonics(Color *cubemap_face[6], size_t edge_size);
|
||||
|
||||
public:
|
||||
SphericalHarmonics(const std::vector<irr::video::ITexture *> &spherical_harmonics_textures);
|
||||
SphericalHarmonics(const irr::video::SColor &ambient);
|
||||
|
||||
void setTextures(const std::vector<irr::video::ITexture *> &spherical_harmonics_textures);
|
||||
void setAmbientLight(const irr::video::SColor &ambient);
|
||||
|
||||
inline const float* getBlueSHCoeff () const {return m_blue_SH_coeff; }
|
||||
inline const float* getGreenSHCoeff() const {return m_green_SH_coeff; }
|
||||
inline const float* getRedSHCoeff () const {return m_red_SH_coeff; }
|
||||
|
||||
inline bool has6Textures() const {return m_spherical_harmonics_textures.size()==6;}
|
||||
|
||||
void printCoeff();
|
||||
|
||||
void unprojectSH (size_t width, size_t height,
|
||||
float *Y00[], float *Y1minus1[], float *Y10[],
|
||||
float *Y11[], float *Y2minus2[], float *Y2minus1[],
|
||||
float * Y20[], float *Y21[], float *Y22[],
|
||||
float *output[]);
|
||||
};
|
||||
|
||||
#endif //HEADER_SPHERICAL_HARMONICS_HPP
|
@ -44,7 +44,7 @@ IconButtonWidget::IconButtonWidget(ScaleMode scale_mode, const bool tab_stop,
|
||||
m_texture = NULL;
|
||||
m_deactivated_texture = NULL;
|
||||
m_highlight_texture = NULL;
|
||||
|
||||
|
||||
m_custom_aspect_ratio = 1.0f;
|
||||
|
||||
m_texture_w = 0;
|
||||
@ -112,7 +112,7 @@ void IconButtonWidget::add()
|
||||
// irrlicht widgets don't support scaling while keeping aspect ratio
|
||||
// so, happily, let's implement it ourselves
|
||||
float useAspectRatio = -1.0f;
|
||||
|
||||
|
||||
if (m_properties[PROP_CUSTOM_RATIO] != "")
|
||||
{
|
||||
StringUtils::fromString(m_properties[PROP_CUSTOM_RATIO],
|
||||
@ -182,7 +182,7 @@ void IconButtonWidget::add()
|
||||
x1 += diff;
|
||||
x2 += diff;
|
||||
}
|
||||
else if (x2 > irr_driver->getActualScreenSize().Width)
|
||||
else if (x2 > (int)irr_driver->getActualScreenSize().Width)
|
||||
{
|
||||
int diff = x2 - irr_driver->getActualScreenSize().Width;
|
||||
x2 -= diff;
|
||||
@ -227,7 +227,7 @@ void IconButtonWidget::add()
|
||||
m_id = m_element->getID();
|
||||
if (m_tab_stop) m_element->setTabOrder(m_id);
|
||||
m_element->setTabGroup(false);
|
||||
|
||||
|
||||
if (!m_is_visible)
|
||||
m_element->setVisible(false);
|
||||
}
|
||||
@ -334,7 +334,7 @@ video::ITexture* IconButtonWidget::getDeactivatedTexture(video::ITexture* textur
|
||||
|
||||
std::string name = texture->getName().getPath().c_str();
|
||||
name += "_disabled";
|
||||
t = irr_driver->getTexture(name, /*premul*/false, /*prediv*/false,
|
||||
t = irr_driver->getTexture(name, /*premul*/false, /*prediv*/false,
|
||||
/*compain_if_not_found*/false);
|
||||
if (t == NULL)
|
||||
{
|
||||
@ -342,7 +342,7 @@ video::ITexture* IconButtonWidget::getDeactivatedTexture(video::ITexture* textur
|
||||
u32 g;
|
||||
|
||||
video::IVideoDriver* driver = irr_driver->getVideoDriver();
|
||||
std::auto_ptr<video::IImage> image (driver->createImageFromData (texture->getColorFormat(),
|
||||
std::unique_ptr<video::IImage> image (driver->createImageFromData (texture->getColorFormat(),
|
||||
texture->getSize(), texture->lock(), false));
|
||||
texture->unlock();
|
||||
|
||||
|
@ -251,7 +251,7 @@ void ModelViewWidget::setupRTTScene(PtrVector<scene::IMesh, REF>& mesh,
|
||||
}
|
||||
}
|
||||
|
||||
irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 35, 35, 35));
|
||||
irr_driver->setAmbientLight(video::SColor(255, 35, 35, 35));
|
||||
|
||||
const core::vector3df &spot_pos = core::vector3df(0, 30, 40);
|
||||
m_light = irr_driver->addLight(spot_pos, 0.3f /* energy */, 10 /* distance */, 1.0f /* r */, 1.0f /* g */, 1.0f /* g*/, true, NULL);
|
||||
|
@ -560,7 +560,9 @@ EventPropagation RibbonWidget::focused(const int playerID)
|
||||
{
|
||||
if (m_selection[playerID] != -1)
|
||||
{
|
||||
m_active_children.get(m_selection[playerID])->focused(playerID);
|
||||
int selection = m_selection[playerID];
|
||||
if (selection < (int)m_active_children.size())
|
||||
m_active_children.get(selection)->focused(playerID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,45 +110,85 @@ irr::core::stringw Binding::getAsString() const
|
||||
case 221: s="]"; break;
|
||||
case 222: s="'"; break;
|
||||
#endif
|
||||
case irr::KEY_LBUTTON : s = "left mouse button"; break;
|
||||
case irr::KEY_RBUTTON : s = "right mouse button"; break;
|
||||
case irr::KEY_CANCEL : s = "cancel"; break;
|
||||
case irr::KEY_MBUTTON : s = "middle mouse button"; break;
|
||||
case irr::KEY_XBUTTON1 : s = "X1 mouse button"; break;
|
||||
case irr::KEY_XBUTTON2 : s = "X2 mouse button"; break;
|
||||
case irr::KEY_BACK : s = "backspace"; break;
|
||||
case irr::KEY_TAB : s = "tab"; break;
|
||||
case irr::KEY_CLEAR : s = "clear"; break;
|
||||
case irr::KEY_RETURN : s = "return"; break;
|
||||
case irr::KEY_SHIFT : s = "shift"; break;
|
||||
case irr::KEY_CONTROL : s = "control"; break;
|
||||
case irr::KEY_MENU : s = "alt/menu"; break;
|
||||
case irr::KEY_PAUSE : s = "pause"; break;
|
||||
case irr::KEY_CAPITAL : s = "caps lock"; break;
|
||||
case irr::KEY_KANA : s = "kana"; break;
|
||||
case irr::KEY_JUNJA : s = "junja"; break;
|
||||
case irr::KEY_FINAL : s = "final"; break;
|
||||
case irr::KEY_ESCAPE : s = "escape"; break;
|
||||
case irr::KEY_CONVERT : s = "convert"; break;
|
||||
case irr::KEY_NONCONVERT : s = "nonconvert"; break;
|
||||
case irr::KEY_ACCEPT : s = "accept"; break;
|
||||
case irr::KEY_MODECHANGE : s = "modechange"; break;
|
||||
case irr::KEY_SPACE : s = "space"; break;
|
||||
case irr::KEY_PRIOR : s = "page up"; break;
|
||||
case irr::KEY_NEXT : s = "page down"; break;
|
||||
case irr::KEY_END : s = "end"; break;
|
||||
case irr::KEY_HOME : s = "home"; break;
|
||||
case irr::KEY_LEFT : s = "left"; break;
|
||||
case irr::KEY_UP : s = "up"; break;
|
||||
case irr::KEY_RIGHT : s = "right"; break;
|
||||
case irr::KEY_DOWN : s = "down"; break;
|
||||
case irr::KEY_SELECT : s = "select"; break;
|
||||
case irr::KEY_PRINT : s = "print"; break;
|
||||
case irr::KEY_EXECUT : s = "exec"; break;
|
||||
case irr::KEY_SNAPSHOT : s = "print screen"; break;
|
||||
case irr::KEY_INSERT : s = "insert"; break;
|
||||
case irr::KEY_DELETE : s = "delete"; break;
|
||||
case irr::KEY_HELP : s = "help"; break;
|
||||
//I18N: input configuration screen: mouse button
|
||||
case irr::KEY_LBUTTON : s = _("Left Mouse Button"); break;
|
||||
//I18N: input configuration screen: mouse button
|
||||
case irr::KEY_RBUTTON : s = _("Right Mouse Button"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_CANCEL : s = _("Cancel"); break;
|
||||
//I18N: input configuration screen: mouse button
|
||||
case irr::KEY_MBUTTON : s = _("Middle Mouse Button"); break;
|
||||
//I18N: input configuration screen: mouse button
|
||||
case irr::KEY_XBUTTON1 : s = _("X1 Mouse Button"); break;
|
||||
//I18N: input configuration screen: mouse button
|
||||
case irr::KEY_XBUTTON2 : s = _("X2 Mouse Button"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_BACK : s = _("Backspace"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_TAB : s = _("Tab"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_CLEAR : s = _("Clear"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_RETURN : s = _("Return"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_SHIFT : s = _("Shift"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_CONTROL : s = _("Control"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_MENU : s = _("Alt/Menu"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_PAUSE : s = _("Pause"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_CAPITAL : s = _("Caps Lock"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_KANA : s = _("Kana"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_JUNJA : s = _("Junja"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_FINAL : s = _("Final"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_ESCAPE : s = _("Escape"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_CONVERT : s = _("Convert"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NONCONVERT : s = _("Nonconvert"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_ACCEPT : s = _("Accept"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_MODECHANGE : s = _("Modechange"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_SPACE : s = _("Space"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_PRIOR : s = _("Page Up"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NEXT : s = _("Page Down"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_END : s = _("End"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_HOME : s = _("Home"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_LEFT : s = _("Left"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_UP : s = _("Up"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_RIGHT : s = _("Right"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_DOWN : s = _("Down"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_SELECT : s = _("Select"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_PRINT : s = _("Print"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_EXECUT : s = _("Exec"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_SNAPSHOT : s = _("Print Screen"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_INSERT : s = _("Insert"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_DELETE : s = _("Delete"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_HELP : s = _("Help"); break;
|
||||
case irr::KEY_KEY_0 : s = "0"; break;
|
||||
case irr::KEY_KEY_1 : s = "1"; break;
|
||||
case irr::KEY_KEY_2 : s = "2"; break;
|
||||
@ -185,26 +225,44 @@ irr::core::stringw Binding::getAsString() const
|
||||
case irr::KEY_KEY_X : s = "X"; break;
|
||||
case irr::KEY_KEY_Y : s = "Y"; break;
|
||||
case irr::KEY_KEY_Z : s = "Z"; break;
|
||||
case irr::KEY_LWIN : s = "Left Logo"; break;
|
||||
case irr::KEY_RWIN : s = "Right Logo"; break;
|
||||
case irr::KEY_APPS : s = "apps"; break;
|
||||
case irr::KEY_SLEEP : s = "sleep"; break;
|
||||
case irr::KEY_NUMPAD0 : s = "numpad 0"; break;
|
||||
case irr::KEY_NUMPAD1 : s = "numpad 1"; break;
|
||||
case irr::KEY_NUMPAD2 : s = "numpad 2"; break;
|
||||
case irr::KEY_NUMPAD3 : s = "numpad 3"; break;
|
||||
case irr::KEY_NUMPAD4 : s = "numpad 4"; break;
|
||||
case irr::KEY_NUMPAD5 : s = "numpad 5"; break;
|
||||
case irr::KEY_NUMPAD6 : s = "numpad 6"; break;
|
||||
case irr::KEY_NUMPAD7 : s = "numpad 7"; break;
|
||||
case irr::KEY_NUMPAD8 : s = "numpad 8"; break;
|
||||
case irr::KEY_NUMPAD9 : s = "numpad 9"; break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_LWIN : s = _("Left Logo"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_RWIN : s = _("Right Logo"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_APPS : s = _("Apps"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_SLEEP : s = _("Sleep"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD0 : s = _("Numpad 0"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD1 : s = _("Numpad 1"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD2 : s = _("Numpad 2"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD3 : s = _("Numpad 3"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD4 : s = _("Numpad 4"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD5 : s = _("Numpad 5"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD6 : s = _("Numpad 6"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD7 : s = _("Numpad 7"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD8 : s = _("Numpad 8"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMPAD9 : s = _("Numpad 9"); break;
|
||||
case irr::KEY_MULTIPLY : s = "*"; break;
|
||||
case irr::KEY_ADD : s = "+"; break;
|
||||
case irr::KEY_SEPARATOR : s = "separator"; break;
|
||||
case irr::KEY_SUBTRACT : s = "- (subtract)"; break;
|
||||
case irr::KEY_DECIMAL : s = "decimal"; break;
|
||||
case irr::KEY_DIVIDE : s = "/ (divide)"; break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_SEPARATOR : s = _("Separator"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_SUBTRACT : s = _("- (Subtract)"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_DECIMAL : s = _("Decimal"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_DIVIDE : s = _("/ (Divide)"); break;
|
||||
case irr::KEY_F1 : s = "F1"; break;
|
||||
case irr::KEY_F2 : s = "F2"; break;
|
||||
case irr::KEY_F3 : s = "F3"; break;
|
||||
@ -229,26 +287,42 @@ irr::core::stringw Binding::getAsString() const
|
||||
case irr::KEY_F22 : s = "F22"; break;
|
||||
case irr::KEY_F23 : s = "F23"; break;
|
||||
case irr::KEY_F24 : s = "F24"; break;
|
||||
case irr::KEY_NUMLOCK : s = "num lock"; break;
|
||||
case irr::KEY_SCROLL : s = "scroll lock"; break;
|
||||
case irr::KEY_LSHIFT : s = "left shift"; break;
|
||||
case irr::KEY_RSHIFT : s = "right shift"; break;
|
||||
case irr::KEY_LCONTROL : s = "left control"; break;
|
||||
case irr::KEY_RCONTROL : s = "right control"; break;
|
||||
case irr::KEY_LMENU : s = "left menu"; break;
|
||||
case irr::KEY_RMENU : s = "right menu"; break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_NUMLOCK : s = _("Num Lock"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_SCROLL : s = _("Scroll Lock"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_LSHIFT : s = _("Left Shift"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_RSHIFT : s = _("Right Shift"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_LCONTROL : s = _("Left Control"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_RCONTROL : s = _("Right Control"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_LMENU : s = _("Left Menu"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_RMENU : s = _("Right Menu"); break;
|
||||
case irr::KEY_PLUS : s = "+"; break;
|
||||
case irr::KEY_COMMA : s = ","; break;
|
||||
case irr::KEY_MINUS : s = "-"; break;
|
||||
case irr::KEY_PERIOD : s = "."; break;
|
||||
case irr::KEY_ATTN : s = "attn"; break;
|
||||
case irr::KEY_CRSEL : s = "crsel"; break;
|
||||
case irr::KEY_EXSEL : s = "exsel"; break;
|
||||
case irr::KEY_EREOF : s = "ereof"; break;
|
||||
case irr::KEY_PLAY : s = "play"; break;
|
||||
case irr::KEY_ZOOM : s = "zoom"; break;
|
||||
case irr::KEY_PA1 : s = "pa1"; break;
|
||||
case irr::KEY_OEM_CLEAR : s = "oem clear"; break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_ATTN : s = _("Attn"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_CRSEL : s = _("Crsel"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_EXSEL : s = _("Exsel"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_EREOF : s = _("Ereof"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_PLAY : s = _("Play"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_ZOOM : s = _("Zoom"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_PA1 : s = _("Pa1"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::KEY_OEM_CLEAR : s = _("Oem Clear"); break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -142,7 +142,7 @@ FileManager::FileManager()
|
||||
|
||||
m_file_system = irr::io::createFileSystem();
|
||||
|
||||
irr::io::path exe_path;
|
||||
std::string exe_path;
|
||||
|
||||
// Search for the root directory
|
||||
// =============================
|
||||
@ -151,8 +151,11 @@ FileManager::FileManager()
|
||||
// This is esp. useful for Visual Studio, since it's not necessary
|
||||
// to define the working directory when debugging, it works automatically.
|
||||
std::string root_dir;
|
||||
if(m_file_system->existFile(CommandLine::getExecName().c_str()))
|
||||
exe_path = m_file_system->getFileDir(CommandLine::getExecName().c_str());
|
||||
const std::string version = std::string("supertuxkart.") + STK_VERSION;
|
||||
if (fileExists(CommandLine::getExecName()))
|
||||
{
|
||||
exe_path = StringUtils::getPath(CommandLine::getExecName());
|
||||
}
|
||||
if(exe_path.size()==0 || exe_path[exe_path.size()-1]!='/')
|
||||
exe_path += "/";
|
||||
if ( getenv ( "SUPERTUXKART_DATADIR" ) != NULL )
|
||||
@ -160,19 +163,19 @@ FileManager::FileManager()
|
||||
#ifdef __APPLE__
|
||||
else if( macSetBundlePathIfRelevant( root_dir ) ) { root_dir = root_dir + "data/"; }
|
||||
#endif
|
||||
else if(m_file_system->existFile("data/stk_config.xml"))
|
||||
else if(fileExists("data/", version))
|
||||
root_dir = "data/" ;
|
||||
else if(m_file_system->existFile("../data/stk_config.xml"))
|
||||
else if(fileExists("../data/", version))
|
||||
root_dir = "../data/" ;
|
||||
else if(m_file_system->existFile("../../data/stk_config.xml"))
|
||||
else if(fileExists("../../data/", version))
|
||||
root_dir = "../../data/" ;
|
||||
// Test for old style build environment, with executable in root of stk
|
||||
else if(m_file_system->existFile(exe_path+"data/stk_config.xml"))
|
||||
else if(fileExists(exe_path+"data/"+version))
|
||||
root_dir = (exe_path+"data/").c_str();
|
||||
// Check for windows cmake style: bld/Debug/bin/supertuxkart.exe
|
||||
else if (m_file_system->existFile(exe_path + "../../../data/stk_config.xml"))
|
||||
root_dir = (exe_path + "../../../data/").c_str();
|
||||
else if (m_file_system->existFile(exe_path + "../data/stk_config.xml"))
|
||||
else if (fileExists(exe_path + "../../../data/"+version))
|
||||
root_dir = exe_path + "../../../data/";
|
||||
else if (fileExists(exe_path + "../data/"+version))
|
||||
{
|
||||
root_dir = exe_path.c_str();
|
||||
root_dir += "../data/";
|
||||
@ -181,14 +184,22 @@ FileManager::FileManager()
|
||||
{
|
||||
#ifdef SUPERTUXKART_DATADIR
|
||||
root_dir = SUPERTUXKART_DATADIR"/data/";
|
||||
if(root_dir.size()==0 || root_dir[root_dir.size()-1]!='/')
|
||||
root_dir+='/';
|
||||
|
||||
#else
|
||||
root_dir = "/usr/local/share/games/supertuxkart/";
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!m_file_system->existFile((root_dir + version).c_str()))
|
||||
{
|
||||
Log::error("FileManager", "Could not file '%s'in any "
|
||||
"standard location (esp. ../data).", version.c_str());
|
||||
Log::error("FileManager",
|
||||
"Last location checked '%s'.", root_dir.c_str());
|
||||
Log::fatal("FileManager",
|
||||
"Set $SUPERTUXKART_DATADIR to point to the data directory.");
|
||||
// fatal will exit the application
|
||||
}
|
||||
|
||||
addRootDirs(root_dir);
|
||||
if( fileExists(root_dir+"../../stk-assets"))
|
||||
addRootDirs(root_dir+"../../stk-assets");
|
||||
|
@ -134,6 +134,14 @@ public:
|
||||
std::string searchTexture(const std::string& fname) const;
|
||||
std::string getUserConfigFile(const std::string& fname) const;
|
||||
bool fileExists(const std::string& path) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Convenience function to save some typing in the
|
||||
* file manager constructor. */
|
||||
bool fileExists(const char *prefix, const std::string& path) const
|
||||
{
|
||||
return fileExists(std::string(prefix) + path);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void listFiles (std::set<std::string>& result,
|
||||
const std::string& dir,
|
||||
bool make_full_path=false) const;
|
||||
|
@ -108,11 +108,8 @@ ExplosionAnimation::ExplosionAnimation(AbstractKart *kart,
|
||||
// Set invulnerable time, and graphical effects
|
||||
float t = m_kart->getCharacteristic()->getExplosionInvulnerabilityTime();
|
||||
m_kart->setInvulnerableTime(t);
|
||||
if ( UserConfigParams::m_graphical_effects )
|
||||
{
|
||||
m_kart->showStarEffect(t);
|
||||
}
|
||||
|
||||
m_kart->showStarEffect(t);
|
||||
|
||||
m_kart->getAttachment()->clear();
|
||||
|
||||
}; // ExplosionAnimation
|
||||
|
@ -1124,11 +1124,8 @@ void Kart::update(float dt)
|
||||
m_max_speed->getCurrentMaxSpeed());
|
||||
#endif
|
||||
|
||||
if ( UserConfigParams::m_graphical_effects )
|
||||
{
|
||||
// update star effect (call will do nothing if stars are not activated)
|
||||
m_stars_effect->update(dt);
|
||||
}
|
||||
// update star effect (call will do nothing if stars are not activated)
|
||||
m_stars_effect->update(dt);
|
||||
|
||||
if(m_squash_time>=0)
|
||||
{
|
||||
@ -1915,29 +1912,6 @@ void Kart::crashed(const Material *m, const Vec3 &normal)
|
||||
push[1] = 0.1f;
|
||||
m_body->applyCentralImpulse( -4000.0f*push );
|
||||
m_bounce_back_time = 2.0f;
|
||||
|
||||
core::stringw msg = _("You need more points\n"
|
||||
"to enter this challenge!\n"
|
||||
"Check the minimap for\n"
|
||||
"available challenges.");
|
||||
std::vector<core::stringw> parts =
|
||||
StringUtils::split(msg, '\n', false);
|
||||
|
||||
// For now, until we have scripting, special-case
|
||||
// the overworld... (TODO)
|
||||
if (dynamic_cast<OverWorld*>(World::getWorld()) != NULL)
|
||||
{
|
||||
SFXManager::get()->quickSound("forcefield");
|
||||
World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
|
||||
for (unsigned int n = 0; n < parts.size(); n++)
|
||||
{
|
||||
World::getWorld()->getRaceGUI()
|
||||
->addMessage(parts[n], NULL, 4.0f,
|
||||
video::SColor(255, 255,255,255),
|
||||
true, true);
|
||||
} // for n<parts.size()
|
||||
} // if world exist
|
||||
} // if m_bounce_back_time <= 0.2f
|
||||
} // if (m->getCollisionReaction() == Material::PUSH_BACK)
|
||||
} // if(m && m->getCollisionReaction() != Material::NORMAL &&
|
||||
@ -2635,9 +2609,8 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
// the normal maximum speed of the kart.
|
||||
if(nitro_frac>1.0f) nitro_frac = 1.0f;
|
||||
}
|
||||
// speed * dt is the new size of the box in which particles start
|
||||
m_kart_gfx->updateNitroGraphics(nitro_frac, getSpeed()*dt);
|
||||
|
||||
m_kart_gfx->updateNitroGraphics(nitro_frac);
|
||||
|
||||
// Handle leaning of karts
|
||||
// -----------------------
|
||||
// Note that we compare with maximum speed of the kart, not
|
||||
|
@ -350,11 +350,10 @@ void KartGFX::update(float dt)
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Updates nitro dependent particle effects (and box sizes).
|
||||
/** Updates nitro dependent particle effects.
|
||||
* \param nitro_frac Nitro fraction/
|
||||
* \param new_size New size of the box in which new particles are emitted.
|
||||
*/
|
||||
void KartGFX::updateNitroGraphics(float nitro_frac, float new_size)
|
||||
void KartGFX::updateNitroGraphics(float nitro_frac)
|
||||
{
|
||||
// Upate particle effects (creation rate, and emitter size
|
||||
// depending on speed)
|
||||
@ -375,11 +374,6 @@ void KartGFX::updateNitroGraphics(float nitro_frac, float new_size)
|
||||
setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, 0);
|
||||
m_nitro_light->setVisible(false);
|
||||
}
|
||||
resizeBox(KartGFX::KGFX_NITRO1, new_size);
|
||||
resizeBox(KartGFX::KGFX_NITRO2, new_size);
|
||||
resizeBox(KartGFX::KGFX_NITROSMOKE1, new_size);
|
||||
resizeBox(KartGFX::KGFX_NITROSMOKE2, new_size);
|
||||
resizeBox(KartGFX::KGFX_ZIPPER, new_size);
|
||||
|
||||
} // updateGraphics
|
||||
|
||||
|
@ -99,7 +99,7 @@ public:
|
||||
void setCreationRateRelative(const KartGFXType type, float f);
|
||||
void updateTerrain(const ParticleKind *pk);
|
||||
void update(float dt);
|
||||
void updateNitroGraphics(float f, float new_size);
|
||||
void updateNitroGraphics(float f);
|
||||
void updateSkidLight(unsigned int level);
|
||||
|
||||
}; // KartWGFX
|
||||
|
@ -1,71 +0,0 @@
|
||||
diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp
|
||||
index de14bbe..47bbee9 100644
|
||||
--- a/src/karts/kart.cpp
|
||||
+++ b/src/karts/kart.cpp
|
||||
@@ -2476,11 +2476,12 @@ void Kart::kartIsInRestNow()
|
||||
for(int i=0; i<m_vehicle->getNumWheels(); i++)
|
||||
{
|
||||
const btWheelInfo &wi = m_vehicle->getWheelInfo(i);
|
||||
- f += wi.m_chassisConnectionPointCS.getY()
|
||||
- - wi.m_raycastInfo.m_suspensionLength - wi.m_wheelsRadius;
|
||||
+ f += wi.m_raycastInfo.m_suspensionLength;
|
||||
}
|
||||
+ m_terrain_info->update(getTrans());
|
||||
m_graphical_y_offset = f/m_vehicle->getNumWheels()
|
||||
+ getKartProperties()->getGraphicalYOffset();
|
||||
+ m_graphical_y_offset = m_kart_model->getLowestPoint() - (getXYZ().getY() - m_terrain_info->getHoT());
|
||||
|
||||
m_kart_model->setDefaultSuspension();
|
||||
} // kartIsInRestNow
|
||||
@@ -2595,11 +2596,6 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
} // for i<num_wheels
|
||||
const btWheelInfo &w = getVehicle()->getWheelInfo(0);
|
||||
|
||||
- // Determine the shadow position from the terrain Y position. This
|
||||
- // leaves the shadow on the ground even if the kart is jumping because
|
||||
- // of skidding (shadows are disabled when wheel are not on the track).
|
||||
- m_shadow->update(m_terrain_info->getHoT() - getXYZ().getY()
|
||||
- -m_skidding->getGraphicalJumpOffset());
|
||||
// Recompute the default average suspension length, see
|
||||
// kartIsInRestNow() how to get from y-offset to susp. len.
|
||||
float av_sus_len = -m_graphical_y_offset
|
||||
@@ -2628,6 +2624,9 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
+ lean_height
|
||||
- m_kart_model->getLowestPoint());
|
||||
|
||||
+ center_shift.setY(m_skidding->getGraphicalJumpOffset()
|
||||
+ + lean_height
|
||||
+ +m_graphical_y_offset);
|
||||
center_shift = getTrans().getBasis() * center_shift;
|
||||
|
||||
Moveable::updateGraphics(dt, center_shift,
|
||||
@@ -2637,6 +2636,14 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
// how much the wheels need to rotate.
|
||||
m_kart_model->update(dt, m_speed*dt, getSteerPercent(), m_speed);
|
||||
|
||||
+ // Determine the shadow position from the terrain Y position. This
|
||||
+ // leaves the shadow on the ground even if the kart is jumping because
|
||||
+ // of skidding (shadows are disabled when wheel are not on the track).
|
||||
+ m_shadow->update( m_terrain_info->getHoT() - getXYZ().getY()
|
||||
+ - m_skidding->getGraphicalJumpOffset()
|
||||
+ - m_graphical_y_offset
|
||||
+ - m_kart_model->getLowestPoint());
|
||||
+
|
||||
#ifdef XX
|
||||
// cheap wheelie effect
|
||||
if (m_controls.m_nitro)
|
||||
diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp
|
||||
index 65879d3..36b03b7 100644
|
||||
--- a/src/karts/kart_model.cpp
|
||||
+++ b/src/karts/kart_model.cpp
|
||||
@@ -813,7 +813,9 @@ void KartModel::update(float dt, float distance, float steer, float speed)
|
||||
core::vector3df pos = m_wheel_graphics_position[i].toIrrVector();
|
||||
|
||||
const btWheelInfo &wi = m_kart->getVehicle()->getWheelInfo(i);
|
||||
- pos.Y = -wi.m_raycastInfo.m_suspensionLength + m_wheel_graphics_radius[i] + getLowestPoint();
|
||||
+ pos.Y += m_default_physics_suspension[i]
|
||||
+ - wi.m_raycastInfo.m_suspensionLength
|
||||
+ - getLowestPoint();
|
||||
m_wheel_node[i]->setPosition(pos);
|
||||
|
||||
// Now calculate the new rotation: (old + change) mod 360
|
@ -1078,7 +1078,7 @@ int handleCmdLine()
|
||||
void initUserConfig()
|
||||
{
|
||||
file_manager = new FileManager();
|
||||
user_config = new UserConfig(); // needs file_manager
|
||||
user_config = new UserConfig(); // needs file_manager
|
||||
user_config->loadConfig();
|
||||
// Some parts of the file manager needs user config (paths for models
|
||||
// depend on artist debug flag). So init the rest of the file manager
|
||||
|
@ -77,13 +77,8 @@ void CutsceneWorld::init()
|
||||
|
||||
m_duration = -1.0f;
|
||||
|
||||
//const btTransform &s = getTrack()->getStartTransform(0);
|
||||
//const Vec3 &v = s.getOrigin();
|
||||
Camera* stk_cam = Camera::createCamera(NULL);
|
||||
m_camera = stk_cam->getCameraSceneNode();
|
||||
//m_camera = irr_driver->getSceneManager()
|
||||
// ->addCameraSceneNode(NULL, core::vector3df(0.0f, 0.0f, 0.0f),
|
||||
// core::vector3df(0.0f, 0.0f, 0.0f));
|
||||
m_camera->setFOV(0.61f);
|
||||
m_camera->bindTargetAndRotation(true); // no "look-at"
|
||||
|
||||
|
@ -53,6 +53,7 @@ FollowTheLeaderRace::FollowTheLeaderRace() : LinearWorld()
|
||||
*/
|
||||
void FollowTheLeaderRace::init()
|
||||
{
|
||||
m_last_eliminated_time = 0;
|
||||
LinearWorld::init();
|
||||
// WorldWithRank determines the score based on getNumKarts(), but since
|
||||
// we ignore the leader, the points need to be based on number of karts -1
|
||||
@ -100,11 +101,23 @@ int FollowTheLeaderRace::getScoreForPosition(int p)
|
||||
return m_score_for_position[p - 2];
|
||||
} // getScoreForPosition
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const btTransform &FollowTheLeaderRace::getStartTransform(int index)
|
||||
{
|
||||
if (index == 0) // Leader start position
|
||||
return m_track->getStartTransform(index);
|
||||
|
||||
// Otherwise the karts will start at the rear starting positions
|
||||
int start_index = stk_config->m_max_karts
|
||||
- race_manager->getNumberOfKarts() + index;
|
||||
return m_track->getStartTransform(start_index);
|
||||
} // getStartTransform
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the original time at which the countdown timer started. This is
|
||||
* used by the race_gui to display the music credits in FTL mode correctly.
|
||||
*/
|
||||
float FollowTheLeaderRace::getClockStartTime()
|
||||
float FollowTheLeaderRace::getClockStartTime() const
|
||||
{
|
||||
return m_leader_intervals[0];
|
||||
} // getClockStartTime
|
||||
@ -114,6 +127,7 @@ float FollowTheLeaderRace::getClockStartTime()
|
||||
*/
|
||||
void FollowTheLeaderRace::countdownReachedZero()
|
||||
{
|
||||
m_last_eliminated_time += m_leader_intervals[0];
|
||||
if(m_leader_intervals.size()>1)
|
||||
m_leader_intervals.erase(m_leader_intervals.begin());
|
||||
WorldStatus::setTime(m_leader_intervals[0]);
|
||||
@ -162,7 +176,7 @@ void FollowTheLeaderRace::countdownReachedZero()
|
||||
updateRacePosition();
|
||||
}
|
||||
// Time doesn't make any sense in FTL (and it is not displayed)
|
||||
kart->finishedRace(-1.0f);
|
||||
kart->finishedRace(m_last_eliminated_time);
|
||||
|
||||
// Move any camera for this kart to the leader, facing backwards,
|
||||
// so that the eliminated player has something to watch.
|
||||
@ -229,34 +243,31 @@ void FollowTheLeaderRace::terminateRace()
|
||||
// position 1, the leader now position 2, but the point distribution
|
||||
// depends on the 'first' (non-leader) kart to be on position 2.
|
||||
// That situation can also occur during the delay after eliminating
|
||||
// the last kart before the race result is shown.
|
||||
// To avoid this problem, adjust the position of any kart that is
|
||||
// ahead of the leader.
|
||||
// the last kart before the race result is shown (when the leader
|
||||
// is overtaken during that time). To avoid this problem, adjust the
|
||||
// position of any kart that is ahead of the leader.
|
||||
beginSetKartPositions();
|
||||
for (unsigned int i = 0; i < getNumKarts(); i++)
|
||||
{
|
||||
if (!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
|
||||
if (!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated() &&
|
||||
m_karts[i]->getPosition() < pos_leader)
|
||||
{
|
||||
if (m_karts[i]->getPosition() < pos_leader)
|
||||
{
|
||||
setKartPosition(i, m_karts[i]->getPosition() + 1);
|
||||
}
|
||||
// Update the estimated finishing time for all karts that haven't
|
||||
// finished yet.
|
||||
m_karts[i]->finishedRace(0.0f);
|
||||
setKartPosition(i, m_karts[i]->getPosition() + 1);
|
||||
}
|
||||
} // i < number of karts
|
||||
setKartPosition(/*kart id*/0, /*position*/1);
|
||||
endSetKartPositions();
|
||||
|
||||
// Mark all still racing karts to be finished.
|
||||
for (unsigned int n = 0; n < m_karts.size(); n++)
|
||||
for (int i = m_karts.size(); i>0; i--)
|
||||
{
|
||||
if (!m_karts[n]->isEliminated() &&
|
||||
!m_karts[n]->hasFinishedRace())
|
||||
{
|
||||
m_karts[n]->finishedRace(getTime());
|
||||
}
|
||||
AbstractKart *kart = getKartAtPosition(i);
|
||||
if (kart->isEliminated() || kart->hasFinishedRace())
|
||||
continue;
|
||||
m_last_eliminated_time += m_leader_intervals[0];
|
||||
if (m_leader_intervals.size() > 1)
|
||||
m_leader_intervals.erase(m_leader_intervals.begin());
|
||||
kart->finishedRace(m_last_eliminated_time);
|
||||
}
|
||||
|
||||
|
||||
|
@ -33,6 +33,9 @@ private:
|
||||
/** A timer used before terminating the race. */
|
||||
float m_is_over_delay;
|
||||
|
||||
/** Time the last kart was eliminated. It is used to assign each
|
||||
* kart a 'finish' time (i.e. how long they lasted). */
|
||||
float m_last_eliminated_time;
|
||||
public:
|
||||
|
||||
FollowTheLeaderRace();
|
||||
@ -45,14 +48,19 @@ public:
|
||||
// overriding World methods
|
||||
virtual void reset() OVERRIDE;
|
||||
virtual const std::string& getIdent() const OVERRIDE;
|
||||
virtual float getClockStartTime();
|
||||
virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
|
||||
virtual const btTransform &getStartTransform(int index);
|
||||
virtual float getClockStartTime() const;
|
||||
virtual void getKartsDisplayInfo(
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
|
||||
virtual void init() OVERRIDE;
|
||||
virtual void terminateRace() OVERRIDE;
|
||||
virtual bool isRaceOver() OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this type of race has laps. */
|
||||
virtual bool raceHasLaps() OVERRIDE { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if faster music should be used at the end. */
|
||||
virtual bool useFastMusicNearEnd() const OVERRIDE { return false; }
|
||||
}; // FollowTheLeader
|
||||
|
||||
|
||||
|
@ -160,6 +160,37 @@ void OverWorld::update(float dt)
|
||||
}
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Finds the starting position which is closest to the kart.
|
||||
* \param kart The kart for which a rescue position needs to be determined.
|
||||
*/
|
||||
unsigned int OverWorld::getRescuePositionIndex(AbstractKart *kart)
|
||||
{
|
||||
// find closest point to drop kart on
|
||||
const int start_spots_amount = getNumberOfRescuePositions();
|
||||
assert(start_spots_amount > 0);
|
||||
|
||||
int closest_id = -1;
|
||||
float closest_distance = 999999999.0f;
|
||||
|
||||
for (int n=0; n<start_spots_amount; n++)
|
||||
{
|
||||
const btTransform &s = getStartTransform(n);
|
||||
const Vec3 &v = s.getOrigin();
|
||||
|
||||
float abs_distance = (v - kart->getXYZ()).length();
|
||||
|
||||
if (abs_distance < closest_distance)
|
||||
{
|
||||
closest_distance = abs_distance;
|
||||
closest_id = n;
|
||||
}
|
||||
}
|
||||
|
||||
assert(closest_id != -1);
|
||||
return closest_id;
|
||||
} // getRescuePositionIndex
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function is not used in the overworld race gui.
|
||||
*/
|
||||
@ -193,10 +224,6 @@ void OverWorld::onFirePressed(Controller* who)
|
||||
|
||||
for (unsigned int n=0; n<challenges.size(); n++)
|
||||
{
|
||||
if ( challenges[n].isForceFieldSet() &&
|
||||
challenges[n].getForceField().m_is_locked )
|
||||
continue;
|
||||
|
||||
if ( (kart_xyz - Vec3(challenges[n].m_position)).length2_2d()
|
||||
< CHALLENGE_DISTANCE_SQUARED)
|
||||
{
|
||||
@ -207,9 +234,22 @@ void OverWorld::onFirePressed(Controller* who)
|
||||
}
|
||||
else
|
||||
{
|
||||
race_manager->setKartLastPositionOnOverworld(kart_xyz);
|
||||
new SelectChallengeDialog(0.8f, 0.8f,
|
||||
challenges[n].m_challenge_id);
|
||||
const ChallengeData* challenge = unlock_manager->getChallengeData(challenges[n].m_challenge_id);
|
||||
if (challenge == NULL)
|
||||
{
|
||||
Log::error("track", "Cannot find challenge named '%s'\n",
|
||||
challenges[n].m_challenge_id.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
const unsigned int val = challenge->getNumTrophies();
|
||||
bool unlocked = (PlayerManager::getCurrentPlayer()->getPoints() >= val);
|
||||
if (unlocked)
|
||||
{
|
||||
race_manager->setKartLastPositionOnOverworld(kart_xyz);
|
||||
new SelectChallengeDialog(0.8f, 0.8f,
|
||||
challenges[n].m_challenge_id);
|
||||
}
|
||||
}
|
||||
} // end if
|
||||
} // end for
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
static void enterOverWorld();
|
||||
|
||||
virtual void update(float delta) OVERRIDE;
|
||||
unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE;
|
||||
virtual void getKartsDisplayInfo(
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -108,7 +108,7 @@ AbstractKart *ProfileWorld::createKart(const std::string &kart_ident, int index,
|
||||
RaceManager::KartType type,
|
||||
PerPlayerDifficulty difficulty)
|
||||
{
|
||||
btTransform init_pos = m_track->getStartTransform(index);
|
||||
btTransform init_pos = getStartTransform(index);
|
||||
|
||||
Kart *new_kart = new KartWithStats(kart_ident,
|
||||
/*world kart id*/ index,
|
||||
|
@ -316,88 +316,6 @@ void SoccerWorld::getKartsDisplayInfo(
|
||||
*/
|
||||
} // getKartsDisplayInfo
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Moves a kart to its rescue position.
|
||||
* \param kart The kart that was rescued.
|
||||
*/
|
||||
void SoccerWorld::moveKartAfterRescue(AbstractKart* kart)
|
||||
{
|
||||
// find closest point to drop kart on
|
||||
World *world = World::getWorld();
|
||||
const int start_spots_amount = world->getTrack()->getNumberOfStartPositions();
|
||||
assert(start_spots_amount > 0);
|
||||
|
||||
float largest_accumulated_distance_found = -1;
|
||||
int furthest_id_found = -1;
|
||||
|
||||
const float kart_x = kart->getXYZ().getX();
|
||||
const float kart_z = kart->getXYZ().getZ();
|
||||
|
||||
for(int n=0; n<start_spots_amount; n++)
|
||||
{
|
||||
// no need for the overhead to compute exact distance with sqrt(),
|
||||
// so using the 'manhattan' heuristic which will do fine enough.
|
||||
const btTransform &s = world->getTrack()->getStartTransform(n);
|
||||
const Vec3 &v=s.getOrigin();
|
||||
float accumulatedDistance = .0f;
|
||||
bool spawnPointClear = true;
|
||||
|
||||
for(unsigned int k=0; k<getCurrentNumKarts(); k++)
|
||||
{
|
||||
const AbstractKart *currentKart = World::getWorld()->getKart(k);
|
||||
const float currentKart_x = currentKart->getXYZ().getX();
|
||||
const float currentKartk_z = currentKart->getXYZ().getZ();
|
||||
|
||||
if(kart_x!=currentKart_x && kart_z !=currentKartk_z)
|
||||
{
|
||||
float absDistance = fabs(currentKart_x - v.getX()) +
|
||||
fabs(currentKartk_z - v.getZ());
|
||||
if(absDistance < CLEAR_SPAWN_RANGE)
|
||||
{
|
||||
spawnPointClear = false;
|
||||
break;
|
||||
}
|
||||
accumulatedDistance += absDistance;
|
||||
}
|
||||
}
|
||||
|
||||
if(largest_accumulated_distance_found < accumulatedDistance && spawnPointClear)
|
||||
{
|
||||
furthest_id_found = n;
|
||||
largest_accumulated_distance_found = accumulatedDistance;
|
||||
}
|
||||
}
|
||||
|
||||
assert(furthest_id_found != -1);
|
||||
const btTransform &s = world->getTrack()->getStartTransform(furthest_id_found);
|
||||
const Vec3 &xyz = s.getOrigin();
|
||||
kart->setXYZ(xyz);
|
||||
kart->setRotation(s.getRotation());
|
||||
|
||||
//position kart from same height as in World::resetAllKarts
|
||||
btTransform pos;
|
||||
pos.setOrigin(kart->getXYZ()+btVector3(0, 0.5f*kart->getKartHeight(), 0.0f));
|
||||
pos.setRotation( btQuaternion(btVector3(0.0f, 1.0f, 0.0f), 0 /* angle */) );
|
||||
|
||||
kart->getBody()->setCenterOfMassTransform(pos);
|
||||
|
||||
//project kart to surface of track
|
||||
bool kart_over_ground = m_track->findGround(kart);
|
||||
|
||||
if (kart_over_ground)
|
||||
{
|
||||
//add vertical offset so that the kart starts off above the track
|
||||
float vertical_offset = kart->getCharacteristic()->getRescueVertOffset() *
|
||||
kart->getKartHeight();
|
||||
kart->getBody()->translate(btVector3(0, vertical_offset, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::warn("[SoccerWorld]", " Invalid position after rescue for kart %s on track %s.",
|
||||
kart->getIdent().c_str(), m_track->getIdent().c_str());
|
||||
}
|
||||
} // moveKartAfterRescue
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Set position and team for the karts */
|
||||
void SoccerWorld::initKartList()
|
||||
@ -482,7 +400,7 @@ AbstractKart *SoccerWorld::createKart(const std::string &kart_ident, int index,
|
||||
if(index % 2 != 0) posIndex += 1;
|
||||
}
|
||||
|
||||
btTransform init_pos = m_track->getStartTransform(posIndex);
|
||||
btTransform init_pos = getStartTransform(posIndex);
|
||||
|
||||
AbstractKart *new_kart = new Kart(kart_ident, index, position, init_pos,
|
||||
difficulty);
|
||||
|
@ -76,8 +76,7 @@ public:
|
||||
virtual void getKartsDisplayInfo(
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info);
|
||||
int getScore(unsigned int i);
|
||||
virtual bool raceHasLaps(){ return false; }
|
||||
virtual void moveKartAfterRescue(AbstractKart* kart);
|
||||
virtual bool raceHasLaps() { return false; }
|
||||
|
||||
virtual const std::string& getIdent() const;
|
||||
|
||||
|
@ -477,53 +477,3 @@ void ThreeStrikesBattle::getKartsDisplayInfo(
|
||||
}
|
||||
} // getKartsDisplayInfo
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Determines the rescue position for a kart. The rescue position is the
|
||||
* start position which is has the biggest accumulated distance to all other
|
||||
* karts, and which has no other kart very close. The latter avoids dropping
|
||||
* a kart on top of another kart.
|
||||
* \param kart The kart that is going to be rescued.
|
||||
* \returns The index of the start position to which the rescued kart
|
||||
* should be moved to.
|
||||
*/
|
||||
|
||||
unsigned int ThreeStrikesBattle::getRescuePositionIndex(AbstractKart *kart)
|
||||
{
|
||||
const int start_spots_amount = getTrack()->getNumberOfStartPositions();
|
||||
assert(start_spots_amount > 0);
|
||||
|
||||
float largest_accumulated_distance_found = -1;
|
||||
int furthest_id_found = -1;
|
||||
|
||||
for(int n=0; n<start_spots_amount; n++)
|
||||
{
|
||||
const btTransform &s = getTrack()->getStartTransform(n);
|
||||
const Vec3 &v=s.getOrigin();
|
||||
float accumulated_distance = .0f;
|
||||
bool spawn_point_clear = true;
|
||||
|
||||
for(unsigned int k=0; k<getCurrentNumKarts(); k++)
|
||||
{
|
||||
if(kart->getWorldKartId()==k) continue;
|
||||
float abs_distance2 = (getKart(k)->getXYZ()-v).length2_2d();
|
||||
const float CLEAR_SPAWN_RANGE2 = 5*5;
|
||||
if( abs_distance2 < CLEAR_SPAWN_RANGE2)
|
||||
{
|
||||
spawn_point_clear = false;
|
||||
break;
|
||||
}
|
||||
accumulated_distance += sqrt(abs_distance2);
|
||||
}
|
||||
|
||||
if(accumulated_distance > largest_accumulated_distance_found &&
|
||||
spawn_point_clear)
|
||||
{
|
||||
furthest_id_found = n;
|
||||
largest_accumulated_distance_found = accumulated_distance;
|
||||
}
|
||||
}
|
||||
|
||||
assert(furthest_id_found != -1);
|
||||
return furthest_id_found;
|
||||
} // getRescuePositionIndex
|
||||
|
||||
|
@ -97,7 +97,6 @@ public:
|
||||
virtual void getKartsDisplayInfo(
|
||||
std::vector<RaceGUIBase::KartIconDisplayInfo> *info);
|
||||
virtual bool raceHasLaps(){ return false; }
|
||||
virtual unsigned int getRescuePositionIndex(AbstractKart *kart);
|
||||
|
||||
virtual const std::string& getIdent() const;
|
||||
|
||||
|
@ -26,3 +26,29 @@ TutorialWorld::TutorialWorld()
|
||||
{
|
||||
m_stop_music_when_dialog_open = false;
|
||||
} // TutorialWorld
|
||||
|
||||
unsigned int TutorialWorld::getRescuePositionIndex(AbstractKart *kart)
|
||||
{
|
||||
const int start_spots_amount = getTrack()->getNumberOfStartPositions();
|
||||
assert(start_spots_amount > 0);
|
||||
|
||||
float closest_distance = 999999.0f;
|
||||
int closest_id_found = 0;
|
||||
|
||||
Vec3 kart_pos = kart->getFrontXYZ();
|
||||
|
||||
for (int n = 0; n<start_spots_amount; n++)
|
||||
{
|
||||
const btTransform &s = getStartTransform(n);
|
||||
const Vec3 &v = s.getOrigin();
|
||||
float distance = (v - kart_pos).length2_2d();
|
||||
|
||||
if (n == 0 || distance < closest_distance)
|
||||
{
|
||||
closest_id_found = n;
|
||||
closest_distance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
return closest_id_found;
|
||||
}
|
||||
|
@ -35,12 +35,7 @@ public:
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Determines the rescue position index of the specified kart. */
|
||||
virtual unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE
|
||||
{
|
||||
// Don't use LinearWorld's function, but WorldWithRank, since the
|
||||
// latter is based on rescuing to start positions
|
||||
return WorldWithRank::getRescuePositionIndex(kart);
|
||||
}
|
||||
virtual unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the bullet transformation for the specified rescue index. */
|
||||
virtual btTransform getRescueTransform(unsigned int index) const OVERRIDE
|
||||
@ -50,6 +45,8 @@ public:
|
||||
return WorldWithRank::getRescueTransform(index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}; // class TutorialWorld
|
||||
|
||||
#endif
|
||||
|
@ -209,8 +209,6 @@ void World::init()
|
||||
m_weather = new Weather(m_track->getWeatherLightning(),
|
||||
m_track->getWeatherSound());
|
||||
}
|
||||
|
||||
m_script_engine->compileLoadedScripts();
|
||||
} // init
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -303,9 +301,9 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
||||
PerPlayerDifficulty difficulty)
|
||||
{
|
||||
int position = index+1;
|
||||
btTransform init_pos = m_track->getStartTransform(index);
|
||||
btTransform init_pos = getStartTransform(index);
|
||||
AbstractKart *new_kart = new Kart(kart_ident, index, position, init_pos,
|
||||
difficulty);
|
||||
difficulty);
|
||||
new_kart->init(race_manager->getKartType(index));
|
||||
Controller *controller = NULL;
|
||||
switch(kart_type)
|
||||
@ -335,6 +333,14 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
||||
return new_kart;
|
||||
} // createKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the start coordinates for a kart with a given index.
|
||||
* \param index Index of kart ranging from 0 to kart_num-1. */
|
||||
const btTransform &World::getStartTransform(int index)
|
||||
{
|
||||
return m_track->getStartTransform(index);
|
||||
} // getStartTransform
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Creates an AI controller for the kart.
|
||||
* \param kart The kart to be controlled by an AI.
|
||||
|
@ -231,7 +231,7 @@ public:
|
||||
/** Returns the bullet transformation for the specified rescue index. */
|
||||
virtual btTransform getRescueTransform(unsigned int index) const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
void moveKartAfterRescue(AbstractKart* kart);
|
||||
virtual void moveKartAfterRescue(AbstractKart* kart);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when it is needed to know whether this kind of race involves
|
||||
* counting laps. */
|
||||
@ -294,6 +294,7 @@ public:
|
||||
PhysicalObject *object);
|
||||
AbstractKart* getPlayerKart(unsigned int player) const;
|
||||
AbstractKart* getLocalPlayerKart(unsigned int n) const;
|
||||
virtual const btTransform &getStartTransform(int index);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the race gui. */
|
||||
RaceGUIBase *getRaceGUI() const { return m_race_gui;}
|
||||
|
@ -134,35 +134,54 @@ unsigned int WorldWithRank::getNumberOfRescuePositions() const
|
||||
return getTrack()->getNumberOfStartPositions();
|
||||
} // getNumberOfRescuePositions
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Finds the starting position which is closest to the kart.
|
||||
* \param kart The kart for which a rescue position needs to be determined.
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Determines the rescue position for a kart. The rescue position is the
|
||||
* start position which is has the biggest accumulated distance to all other
|
||||
* karts, and which has no other kart very close. The latter avoids dropping
|
||||
* a kart on top of another kart. This is the method used
|
||||
* \param kart The kart that is going to be rescued.
|
||||
* \returns The index of the start position to which the rescued kart
|
||||
* should be moved to.
|
||||
*/
|
||||
|
||||
unsigned int WorldWithRank::getRescuePositionIndex(AbstractKart *kart)
|
||||
{
|
||||
// find closest point to drop kart on
|
||||
const int start_spots_amount = getNumberOfRescuePositions();
|
||||
const int start_spots_amount = getTrack()->getNumberOfStartPositions();
|
||||
assert(start_spots_amount > 0);
|
||||
|
||||
int closest_id = -1;
|
||||
float closest_distance = 999999999.0f;
|
||||
float largest_accumulated_distance_found = -1;
|
||||
int furthest_id_found = -1;
|
||||
|
||||
for (int n=0; n<start_spots_amount; n++)
|
||||
for(int n=0; n<start_spots_amount; n++)
|
||||
{
|
||||
const btTransform &s = getTrack()->getStartTransform(n);
|
||||
const Vec3 &v = s.getOrigin();
|
||||
const btTransform &s = getStartTransform(n);
|
||||
const Vec3 &v=s.getOrigin();
|
||||
float accumulated_distance = .0f;
|
||||
bool spawn_point_clear = true;
|
||||
|
||||
float abs_distance = (v - kart->getXYZ()).length();
|
||||
|
||||
if (abs_distance < closest_distance)
|
||||
for(unsigned int k=0; k<getCurrentNumKarts(); k++)
|
||||
{
|
||||
closest_distance = abs_distance;
|
||||
closest_id = n;
|
||||
if(kart->getWorldKartId()==k) continue;
|
||||
float abs_distance2 = (getKart(k)->getXYZ()-v).length2_2d();
|
||||
const float CLEAR_SPAWN_RANGE2 = 5*5;
|
||||
if( abs_distance2 < CLEAR_SPAWN_RANGE2)
|
||||
{
|
||||
spawn_point_clear = false;
|
||||
break;
|
||||
}
|
||||
accumulated_distance += sqrt(abs_distance2);
|
||||
}
|
||||
|
||||
if(accumulated_distance > largest_accumulated_distance_found &&
|
||||
spawn_point_clear)
|
||||
{
|
||||
furthest_id_found = n;
|
||||
largest_accumulated_distance_found = accumulated_distance;
|
||||
}
|
||||
}
|
||||
|
||||
assert(closest_id != -1);
|
||||
return closest_id;
|
||||
assert(furthest_id_found != -1);
|
||||
return furthest_id_found;
|
||||
} // getRescuePositionIndex
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -211,7 +211,11 @@ namespace Online
|
||||
int userid_fetched = input->get("userid", &userid);
|
||||
setLastOnlineName(username);
|
||||
|
||||
m_profile = new OnlineProfile(userid, username, true);
|
||||
OnlineProfile* profile = new OnlineProfile(userid, username, true);
|
||||
// Note that addPersistent might decide to merge profile with an
|
||||
// existing profile, and then delete profile. Only the returned
|
||||
// pointer is save to use.
|
||||
m_profile = ProfileManager::get()->addPersistent(profile);
|
||||
assert(token_fetched && username_fetched && userid_fetched);
|
||||
m_online_state = OS_SIGNED_IN;
|
||||
if(rememberPassword())
|
||||
@ -219,7 +223,6 @@ namespace Online
|
||||
saveSession(getOnlineId(), getToken());
|
||||
}
|
||||
|
||||
ProfileManager::get()->addPersistent(m_profile);
|
||||
std::string achieved_string("");
|
||||
|
||||
// Even if no achievements were sent, we have to call sync
|
||||
|
@ -253,7 +253,7 @@ bool ProfileManager::inPersistent(const uint32_t id)
|
||||
* the friends, while the other could have fetched the achievements.)
|
||||
* \param profile The profile to make persistent.
|
||||
*/
|
||||
void ProfileManager::addPersistent(OnlineProfile * profile)
|
||||
OnlineProfile* ProfileManager::addPersistent(OnlineProfile * profile)
|
||||
{
|
||||
if (inPersistent(profile->getID()))
|
||||
{
|
||||
@ -263,6 +263,8 @@ void ProfileManager::addPersistent(OnlineProfile * profile)
|
||||
{
|
||||
m_profiles_persistent[profile->getID()] = profile;
|
||||
}
|
||||
|
||||
return m_profiles_persistent[profile->getID()];
|
||||
} // addPersistent
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
void addToCache(OnlineProfile *profile);
|
||||
void addPersistent(OnlineProfile *profile);
|
||||
OnlineProfile* addPersistent(OnlineProfile *profile);
|
||||
void deleteFromPersistent(const uint32_t id);
|
||||
void clearPersistent();
|
||||
void moveToCache(const uint32_t id);
|
||||
|
@ -447,9 +447,12 @@ void btKart::updateVehicle( btScalar step )
|
||||
{
|
||||
btVector3 kart_up = getChassisWorldTransform().getBasis().getColumn(1);
|
||||
btVector3 terrain_up(0,1,0);
|
||||
// Length of axis depends on the angle - i.e. the further awat
|
||||
// the kart is from being upright, the larger the applied impulse
|
||||
// will be, resulting in fast changes when the kart is on its
|
||||
// side, but not overcompensating (and therefore shaking) when
|
||||
// the kart is not much away from being upright.
|
||||
btVector3 axis = kart_up.cross(terrain_up);
|
||||
if(!axis.fuzzyZero())
|
||||
axis.normalize();
|
||||
|
||||
// To avoid the kart going backwards/forwards (or rolling sideways),
|
||||
// set the pitch/roll to 0 before applying the 'straightening' impulse.
|
||||
|
@ -129,7 +129,7 @@ PhysicalObject::PhysicalObject(bool is_dynamic,
|
||||
|
||||
m_object = object;
|
||||
|
||||
m_init_xyz = object->getAbsolutePosition();
|
||||
m_init_xyz = object->getAbsoluteCenterPosition();
|
||||
m_init_hpr = object->getRotation();
|
||||
m_init_scale = object->getScale();
|
||||
|
||||
@ -252,8 +252,14 @@ void PhysicalObject::init()
|
||||
Log::fatal("PhysicalObject", "Unknown node type");
|
||||
}
|
||||
|
||||
max = max * Vec3(m_init_scale);
|
||||
min = min * Vec3(m_init_scale);
|
||||
Vec3 parent_scale(1.0f, 1.0f, 1.0f);
|
||||
if (m_object->getParentLibrary() != NULL)
|
||||
{
|
||||
parent_scale = m_object->getParentLibrary()->getScale();
|
||||
}
|
||||
|
||||
max = max * (Vec3(m_init_scale) * parent_scale);
|
||||
min = min * (Vec3(m_init_scale) * parent_scale);
|
||||
|
||||
Vec3 extend = max-min;
|
||||
// Adjust the mesth of the graphical object so that its center is where it
|
||||
@ -461,8 +467,31 @@ void PhysicalObject::init()
|
||||
// 2. Create the rigid object
|
||||
// --------------------------
|
||||
// m_init_pos is the point on the track - add the offset
|
||||
m_init_pos.setOrigin(m_init_pos.getOrigin() +
|
||||
btVector3(0,extend.getY()*0.5f, 0));
|
||||
if (m_is_dynamic)
|
||||
{
|
||||
m_init_pos.setOrigin(m_init_pos.getOrigin() +
|
||||
btVector3(0, extend.getY()*0.5f, 0));
|
||||
}
|
||||
|
||||
|
||||
// If this object has a parent, apply the parent's rotation
|
||||
if (m_object->getParentLibrary() != NULL)
|
||||
{
|
||||
core::vector3df parent_rot_hpr = m_object->getParentLibrary()->getInitRotation();
|
||||
core::matrix4 parent_rot_matrix;
|
||||
parent_rot_matrix.setRotationDegrees(parent_rot_hpr);
|
||||
|
||||
btQuaternion child_rot_quat = m_init_pos.getRotation();
|
||||
core::matrix4 child_rot_matrix;
|
||||
Vec3 axis = child_rot_quat.getAxis();
|
||||
child_rot_matrix.setRotationAxisRadians(child_rot_quat.getAngle(), axis.toIrrVector());
|
||||
|
||||
irr::core::quaternion tempQuat(parent_rot_matrix * child_rot_matrix);
|
||||
btQuaternion q(tempQuat.X, tempQuat.Y, tempQuat.Z, tempQuat.W);
|
||||
|
||||
m_init_pos.setRotation(q);
|
||||
}
|
||||
|
||||
m_motion_state = new btDefaultMotionState(m_init_pos);
|
||||
btVector3 inertia(1,1,1);
|
||||
if (m_body_type != MP_EXACT)
|
||||
|
@ -106,7 +106,7 @@ void GrandPrixData::changeTrackNumber(const unsigned int number_of_tracks,
|
||||
// Ignore no-racing tracks:
|
||||
if(!track->isRaceTrack())
|
||||
continue;
|
||||
|
||||
|
||||
if (PlayerManager::getCurrentPlayer()->isLocked(track->getIdent()))
|
||||
continue;
|
||||
|
||||
@ -132,10 +132,10 @@ void GrandPrixData::changeTrackNumber(const unsigned int number_of_tracks,
|
||||
|
||||
const Track *track = track_manager->getTrack(track_index);
|
||||
std::string id = track->getIdent();
|
||||
|
||||
|
||||
if (PlayerManager::getCurrentPlayer()->isLocked(track->getIdent()))
|
||||
continue;
|
||||
|
||||
|
||||
bool is_already_added = false;
|
||||
for (unsigned int i = 0; i < m_tracks.size(); i++)
|
||||
{
|
||||
@ -145,7 +145,7 @@ void GrandPrixData::changeTrackNumber(const unsigned int number_of_tracks,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!is_already_added)
|
||||
{
|
||||
m_tracks.push_back(id);
|
||||
@ -251,7 +251,7 @@ void GrandPrixData::reload()
|
||||
m_laps.clear();
|
||||
m_reversed.clear();
|
||||
|
||||
std::auto_ptr<XMLNode> root(file_manager->createXMLTree(m_filename));
|
||||
std::unique_ptr<XMLNode> root(file_manager->createXMLTree(m_filename));
|
||||
if (root.get() == NULL)
|
||||
{
|
||||
Log::error("GrandPrixData",
|
||||
|
@ -39,8 +39,6 @@ GrandPrixManager::GrandPrixManager()
|
||||
// ----------------------------------------------------------------------------
|
||||
GrandPrixManager::~GrandPrixManager()
|
||||
{
|
||||
for(unsigned int i=0; i<m_gp_data.size(); i++)
|
||||
delete m_gp_data[i];
|
||||
} // ~GrandPrixManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -84,9 +82,10 @@ void GrandPrixManager::loadDir(const std::string& dir, enum GrandPrixData::GPGro
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixManager::load(const std::string& filename, enum GrandPrixData::GPGroupType group)
|
||||
{
|
||||
GrandPrixData* gp = NULL;
|
||||
try
|
||||
{
|
||||
GrandPrixData* gp = new GrandPrixData(filename, group);
|
||||
gp = new GrandPrixData(filename, group);
|
||||
m_gp_data.push_back(gp);
|
||||
Log::debug("GrandPrixManager",
|
||||
"Grand Prix '%s' loaded from %s",
|
||||
@ -94,6 +93,8 @@ void GrandPrixManager::load(const std::string& filename, enum GrandPrixData::GPG
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
if (gp != NULL)
|
||||
delete gp;
|
||||
Log::error("GrandPrixManager",
|
||||
"Ignoring Grand Prix %s (%s)\n", filename.c_str(), e.what());
|
||||
}
|
||||
@ -102,9 +103,7 @@ void GrandPrixManager::load(const std::string& filename, enum GrandPrixData::GPG
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixManager::reload()
|
||||
{
|
||||
for(unsigned int i=0; i<m_gp_data.size(); i++)
|
||||
delete m_gp_data[i];
|
||||
m_gp_data.clear();
|
||||
m_gp_data.clearAndDeleteAll();
|
||||
|
||||
loadFiles();
|
||||
} // reload
|
||||
@ -124,7 +123,7 @@ std::string GrandPrixManager::generateId()
|
||||
unique = true;
|
||||
for (unsigned int i = 0; i < m_gp_data.size(); i++)
|
||||
{
|
||||
if (m_gp_data[i]->getId() == s.str())
|
||||
if (m_gp_data[i].getId() == s.str())
|
||||
{
|
||||
unique = false;
|
||||
break;
|
||||
@ -139,25 +138,31 @@ std::string GrandPrixManager::generateId()
|
||||
bool GrandPrixManager::existsName(const irr::core::stringw& name) const
|
||||
{
|
||||
for (unsigned int i = 0; i < m_gp_data.size(); i++)
|
||||
if (m_gp_data[i]->getName() == name)
|
||||
if (m_gp_data[i].getName() == name)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
} // existsName
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GrandPrixData* GrandPrixManager::getGrandPrix(const std::string& s) const
|
||||
const GrandPrixData* GrandPrixManager::getGrandPrix(const std::string& s) const
|
||||
{
|
||||
return editGrandPrix(s);
|
||||
for (unsigned int i = 0; i<m_gp_data.size(); i++)
|
||||
{
|
||||
if (m_gp_data[i].getId() == s)
|
||||
return m_gp_data.get(i);
|
||||
} // for i in m_gp_data
|
||||
|
||||
return NULL;
|
||||
} // getGrandPrix
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
GrandPrixData* GrandPrixManager::editGrandPrix(const std::string& s) const
|
||||
GrandPrixData* GrandPrixManager::editGrandPrix(const std::string& s)
|
||||
{
|
||||
for(unsigned int i=0; i<m_gp_data.size(); i++)
|
||||
{
|
||||
if(m_gp_data[i]->getId() == s)
|
||||
return m_gp_data[i];
|
||||
if (m_gp_data[i].getId() == s)
|
||||
return m_gp_data.get(i);
|
||||
} // for i in m_gp_data
|
||||
|
||||
return NULL;
|
||||
@ -166,13 +171,12 @@ GrandPrixData* GrandPrixManager::editGrandPrix(const std::string& s) const
|
||||
// ----------------------------------------------------------------------------
|
||||
void GrandPrixManager::checkConsistency()
|
||||
{
|
||||
for(unsigned int i=0; i<m_gp_data.size(); i++)
|
||||
for (int i = (int)m_gp_data.size() - 1; i >= 0; i--)
|
||||
{
|
||||
if(!m_gp_data[i]->checkConsistency())
|
||||
if (!m_gp_data[i].checkConsistency())
|
||||
{
|
||||
// delete this GP, since a track is missing
|
||||
delete *(m_gp_data.erase(m_gp_data.begin()+i));
|
||||
i--;
|
||||
m_gp_data.erase(i);
|
||||
}
|
||||
}
|
||||
} // checkConsistency
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
#include "irrlicht.h"
|
||||
class GrandPrixData;
|
||||
@ -35,7 +36,7 @@ class GrandPrixManager
|
||||
private:
|
||||
static const char* SUFFIX;
|
||||
|
||||
std::vector<GrandPrixData*> m_gp_data;
|
||||
PtrVector<GrandPrixData> m_gp_data;
|
||||
|
||||
/** Load all the grands prix from the 3 directories known */
|
||||
void loadFiles();
|
||||
@ -51,20 +52,23 @@ public:
|
||||
GrandPrixManager();
|
||||
~GrandPrixManager();
|
||||
void reload();
|
||||
GrandPrixData* getGrandPrix(const std::string& s) const;
|
||||
bool existsName(const irr::core::stringw& name) const;
|
||||
void checkConsistency();
|
||||
|
||||
// Methods for the gp editor
|
||||
GrandPrixData* editGrandPrix(const std::string& s) const;
|
||||
GrandPrixData* editGrandPrix(const std::string& s);
|
||||
GrandPrixData* createNewGP(const irr::core::stringw& newName);
|
||||
GrandPrixData* copy(const std::string& id,
|
||||
const irr::core::stringw& newName);
|
||||
void remove(const std::string& id);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the data for the specified GP.
|
||||
* \param i Index of the GP. */
|
||||
const GrandPrixData* getGrandPrix(const std::string& s) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the data for the specified GP.
|
||||
* \param i Index of the GP. */
|
||||
GrandPrixData* getGrandPrix(const int i) const { return m_gp_data[i]; }
|
||||
const GrandPrixData* getGrandPrix(const int i) const { return m_gp_data.get(i); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of GPs. */
|
||||
unsigned int getNumberOfGrandPrix() const { return (int)m_gp_data.size(); }
|
||||
|
@ -182,6 +182,8 @@ void History::Save()
|
||||
fprintf(fd, "numkarts: %d\n", num_karts);
|
||||
fprintf(fd, "numplayers: %d\n", race_manager->getNumPlayers());
|
||||
fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty());
|
||||
fprintf(fd, "reverse: %c\n", race_manager->getReverseTrack() ? 'y' : 'n');
|
||||
|
||||
fprintf(fd, "track: %s\n", world->getTrack()->getIdent().c_str());
|
||||
|
||||
assert(num_karts > 0);
|
||||
@ -269,7 +271,17 @@ void History::Load()
|
||||
Log::fatal("History", "No difficulty found in history file.");
|
||||
race_manager->setDifficulty((RaceManager::Difficulty)n);
|
||||
|
||||
|
||||
// Optional (not supported in older history files): include reverse
|
||||
fgets(s, 1023, fd);
|
||||
char r;
|
||||
if (!sscanf(s, "reverse: %c", &r) != 1)
|
||||
{
|
||||
fgets(s, 1023, fd);
|
||||
race_manager->setReverseTrack(r == 'y');
|
||||
}
|
||||
|
||||
|
||||
if(sscanf(s, "track: %1023s",s1)!=1)
|
||||
Log::warn("History", "Track not found in history file.");
|
||||
race_manager->setTrack(s1);
|
||||
|
@ -546,7 +546,7 @@ void RaceManager::saveGP()
|
||||
m_saved_gp->setKarts(m_kart_status);
|
||||
m_saved_gp->setNextTrack(m_track_number);
|
||||
}
|
||||
else
|
||||
else if(!m_grand_prix.isRandomGP())
|
||||
{
|
||||
m_saved_gp = new SavedGrandPrix(
|
||||
StateManager::get()->getActivePlayerProfile(0)->getUniqueID(),
|
||||
@ -556,12 +556,30 @@ void RaceManager::saveGP()
|
||||
m_track_number,
|
||||
m_grand_prix.getReverseType(),
|
||||
m_kart_status);
|
||||
|
||||
|
||||
// If a new GP is saved, delete any other saved data for this
|
||||
// GP at the same difficulty (even if #karts is different, otherwise
|
||||
// the user has to remember the number of AI karts, with no indication
|
||||
// on which ones are saved).
|
||||
for (unsigned int i = 0;
|
||||
i < UserConfigParams::m_saved_grand_prix_list.size();)
|
||||
{
|
||||
// Delete other save files (and random GP, which should never
|
||||
// have been saved in the first place)
|
||||
const SavedGrandPrix &sgp = UserConfigParams::m_saved_grand_prix_list[i];
|
||||
if (sgp.getGPID() == "random" ||
|
||||
(sgp.getGPID() == m_saved_gp->getGPID() &&
|
||||
sgp.getDifficulty() == m_saved_gp->getDifficulty()) )
|
||||
{
|
||||
UserConfigParams::m_saved_grand_prix_list.erase(i);
|
||||
}
|
||||
else i++;
|
||||
}
|
||||
UserConfigParams::m_saved_grand_prix_list.push_back(m_saved_gp);
|
||||
}
|
||||
|
||||
user_config->saveConfig();
|
||||
}
|
||||
} // saveGP
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -19,10 +19,14 @@
|
||||
#include "script_track.hpp"
|
||||
|
||||
#include "animations/three_d_animation.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
#include "input/input_device.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "challenges/unlock_manager.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/stk_text_billboard.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/scalable_font.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_object.hpp"
|
||||
@ -30,6 +34,8 @@
|
||||
|
||||
#include <angelscript.h>
|
||||
#include <assert.h>
|
||||
#include <ISceneManager.h>
|
||||
#include <IBillboardTextSceneNode.h>
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
namespace Scripting
|
||||
@ -58,6 +64,38 @@ namespace Scripting
|
||||
return track->getChallengeList().size();
|
||||
}
|
||||
|
||||
int getChallengeRequiredPoints(std::string* challenge_name)
|
||||
{
|
||||
::Track* track = World::getWorld()->getTrack();
|
||||
const ChallengeData* challenge = unlock_manager->getChallengeData(*challenge_name);
|
||||
if (challenge == NULL)
|
||||
{
|
||||
if (*challenge_name != "tutorial")
|
||||
Log::error("track", "Cannot find challenge named '%s'\n",
|
||||
challenge_name->c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return challenge->getNumTrophies();
|
||||
}
|
||||
|
||||
bool isChallengeUnlocked(std::string* challenge_name)
|
||||
{
|
||||
::Track* track = World::getWorld()->getTrack();
|
||||
const ChallengeData* challenge = unlock_manager->getChallengeData(*challenge_name);
|
||||
if (challenge == NULL)
|
||||
{
|
||||
if (*challenge_name != "tutorial")
|
||||
Log::error("track", "Cannot find challenge named '%s'\n",
|
||||
challenge_name->c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned int val = challenge->getNumTrophies();
|
||||
bool shown = (PlayerManager::getCurrentPlayer()->getPoints() >= val);
|
||||
return shown;
|
||||
}
|
||||
|
||||
/** @}*/
|
||||
/** @}*/
|
||||
|
||||
@ -69,6 +107,8 @@ namespace Scripting
|
||||
|
||||
r = engine->RegisterGlobalFunction("int getCompletedChallengesCount()", asFUNCTION(getCompletedChallengesCount), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("int getChallengeCount()", asFUNCTION(getChallengeCount), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("bool isChallengeUnlocked(string &in)", asFUNCTION(isChallengeUnlocked), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("int getChallengeRequiredPoints(string &in)", asFUNCTION(getChallengeRequiredPoints), asCALL_CDECL); assert(r >= 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ namespace Scripting
|
||||
script.resize(len);
|
||||
int c = fread(&script[0], len, 1, f);
|
||||
fclose(f);
|
||||
if (c == NULL)
|
||||
if (c != 1)
|
||||
{
|
||||
Log::error("Scripting", "Failed to load script file.");
|
||||
return "";
|
||||
|
@ -53,20 +53,40 @@ namespace Scripting
|
||||
{
|
||||
InputDevice* device = input_manager->getDeviceManager()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw control;
|
||||
PlayerAction ScriptAction = (PlayerAction)Enum_value;
|
||||
control = config->getBindingAsString(ScriptAction);
|
||||
std::string key = std::string(irr::core::stringc(control).c_str());
|
||||
irr::core::stringw control = config->getBindingAsString(ScriptAction);
|
||||
std::string key = StringUtils::wide_to_utf8(control.c_str());
|
||||
return key;
|
||||
}
|
||||
|
||||
/** Show the specified message in a popup */
|
||||
void displayMessage(std::string* input)
|
||||
void displayModalMessage(std::string* input)
|
||||
{
|
||||
irr::core::stringw out = StringUtils::utf8_to_wide(input->c_str());
|
||||
new TutorialMessageDialog((out), true);
|
||||
}
|
||||
|
||||
void clearOverlayMessages()
|
||||
{
|
||||
World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
}
|
||||
|
||||
/** Display text in the center of the screen for a few seconds */
|
||||
void displayOverlayMessage(std::string* input)
|
||||
{
|
||||
irr::core::stringw msg = StringUtils::utf8_to_wide(input->c_str());
|
||||
std::vector<core::stringw> parts =
|
||||
StringUtils::split(msg, '\n', false);
|
||||
|
||||
for (unsigned int n = 0; n < parts.size(); n++)
|
||||
{
|
||||
World::getWorld()->getRaceGUI()
|
||||
->addMessage(parts[n], NULL, 4.0f,
|
||||
video::SColor(255, 255,255,255),
|
||||
true, true);
|
||||
} // for n<parts.size()
|
||||
}
|
||||
|
||||
/** Get translated version of string */
|
||||
std::string translate(std::string* input)
|
||||
{
|
||||
@ -150,7 +170,9 @@ namespace Scripting
|
||||
{
|
||||
int r; // of type asERetCodes
|
||||
engine->SetDefaultNamespace("GUI");
|
||||
r = engine->RegisterGlobalFunction("void displayMessage(const string &in)", asFUNCTION(displayMessage), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void displayModalMessage(const string &in)", asFUNCTION(displayModalMessage), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void displayOverlayMessage(const string &in)", asFUNCTION(displayOverlayMessage), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void clearOverlayMessages()", asFUNCTION(clearOverlayMessages), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string getKeyBinding(int input)", asFUNCTION(getKeyBinding), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string translate(const string &in)", asFUNCTION(proxy_translate), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string translate(const string &in, const string &in)", asFUNCTION(proxy_translateAndInsertValues1), asCALL_CDECL); assert(r >= 0);
|
||||
|
@ -19,6 +19,9 @@
|
||||
#include "script_track.hpp"
|
||||
|
||||
#include "animations/three_d_animation.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/stk_text_billboard.hpp"
|
||||
#include "guiengine/scalable_font.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
#include "input/input_device.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
@ -29,8 +32,10 @@
|
||||
#include "tracks/track_object.hpp"
|
||||
#include "tracks/track_object_manager.hpp"
|
||||
|
||||
#include <IBillboardTextSceneNode.h>
|
||||
#include <angelscript.h>
|
||||
#include <assert.h>
|
||||
#include <ISceneManager.h>
|
||||
|
||||
/** \cond DOXYGEN_IGNORE */
|
||||
namespace Scripting
|
||||
@ -57,13 +62,13 @@ namespace Scripting
|
||||
* Get a track object by ID.
|
||||
* @return An object of type @ref Scripting_TrackObject
|
||||
*/
|
||||
TrackObject* getTrackObject(std::string* libraryInstance, std::string* objID)
|
||||
::TrackObject* getTrackObject(std::string* libraryInstance, std::string* objID)
|
||||
{
|
||||
return World::getWorld()->getTrack()->getTrackObjectManager()->getTrackObject(*libraryInstance, *objID);
|
||||
}
|
||||
|
||||
/** Creates a trigger at the specified location */
|
||||
void createTrigger(std::string* triggerID, Vec3* creation_loc, float distance)
|
||||
void createTrigger(std::string* triggerID, SimpleVec3* creation_loc, float distance)
|
||||
{
|
||||
float x = creation_loc->getX();
|
||||
float y = creation_loc->getY();
|
||||
@ -73,12 +78,51 @@ namespace Scripting
|
||||
core::vector3df scale(1.0f, 1.0f, 1.0f);
|
||||
TrackObjectPresentationActionTrigger* newtrigger =
|
||||
new TrackObjectPresentationActionTrigger(posi, *triggerID, distance);
|
||||
TrackObject* tobj = new TrackObject(posi, hpr, scale,
|
||||
::TrackObject* tobj = new ::TrackObject(posi, hpr, scale,
|
||||
"none", newtrigger, false /* isDynamic */, NULL /* physics settings */);
|
||||
tobj->setID(*triggerID);
|
||||
World::getWorld()->getTrack()->getTrackObjectManager()->insertObject(tobj);
|
||||
}
|
||||
|
||||
void createTextBillboard(std::string* text, SimpleVec3* location)
|
||||
{
|
||||
core::stringw wtext = StringUtils::utf8_to_wide(text->c_str());
|
||||
core::dimension2d<u32> textsize = GUIEngine::getHighresDigitFont()
|
||||
->getDimension(wtext.c_str());
|
||||
|
||||
assert(GUIEngine::getHighresDigitFont() != NULL);
|
||||
|
||||
core::vector3df xyz(location->getX(), location->getY(), location->getZ());
|
||||
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
gui::ScalableFont* font = GUIEngine::getHighresDigitFont();
|
||||
STKTextBillboard* tb = new STKTextBillboard(wtext.c_str(), font,
|
||||
video::SColor(255, 255, 225, 0),
|
||||
video::SColor(255, 255, 89, 0),
|
||||
irr_driver->getSceneManager()->getRootSceneNode(),
|
||||
irr_driver->getSceneManager(), -1, xyz,
|
||||
core::vector3df(1.5f, 1.5f, 1.5f));
|
||||
|
||||
World::getWorld()->getTrack()->addNode(tb);
|
||||
}
|
||||
else
|
||||
{
|
||||
scene::ISceneManager* sm = irr_driver->getSceneManager();
|
||||
scene::ISceneNode* sn =
|
||||
sm->addBillboardTextSceneNode(GUIEngine::getHighresDigitFont(),
|
||||
wtext.c_str(),
|
||||
NULL,
|
||||
core::dimension2df(textsize.Width / 35.0f,
|
||||
textsize.Height / 35.0f),
|
||||
xyz,
|
||||
-1, // id
|
||||
video::SColor(255, 255, 225, 0),
|
||||
video::SColor(255, 255, 89, 0));
|
||||
World::getWorld()->getTrack()->addNode(sn);
|
||||
}
|
||||
}
|
||||
|
||||
/** Exits the race to the main menu */
|
||||
void exitRace()
|
||||
{
|
||||
@ -96,6 +140,21 @@ namespace Scripting
|
||||
{
|
||||
/** \endcond */
|
||||
|
||||
namespace TrackObject
|
||||
{
|
||||
SimpleVec3 getCenterPosition(::TrackObject* obj)
|
||||
{
|
||||
core::vector3df pos = obj->getAbsoluteCenterPosition();
|
||||
return SimpleVec3(pos.X, pos.Y, pos.Z);
|
||||
}
|
||||
|
||||
SimpleVec3 getOrigin(::TrackObject* obj)
|
||||
{
|
||||
core::vector3df pos = obj->getAbsolutePosition();
|
||||
return SimpleVec3(pos.X, pos.Y, pos.Z);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------- TrackObjectPresentationMesh methods -----------
|
||||
// TODO: this method is WRONG, we should in most cases move not the presentation but the entire object
|
||||
//void movePresentation(Vec3 *new_pos, void *memory)
|
||||
@ -237,19 +296,22 @@ namespace Scripting
|
||||
//r = engine->RegisterGlobalFunction("void disableTrigger(const string &in)", asFUNCTION(disableTrigger), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void createTrigger(const string &in, const Vec3 &in, float distance)",
|
||||
asFUNCTION(createTrigger), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void createTextBillboard(const string &in, const Vec3 &in)",
|
||||
asFUNCTION(createTextBillboard), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("TrackObject@ getTrackObject(const string &in, const string &in)", asFUNCTION(getTrackObject), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void exitRace()", asFUNCTION(exitRace), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void pauseRace()", asFUNCTION(pauseRace), asCALL_CDECL); assert(r >= 0);
|
||||
|
||||
// TrackObject
|
||||
r = engine->RegisterObjectMethod("TrackObject", "void setEnabled(bool status)", asMETHOD(TrackObject, setEnabled), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "SoundEmitter@ getSoundEmitter()", asMETHOD(TrackObject, getSoundEmitter), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "PhysicalObject@ getPhysics()", asMETHOD(TrackObject, getPhysics), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Mesh@ getMesh()", asMETHOD(TrackObject, getMesh), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "ParticleEmitter@ getParticleEmitter()", asMETHOD(TrackObject, getParticleEmitter), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Animator@ getIPOAnimator()", asMETHOD(TrackObject, getIPOAnimator), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "void moveTo(const Vec3 &in, bool)", asMETHOD(TrackObject, moveTo), asCALL_THISCALL); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterObjectMethod("TrackObject", "void setEnabled(bool status)", asMETHOD(::TrackObject, setEnabled), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "SoundEmitter@ getSoundEmitter()", asMETHOD(::TrackObject, getSoundEmitter), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "PhysicalObject@ getPhysics()", asMETHOD(::TrackObject, getPhysics), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Mesh@ getMesh()", asMETHOD(::TrackObject, getMesh), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "ParticleEmitter@ getParticleEmitter()", asMETHOD(::TrackObject, getParticleEmitter), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Animator@ getIPOAnimator()", asMETHOD(::TrackObject, getIPOAnimator), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "void moveTo(const Vec3 &in, bool)", asMETHOD(::TrackObject, moveTo), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Vec3 getCenterPosition()", asFUNCTION(TrackObject::getCenterPosition), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("TrackObject", "Vec3 getOrigin()", asFUNCTION(TrackObject::getOrigin), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
// PhysicalObject
|
||||
r = engine->RegisterObjectMethod("PhysicalObject", "bool isFlattenKartObject()", asMETHOD(PhysicalObject, isFlattenKartObject), asCALL_THISCALL); assert(r >= 0);
|
||||
|
@ -16,10 +16,10 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "config/user_config.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/scalable_font.hpp"
|
||||
#include "graphics/2dutils.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "states_screens/cutscene_gui.hpp"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -40,21 +40,23 @@ CutsceneGUI::~CutsceneGUI()
|
||||
|
||||
void CutsceneGUI::renderGlobal(float dt)
|
||||
{
|
||||
core::dimension2d<u32> screen_size = irr_driver->getActualScreenSize();
|
||||
|
||||
if (m_fade_level > 0.0f)
|
||||
{
|
||||
GL32_draw2DRectangle(
|
||||
video::SColor((int)(m_fade_level*255), 0,0,0),
|
||||
core::rect<s32>(0, 0,
|
||||
UserConfigParams::m_width,
|
||||
UserConfigParams::m_height));
|
||||
screen_size.Width,
|
||||
screen_size.Height));
|
||||
}
|
||||
|
||||
if (m_subtitle.size() > 0)
|
||||
{
|
||||
core::rect<s32> r(0, UserConfigParams::m_height - GUIEngine::getFontHeight()*2,
|
||||
UserConfigParams::m_width, UserConfigParams::m_height);
|
||||
core::rect<s32> r(0, screen_size.Height - GUIEngine::getFontHeight()*2,
|
||||
screen_size.Width, screen_size.Height);
|
||||
|
||||
if (GUIEngine::getFont()->getDimension(m_subtitle.c_str()).Width > (unsigned int)UserConfigParams::m_width)
|
||||
if (GUIEngine::getFont()->getDimension(m_subtitle.c_str()).Width > screen_size.Width)
|
||||
{
|
||||
GUIEngine::getSmallFont()->draw(m_subtitle, r,
|
||||
video::SColor(255,255,255,255), true, true, NULL);
|
||||
|
@ -331,12 +331,15 @@ void AddonsLoading::stopDownload()
|
||||
// (and not uninstalling an installed one):
|
||||
if(m_download_request)
|
||||
{
|
||||
// In case of a cancel we can't free the memory, since
|
||||
// network_http will potentially update the request. So in
|
||||
// order to avoid a memory leak, we let network_http free
|
||||
// the request.
|
||||
//m_download_request->setManageMemory(true);
|
||||
// In case of a cancel we can't free the memory, since the
|
||||
// request manager thread is potentially working on this request. So
|
||||
// in order to avoid a memory leak, we let the request manager
|
||||
// free the data. This is thread safe since freeing the data is done
|
||||
// when the request manager handles the result queue - and this is
|
||||
// done by the main thread (i.e. this thread).
|
||||
m_download_request->setManageMemory(true);
|
||||
m_download_request->cancel();
|
||||
m_download_request = NULL;
|
||||
};
|
||||
} // startDownload
|
||||
|
||||
|
@ -171,16 +171,19 @@ void EditGPScreen::init()
|
||||
|
||||
if (edit->getResult())
|
||||
{
|
||||
bool reverse = edit->getTrack()->reverseAvailable() ?
|
||||
edit->getReverse() : false;
|
||||
|
||||
if (m_action == "add")
|
||||
{
|
||||
m_gp->addTrack(edit->getTrack(), edit->getLaps(), edit->getReverse(),
|
||||
m_selected);
|
||||
m_gp->addTrack(edit->getTrack(), edit->getLaps(), reverse,
|
||||
m_selected);
|
||||
setSelected(m_selected + 1);
|
||||
}
|
||||
else if (m_action == "edit")
|
||||
{
|
||||
m_gp->editTrack(m_selected, edit->getTrack(), edit->getLaps(),
|
||||
edit->getReverse());
|
||||
reverse);
|
||||
}
|
||||
setModified(true);
|
||||
}
|
||||
|
@ -291,6 +291,7 @@ void GrandPrixEditorScreen::onNewGPWithName(const stringw& newName)
|
||||
{
|
||||
m_selection->setName(newName);
|
||||
m_selection->writeToFile();
|
||||
setSelection(grand_prix_manager->getGrandPrix(m_selection->getId()));
|
||||
}
|
||||
else if (m_action == "new")
|
||||
{
|
||||
|
@ -59,7 +59,8 @@ void OptionsScreenAudio::init()
|
||||
{
|
||||
Screen::init();
|
||||
RibbonWidget* ribbon = this->getWidget<RibbonWidget>("options_choice");
|
||||
if (ribbon != NULL) ribbon->select( "tab_audio", PLAYER_ID_GAME_MASTER );
|
||||
assert(ribbon != NULL);
|
||||
ribbon->select( "tab_audio", PLAYER_ID_GAME_MASTER );
|
||||
|
||||
ribbon->getRibbonChildren()[0].setTooltip( _("Graphics") );
|
||||
ribbon->getRibbonChildren()[2].setTooltip( _("User Interface") );
|
||||
|
@ -133,7 +133,8 @@ void OptionsScreenInput::init()
|
||||
{
|
||||
Screen::init();
|
||||
RibbonWidget* tabBar = this->getWidget<RibbonWidget>("options_choice");
|
||||
if (tabBar != NULL) tabBar->select( "tab_controls", PLAYER_ID_GAME_MASTER );
|
||||
assert(tabBar != NULL);
|
||||
tabBar->select( "tab_controls", PLAYER_ID_GAME_MASTER );
|
||||
|
||||
tabBar->getRibbonChildren()[0].setTooltip( _("Graphics") );
|
||||
tabBar->getRibbonChildren()[1].setTooltip( _("Audio") );
|
||||
|
@ -79,8 +79,8 @@ void OptionsScreenInput2::init()
|
||||
{
|
||||
Screen::init();
|
||||
RibbonWidget* tabBar = getWidget<RibbonWidget>("options_choice");
|
||||
if (tabBar != NULL) tabBar->select( "tab_controls",
|
||||
PLAYER_ID_GAME_MASTER );
|
||||
assert(tabBar != NULL);
|
||||
tabBar->select( "tab_controls", PLAYER_ID_GAME_MASTER );
|
||||
|
||||
tabBar->getRibbonChildren()[0].setTooltip( _("Graphics") );
|
||||
tabBar->getRibbonChildren()[1].setTooltip( _("Audio") );
|
||||
@ -89,7 +89,7 @@ void OptionsScreenInput2::init()
|
||||
|
||||
|
||||
ButtonWidget* delete_button = getWidget<ButtonWidget>("delete");
|
||||
if (m_config->isKeyboard())
|
||||
if (!m_config->isKeyboard())
|
||||
{
|
||||
core::stringw label = (m_config->isEnabled()
|
||||
? //I18N: button to disable a gamepad configuration
|
||||
|
@ -112,7 +112,8 @@ void OptionsScreenUI::init()
|
||||
{
|
||||
Screen::init();
|
||||
RibbonWidget* ribbon = getWidget<RibbonWidget>("options_choice");
|
||||
if (ribbon != NULL) ribbon->select( "tab_ui", PLAYER_ID_GAME_MASTER );
|
||||
assert(ribbon != NULL);
|
||||
ribbon->select( "tab_ui", PLAYER_ID_GAME_MASTER );
|
||||
|
||||
ribbon->getRibbonChildren()[0].setTooltip( _("Graphics") );
|
||||
ribbon->getRibbonChildren()[1].setTooltip( _("Audio") );
|
||||
|
@ -95,6 +95,13 @@ static GFXPreset GFX_PRESETS[] =
|
||||
false /* depth of field */, false /* global illumination */, false /* degraded IBL */, 1 /* hd_textures */
|
||||
},
|
||||
|
||||
{
|
||||
true /* light */, 512 /* shadow */, true /* bloom */, true /* motionblur */,
|
||||
true /* lightshaft */, true /* glow */, true /* mlaa */, true /* ssao */, true /* weather */,
|
||||
true /* animatedScenery */, 2 /* animatedCharacters */, 16 /* anisotropy */,
|
||||
true /* depth of field */, false /* global illumination */, false /* degraded IBL */, 1 /* hd_textures */
|
||||
},
|
||||
|
||||
{
|
||||
true /* light */, 1024 /* shadow */, true /* bloom */, true /* motionblur */,
|
||||
true /* lightshaft */, true /* glow */, true /* mlaa */, true /* ssao */, true /* weather */,
|
||||
@ -103,7 +110,7 @@ static GFXPreset GFX_PRESETS[] =
|
||||
}
|
||||
};
|
||||
|
||||
static const int GFX_LEVEL_AMOUNT = 5;
|
||||
static const int GFX_LEVEL_AMOUNT = 6;
|
||||
|
||||
struct Resolution
|
||||
{
|
||||
@ -159,7 +166,8 @@ void OptionsScreenVideo::init()
|
||||
{
|
||||
Screen::init();
|
||||
RibbonWidget* ribbon = getWidget<RibbonWidget>("options_choice");
|
||||
if (ribbon != NULL) ribbon->select( "tab_video", PLAYER_ID_GAME_MASTER );
|
||||
assert(ribbon != NULL);
|
||||
ribbon->select( "tab_video", PLAYER_ID_GAME_MASTER );
|
||||
|
||||
ribbon->getRibbonChildren()[1].setTooltip( _("Audio") );
|
||||
ribbon->getRibbonChildren()[2].setTooltip( _("User Interface") );
|
||||
|
@ -400,9 +400,10 @@ void RaceGUIOverworld::drawGlobalMiniMap()
|
||||
Vec3 draw_at;
|
||||
track->mapPoint2MiniMap(challenges[n].m_position, &draw_at);
|
||||
|
||||
//const ChallengeData* c = unlock_manager->getChallenge(challenges[n].m_challenge_id);
|
||||
// bool locked = (m_locked_challenges.find(c) != m_locked_challenges.end());
|
||||
int state = (challenges[n].getForceField().m_is_locked ? LOCKED : OPEN);
|
||||
const ChallengeData* challenge = unlock_manager->getChallengeData(challenges[n].m_challenge_id);
|
||||
const unsigned int val = challenge->getNumTrophies();
|
||||
bool unlocked = (PlayerManager::getCurrentPlayer()->getPoints() >= val);
|
||||
int state = (unlocked ? OPEN : LOCKED);
|
||||
|
||||
const ChallengeStatus* c = PlayerManager::getCurrentPlayer()
|
||||
->getChallengeStatus(challenges[n].m_challenge_id);
|
||||
@ -442,8 +443,14 @@ void RaceGUIOverworld::drawGlobalMiniMap()
|
||||
m_close_to_a_challenge = false;
|
||||
for (unsigned int n=0; n<challenges.size(); n++)
|
||||
{
|
||||
if (challenges[n].m_challenge_id != "tutorial" &&
|
||||
challenges[n].getForceField().m_is_locked) continue;
|
||||
if (challenges[n].m_challenge_id != "tutorial")
|
||||
{
|
||||
const ChallengeData* challenge = unlock_manager->getChallengeData(challenges[n].m_challenge_id);
|
||||
const unsigned int val = challenge->getNumTrophies();
|
||||
bool unlocked = (PlayerManager::getCurrentPlayer()->getPoints() >= val);
|
||||
if (!unlocked)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((kart_xyz - Vec3(challenges[n].m_position)).length2_2d() < CHALLENGE_DISTANCE_SQUARED &&
|
||||
fabsf(kart_xyz[1] - challenges[n].m_position.Y) < CHALLENGE_HEIGHT)
|
||||
|
@ -468,7 +468,9 @@ void RaceResultGUI::determineTableLayout()
|
||||
kart->getKartProperties()->getIconMaterial()->getTexture();
|
||||
ri->m_kart_icon = icon;
|
||||
|
||||
if (kart->isEliminated())
|
||||
// FTL karts will get a time assigned, they are not shown as eliminated
|
||||
if (kart->isEliminated() &&
|
||||
race_manager->getMinorMode()!=RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
ri->m_finish_time_string = core::stringw(_("Eliminated"));
|
||||
}
|
||||
@ -830,16 +832,19 @@ void RaceResultGUI::determineGPLayout()
|
||||
ri->m_player = ri->m_is_player_kart
|
||||
? kart->getController()->getPlayer() : NULL;
|
||||
|
||||
if (!kart->isEliminated())
|
||||
// In FTL karts do have a time, which is shown even when the kart
|
||||
// is eliminated
|
||||
if (kart->isEliminated() &&
|
||||
race_manager->getMinorMode()!=RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
ri->m_finish_time_string = core::stringw(_("Eliminated"));
|
||||
}
|
||||
else
|
||||
{
|
||||
float time = race_manager->getOverallTime(kart_id);
|
||||
ri->m_finish_time_string
|
||||
= StringUtils::timeToString(time).c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
ri->m_finish_time_string = core::stringw(_("Eliminated"));
|
||||
}
|
||||
ri->m_start_at = m_time_between_rows * rank;
|
||||
ri->m_x_pos = (float)UserConfigParams::m_width;
|
||||
ri->m_y_pos = (float)(m_top+rank*m_distance_between_rows);
|
||||
@ -916,15 +921,10 @@ void RaceResultGUI::displayOneEntry(unsigned int x, unsigned int y,
|
||||
current_x += m_width_kart_name + m_width_column_space;
|
||||
|
||||
|
||||
// Draw the time except in FTL mode
|
||||
// --------------------------------
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
core::recti dest_rect = core::recti(current_x, y, current_x+100, y+10);
|
||||
m_font->draw(ri->m_finish_time_string, dest_rect, color, false, false,
|
||||
NULL, true /* ignoreRTL */);
|
||||
current_x += m_width_finish_time + m_width_column_space;
|
||||
}
|
||||
core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10);
|
||||
m_font->draw(ri->m_finish_time_string, dest_rect, color, false, false,
|
||||
NULL, true /* ignoreRTL */);
|
||||
current_x += m_width_finish_time + m_width_column_space;
|
||||
|
||||
// Only display points in GP mode and when the GP results are displayed.
|
||||
// =====================================================================
|
||||
|
@ -631,7 +631,8 @@ void BaseUserScreen::unloaded()
|
||||
void TabbedUserScreen::init()
|
||||
{
|
||||
RibbonWidget* tab_bar = getWidget<RibbonWidget>("options_choice");
|
||||
if (tab_bar) tab_bar->select("tab_players", PLAYER_ID_GAME_MASTER);
|
||||
assert(tab_bar != NULL);
|
||||
tab_bar->select("tab_players", PLAYER_ID_GAME_MASTER);
|
||||
tab_bar->getRibbonChildren()[0].setTooltip( _("Graphics") );
|
||||
tab_bar->getRibbonChildren()[1].setTooltip( _("Audio") );
|
||||
tab_bar->getRibbonChildren()[2].setTooltip( _("User Interface") );
|
||||
|
@ -156,7 +156,7 @@ DictionaryManager::get_dictionary(const Language& language)
|
||||
std::string pofile = *p + "/" + best_filename;
|
||||
try
|
||||
{
|
||||
std::auto_ptr<std::istream> in = filesystem->open_file(pofile);
|
||||
std::unique_ptr<std::istream> in = filesystem->open_file(pofile);
|
||||
if (!in.get())
|
||||
{
|
||||
Log::error("tinygettext", "error: failure opening: '%s'.",
|
||||
@ -252,11 +252,11 @@ DictionaryManager::add_directory(const std::string& pathname)
|
||||
search_path.push_back(pathname);
|
||||
}
|
||||
|
||||
/*void
|
||||
DictionaryManager::set_filesystem(std::auto_ptr<FileSystem> filesystem_)
|
||||
void
|
||||
DictionaryManager::set_filesystem(std::unique_ptr<FileSystem> filesystem_)
|
||||
{
|
||||
filesystem = filesystem_;
|
||||
}*/
|
||||
filesystem = std::move(filesystem_);
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function converts a .po filename (e.g. zh_TW.po) into a language
|
||||
* specification (zh_TW). On case insensitive file systems (think windows)
|
||||
|
@ -51,7 +51,7 @@ private:
|
||||
|
||||
Dictionary empty_dict;
|
||||
|
||||
std::auto_ptr<FileSystem> filesystem;
|
||||
std::unique_ptr<FileSystem> filesystem;
|
||||
|
||||
void clear_cache();
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
/** Return a set of the available languages in their country code */
|
||||
std::set<Language> get_languages();
|
||||
|
||||
//void set_filesystem(std::auto_ptr<FileSystem> filesystem);
|
||||
void set_filesystem(std::unique_ptr<FileSystem> filesystem);
|
||||
std::string convertFilename2Language(const std::string &s_in) const;
|
||||
|
||||
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
virtual ~FileSystem() {}
|
||||
|
||||
virtual std::vector<std::string> open_directory(const std::string& pathname) =0;
|
||||
virtual std::auto_ptr<std::istream> open_file(const std::string& filename) =0;
|
||||
virtual std::unique_ptr<std::istream> open_file(const std::string& filename) =0;
|
||||
};
|
||||
|
||||
} // namespace tinygettext
|
||||
|
@ -44,10 +44,10 @@ StkFileSystem::open_directory(const std::string& pathname)
|
||||
return files;
|
||||
}
|
||||
|
||||
std::auto_ptr<std::istream>
|
||||
std::unique_ptr<std::istream>
|
||||
StkFileSystem::open_file(const std::string& filename)
|
||||
{
|
||||
return std::auto_ptr<std::istream>(new std::ifstream(filename.c_str()));
|
||||
return std::unique_ptr<std::istream>(new std::ifstream(filename.c_str()));
|
||||
}
|
||||
|
||||
} // namespace tinygettext
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
StkFileSystem();
|
||||
|
||||
std::vector<std::string> open_directory(const std::string& pathname);
|
||||
std::auto_ptr<std::istream> open_file(const std::string& filename);
|
||||
std::unique_ptr<std::istream> open_file(const std::string& filename);
|
||||
};
|
||||
|
||||
} // namespace tinygettext
|
||||
|
@ -69,7 +69,7 @@ void CheckGoal::update(float dt)
|
||||
continue;
|
||||
|
||||
const Vec3 &xyz = obj->getPresentation<TrackObjectPresentationMesh>()->getNode()->getPosition();
|
||||
if(isTriggered(m_previous_position[ball_index], xyz, ball_index))
|
||||
if(isTriggered(m_previous_position[ball_index], xyz, -1))
|
||||
{
|
||||
if(UserConfigParams::m_check_debug)
|
||||
Log::info("CheckGoal", "Goal check structure %d triggered for object %s.",
|
||||
@ -101,7 +101,7 @@ void CheckGoal::trigger(unsigned int kart_index)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool CheckGoal::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
unsigned int indx)
|
||||
unsigned int kartIndex)
|
||||
{
|
||||
core::vector2df cross_point;
|
||||
|
||||
|
@ -63,10 +63,6 @@ bool CheckLap::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
{
|
||||
World* w = World::getWorld();
|
||||
LinearWorld* lin_world = dynamic_cast<LinearWorld*>(w);
|
||||
if (lin_world != NULL)
|
||||
{
|
||||
lin_world->getTrackSector(kart_index).setLastTriggeredCheckline(m_index);
|
||||
}
|
||||
|
||||
float track_length = w->getTrack()->getTrackLength();
|
||||
// Can happen if a non-lap based race mode is used with a scene file that
|
||||
@ -87,10 +83,7 @@ bool CheckLap::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
m_previous_distance[kart_index] = current_distance;
|
||||
|
||||
if (result)
|
||||
{
|
||||
LinearWorld* lw = dynamic_cast<LinearWorld*>(w);
|
||||
if (lw != NULL)
|
||||
lw->setLastTriggeredCheckline(kart_index, m_index);
|
||||
}
|
||||
lin_world->setLastTriggeredCheckline(kart_index, m_index);
|
||||
|
||||
return result;
|
||||
} // isTriggered
|
||||
|
@ -120,10 +120,11 @@ CheckLine::~CheckLine()
|
||||
void CheckLine::reset(const Track &track)
|
||||
{
|
||||
CheckStructure::reset(track);
|
||||
for(unsigned int i=0; i<m_previous_sign.size(); i++)
|
||||
|
||||
for (unsigned int i = 0; i<m_previous_sign.size(); i++)
|
||||
{
|
||||
core::vector2df p = m_previous_position[i].toIrrVector2d();
|
||||
m_previous_sign[i] = m_line.getPointOrientation(p)>=0;
|
||||
m_previous_sign[i] = m_line.getPointOrientation(p) >= 0;
|
||||
}
|
||||
} // reset
|
||||
|
||||
@ -158,9 +159,22 @@ bool CheckLine::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
core::vector2df p=new_pos.toIrrVector2d();
|
||||
bool sign = m_line.getPointOrientation(p)>=0;
|
||||
bool result;
|
||||
|
||||
bool previous_sign;
|
||||
|
||||
if (kart_index == -1)
|
||||
{
|
||||
core::vector2df p = old_pos.toIrrVector2d();
|
||||
previous_sign = (m_line.getPointOrientation(p) >= 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_sign = m_previous_sign[kart_index];
|
||||
}
|
||||
|
||||
// If the sign has changed, i.e. the infinite line was crossed somewhere,
|
||||
// check if the finite line was actually crossed:
|
||||
if (sign != m_previous_sign[kart_index] &&
|
||||
if (sign != previous_sign &&
|
||||
m_line.intersectWith(core::line2df(old_pos.toIrrVector2d(),
|
||||
new_pos.toIrrVector2d()),
|
||||
m_cross_point) )
|
||||
@ -188,9 +202,11 @@ bool CheckLine::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
m_previous_sign[kart_index] = sign;
|
||||
|
||||
if (result)
|
||||
if (kart_index != -1)
|
||||
m_previous_sign[kart_index] = sign;
|
||||
|
||||
if (result && kart_index != -1)
|
||||
{
|
||||
LinearWorld* lw = dynamic_cast<LinearWorld*>(w);
|
||||
if (lw != NULL)
|
||||
|
@ -168,7 +168,7 @@ int CheckManager::getChecklineTriggering(const Vec3 &from,
|
||||
// FIXME: why is the lapline skipped?
|
||||
if (dynamic_cast<CheckLap*>(c) != NULL) continue;
|
||||
|
||||
if (c->isTriggered(from, to, 0 /* kart id */))
|
||||
if (c->isTriggered(from, to, -1 /* kart id */))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
|
@ -72,6 +72,7 @@
|
||||
#include <IMeshManipulator.h>
|
||||
#include <IMeshSceneNode.h>
|
||||
#include <ISceneManager.h>
|
||||
#include <SMeshBuffer.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
@ -294,6 +295,11 @@ void Track::cleanup()
|
||||
irr_driver->removeNode(m_all_nodes[i]);
|
||||
}
|
||||
m_all_nodes.clear();
|
||||
|
||||
for (unsigned int i = 0; i < m_static_physics_only_nodes.size(); i++)
|
||||
{
|
||||
m_static_physics_only_nodes[i]->remove();
|
||||
}
|
||||
m_static_physics_only_nodes.clear();
|
||||
|
||||
m_all_emitters.clearAndDeleteAll();
|
||||
@ -737,9 +743,32 @@ void Track::createPhysicsModel(unsigned int main_track_count)
|
||||
for (unsigned int i = 0; i<m_static_physics_only_nodes.size(); i++)
|
||||
{
|
||||
convertTrackToBullet(m_static_physics_only_nodes[i]);
|
||||
irr_driver->removeNode(m_static_physics_only_nodes[i]);
|
||||
if (UserConfigParams::m_physics_debug &&
|
||||
m_static_physics_only_nodes[i]->getType() == scene::ESNT_MESH)
|
||||
{
|
||||
const video::SColor color(255, 255, 105, 180);
|
||||
|
||||
scene::IMesh *mesh = ((scene::IMeshSceneNode*)m_static_physics_only_nodes[i])->getMesh();
|
||||
scene::IMeshBuffer *mb = mesh->getMeshBuffer(0);
|
||||
mb->getMaterial().BackfaceCulling = false;
|
||||
video::S3DVertex * const verts = (video::S3DVertex *) mb->getVertices();
|
||||
const u32 max = mb->getVertexCount();
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
verts[i].Color = color;
|
||||
}
|
||||
|
||||
// Color
|
||||
mb->getMaterial().setTexture(0, getUnicolorTexture(video::SColor(255, 255, 105, 180)));
|
||||
irr_driver->grabAllTextures(mesh);
|
||||
// Gloss
|
||||
mb->getMaterial().setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0)));
|
||||
}
|
||||
else
|
||||
irr_driver->removeNode(m_static_physics_only_nodes[i]);
|
||||
}
|
||||
m_static_physics_only_nodes.clear();
|
||||
if (!UserConfigParams::m_physics_debug)
|
||||
m_static_physics_only_nodes.clear();
|
||||
|
||||
for (unsigned int i = 0; i<m_object_physics_only_nodes.size(); i++)
|
||||
{
|
||||
@ -835,7 +864,7 @@ void Track::convertTrackToBullet(scene::ISceneNode *node)
|
||||
|
||||
for(unsigned int i=0; i<mesh->getMeshBufferCount(); i++)
|
||||
{
|
||||
scene::IMeshBuffer *mb = mesh->getMeshBuffer(i);
|
||||
scene::IMeshBuffer *mb = mesh->getMeshBuffer(i);
|
||||
// FIXME: take translation/rotation into account
|
||||
if (mb->getVertexType() != video::EVT_STANDARD &&
|
||||
mb->getVertexType() != video::EVT_2TCOORDS &&
|
||||
@ -886,6 +915,18 @@ void Track::convertTrackToBullet(scene::ISceneNode *node)
|
||||
if (mb->getVertexType() == video::EVT_STANDARD)
|
||||
{
|
||||
irr::video::S3DVertex* mbVertices=(video::S3DVertex*)mb->getVertices();
|
||||
if (race_manager->getReverseTrack() &&
|
||||
material->getMirrorAxisInReverse() != ' ')
|
||||
{
|
||||
for (unsigned int i = 0; i < mb->getVertexCount(); i++)
|
||||
{
|
||||
core::vector2df &tc = mb->getTCoords(i);
|
||||
if (material->getMirrorAxisInReverse() == 'V')
|
||||
tc.Y = 1 - tc.Y;
|
||||
else
|
||||
tc.X = 1 - tc.X;
|
||||
}
|
||||
} // reverse track and texture needs mirroring
|
||||
for (unsigned int matrix_index = 0; matrix_index < matrices.size(); matrix_index++)
|
||||
{
|
||||
for (unsigned int j = 0; j < mb->getIndexCount(); j += 3)
|
||||
@ -977,7 +1018,6 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
assert(m_gfx_effect_mesh==NULL);
|
||||
|
||||
m_challenges.clear();
|
||||
m_force_fields.clear();
|
||||
|
||||
m_track_mesh = new TriangleMesh();
|
||||
m_gfx_effect_mesh = new TriangleMesh();
|
||||
@ -1106,7 +1146,6 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
core::vector3df xyz(0,0,0);
|
||||
n->get("xyz", &xyz);
|
||||
core::vector3df hpr(0,0,0);
|
||||
@ -1114,117 +1153,6 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
core::vector3df scale(1.0f, 1.0f, 1.0f);
|
||||
n->get("scale", &scale);
|
||||
|
||||
// some static meshes are conditional
|
||||
std::string condition;
|
||||
n->get("if", &condition);
|
||||
|
||||
// TODO: convert "if" and "ifnot" to scripting.
|
||||
if (condition == "splatting")
|
||||
{
|
||||
if (!irr_driver->supportsSplatting()) continue;
|
||||
}
|
||||
else if (condition == "trophies")
|
||||
{
|
||||
// Associate force fields and challenges
|
||||
// FIXME: this assumes that challenges will appear before force fields in scene.xml
|
||||
// (which however seems to be the case atm)
|
||||
int closest_challenge_id = -1;
|
||||
float closest_distance = 99999.0f;
|
||||
for (unsigned int c=0; c<m_challenges.size(); c++)
|
||||
{
|
||||
|
||||
float dist = xyz.getDistanceFromSQ(m_challenges[c].m_position);
|
||||
if (closest_challenge_id == -1 || dist < closest_distance)
|
||||
{
|
||||
closest_challenge_id = c;
|
||||
closest_distance = dist;
|
||||
}
|
||||
}
|
||||
|
||||
assert(closest_challenge_id >= 0);
|
||||
assert(closest_challenge_id < (int)m_challenges.size());
|
||||
|
||||
const std::string &s = m_challenges[closest_challenge_id].m_challenge_id;
|
||||
const ChallengeData* challenge = unlock_manager->getChallengeData(s);
|
||||
if (challenge == NULL)
|
||||
{
|
||||
if (s != "tutorial")
|
||||
Log::error("track", "Cannot find challenge named '%s'\n",
|
||||
m_challenges[closest_challenge_id].m_challenge_id.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
const unsigned int val = challenge->getNumTrophies();
|
||||
bool shown = (PlayerManager::getCurrentPlayer()->getPoints() < val);
|
||||
m_force_fields.push_back(OverworldForceField(xyz, shown, val));
|
||||
|
||||
m_challenges[closest_challenge_id].setForceField(
|
||||
m_force_fields[m_force_fields.size() - 1]);
|
||||
|
||||
core::stringw msg = StringUtils::toWString(val);
|
||||
core::dimension2d<u32> textsize = GUIEngine::getHighresDigitFont()
|
||||
->getDimension(msg.c_str());
|
||||
|
||||
assert(GUIEngine::getHighresDigitFont() != NULL);
|
||||
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
gui::ScalableFont* font = GUIEngine::getHighresDigitFont();
|
||||
STKTextBillboard* tb = new STKTextBillboard(msg.c_str(), font,
|
||||
video::SColor(255, 255, 225, 0),
|
||||
video::SColor(255, 255, 89, 0),
|
||||
irr_driver->getSceneManager()->getRootSceneNode(),
|
||||
irr_driver->getSceneManager(), -1, xyz,
|
||||
core::vector3df(1.5f, 1.5f, 1.5f));
|
||||
m_all_nodes.push_back(tb);
|
||||
}
|
||||
else
|
||||
{
|
||||
scene::ISceneManager* sm = irr_driver->getSceneManager();
|
||||
scene::ISceneNode* sn =
|
||||
sm->addBillboardTextSceneNode(GUIEngine::getHighresDigitFont(),
|
||||
msg.c_str(),
|
||||
NULL,
|
||||
core::dimension2df(textsize.Width / 35.0f,
|
||||
textsize.Height / 35.0f),
|
||||
xyz,
|
||||
-1, // id
|
||||
video::SColor(255, 255, 225, 0),
|
||||
video::SColor(255, 255, 89, 0));
|
||||
m_all_nodes.push_back(sn);
|
||||
}
|
||||
|
||||
if (!shown) continue;
|
||||
}
|
||||
else if (condition.size() > 0)
|
||||
{
|
||||
unsigned char result = -1;
|
||||
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||
std::function<void(asIScriptContext*)> null_callback;
|
||||
script_engine->runFunction(true, "bool " + condition + "()", null_callback,
|
||||
[&](asIScriptContext* ctx) { result = ctx->GetReturnByte(); });
|
||||
if (result == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string neg_condition;
|
||||
n->get("ifnot", &neg_condition);
|
||||
if (neg_condition == "splatting")
|
||||
{
|
||||
if (irr_driver->supportsSplatting()) continue;
|
||||
}
|
||||
else if (neg_condition.size() > 0)
|
||||
{
|
||||
unsigned char result = -1;
|
||||
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||
std::function<void(asIScriptContext*)> null_callback;
|
||||
script_engine->runFunction(true, "bool " + neg_condition + "()", null_callback,
|
||||
[&](asIScriptContext* ctx) { result = ctx->GetReturnByte(); });
|
||||
if (result != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
bool tangent = false;
|
||||
n->get("tangents", &tangent);
|
||||
|
||||
@ -1242,49 +1170,6 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
bool lod_instance = false;
|
||||
n->get("lod_instance", &lod_instance);
|
||||
|
||||
/*
|
||||
if (tangent)
|
||||
{
|
||||
scene::IMesh* original_mesh = irr_driver->getMesh(full_path);
|
||||
|
||||
if (std::find(m_detached_cached_meshes.begin(),
|
||||
m_detached_cached_meshes.end(),
|
||||
original_mesh) == m_detached_cached_meshes.end())
|
||||
{
|
||||
m_detached_cached_meshes.push_back(original_mesh);
|
||||
}
|
||||
|
||||
// create a node out of this mesh just for bullet; delete it after, normal maps are special
|
||||
// and require tangent meshes
|
||||
scene_node = irr_driver->addMesh(original_mesh, "original_mesh");
|
||||
|
||||
scene_node->setPosition(xyz);
|
||||
scene_node->setRotation(hpr);
|
||||
scene_node->setScale(scale);
|
||||
|
||||
convertTrackToBullet(scene_node);
|
||||
scene_node->remove();
|
||||
irr_driver->grabAllTextures(original_mesh);
|
||||
|
||||
scene::IMesh* mesh = MeshTools::createMeshWithTangents(original_mesh, &MeshTools::isNormalMap);
|
||||
mesh->grab();
|
||||
irr_driver->grabAllTextures(mesh);
|
||||
|
||||
m_all_cached_meshes.push_back(mesh);
|
||||
scene_node = irr_driver->addMesh(mesh, "original_mesh_with_tangents");
|
||||
scene_node->setPosition(xyz);
|
||||
scene_node->setRotation(hpr);
|
||||
scene_node->setScale(scale);
|
||||
|
||||
#ifdef DEBUG
|
||||
std::string debug_name = model_name+" (tangent static track-object)";
|
||||
scene_node->setName(debug_name.c_str());
|
||||
#endif
|
||||
|
||||
handleAnimatedTextures(scene_node, *n);
|
||||
m_all_nodes.push_back( scene_node );
|
||||
}
|
||||
else*/
|
||||
if (lod_instance)
|
||||
{
|
||||
LODNode* node = lodLoader.instanciateAsLOD(n, NULL);
|
||||
@ -1334,6 +1219,7 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
handleAnimatedTextures(scene_node, *n);
|
||||
|
||||
// for challenge orbs, a bit more work to do
|
||||
// TODO: this is hardcoded for the overworld, convert to scripting
|
||||
if (challenge.size() > 0)
|
||||
{
|
||||
const ChallengeData* c = NULL;
|
||||
@ -1737,7 +1623,14 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
|
||||
|
||||
if (!m_is_arena && !m_is_soccer && !m_is_cutscene)
|
||||
{
|
||||
m_start_transforms.resize(race_manager->getNumberOfKarts());
|
||||
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
// In a FTL race the non-leader karts are placed at the end of the
|
||||
// field, so we need all start positions.
|
||||
m_start_transforms.resize(stk_config->m_max_karts);
|
||||
}
|
||||
else
|
||||
m_start_transforms.resize(race_manager->getNumberOfKarts());
|
||||
QuadGraph::get()->setDefaultStartPositions(&m_start_transforms,
|
||||
karts_per_row,
|
||||
forwards_distance,
|
||||
@ -1792,6 +1685,8 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
|
||||
|
||||
model_def_loader.cleanLibraryNodesAfterLoad();
|
||||
|
||||
World::getWorld()->getScriptEngine()->compileLoadedScripts();
|
||||
|
||||
// Init all track objects
|
||||
m_track_object_manager->init();
|
||||
|
||||
@ -1866,7 +1761,9 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
|
||||
// ---- Set ambient color
|
||||
m_ambient_color = m_default_ambient_color;
|
||||
irr_driver->getSceneManager()->setAmbientLight(m_ambient_color);
|
||||
|
||||
if (m_spherical_harmonics_textures.size() != 6)
|
||||
irr_driver->getSphericalHarmonics()->setAmbientLight(m_ambient_color);
|
||||
|
||||
// ---- Create sun (non-ambient directional light)
|
||||
if (m_sun_position.getLengthSQ() < 0.03f)
|
||||
{
|
||||
|
@ -69,30 +69,10 @@ namespace Scripting
|
||||
|
||||
const int HEIGHT_MAP_RESOLUTION = 256;
|
||||
|
||||
struct OverworldForceField
|
||||
{
|
||||
core::vector3df m_position;
|
||||
bool m_is_locked;
|
||||
int m_required_points;
|
||||
|
||||
OverworldForceField()
|
||||
{
|
||||
}
|
||||
|
||||
OverworldForceField(core::vector3df position, bool is_locked, int required_points)
|
||||
{
|
||||
m_position = position;
|
||||
m_is_locked = is_locked;
|
||||
m_required_points = required_points;
|
||||
}
|
||||
};
|
||||
// TODO: eventually remove this and fully replace with scripting
|
||||
struct OverworldChallenge
|
||||
{
|
||||
private:
|
||||
OverworldForceField m_force_field;
|
||||
bool m_force_field_set;
|
||||
public:
|
||||
|
||||
core::vector3df m_position;
|
||||
std::string m_challenge_id;
|
||||
|
||||
@ -100,27 +80,6 @@ public:
|
||||
{
|
||||
m_position = position;
|
||||
m_challenge_id = challenge_id;
|
||||
m_force_field_set = false;
|
||||
}
|
||||
|
||||
void setForceField(OverworldForceField f)
|
||||
{
|
||||
m_force_field = f;
|
||||
m_force_field_set = true;
|
||||
}
|
||||
|
||||
OverworldForceField& getForceField()
|
||||
{
|
||||
assert(m_force_field_set);
|
||||
return m_force_field;
|
||||
}
|
||||
|
||||
bool isForceFieldSet() const { return m_force_field_set; }
|
||||
|
||||
const OverworldForceField& getForceField() const
|
||||
{
|
||||
assert(m_force_field_set);
|
||||
return m_force_field;
|
||||
}
|
||||
};
|
||||
|
||||
@ -160,8 +119,6 @@ private:
|
||||
/** Will only be used on overworld */
|
||||
std::vector<OverworldChallenge> m_challenges;
|
||||
|
||||
std::vector<OverworldForceField> m_force_fields;
|
||||
|
||||
std::vector<Subtitle> m_subtitles;
|
||||
|
||||
/** Start transforms of karts (either the default, or the ones taken
|
||||
@ -523,7 +480,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the start coordinates for a kart with a given index.
|
||||
* \param index Index of kart ranging from 0 to kart_num-1. */
|
||||
btTransform getStartTransform (unsigned int index) const
|
||||
const btTransform& getStartTransform (unsigned int index) const
|
||||
{
|
||||
if (index >= m_start_transforms.size())
|
||||
Log::fatal("Track", "No start position for kart %i.", index);
|
||||
|
@ -131,23 +131,11 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent,
|
||||
m_type = type;
|
||||
|
||||
m_initially_visible = true;
|
||||
std::string condition;
|
||||
xml_node.get("if", &condition);
|
||||
if (condition == "false")
|
||||
xml_node.get("if", &m_visibility_condition);
|
||||
if (m_visibility_condition == "false")
|
||||
{
|
||||
m_initially_visible = false;
|
||||
}
|
||||
else if (condition.size() > 0)
|
||||
{
|
||||
unsigned char result = -1;
|
||||
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||
std::function<void(asIScriptContext*)> null_callback;
|
||||
script_engine->runFunction(true, "bool " + condition + "()", null_callback,
|
||||
[&](asIScriptContext* ctx) { result = ctx->GetReturnByte(); });
|
||||
|
||||
if (result == 0)
|
||||
m_initially_visible = false;
|
||||
}
|
||||
if (!m_initially_visible)
|
||||
setEnabled(false);
|
||||
|
||||
@ -295,6 +283,68 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent,
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void TrackObject::onWorldReady()
|
||||
{
|
||||
if (m_visibility_condition == "false")
|
||||
{
|
||||
m_initially_visible = false;
|
||||
}
|
||||
else if (m_visibility_condition.size() > 0)
|
||||
{
|
||||
unsigned char result = -1;
|
||||
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||
|
||||
std::ostringstream fn_signature;
|
||||
std::vector<std::string> arguments;
|
||||
if (m_visibility_condition.find("(") != std::string::npos &&
|
||||
m_visibility_condition.find(")") != std::string::npos)
|
||||
{
|
||||
// There are arguments to pass to the function
|
||||
// TODO: For the moment we only support string arguments
|
||||
// TODO: this parsing could be improved
|
||||
unsigned first = m_visibility_condition.find("(");
|
||||
unsigned last = m_visibility_condition.find_last_of(")");
|
||||
std::string fn_name = m_visibility_condition.substr(0, first);
|
||||
std::string str_arguments = m_visibility_condition.substr(first + 1, last - first - 1);
|
||||
arguments = StringUtils::split(str_arguments, ',');
|
||||
|
||||
fn_signature << "bool " << fn_name << "(";
|
||||
|
||||
for (int i = 0; i < arguments.size(); i++)
|
||||
{
|
||||
if (i > 0)
|
||||
fn_signature << ",";
|
||||
fn_signature << "string";
|
||||
}
|
||||
|
||||
fn_signature << ",Track::TrackObject@)";
|
||||
}
|
||||
else
|
||||
{
|
||||
fn_signature << "bool " << m_visibility_condition << "(Track::TrackObject@)";
|
||||
}
|
||||
|
||||
TrackObject* self = this;
|
||||
script_engine->runFunction(true, fn_signature.str(),
|
||||
[&](asIScriptContext* ctx)
|
||||
{
|
||||
for (int i = 0; i < arguments.size(); i++)
|
||||
{
|
||||
ctx->SetArgObject(i, &arguments[i]);
|
||||
}
|
||||
ctx->SetArgObject(arguments.size(), self);
|
||||
},
|
||||
[&](asIScriptContext* ctx) { result = ctx->GetReturnByte(); });
|
||||
|
||||
if (result == 0)
|
||||
m_initially_visible = false;
|
||||
}
|
||||
if (!m_initially_visible)
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/** Destructor. Removes the node from the scene graph, and also
|
||||
* drops the textures of the mesh. Sound buffers are also freed.
|
||||
*/
|
||||
@ -456,6 +506,17 @@ const core::vector3df& TrackObject::getPosition() const
|
||||
return m_init_xyz;
|
||||
} // getPosition
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const core::vector3df TrackObject::getAbsoluteCenterPosition() const
|
||||
{
|
||||
if (m_presentation != NULL)
|
||||
return m_presentation->getAbsoluteCenterPosition();
|
||||
else
|
||||
return m_init_xyz;
|
||||
} // getAbsolutePosition
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const core::vector3df TrackObject::getAbsolutePosition() const
|
||||
@ -483,7 +544,7 @@ const core::vector3df& TrackObject::getScale() const
|
||||
if (m_presentation != NULL)
|
||||
return m_presentation->getScale();
|
||||
else
|
||||
return m_init_xyz;
|
||||
return m_init_scale;
|
||||
} // getScale
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -94,6 +94,8 @@ protected:
|
||||
|
||||
bool m_initially_visible;
|
||||
|
||||
std::string m_visibility_condition;
|
||||
|
||||
void init(const XMLNode &xml_node, scene::ISceneNode* parent,
|
||||
ModelDefinitionLoader& model_def_loader,
|
||||
TrackObject* parent_library);
|
||||
@ -120,6 +122,7 @@ public:
|
||||
virtual void reset();
|
||||
const core::vector3df& getPosition() const;
|
||||
const core::vector3df getAbsolutePosition() const;
|
||||
const core::vector3df getAbsoluteCenterPosition() const;
|
||||
const core::vector3df& getRotation() const;
|
||||
const core::vector3df& getScale() const;
|
||||
bool castRay(const btVector3 &from,
|
||||
@ -135,7 +138,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** To finish object constructions. Called after the track model
|
||||
* is ready. */
|
||||
virtual void init() {};
|
||||
virtual void onWorldReady();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when an explosion happens. As a default does nothing, will
|
||||
* e.g. be overwritten by physical objects etc. */
|
||||
|
@ -66,11 +66,9 @@ void TrackObjectManager::add(const XMLNode &xml_node, scene::ISceneNode* parent,
|
||||
*/
|
||||
void TrackObjectManager::init()
|
||||
{
|
||||
|
||||
TrackObject* curr;
|
||||
for_in (curr, m_all_objects)
|
||||
for_var_in(TrackObject*, curr, m_all_objects)
|
||||
{
|
||||
curr->init();
|
||||
curr->onWorldReady();
|
||||
}
|
||||
} // reset
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -88,6 +88,16 @@ const core::vector3df TrackObjectPresentationSceneNode::getAbsolutePosition() co
|
||||
return m_node->getAbsolutePosition();
|
||||
} // getAbsolutePosition
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const core::vector3df TrackObjectPresentationSceneNode::getAbsoluteCenterPosition() const
|
||||
{
|
||||
if (m_node == NULL) return m_init_xyz;
|
||||
m_node->updateAbsolutePosition();
|
||||
core::aabbox3d<f32> bounds = m_node->getTransformedBoundingBox();
|
||||
return bounds.getCenter();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
const core::vector3df& TrackObjectPresentationSceneNode::getRotation() const
|
||||
{
|
||||
@ -583,6 +593,7 @@ TrackObjectPresentationSound::TrackObjectPresentationSound(
|
||||
{
|
||||
// TODO: respect 'parent' if any
|
||||
|
||||
m_enabled = true;
|
||||
m_sound = NULL;
|
||||
m_xyz = m_init_xyz;
|
||||
|
||||
@ -642,7 +653,7 @@ TrackObjectPresentationSound::TrackObjectPresentationSound(
|
||||
// ----------------------------------------------------------------------------
|
||||
void TrackObjectPresentationSound::update(float dt)
|
||||
{
|
||||
if (m_sound != NULL)
|
||||
if (m_sound != NULL && m_enabled)
|
||||
{
|
||||
// muting when too far is implemented manually since not supported by
|
||||
// OpenAL so need to call this every frame to update the muting state
|
||||
@ -654,7 +665,7 @@ void TrackObjectPresentationSound::update(float dt)
|
||||
// ----------------------------------------------------------------------------
|
||||
void TrackObjectPresentationSound::onTriggerItemApproached()
|
||||
{
|
||||
if (m_sound != NULL && m_sound->getStatus() != SFXBase::SFX_PLAYING)
|
||||
if (m_sound != NULL && m_sound->getStatus() != SFXBase::SFX_PLAYING && m_enabled)
|
||||
{
|
||||
m_sound->play();
|
||||
}
|
||||
@ -663,7 +674,7 @@ void TrackObjectPresentationSound::onTriggerItemApproached()
|
||||
// ----------------------------------------------------------------------------
|
||||
void TrackObjectPresentationSound::triggerSound(bool loop)
|
||||
{
|
||||
if (m_sound != NULL)
|
||||
if (m_sound != NULL && m_enabled)
|
||||
{
|
||||
m_sound->setLoop(loop);
|
||||
m_sound->play();
|
||||
@ -673,7 +684,8 @@ void TrackObjectPresentationSound::triggerSound(bool loop)
|
||||
// ----------------------------------------------------------------------------
|
||||
void TrackObjectPresentationSound::stopSound()
|
||||
{
|
||||
if (m_sound != NULL) m_sound->stop();
|
||||
if (m_sound != NULL)
|
||||
m_sound->stop();
|
||||
} // stopSound
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -692,9 +704,24 @@ void TrackObjectPresentationSound::move(const core::vector3df& xyz,
|
||||
bool isAbsoluteCoord)
|
||||
{
|
||||
m_xyz = xyz;
|
||||
if (m_sound != NULL) m_sound->setPosition(xyz);
|
||||
if (m_sound != NULL && m_enabled)
|
||||
m_sound->setPosition(xyz);
|
||||
} // move
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void TrackObjectPresentationSound::setEnable(bool enabled)
|
||||
{
|
||||
if (enabled != m_enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
if (enabled)
|
||||
triggerSound(true);
|
||||
else
|
||||
stopSound();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
TrackObjectPresentationBillboard::TrackObjectPresentationBillboard(
|
||||
const XMLNode& xml_node,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user