Merge remote-tracking branch 'origin/master' into refactor_networking
This commit is contained in:
commit
b8ed2025ed
@ -4,6 +4,7 @@
|
||||
<card is="Intel(R) HD Graphics 3000" os="windows" disable="AdvancedPipeline"/>
|
||||
<card is="Intel(R) HD Graphics 3000" os="windows" disable="FramebufferSRGBWorking"/>
|
||||
<card contains="Intel" os="osx" disable="GI"/>
|
||||
<card contains="Intel" os="linux" version="<12.0" disable="ComputeShader"/>
|
||||
<card contains="Intel" os="linux" version="<12.0" disable="FramebufferSRGBCapable"/>
|
||||
<card contains="Intel" disable="TextureCompressionS3TC"/>
|
||||
<card contains="Intel" os="windows" disable="HighDefinitionTextures"/>
|
||||
|
@ -40,9 +40,12 @@
|
||||
<label id="highscore3" proportion="1" text="(Empty)"/>
|
||||
</div>
|
||||
|
||||
<spacer width="1" height="10%"/>
|
||||
<spacer width="1" height="2%"/>
|
||||
|
||||
<label id="author" width="100%" text_align="center" word_wrap="true"/>
|
||||
|
||||
<spacer width="1" height="10%"/>
|
||||
<label id="max-arena-players" width="100%" text_align="center" word_wrap="true"/>
|
||||
</div>
|
||||
|
||||
</box>
|
||||
|
@ -99,8 +99,10 @@
|
||||
|
||||
#if !defined(_IRR_WINDOWS_API_) && !defined(_IRR_OSX_PLATFORM_)
|
||||
#ifndef _IRR_SOLARIS_PLATFORM_
|
||||
#if !defined(__linux__) && !defined(__FreeBSD__)
|
||||
#define _IRR_LINUX_PLATFORM_
|
||||
#endif
|
||||
#endif
|
||||
#define _IRR_POSIX_API_
|
||||
#define _IRR_COMPILE_WITH_X11_DEVICE_
|
||||
#endif
|
||||
|
@ -267,6 +267,36 @@ public:
|
||||
|
||||
*this = &tmpbuf[idx];
|
||||
}
|
||||
|
||||
//! Constructs a string from an unsigned long long
|
||||
explicit string(unsigned long long number)
|
||||
: array(0), allocated(0), used(0)
|
||||
{
|
||||
// temporary buffer for 32 numbers
|
||||
|
||||
c8 tmpbuf[32]={0};
|
||||
u32 idx = 31;
|
||||
|
||||
// special case '0'
|
||||
|
||||
if (!number)
|
||||
{
|
||||
tmpbuf[30] = '0';
|
||||
*this = &tmpbuf[30];
|
||||
return;
|
||||
}
|
||||
|
||||
// add numbers
|
||||
|
||||
while(number && idx)
|
||||
{
|
||||
--idx;
|
||||
tmpbuf[idx] = (c8)('0' + (number % 10));
|
||||
number /= 10;
|
||||
}
|
||||
|
||||
*this = &tmpbuf[idx];
|
||||
}
|
||||
|
||||
|
||||
//! Constructor for copying a string from a pointer with a given length
|
||||
|
@ -2028,7 +2028,7 @@ public:
|
||||
{
|
||||
u32 tmp;
|
||||
sscanf(text, "0x%x", &tmp);
|
||||
Value = (void *) tmp;
|
||||
Value = reinterpret_cast<void *>(tmp);
|
||||
}
|
||||
|
||||
virtual E_ATTRIBUTE_TYPE getType() const
|
||||
|
@ -39,7 +39,7 @@ extern bool GLContextDebugBit;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/joystick.h>
|
||||
#else
|
||||
#elif defined(__linux__)
|
||||
|
||||
// linux/joystick.h includes linux/input.h, which #defines values for various KEY_FOO keys.
|
||||
// These override the irr::KEY_FOO equivalents, which stops key handling from working.
|
||||
@ -2185,7 +2185,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
|
||||
#ifdef __FreeBSD__
|
||||
info.axes=2;
|
||||
info.buttons=2;
|
||||
#else
|
||||
#elif defined(__linux__)
|
||||
ioctl( info.fd, JSIOCGAXES, &(info.axes) );
|
||||
ioctl( info.fd, JSIOCGBUTTONS, &(info.buttons) );
|
||||
fcntl( info.fd, F_SETFL, O_NONBLOCK );
|
||||
@ -2207,7 +2207,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
|
||||
returnInfo.Axes = info.axes;
|
||||
returnInfo.Buttons = info.buttons;
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
|
||||
char name[80];
|
||||
ioctl( info.fd, JSIOCGNAME(80), name);
|
||||
returnInfo.Name = name;
|
||||
@ -2252,7 +2252,7 @@ void CIrrDeviceLinux::pollJoysticks()
|
||||
info.persistentData.JoystickEvent.Axis[0] = js.x; /* X axis */
|
||||
info.persistentData.JoystickEvent.Axis[1] = js.y; /* Y axis */
|
||||
}
|
||||
#else
|
||||
#elif defined(__linux__)
|
||||
struct js_event event;
|
||||
while (sizeof(event) == read(info.fd, &event, sizeof(event)))
|
||||
{
|
||||
|
@ -478,7 +478,7 @@ bool CIrrDeviceSDL::run()
|
||||
joyevent.JoystickEvent.ButtonStates |= (SDL_JoystickGetButton(joystick, j)<<j);
|
||||
|
||||
// query all axes, already in correct range
|
||||
const int numAxes = core::min_(SDL_JoystickNumAxes(joystick), SEvent::SJoystickEvent::NUMBER_OF_AXES);
|
||||
const int numAxes = core::min_(SDL_JoystickNumAxes(joystick), static_cast<int>(SEvent::SJoystickEvent::NUMBER_OF_AXES));
|
||||
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X]=0;
|
||||
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y]=0;
|
||||
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z]=0;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#if !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__CYGWIN__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
@ -22,10 +22,14 @@
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define bswap_16(X) OSReadSwapInt16(&X,0)
|
||||
#define bswap_32(X) OSReadSwapInt32(&X,0)
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/endian.h>
|
||||
#define bswap_16(X) bswap16(X)
|
||||
#define bswap_32(X) bswap32(X)
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <endian.h>
|
||||
#define bswap_16(X) swap16(X)
|
||||
#define bswap_32(X) swap32(X)
|
||||
#elif !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__PPC__) && !defined(_IRR_WINDOWS_API_)
|
||||
#include <byteswap.h>
|
||||
#else
|
||||
|
@ -36,6 +36,7 @@ void CentralVideoSettings::init()
|
||||
hasBuffserStorage = false;
|
||||
hasDrawIndirect = false;
|
||||
hasComputeShaders = false;
|
||||
hasArraysOfArrays = false;
|
||||
hasTextureStorage = false;
|
||||
hasTextureView = false;
|
||||
hasBindlessTexture = false;
|
||||
@ -46,11 +47,11 @@ void CentralVideoSettings::init()
|
||||
hasTextureCompression = false;
|
||||
hasUBO = false;
|
||||
hasGS = false;
|
||||
hasSRGBCapableVisual = true;
|
||||
m_GI_has_artifact = false;
|
||||
|
||||
m_GI_has_artifact = false;
|
||||
m_need_rh_workaround = false;
|
||||
m_need_srgb_workaround = false;
|
||||
m_need_srgb_visual_workaround = false;
|
||||
|
||||
// Call to glGetIntegerv should not be made if --no-graphics is used
|
||||
if (!ProfileWorld::isNoGraphics())
|
||||
@ -103,6 +104,11 @@ void CentralVideoSettings::init()
|
||||
hasComputeShaders = true;
|
||||
Log::info("GLDriver", "ARB Compute Shader Present");
|
||||
}
|
||||
if (!GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_ARRAYS_OF_ARRAYS) &&
|
||||
hasGLExtension("GL_ARB_arrays_of_arrays")) {
|
||||
hasArraysOfArrays = true;
|
||||
Log::info("GLDriver", "ARB Arrays of Arrays Present");
|
||||
}
|
||||
if (!GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_TEXTURE_STORAGE) &&
|
||||
hasGLExtension("GL_ARB_texture_storage")) {
|
||||
hasTextureStorage = true;
|
||||
@ -188,7 +194,7 @@ void CentralVideoSettings::init()
|
||||
GLint param = GL_SRGB;
|
||||
glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_BACK_LEFT,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, ¶m);
|
||||
hasSRGBCapableVisual = (param == GL_SRGB);
|
||||
m_need_srgb_visual_workaround = (param != GL_SRGB);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -220,7 +226,7 @@ bool CentralVideoSettings::needsRGBBindlessWorkaround() const
|
||||
|
||||
bool CentralVideoSettings::needsSRGBCapableVisualWorkaround() const
|
||||
{
|
||||
return !hasSRGBCapableVisual;
|
||||
return m_need_srgb_visual_workaround;
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::isARBGeometryShader4Usable() const
|
||||
@ -263,6 +269,11 @@ bool CentralVideoSettings::isARBComputeShaderUsable() const
|
||||
return hasComputeShaders;
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::isARBArraysOfArraysUsable() const
|
||||
{
|
||||
return hasArraysOfArrays;
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::isARBTextureStorageUsable() const
|
||||
{
|
||||
return hasTextureStorage;
|
||||
@ -315,7 +326,7 @@ bool CentralVideoSettings::supportsIndirectInstancingRendering() const
|
||||
|
||||
bool CentralVideoSettings::supportsComputeShadersFiltering() const
|
||||
{
|
||||
return isARBBufferStorageUsable() && isARBImageLoadStoreUsable() && isARBComputeShaderUsable();
|
||||
return isARBBufferStorageUsable() && isARBImageLoadStoreUsable() && isARBComputeShaderUsable() && isARBArraysOfArraysUsable();
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::supportsAsyncInstanceUpload() const
|
||||
|
@ -30,6 +30,7 @@ private:
|
||||
bool hasDrawIndirect;
|
||||
bool hasBuffserStorage;
|
||||
bool hasComputeShaders;
|
||||
bool hasArraysOfArrays;
|
||||
bool hasTextureStorage;
|
||||
bool hasTextureView;
|
||||
bool hasBindlessTexture;
|
||||
@ -40,10 +41,10 @@ private:
|
||||
bool hasSSBO;
|
||||
bool hasImageLoadStore;
|
||||
bool hasMultiDrawIndirect;
|
||||
bool hasSRGBCapableVisual;
|
||||
|
||||
bool m_need_rh_workaround;
|
||||
bool m_need_srgb_workaround;
|
||||
bool m_need_srgb_visual_workaround;
|
||||
bool m_GI_has_artifact;
|
||||
public:
|
||||
void init();
|
||||
@ -63,6 +64,7 @@ public:
|
||||
bool isARBTextureStorageUsable() const;
|
||||
bool isAMDVertexShaderLayerUsable() const;
|
||||
bool isARBComputeShaderUsable() const;
|
||||
bool isARBArraysOfArraysUsable() const;
|
||||
bool isARBBindlessTextureUsable() const;
|
||||
bool isARBBufferStorageUsable() const;
|
||||
bool isARBBaseInstanceUsable() const;
|
||||
|
@ -48,6 +48,7 @@ namespace GraphicsRestrictions
|
||||
"ImageLoadStore",
|
||||
"BaseInstance",
|
||||
"ComputeShader",
|
||||
"ArraysOfArrays",
|
||||
"ShaderStorageBufferObject",
|
||||
"MultiDrawIndirect",
|
||||
"ShaderAtomicCounters",
|
||||
|
@ -42,6 +42,7 @@ namespace GraphicsRestrictions
|
||||
GR_IMAGE_LOAD_STORE,
|
||||
GR_BASE_INSTANCE,
|
||||
GR_COMPUTE_SHADER,
|
||||
GR_ARRAYS_OF_ARRAYS,
|
||||
GR_SHADER_STORAGE_BUFFER_OBJECT,
|
||||
GR_MULTI_DRAW_INDIRECT,
|
||||
GR_SHADER_ATOMIC_COUNTERS,
|
||||
|
@ -66,8 +66,24 @@ GLuint ShaderBase::loadShader(const std::string &file, unsigned type)
|
||||
std::ostringstream code;
|
||||
code << "#version " << CVS->getGLSLVersion()<<"\n";
|
||||
|
||||
// Some drivers report that the compute shaders extension is available,
|
||||
// but they report only OpenGL 3.x version, and thus these extensions
|
||||
// must be enabled manually. Otherwise the shaders compilation will fail
|
||||
// because STK tries to use extensions which are available, but disabled
|
||||
// by default.
|
||||
if (type == GL_COMPUTE_SHADER)
|
||||
{
|
||||
if (CVS->isARBComputeShaderUsable())
|
||||
code << "#extension GL_ARB_compute_shader : enable\n";
|
||||
if (CVS->isARBImageLoadStoreUsable())
|
||||
code << "#extension GL_ARB_shader_image_load_store : enable\n";
|
||||
if (CVS->isARBArraysOfArraysUsable())
|
||||
code << "#extension GL_ARB_arrays_of_arrays : enable\n";
|
||||
}
|
||||
|
||||
if (CVS->isAMDVertexShaderLayerUsable())
|
||||
code << "#extension GL_AMD_vertex_shader_layer : enable\n";
|
||||
|
||||
if (CVS->isAZDOEnabled())
|
||||
{
|
||||
code << "#extension GL_ARB_bindless_texture : enable\n";
|
||||
@ -80,7 +96,7 @@ GLuint ShaderBase::loadShader(const std::string &file, unsigned type)
|
||||
code << "#define VSLayer\n";
|
||||
if (CVS->needsRGBBindlessWorkaround())
|
||||
code << "#define SRGBBindlessFix\n";
|
||||
|
||||
|
||||
//shader compilation fails with some drivers if there is no precision qualifier
|
||||
if (type == GL_FRAGMENT_SHADER)
|
||||
code << "precision mediump float;\n";
|
||||
|
@ -491,6 +491,7 @@ std::set<wchar_t> ScalableFont::getPreloadCharacters(const GUIEngine::TTFLoading
|
||||
preload_char.insert((wchar_t)i); //Include basic Latin too, starting from A (char code 65)
|
||||
|
||||
setlocale(LC_ALL, "en_US.UTF8");
|
||||
std::set<wchar_t> upper;
|
||||
std::set<wchar_t>::iterator it = preload_char.begin();
|
||||
|
||||
while (it != preload_char.end())
|
||||
@ -498,7 +499,15 @@ std::set<wchar_t> ScalableFont::getPreloadCharacters(const GUIEngine::TTFLoading
|
||||
//Only use all capital letter for bold char with latin (<640 of char code).
|
||||
//Remove all characters (>char code 8191) not used by the title
|
||||
if (((iswlower((wchar_t)*it) || !iswalpha((wchar_t)*it)) && *it < 640) || *it > 8191)
|
||||
{
|
||||
if (*it < 8192 && iswalpha((wchar_t)*it))
|
||||
{
|
||||
//Make sure we include all upper case letters,
|
||||
//because the title font shows all characters as capital letters
|
||||
upper.insert(towupper((wchar_t)*it));
|
||||
}
|
||||
it = preload_char.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
@ -507,6 +516,7 @@ std::set<wchar_t> ScalableFont::getPreloadCharacters(const GUIEngine::TTFLoading
|
||||
for (u32 i = 32; i < 65; ++i)
|
||||
preload_char.insert((wchar_t)i); //Include basic symbol (from space (char code 32) to @(char code 64))
|
||||
|
||||
preload_char.insert(upper.begin(), upper.end());
|
||||
preload_char.insert((wchar_t)160); //Non-breaking space
|
||||
|
||||
//Remove Ordinal indicator (char code 170 and 186)
|
||||
|
@ -447,6 +447,9 @@ public:
|
||||
/** Counter which is used for displaying wrong way message after a delay */
|
||||
virtual float getWrongwayCounter() = 0;
|
||||
virtual void setWrongwayCounter(float counter) = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart wins or loses. */
|
||||
virtual bool getRaceResult() const = 0;
|
||||
|
||||
}; // AbstractKart
|
||||
|
||||
|
@ -23,10 +23,6 @@
|
||||
#include "states_screens/state_manager.hpp"
|
||||
|
||||
class AIProperties;
|
||||
class LinearWorld;
|
||||
class ThreeStrikesBattle;
|
||||
class QuadGraph;
|
||||
class BattleGraph;
|
||||
class Track;
|
||||
class Vec3;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
|
||||
// Copyright (C) 2006-2007 Eduardo Hernandez Munoz
|
||||
// Copyright (C) 2008-2012 Joerg Henrichs
|
||||
// Copyright (C) 2008-2015 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -33,8 +33,7 @@
|
||||
#include "karts/rescue_animation.hpp"
|
||||
#include "karts/skidding.hpp"
|
||||
#include "modes/three_strikes_battle.hpp"
|
||||
#include "tracks/nav_poly.hpp"
|
||||
#include "tracks/navmesh.hpp"
|
||||
#include "tracks/battle_graph.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
@ -96,19 +95,21 @@ BattleAI::~BattleAI()
|
||||
*/
|
||||
void BattleAI::reset()
|
||||
{
|
||||
m_current_node = BattleGraph::UNKNOWN_POLY;
|
||||
m_target_node = BattleGraph::UNKNOWN_POLY;
|
||||
m_adjusting_side = false;
|
||||
m_closest_kart = NULL;
|
||||
m_closest_kart_node = BattleGraph::UNKNOWN_POLY;
|
||||
m_closest_kart_point = Vec3(0, 0, 0);
|
||||
m_closest_kart_pos_data = {0};
|
||||
m_cur_kart_pos_data = {0};
|
||||
m_is_steering_overridden = false;
|
||||
m_is_stuck = false;
|
||||
m_is_uturn = false;
|
||||
m_target_point = Vec3(0, 0, 0);
|
||||
m_time_since_last_shot = 0.0f;
|
||||
m_time_since_driving = 0.0f;
|
||||
m_time_since_reversing = 0.0f;
|
||||
m_time_since_steering_overridden = 0.0f;
|
||||
m_time_since_uturn = 0.0f;
|
||||
m_on_node.clear();
|
||||
m_path_corners.clear();
|
||||
@ -165,6 +166,7 @@ void BattleAI::update(float dt)
|
||||
findClosestKart(true);
|
||||
findTarget();
|
||||
handleItems(dt);
|
||||
handleBanana();
|
||||
|
||||
if (m_kart->getSpeed() > 15.0f && m_cur_kart_pos_data.angle < 0.2f)
|
||||
{
|
||||
@ -198,7 +200,7 @@ void BattleAI::checkIfStuck(const float dt)
|
||||
m_time_since_driving = 0.0f;
|
||||
}
|
||||
|
||||
m_on_node.insert(m_current_node);
|
||||
m_on_node.insert(m_world->getKartNode(m_kart->getWorldKartId()));
|
||||
m_time_since_driving += dt;
|
||||
|
||||
if ((m_time_since_driving >=
|
||||
@ -291,19 +293,8 @@ void BattleAI::findClosestKart(bool difficulty)
|
||||
}
|
||||
|
||||
const AbstractKart* closest_kart = m_world->getKart(closest_kart_num);
|
||||
if (!closest_kart->getController()->isPlayerController())
|
||||
{
|
||||
BattleAI* controller = (BattleAI*)(closest_kart->getController());
|
||||
m_closest_kart_node = controller->getCurrentNode();
|
||||
m_closest_kart_point = closest_kart->getXYZ();
|
||||
}
|
||||
|
||||
else if (closest_kart->getController()->isPlayerController())
|
||||
{
|
||||
PlayerController* controller = (PlayerController*)(closest_kart->getController());
|
||||
m_closest_kart_node = controller->getCurrentNode();
|
||||
m_closest_kart_point = closest_kart->getXYZ();
|
||||
}
|
||||
m_closest_kart_node = m_world->getKartNode(closest_kart_num);
|
||||
m_closest_kart_point = closest_kart->getXYZ();
|
||||
|
||||
if (!difficulty)
|
||||
{
|
||||
@ -347,7 +338,7 @@ void BattleAI::handleAcceleration(const float dt)
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::handleUTurn(const float dt)
|
||||
{
|
||||
const float turn_side = (m_cur_kart_pos_data.on_side ? 1.0f : -1.0f);
|
||||
const float turn_side = (m_adjusting_side ? 1.0f : -1.0f);
|
||||
|
||||
if (fabsf(m_kart->getSpeed()) >
|
||||
(m_kart->getKartProperties()->getEngineMaxSpeed() / 5)
|
||||
@ -380,10 +371,29 @@ void BattleAI::handleUTurn(const float dt)
|
||||
*/
|
||||
void BattleAI::handleSteering(const float dt)
|
||||
{
|
||||
if (m_current_node == BattleGraph::UNKNOWN_POLY ||
|
||||
const int current_node = m_world->getKartNode(m_kart->getWorldKartId());
|
||||
|
||||
if (current_node == BattleGraph::UNKNOWN_POLY ||
|
||||
m_target_node == BattleGraph::UNKNOWN_POLY) return;
|
||||
|
||||
if (m_target_node == m_current_node)
|
||||
if (m_is_steering_overridden)
|
||||
{
|
||||
// Steering is overridden to avoid eating banana
|
||||
const float turn_side = (m_adjusting_side ? 1.0f : -1.0f);
|
||||
m_time_since_steering_overridden += dt;
|
||||
if (m_time_since_steering_overridden > 0.35f)
|
||||
setSteering(-(turn_side), dt);
|
||||
else
|
||||
setSteering(turn_side, dt);
|
||||
if (m_time_since_steering_overridden > 0.7f)
|
||||
{
|
||||
m_is_steering_overridden = false;
|
||||
m_time_since_steering_overridden = 0.0f;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_target_node == current_node)
|
||||
{
|
||||
// Very close to the item, steer directly
|
||||
checkPosition(m_target_point, &m_cur_kart_pos_data);
|
||||
@ -392,6 +402,7 @@ void BattleAI::handleSteering(const float dt)
|
||||
#endif
|
||||
if (m_cur_kart_pos_data.behind)
|
||||
{
|
||||
m_adjusting_side = m_cur_kart_pos_data.on_side;
|
||||
m_is_uturn = true;
|
||||
}
|
||||
else
|
||||
@ -402,9 +413,9 @@ void BattleAI::handleSteering(const float dt)
|
||||
return;
|
||||
}
|
||||
|
||||
else if (m_target_node != m_current_node)
|
||||
else if (m_target_node != current_node)
|
||||
{
|
||||
findPortals(m_current_node, m_target_node);
|
||||
findPortals(current_node, m_target_node);
|
||||
stringPull(m_kart->getXYZ(), m_target_point);
|
||||
if (m_path_corners.size() > 0)
|
||||
m_target_point = m_path_corners[0];
|
||||
@ -415,6 +426,7 @@ void BattleAI::handleSteering(const float dt)
|
||||
#endif
|
||||
if (m_cur_kart_pos_data.behind)
|
||||
{
|
||||
m_adjusting_side = m_cur_kart_pos_data.on_side;
|
||||
m_is_uturn = true;
|
||||
}
|
||||
else
|
||||
@ -433,6 +445,34 @@ void BattleAI::handleSteering(const float dt)
|
||||
}
|
||||
} // handleSteering
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::handleBanana()
|
||||
{
|
||||
if (m_is_steering_overridden || m_is_uturn) return;
|
||||
|
||||
const std::vector< std::pair<const Item*, int> >& item_list =
|
||||
BattleGraph::get()->getItemList();
|
||||
const unsigned int items_count = item_list.size();
|
||||
for (unsigned int i = 0; i < items_count; ++i)
|
||||
{
|
||||
const Item* item = item_list[i].first;
|
||||
if (item->getType() == Item::ITEM_BANANA && !item->wasCollected())
|
||||
{
|
||||
posData banana_pos = {0};
|
||||
checkPosition(item->getXYZ(), &banana_pos);
|
||||
if (banana_pos.angle < 0.2f && banana_pos.distance < 7.5f &&
|
||||
!banana_pos.behind)
|
||||
{
|
||||
// Check whether it's straight ahead towards a banana
|
||||
// If so, try to do hard turn to avoid
|
||||
m_adjusting_side = banana_pos.on_side;
|
||||
m_is_steering_overridden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // handleBanana
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function finds the polyon edges(portals) that the AI will cross before
|
||||
* reaching its destination. We start from the current polygon and call
|
||||
@ -592,6 +632,11 @@ void BattleAI::handleBraking()
|
||||
{
|
||||
m_controls->m_brake = false;
|
||||
|
||||
if (m_world->getKartNode(m_kart->getWorldKartId())
|
||||
== BattleGraph::UNKNOWN_POLY ||
|
||||
m_target_node == BattleGraph::UNKNOWN_POLY ||
|
||||
m_is_steering_overridden) return;
|
||||
|
||||
// A kart will not brake when the speed is already slower than this
|
||||
// value. This prevents a kart from going too slow (or even backwards)
|
||||
// in tight curves.
|
||||
@ -599,9 +644,6 @@ void BattleAI::handleBraking()
|
||||
|
||||
std::vector<Vec3> points;
|
||||
|
||||
if (m_current_node == BattleGraph::UNKNOWN_POLY ||
|
||||
m_target_node == BattleGraph::UNKNOWN_POLY) return;
|
||||
|
||||
points.push_back(m_kart->getXYZ());
|
||||
points.push_back(m_path_corners[0]);
|
||||
points.push_back((m_path_corners.size()>=2) ? m_path_corners[1] : m_path_corners[0]);
|
||||
@ -835,6 +877,18 @@ void BattleAI::handleItemCollection(Vec3* aim_point, int* target_node)
|
||||
const std::vector< std::pair<const Item*, int> >& item_list =
|
||||
BattleGraph::get()->getItemList();
|
||||
const unsigned int items_count = item_list.size();
|
||||
|
||||
if (item_list.empty())
|
||||
{
|
||||
// Notice: this should not happen, as it makes no sense
|
||||
// for an arean without items, if so how can attack happen?
|
||||
Log::fatal ("BattleAI",
|
||||
"AI can't find any items in the arena, "
|
||||
"maybe there is something wrong with the navmesh, "
|
||||
"make sure it lies closely to the ground.");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int closest_item_num = 0;
|
||||
|
||||
for (unsigned int i = 0; i < items_count; ++i)
|
||||
|
@ -1,9 +1,8 @@
|
||||
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
|
||||
// Copyright (C) 2006-2007 Eduardo Hernandez Munoz
|
||||
// Copyright (C) 2010 Joerg Henrichs
|
||||
// Copyright (C) 2010-2015 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@ -29,13 +28,9 @@
|
||||
|
||||
#include "karts/controller/ai_base_controller.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/battle_graph.hpp"
|
||||
#include "utils/random_generator.hpp"
|
||||
|
||||
class AIProperties;
|
||||
class ThreeStrikesBattle;
|
||||
class BattleGraph;
|
||||
class Track;
|
||||
class Vec3;
|
||||
class Item;
|
||||
|
||||
@ -53,10 +48,9 @@ private:
|
||||
/** Holds the position info of targets. */
|
||||
struct posData {bool behind; bool on_side; float angle; float distance;};
|
||||
|
||||
/** Holds the current position of the AI on the battle graph. Sets to
|
||||
* BattleGraph::UNKNOWN_POLY if the location is unknown. This variable is
|
||||
* updated in ThreeStrikesBattle::updateKartNodes(). */
|
||||
int m_current_node;
|
||||
/** Used by handleBanana and UTurn, it tells whether to do left or right
|
||||
* turning when steering is overridden. */
|
||||
bool m_adjusting_side;
|
||||
|
||||
int m_closest_kart_node;
|
||||
Vec3 m_closest_kart_point;
|
||||
@ -70,6 +64,10 @@ private:
|
||||
/** Holds the current difficulty. */
|
||||
RaceManager::Difficulty m_cur_difficulty;
|
||||
|
||||
/** Indicates that the steering of kart is overridden, and
|
||||
* m_time_since_steering_overridden is counting down. */
|
||||
bool m_is_steering_overridden;
|
||||
|
||||
/** Indicates that the kart is currently stuck, and m_time_since_reversing is
|
||||
* counting down. */
|
||||
bool m_is_stuck;
|
||||
@ -105,6 +103,9 @@ private:
|
||||
/** This is a timer that counts down when the kart is starting to drive. */
|
||||
float m_time_since_driving;
|
||||
|
||||
/** This is a timer that counts down when the steering of kart is overridden. */
|
||||
float m_time_since_steering_overridden;
|
||||
|
||||
/** This is a timer that counts down when the kart is doing u-turn. */
|
||||
float m_time_since_uturn;
|
||||
|
||||
@ -115,6 +116,7 @@ private:
|
||||
void findPortals(int start, int end);
|
||||
void findTarget();
|
||||
void handleAcceleration(const float dt);
|
||||
void handleBanana();
|
||||
void handleBraking();
|
||||
void handleItems(const float dt);
|
||||
void handleItemCollection(Vec3*, int*);
|
||||
@ -138,8 +140,6 @@ public:
|
||||
BattleAI(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
~BattleAI();
|
||||
unsigned int getCurrentNode() const { return m_current_node; }
|
||||
void setCurrentNode(int i) { m_current_node = i; }
|
||||
virtual void update (float delta);
|
||||
virtual void reset ();
|
||||
|
||||
|
@ -55,6 +55,7 @@ protected:
|
||||
|
||||
/** The name of the controller, mainly used for debugging purposes. */
|
||||
std::string m_controller_name;
|
||||
|
||||
public:
|
||||
Controller (AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
|
@ -67,7 +67,6 @@ void PlayerController::reset()
|
||||
m_prev_accel = 0;
|
||||
m_prev_nitro = false;
|
||||
m_penalty_time = 0;
|
||||
m_current_node = BattleGraph::UNKNOWN_POLY;
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -113,6 +113,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id,
|
||||
m_race_position = position;
|
||||
m_collected_energy = 0;
|
||||
m_finished_race = false;
|
||||
m_race_result = false;
|
||||
m_finish_time = 0.0f;
|
||||
m_bubblegum_time = 0.0f;
|
||||
m_bubblegum_torque = 0.0f;
|
||||
@ -836,71 +837,102 @@ void Kart::finishedRace(float time)
|
||||
m_kart_model->finishedRace();
|
||||
race_manager->kartFinishedRace(this, time);
|
||||
|
||||
if ((race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
&& m_controller->isPlayerController())
|
||||
{
|
||||
RaceGUIBase* m = World::getWorld()->getRaceGUI();
|
||||
if (m)
|
||||
{
|
||||
if (race_manager->
|
||||
getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER &&
|
||||
getPosition() == 2)
|
||||
m->addMessage(_("You won the race!"), this, 2.0f);
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
{
|
||||
m->addMessage((getPosition() == 1 ?
|
||||
_("You won the race!") : _("You finished the race!")) ,
|
||||
this, 2.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_EASTER_EGG)
|
||||
{
|
||||
// Save for music handling in race result gui
|
||||
setRaceResult();
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
// Skip animation if this kart is eliminated
|
||||
if (m_eliminated) return;
|
||||
|
||||
m_kart_model->setAnimation(m_race_result ?
|
||||
KartModel::AF_WIN_START : KartModel::AF_LOSE_START);
|
||||
}
|
||||
} // finishedRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Kart::setRaceResult()
|
||||
{
|
||||
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
{
|
||||
// in modes that support it, start end animation
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
// TODO NetworkController?
|
||||
if (m_controller->isLocalPlayerController()) // if player is on this computer
|
||||
{
|
||||
PlayerProfile *player = PlayerManager::getCurrentPlayer();
|
||||
const ChallengeStatus *challenge = player->getCurrentChallengeStatus();
|
||||
// In case of a GP challenge don't make the end animation depend
|
||||
// on if the challenge is fulfilled
|
||||
if(challenge && !challenge->getData()->isGrandPrix())
|
||||
if (challenge && !challenge->getData()->isGrandPrix())
|
||||
{
|
||||
if(challenge->getData()->isChallengeFulfilled())
|
||||
m_kart_model->setAnimation(KartModel::AF_WIN_START);
|
||||
if (challenge->getData()->isChallengeFulfilled())
|
||||
m_race_result = true;
|
||||
else
|
||||
m_kart_model->setAnimation(KartModel::AF_LOSE_START);
|
||||
|
||||
m_race_result = false;
|
||||
}
|
||||
else if(m_race_position<=0.5f*race_manager->getNumberOfKarts() ||
|
||||
m_race_position==1)
|
||||
m_kart_model->setAnimation(KartModel::AF_WIN_START);
|
||||
else if (this->getPosition() <= 0.5f*race_manager->getNumberOfKarts() ||
|
||||
this->getPosition() == 1)
|
||||
m_race_result = true;
|
||||
else
|
||||
m_kart_model->setAnimation(KartModel::AF_LOSE_START);
|
||||
|
||||
RaceGUIBase* m = World::getWorld()->getRaceGUI();
|
||||
if(m)
|
||||
{
|
||||
m->addMessage((getPosition() == 1 ? _("You won the race!") : _("You finished the race!")) ,
|
||||
this, 2.0f);
|
||||
}
|
||||
m_race_result = false;
|
||||
}
|
||||
}
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
// start end animation
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
if(m_race_position<=2)
|
||||
m_kart_model->setAnimation(KartModel::AF_WIN_START);
|
||||
else if(m_race_position>=0.7f*race_manager->getNumberOfKarts())
|
||||
m_kart_model->setAnimation(KartModel::AF_LOSE_START);
|
||||
|
||||
RaceGUIBase* m = World::getWorld()->getRaceGUI();
|
||||
if(m)
|
||||
else
|
||||
{
|
||||
if (getPosition() == 2)
|
||||
m->addMessage(_("You won the race!"), this, 2.0f);
|
||||
if (this->getPosition() <= 0.5f*race_manager->getNumberOfKarts() ||
|
||||
this->getPosition() == 1)
|
||||
m_race_result = true;
|
||||
else
|
||||
m_race_result = false;
|
||||
}
|
||||
}
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES)
|
||||
{
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
// the kart wins if it isn't eliminated
|
||||
m_race_result = !this->isEliminated();
|
||||
}
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
|
||||
{
|
||||
// TODO complete together with soccer ai!
|
||||
m_race_result = true;
|
||||
}
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_EASTER_EGG)
|
||||
{
|
||||
m_kart_model->setAnimation(KartModel::AF_WIN_START);
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
// Easter egg mode only has one player, so always win
|
||||
m_race_result = true;
|
||||
}
|
||||
else
|
||||
Log::warn("Kart", "Unknown game mode given.");
|
||||
|
||||
} // finishedRace
|
||||
} // setKartResult
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when an item is collected. It will either adjust the collected
|
||||
|
@ -109,6 +109,9 @@ private:
|
||||
/** Offset of the graphical kart chassis from the physical chassis. */
|
||||
float m_graphical_y_offset;
|
||||
|
||||
/** True if the kart wins, false otherwise. */
|
||||
bool m_race_result;
|
||||
|
||||
/** True if the kart is eliminated. */
|
||||
bool m_eliminated;
|
||||
|
||||
@ -438,6 +441,12 @@ public:
|
||||
float getWrongwayCounter() { return m_wrongway_counter; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setWrongwayCounter(float counter) { m_wrongway_counter = counter; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart wins or loses. */
|
||||
virtual bool getRaceResult() const { return m_race_result; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set this kart race result. */
|
||||
void setRaceResult();
|
||||
|
||||
}; // Kart
|
||||
|
||||
|
@ -26,8 +26,6 @@
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/controller/battle_ai.hpp"
|
||||
#include "karts/controller/player_controller.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
@ -87,7 +85,8 @@ void ThreeStrikesBattle::reset()
|
||||
|
||||
for(unsigned int n=0; n<kart_amount; n++)
|
||||
{
|
||||
m_kart_info[n].m_lives = 3;
|
||||
m_kart_info[n].m_lives = 3;
|
||||
m_kart_info[n].m_on_node = BattleGraph::UNKNOWN_POLY;
|
||||
|
||||
// no positions in this mode
|
||||
m_karts[n]->setPosition(-1);
|
||||
@ -174,6 +173,8 @@ void ThreeStrikesBattle::kartHit(const unsigned int kart_id)
|
||||
// check if kart is 'dead'
|
||||
if (m_kart_info[kart_id].m_lives < 1)
|
||||
{
|
||||
if (getCurrentNumPlayers())
|
||||
eliminateKart(kart_id, /*notify_of_elimination*/ true);
|
||||
m_karts[kart_id]->finishedRace(WorldStatus::getTime());
|
||||
scene::ISceneNode** wheels = m_karts[kart_id]->getKartModel()
|
||||
->getWheelNodes();
|
||||
@ -181,8 +182,6 @@ void ThreeStrikesBattle::kartHit(const unsigned int kart_id)
|
||||
if(wheels[1]) wheels[1]->setVisible(false);
|
||||
if(wheels[2]) wheels[2]->setVisible(false);
|
||||
if(wheels[3]) wheels[3]->setVisible(false);
|
||||
if (getCurrentNumPlayers())
|
||||
eliminateKart(kart_id, /*notify_of_elimination*/ true);
|
||||
// Find a camera of the kart with the most lives ("leader"), and
|
||||
// attach all cameras for this kart to the leader.
|
||||
int max_lives = 0;
|
||||
@ -442,7 +441,7 @@ bool ThreeStrikesBattle::isRaceOver()
|
||||
} // isRaceOver
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates the m_current_node value of each kart controller to localize it
|
||||
/** Updates the m_on_node value of each kart to localize it
|
||||
* on the navigation mesh.
|
||||
*/
|
||||
void ThreeStrikesBattle::updateKartNodes()
|
||||
@ -450,111 +449,84 @@ void ThreeStrikesBattle::updateKartNodes()
|
||||
if (isRaceOver()) return;
|
||||
|
||||
const unsigned int n = getNumKarts();
|
||||
for(unsigned int i=0; i<n; i++)
|
||||
for (unsigned int i = 0; i < n; i++)
|
||||
{
|
||||
if(m_karts[i]->isEliminated()) continue;
|
||||
if (m_karts[i]->isEliminated()) continue;
|
||||
|
||||
const AbstractKart* kart = m_karts[i];
|
||||
const int saved_current_node = m_kart_info[i].m_on_node;
|
||||
|
||||
if(!kart->getController()->isPlayerController())
|
||||
if (saved_current_node == BattleGraph::UNKNOWN_POLY)
|
||||
{
|
||||
BattleAI* controller = (BattleAI*)(kart->getController());
|
||||
|
||||
int saved_current_node = controller->getCurrentNode();
|
||||
|
||||
if (saved_current_node != BattleGraph::UNKNOWN_POLY)
|
||||
// Try all nodes in the battle graph
|
||||
bool found = false;
|
||||
unsigned int node = 0;
|
||||
while (!found && node < BattleGraph::get()->getNumNodes())
|
||||
{
|
||||
//check if the kart is still on the same node
|
||||
const NavPoly& p = BattleGraph::get()->getPolyOfNode(controller->getCurrentNode());
|
||||
if(p.pointInPoly(kart->getXYZ())) continue;
|
||||
|
||||
//if not then check all adjacent polys
|
||||
const std::vector<int>& adjacents =
|
||||
NavMesh::get()->getAdjacentPolys(controller->getCurrentNode());
|
||||
|
||||
// Set m_current_node to unknown so that if no adjacent poly checks true
|
||||
// we look everywhere the next time updateCurrentNode is called. This is
|
||||
// useful in cases when you are "teleported" to some other poly, ex. rescue
|
||||
controller->setCurrentNode(BattleGraph::UNKNOWN_POLY);
|
||||
|
||||
for(unsigned int i=0; i<adjacents.size(); i++)
|
||||
const NavPoly& p_all = BattleGraph::get()->getPolyOfNode(node);
|
||||
if ((p_all.pointInPoly(m_karts[i]->getXYZ())))
|
||||
{
|
||||
const NavPoly& p_temp =
|
||||
BattleGraph::get()->getPolyOfNode(adjacents[i]);
|
||||
if(p_temp.pointInPoly(kart->getXYZ()))
|
||||
controller->setCurrentNode(adjacents[i]);
|
||||
m_kart_info[i].m_on_node = node;
|
||||
found = true;
|
||||
}
|
||||
node++;
|
||||
}
|
||||
|
||||
//Current node is still unkown
|
||||
if (saved_current_node == BattleGraph::UNKNOWN_POLY)
|
||||
{
|
||||
bool flag = 0;
|
||||
unsigned int max_count = BattleGraph::get()->getNumNodes();
|
||||
for(unsigned int i=0; i<max_count; i++)
|
||||
{
|
||||
const NavPoly& p = BattleGraph::get()->getPolyOfNode(i);
|
||||
if((p.pointInPoly(kart->getXYZ())))
|
||||
{
|
||||
controller->setCurrentNode(i);
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(flag == 0) controller->setCurrentNode(saved_current_node);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerController* controller = (PlayerController*)(kart->getController());
|
||||
// Check if the kart is still on the same node
|
||||
const NavPoly& p_cur = BattleGraph::get()
|
||||
->getPolyOfNode(saved_current_node);
|
||||
if (p_cur.pointInPoly(m_karts[i]->getXYZ())) continue;
|
||||
|
||||
int saved_current_node = controller->getCurrentNode();
|
||||
// If not then check all adjacent polys
|
||||
const std::vector<int>& adjacents = NavMesh::get()
|
||||
->getAdjacentPolys(saved_current_node);
|
||||
|
||||
if (saved_current_node != BattleGraph::UNKNOWN_POLY)
|
||||
// Set current node to unknown so that if no adjacent polygons,
|
||||
// we look everywhere the next time updateKartNodes is called.
|
||||
// This is useful in cases when you are "teleported"
|
||||
// to some other polygons, ex. rescue
|
||||
m_kart_info[i].m_on_node = BattleGraph::UNKNOWN_POLY;
|
||||
|
||||
bool found = false;
|
||||
unsigned int num = 0;
|
||||
while (!found && num < adjacents.size())
|
||||
{
|
||||
//check if the kart is still on the same node
|
||||
const NavPoly& p = BattleGraph::get()->getPolyOfNode(controller->getCurrentNode());
|
||||
if(p.pointInPoly(kart->getXYZ())) continue;
|
||||
|
||||
//if not then check all adjacent polys
|
||||
const std::vector<int>& adjacents =
|
||||
NavMesh::get()->getAdjacentPolys(controller->getCurrentNode());
|
||||
|
||||
// Set m_current_node to unknown so that if no adjacent poly checks true
|
||||
// we look everywhere the next time updateCurrentNode is called. This is
|
||||
// useful in cases when you are "teleported" to some other poly, ex. rescue
|
||||
controller->setCurrentNode(BattleGraph::UNKNOWN_POLY);
|
||||
|
||||
for(unsigned int i=0; i<adjacents.size(); i++)
|
||||
const NavPoly& p_temp =
|
||||
BattleGraph::get()->getPolyOfNode(adjacents[num]);
|
||||
if (p_temp.pointInPoly(m_karts[i]->getXYZ()))
|
||||
{
|
||||
const NavPoly& p_temp =
|
||||
BattleGraph::get()->getPolyOfNode(adjacents[i]);
|
||||
if(p_temp.pointInPoly(kart->getXYZ()))
|
||||
controller->setCurrentNode(adjacents[i]);
|
||||
m_kart_info[i].m_on_node = adjacents[num];
|
||||
found = true;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
|
||||
if (saved_current_node == BattleGraph::UNKNOWN_POLY)
|
||||
// Current node is still unkown
|
||||
if (m_kart_info[i].m_on_node == BattleGraph::UNKNOWN_POLY)
|
||||
{
|
||||
bool flag = 0;
|
||||
unsigned int max_count = BattleGraph::get()->getNumNodes();
|
||||
for(unsigned int i =0; i<max_count; i++)
|
||||
{
|
||||
const NavPoly& p = BattleGraph::get()->getPolyOfNode(i);
|
||||
if((p.pointInPoly(kart->getXYZ())))
|
||||
{
|
||||
controller->setCurrentNode(i);
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
// Calculated distance from saved node to current position,
|
||||
// if it's close enough than use the saved node anyway, it
|
||||
// may happen when the kart stays on the edge of obstacles
|
||||
const NavPoly& p = BattleGraph::get()
|
||||
->getPolyOfNode(saved_current_node);
|
||||
const float dist = (p.getCenter() - m_karts[i]->getXYZ()).length_2d();
|
||||
|
||||
if(flag == 0) controller->setCurrentNode(saved_current_node);
|
||||
if (dist < 3.0f)
|
||||
m_kart_info[i].m_on_node = saved_current_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Get the which node the kart located in navigation mesh.
|
||||
*/
|
||||
int ThreeStrikesBattle::getKartNode(unsigned int kart_id) const
|
||||
{
|
||||
return m_kart_info[kart_id].m_on_node;
|
||||
} // getKartNode
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when the race finishes, i.e. after playing (if necessary) an
|
||||
* end of race animation. It updates the time for all karts still racing,
|
||||
|
@ -39,7 +39,8 @@ class ThreeStrikesBattle : public WorldWithRank
|
||||
private:
|
||||
struct BattleInfo
|
||||
{
|
||||
int m_lives;
|
||||
int m_lives;
|
||||
int m_on_node;
|
||||
};
|
||||
|
||||
/** This vector contains an 'BattleInfo' struct for every kart in the race.
|
||||
@ -108,6 +109,7 @@ public:
|
||||
|
||||
virtual void kartAdded(AbstractKart* kart, scene::ISceneNode* node);
|
||||
|
||||
int getKartNode(unsigned int kart_id) const;
|
||||
|
||||
void updateKartRanks();
|
||||
}; // ThreeStrikesBattles
|
||||
|
@ -172,6 +172,99 @@ namespace Scripting
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ScriptEngine::runDelegate(asIScriptFunction* delegate)
|
||||
{
|
||||
asIScriptContext *ctx = m_engine->CreateContext();
|
||||
if (ctx == NULL)
|
||||
{
|
||||
Log::error("Scripting", "runMethod: Failed to create the context.");
|
||||
//m_engine->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
int r = ctx->Prepare(delegate);
|
||||
if (r < 0)
|
||||
{
|
||||
Log::error("Scripting", "runMethod: Failed to prepare the context.");
|
||||
ctx->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute the function
|
||||
r = ctx->Execute();
|
||||
if (r != asEXECUTION_FINISHED)
|
||||
{
|
||||
// The execution didn't finish as we had planned. Determine why.
|
||||
if (r == asEXECUTION_ABORTED)
|
||||
{
|
||||
Log::error("Scripting", "The script was aborted before it could finish. Probably it timed out.");
|
||||
}
|
||||
else if (r == asEXECUTION_EXCEPTION)
|
||||
{
|
||||
Log::error("Scripting", "The script ended with an exception : (line %i) %s",
|
||||
ctx->GetExceptionLineNumber(),
|
||||
ctx->GetExceptionString());
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->Release();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
void ScriptEngine::runMethod(asIScriptObject* obj, std::string methodName)
|
||||
{
|
||||
asIObjectType* type = obj->GetObjectType();
|
||||
asIScriptFunction* method = type->GetMethodByName(methodName.c_str());
|
||||
if (method == NULL)
|
||||
Log::error("Scripting", ("runMethod: object does not implement method " + methodName).c_str());
|
||||
|
||||
|
||||
asIScriptContext *ctx = m_engine->CreateContext();
|
||||
if (ctx == NULL)
|
||||
{
|
||||
Log::error("Scripting", "runMethod: Failed to create the context.");
|
||||
//m_engine->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
int r = ctx->Prepare(method);
|
||||
if (r < 0)
|
||||
{
|
||||
Log::error("Scripting", "runMethod: Failed to prepare the context.");
|
||||
ctx->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute the function
|
||||
r = ctx->Execute();
|
||||
if (r != asEXECUTION_FINISHED)
|
||||
{
|
||||
// The execution didn't finish as we had planned. Determine why.
|
||||
if (r == asEXECUTION_ABORTED)
|
||||
{
|
||||
Log::error("Scripting", "The script was aborted before it could finish. Probably it timed out.");
|
||||
}
|
||||
else if (r == asEXECUTION_EXCEPTION)
|
||||
{
|
||||
Log::error("Scripting", "The script ended with an exception.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->Release();
|
||||
}
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** runs the specified script
|
||||
* \param string scriptName = name of script to run
|
||||
*/
|
||||
@ -415,9 +508,35 @@ namespace Scripting
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PendingTimeout::PendingTimeout(double time, asIScriptFunction* callback_delegate)
|
||||
{
|
||||
m_time = time;
|
||||
m_callback_delegate = callback_delegate;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PendingTimeout::~PendingTimeout()
|
||||
{
|
||||
if (m_callback_delegate != NULL)
|
||||
{
|
||||
asIScriptEngine* engine = World::getWorld()->getScriptEngine()->getEngine();
|
||||
m_callback_delegate->Release();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ScriptEngine::addPendingTimeout(double time, const std::string& callback_name)
|
||||
{
|
||||
m_pending_timeouts.push_back(PendingTimeout(time, callback_name));
|
||||
m_pending_timeouts.push_back(new PendingTimeout(time, callback_name));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ScriptEngine::addPendingTimeout(double time, asIScriptFunction* delegate)
|
||||
{
|
||||
m_pending_timeouts.push_back(new PendingTimeout(time, delegate));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -430,8 +549,16 @@ namespace Scripting
|
||||
curr.m_time -= dt;
|
||||
if (curr.m_time <= 0.0)
|
||||
{
|
||||
runFunction(true, "void " + curr.m_callback_name + "()");
|
||||
m_pending_timeouts.erase(m_pending_timeouts.begin() + i);
|
||||
if (curr.m_callback_delegate != NULL)
|
||||
{
|
||||
runDelegate(curr.m_callback_delegate);
|
||||
}
|
||||
else
|
||||
{
|
||||
runFunction(true, "void " + curr.m_callback_name + "()");
|
||||
}
|
||||
|
||||
m_pending_timeouts.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,21 +23,34 @@
|
||||
#include <angelscript.h>
|
||||
#include <functional>
|
||||
|
||||
#include "scriptengine/script_utils.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
class TrackObjectPresentation;
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
/** Represents a scripting function to execute after a given time */
|
||||
struct PendingTimeout
|
||||
struct PendingTimeout : NoCopy
|
||||
{
|
||||
double m_time;
|
||||
|
||||
/** We have two callback types: a string containing the name of the function
|
||||
* to call (simple callback) or a "TimeoutBase" object (advanced callback)
|
||||
*/
|
||||
std::string m_callback_name;
|
||||
asIScriptFunction* m_callback_delegate;
|
||||
|
||||
PendingTimeout(double time, const std::string& callback_name)
|
||||
{
|
||||
m_callback_delegate = NULL;
|
||||
m_time = time;
|
||||
m_callback_name = callback_name;
|
||||
}
|
||||
|
||||
PendingTimeout(double time, asIScriptFunction* callback_delegate);
|
||||
|
||||
~PendingTimeout();
|
||||
};
|
||||
|
||||
class ScriptEngine
|
||||
@ -53,6 +66,7 @@ namespace Scripting
|
||||
void runFunction(bool warn_if_not_found, std::string function_name,
|
||||
std::function<void(asIScriptContext*)> callback,
|
||||
std::function<void(asIScriptContext*)> get_return_value);
|
||||
void runDelegate(asIScriptFunction* delegate_fn);
|
||||
void evalScript(std::string script_fragment);
|
||||
void cleanupCache();
|
||||
|
||||
@ -60,12 +74,15 @@ namespace Scripting
|
||||
bool compileLoadedScripts();
|
||||
|
||||
void addPendingTimeout(double time, const std::string& callback_name);
|
||||
void addPendingTimeout(double time, asIScriptFunction* delegate_fn);
|
||||
void update(double dt);
|
||||
|
||||
asIScriptEngine* getEngine() { return m_engine; }
|
||||
|
||||
private:
|
||||
asIScriptEngine *m_engine;
|
||||
std::map<std::string, asIScriptFunction*> m_functions_cache;
|
||||
std::vector<PendingTimeout> m_pending_timeouts;
|
||||
PtrVector<PendingTimeout> m_pending_timeouts;
|
||||
|
||||
void configureEngine(asIScriptEngine *engine);
|
||||
}; // class ScriptEngine
|
||||
|
@ -135,6 +135,16 @@ namespace Scripting
|
||||
new RacePausedDialog(0.8f, 0.6f);
|
||||
}
|
||||
|
||||
int getNumberOfKarts()
|
||||
{
|
||||
return race_manager->getNumberOfKarts();
|
||||
}
|
||||
|
||||
int getNumLocalPlayers()
|
||||
{
|
||||
return race_manager->getNumLocalPlayers();
|
||||
}
|
||||
|
||||
void setFog(float maxDensity, float start, float end, int r, int g, int b, float duration)
|
||||
{
|
||||
PropertyAnimator* animator = PropertyAnimator::get();
|
||||
@ -365,6 +375,8 @@ namespace Scripting
|
||||
r = engine->RegisterGlobalFunction("void exitRace()", asFUNCTION(exitRace), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void pauseRace()", asFUNCTION(pauseRace), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void setFog(float maxDensity, float start, float end, int r, int g, int b, float duration)", asFUNCTION(setFog), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("int getNumberOfKarts()", asFUNCTION(getNumberOfKarts), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("int getNumLocalPlayers()", asFUNCTION(getNumLocalPlayers), asCALL_CDECL); assert(r >= 0);
|
||||
|
||||
// TrackObject
|
||||
r = engine->RegisterObjectMethod("TrackObject", "void setEnabled(bool status)", asMETHOD(::TrackObject, setEnabled), asCALL_THISCALL); assert(r >= 0);
|
||||
|
@ -16,7 +16,7 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "script_track.hpp"
|
||||
#include "script_utils.hpp"
|
||||
|
||||
#include "animations/three_d_animation.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
@ -132,6 +132,12 @@ namespace Scripting
|
||||
World::getWorld()->getScriptEngine()->addPendingTimeout(delay, *callback_name);
|
||||
}
|
||||
|
||||
/** Call a method from the given object after the specified delay */
|
||||
void setTimeoutDelegate(asIScriptFunction* obj, float delay)
|
||||
{
|
||||
World::getWorld()->getScriptEngine()->addPendingTimeout(delay, obj);
|
||||
}
|
||||
|
||||
/** Log to the console */
|
||||
void logInfo(std::string* log)
|
||||
{
|
||||
@ -180,6 +186,7 @@ namespace Scripting
|
||||
{
|
||||
int r; // of type asERetCodes
|
||||
engine->SetDefaultNamespace("Utils");
|
||||
|
||||
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in)", asFUNCTION(proxy_insertValues1), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in, const string &in)", asFUNCTION(proxy_insertValues2), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in, const string &in, const string &in)", asFUNCTION(proxy_insertValues3), asCALL_CDECL); assert(r >= 0);
|
||||
@ -190,6 +197,9 @@ namespace Scripting
|
||||
r = engine->RegisterGlobalFunction("int randomInt(int, int)", asFUNCTION(randomInt), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("float randomFloat(int, int)", asFUNCTION(randomFloat), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void setTimeout(const string &in, float)", asFUNCTION(setTimeout), asCALL_CDECL); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterFuncdef("void TimeoutCallback()"); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void setTimeoutDelegate(TimeoutCallback@, float)", asFUNCTION(setTimeoutDelegate), asCALL_CDECL); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterGlobalFunction("void logInfo(const string &in)", asFUNCTION(logInfo), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("void logWarning(const string &in)", asFUNCTION(logWarning), asCALL_CDECL); assert(r >= 0);
|
||||
|
@ -63,10 +63,6 @@ DEFINE_SCREEN_SINGLETON( RaceResultGUI );
|
||||
RaceResultGUI::RaceResultGUI() : Screen("race_result.stkgui",
|
||||
/*pause race*/ false)
|
||||
{
|
||||
std::string path = file_manager->getAsset(FileManager::MUSIC,
|
||||
"race_summary.music");
|
||||
m_race_over_music = music_manager->getMusicInformation(path);
|
||||
|
||||
} // RaceResultGUI
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -87,7 +83,25 @@ void RaceResultGUI::init()
|
||||
getWidget("bottom")->setVisible(false);
|
||||
|
||||
music_manager->stopMusic();
|
||||
m_finish_sound = SFXManager::get()->quickSound("race_finish");
|
||||
|
||||
bool human_win = true;
|
||||
unsigned int num_karts = race_manager->getNumberOfKarts();
|
||||
for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++)
|
||||
{
|
||||
const AbstractKart *kart = World::getWorld()->getKart(kart_id);
|
||||
if (kart->getController()->isPlayerController())
|
||||
human_win = human_win && kart->getRaceResult();
|
||||
}
|
||||
|
||||
m_finish_sound = SFXManager::get()->quickSound(
|
||||
human_win ? "gp_end" : "race_finish");
|
||||
|
||||
//std::string path = (human_win ? Different result music too later
|
||||
// file_manager->getAsset(FileManager::MUSIC, "race_summary.music") :
|
||||
// file_manager->getAsset(FileManager::MUSIC, "race_summary.music"));
|
||||
std::string path = file_manager->getAsset(FileManager::MUSIC, "race_summary.music");
|
||||
m_race_over_music = music_manager->getMusicInformation(path);
|
||||
|
||||
if (!m_finish_sound)
|
||||
{
|
||||
// If there is no finish sound (because sfx are disabled), start
|
||||
|
@ -97,8 +97,9 @@ void TrackInfoScreen::setTrack(Track *track)
|
||||
*/
|
||||
void TrackInfoScreen::init()
|
||||
{
|
||||
const bool has_laps = race_manager->modeHasLaps();
|
||||
const bool has_highscores = race_manager->modeHasHighscores();
|
||||
const int max_arena_players = m_track->getMaxArenaPlayers();
|
||||
const bool has_laps = race_manager->modeHasLaps();
|
||||
const bool has_highscores = race_manager->modeHasHighscores();
|
||||
|
||||
getWidget<LabelWidget>("name")->setText(translations->fribidize(m_track->getName()), false);
|
||||
|
||||
@ -107,6 +108,14 @@ void TrackInfoScreen::init()
|
||||
getWidget<LabelWidget>("author")->setText( _("Track by %s", m_track->getDesigner()),
|
||||
false );
|
||||
|
||||
LabelWidget* max_players = getWidget<LabelWidget>("max-arena-players");
|
||||
max_players->setVisible(m_track->isArena());
|
||||
if (m_track->isArena())
|
||||
{
|
||||
//I18N: the max players supported by an arena.
|
||||
max_players->setText( _("Max players supported: %d", max_arena_players), false );
|
||||
}
|
||||
|
||||
// ---- Track screenshot
|
||||
GUIEngine::IconButtonWidget* screenshot = getWidget<IconButtonWidget>("screenshot");
|
||||
|
||||
@ -143,9 +152,11 @@ void TrackInfoScreen::init()
|
||||
|
||||
// Number of AIs
|
||||
// -------------
|
||||
const int local_players = race_manager->getNumLocalPlayers();
|
||||
const bool has_AI =
|
||||
(race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES ?
|
||||
m_track->hasNavMesh() : race_manager->hasAI());
|
||||
m_track->hasNavMesh() && (max_arena_players - local_players) > 0 :
|
||||
race_manager->hasAI());
|
||||
m_ai_kart_spinner->setVisible(has_AI);
|
||||
getWidget<LabelWidget>("ai-text")->setVisible(has_AI);
|
||||
if (has_AI)
|
||||
@ -154,25 +165,25 @@ void TrackInfoScreen::init()
|
||||
|
||||
// Avoid negative numbers (which can happen if e.g. the number of karts
|
||||
// in a previous race was lower than the number of players now.
|
||||
int num_ai = UserConfigParams::m_num_karts - race_manager->getNumLocalPlayers();
|
||||
int num_ai = UserConfigParams::m_num_karts - local_players;
|
||||
if (num_ai < 0) num_ai = 0;
|
||||
m_ai_kart_spinner->setValue(num_ai);
|
||||
race_manager->setNumKarts(num_ai + race_manager->getNumLocalPlayers());
|
||||
// Currently battle arena only has 4 starting position
|
||||
race_manager->setNumKarts(num_ai + local_players);
|
||||
// Set the max karts supported based on the battle arena selected
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES)
|
||||
{
|
||||
m_ai_kart_spinner->setMax(4 - race_manager->getNumLocalPlayers());
|
||||
m_ai_kart_spinner->setMax(max_arena_players - local_players);
|
||||
}
|
||||
else
|
||||
m_ai_kart_spinner->setMax(stk_config->m_max_karts - race_manager->getNumLocalPlayers());
|
||||
m_ai_kart_spinner->setMax(stk_config->m_max_karts - local_players);
|
||||
// A ftl reace needs at least three karts to make any sense
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
m_ai_kart_spinner->setMin(3-race_manager->getNumLocalPlayers());
|
||||
m_ai_kart_spinner->setMin(3 - local_players);
|
||||
}
|
||||
// Make sure in battle mode at least 1 ai for single player
|
||||
else if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES &&
|
||||
race_manager->getNumLocalPlayers() == 1 &&
|
||||
local_players == 1 &&
|
||||
!UserConfigParams::m_artist_debug_mode)
|
||||
m_ai_kart_spinner->setMin(1);
|
||||
else
|
||||
@ -180,7 +191,7 @@ void TrackInfoScreen::init()
|
||||
|
||||
} // has_AI
|
||||
else
|
||||
race_manager->setNumKarts(race_manager->getNumLocalPlayers());
|
||||
race_manager->setNumKarts(local_players);
|
||||
|
||||
// Reverse track
|
||||
// -------------
|
||||
@ -296,20 +307,21 @@ void TrackInfoScreen::onEnterPressedInternal()
|
||||
race_manager->setReverseTrack(reverse_track);
|
||||
|
||||
// Avoid invaild Ai karts number during switching game modes
|
||||
const int max_arena_players = m_track->getMaxArenaPlayers();
|
||||
const int local_players = race_manager->getNumLocalPlayers();
|
||||
const bool has_AI =
|
||||
(race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES ?
|
||||
m_track->hasNavMesh() : race_manager->hasAI());
|
||||
m_track->hasNavMesh() && (max_arena_players - local_players) > 0 :
|
||||
race_manager->hasAI());
|
||||
|
||||
int num_ai = 0;
|
||||
if (has_AI)
|
||||
num_ai = m_ai_kart_spinner->getValue();
|
||||
|
||||
if (UserConfigParams::m_num_karts != (signed)(race_manager
|
||||
->getNumLocalPlayers() + num_ai))
|
||||
if (UserConfigParams::m_num_karts != (local_players + num_ai))
|
||||
{
|
||||
race_manager->setNumKarts(race_manager->getNumLocalPlayers() + num_ai);
|
||||
UserConfigParams::m_num_karts = race_manager->getNumLocalPlayers() +
|
||||
num_ai;
|
||||
race_manager->setNumKarts(local_players + num_ai);
|
||||
UserConfigParams::m_num_karts = local_players + num_ai;
|
||||
}
|
||||
|
||||
// Disable accidentally unlocking of a challenge
|
||||
|
@ -23,12 +23,7 @@
|
||||
#include <IMeshSceneNode.h>
|
||||
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/glwrap.hpp"
|
||||
#include "graphics/shaders.hpp"
|
||||
#include "graphics/rtts.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "tracks/navmesh.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
@ -40,10 +35,6 @@ BattleGraph * BattleGraph::m_battle_graph = NULL;
|
||||
* by the AI. */
|
||||
BattleGraph::BattleGraph(const std::string &navmesh_file_name)
|
||||
{
|
||||
m_node = NULL;
|
||||
m_mesh = NULL;
|
||||
m_mesh_buffer = NULL;
|
||||
m_new_rtt = NULL;
|
||||
m_items_on_graph.clear();
|
||||
|
||||
NavMesh::create(navmesh_file_name);
|
||||
@ -60,8 +51,7 @@ BattleGraph::~BattleGraph(void)
|
||||
|
||||
if(UserConfigParams::m_track_debug)
|
||||
cleanupDebugMesh();
|
||||
if (m_new_rtt != NULL)
|
||||
delete m_new_rtt;
|
||||
GraphStructure::destroyRTT();
|
||||
} // ~BattleGraph
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -132,266 +122,7 @@ void BattleGraph::computeFloydWarshall()
|
||||
} // computeFloydWarshall
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Creates the actual mesh that is used by createDebugMesh() or makeMiniMap() */
|
||||
void BattleGraph::createMesh(bool enable_transparency,
|
||||
const video::SColor *track_color)
|
||||
{
|
||||
// The debug track will not be lighted or culled.
|
||||
video::SMaterial m;
|
||||
m.BackfaceCulling = false;
|
||||
m.Lighting = false;
|
||||
if(enable_transparency)
|
||||
m.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
m.setTexture(0, getUnicolorTexture(video::SColor(255, 255, 255, 255)));
|
||||
m.setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0)));
|
||||
m_mesh = irr_driver->createQuadMesh(&m);
|
||||
m_mesh_buffer = m_mesh->getMeshBuffer(0);
|
||||
assert(m_mesh_buffer->getVertexType()==video::EVT_STANDARD);
|
||||
|
||||
const unsigned int num_nodes = getNumNodes();
|
||||
|
||||
// Four vertices for each of the n-1 remaining quads
|
||||
video::S3DVertex *new_v = new video::S3DVertex[4*num_nodes];
|
||||
// Each quad consists of 2 triangles with 3 elements, so
|
||||
// we need 2*3 indices for each quad.
|
||||
irr::u16 *ind = new irr::u16[6*num_nodes];
|
||||
video::SColor c(255, 255, 0, 0);
|
||||
|
||||
if(track_color)
|
||||
c = *track_color;
|
||||
|
||||
// Now add all quads
|
||||
int i=0;
|
||||
for(unsigned int count=0; count<num_nodes; count++)
|
||||
{
|
||||
// There should not be a poly which isn't made of 4 vertices
|
||||
if((NavMesh::get()->getNavPoly(count).getVerticesIndex()).size() !=4)
|
||||
{
|
||||
Log::warn("Battle Graph", "There is an invalid poly!");
|
||||
continue;
|
||||
}
|
||||
// Swap the colours from red to blue and back
|
||||
if(!track_color)
|
||||
{
|
||||
c.setRed ((i%2) ? 255 : 0);
|
||||
c.setBlue((i%2) ? 0 : 255);
|
||||
}
|
||||
// Transfer the 4 points of the current quad to the list of vertices
|
||||
NavMesh::get()->setVertices(count, new_v+4*i, c);
|
||||
|
||||
// Set up the indices for the triangles
|
||||
// (note, afaik with opengl we could use quads directly, but the code
|
||||
// would not be portable to directx anymore).
|
||||
ind[6*i ] = 4*i+2; // First triangle: vertex 0, 1, 2
|
||||
ind[6*i+1] = 4*i+1;
|
||||
ind[6*i+2] = 4*i;
|
||||
ind[6*i+3] = 4*i+3; // second triangle: vertex 0, 1, 3
|
||||
ind[6*i+4] = 4*i+2;
|
||||
ind[6*i+5] = 4*i;
|
||||
i++;
|
||||
} // for i=1; i<QuadSet::get()
|
||||
|
||||
m_mesh_buffer->append(new_v, num_nodes*4, ind, num_nodes*6);
|
||||
|
||||
// Instead of setting the bounding boxes, we could just disable culling,
|
||||
// since the debug track should always be drawn.
|
||||
//m_node->setAutomaticCulling(scene::EAC_OFF);
|
||||
m_mesh_buffer->recalculateBoundingBox();
|
||||
m_mesh->setBoundingBox(m_mesh_buffer->getBoundingBox());
|
||||
|
||||
m_mesh_buffer->getMaterial().setTexture(0, irr_driver->getTexture("unlit.png"));
|
||||
|
||||
} // createMesh
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Takes a snapshot of the navmesh so they can be used as minimap.
|
||||
*/
|
||||
void BattleGraph::makeMiniMap(const core::dimension2du &dimension,
|
||||
const std::string &name,
|
||||
const video::SColor &fill_color,
|
||||
video::ITexture** oldRttMinimap,
|
||||
FrameBuffer** newRttMinimap)
|
||||
{
|
||||
const video::SColor oldClearColor = World::getWorld()->getClearColor();
|
||||
World::getWorld()->setClearbackBufferColor(video::SColor(0, 255, 255, 255));
|
||||
World::getWorld()->forceFogDisabled(true);
|
||||
*oldRttMinimap = NULL;
|
||||
*newRttMinimap = NULL;
|
||||
|
||||
RTT* newRttProvider = NULL;
|
||||
IrrDriver::RTTProvider* oldRttProvider = NULL;
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
m_new_rtt = newRttProvider = new RTT(dimension.Width, dimension.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldRttProvider = new IrrDriver::RTTProvider(dimension, name, true);
|
||||
}
|
||||
|
||||
irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 255, 255, 255));
|
||||
|
||||
createMesh(/*enable_transparency*/ false,
|
||||
/*track_color*/ &fill_color);
|
||||
|
||||
m_node = irr_driver->addMesh(m_mesh, "mini_map");
|
||||
#ifdef DEBUG
|
||||
m_node->setName("minimap-mesh");
|
||||
#endif
|
||||
|
||||
m_node->setAutomaticCulling(0);
|
||||
m_node->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||
|
||||
// Add the camera:
|
||||
// ---------------
|
||||
scene::ICameraSceneNode *camera = irr_driver->addCameraSceneNode();
|
||||
Vec3 bb_min, bb_max;
|
||||
NavMesh::get()->getBoundingBox(&bb_min, &bb_max);
|
||||
Vec3 center = (bb_max+bb_min)*0.5f;
|
||||
|
||||
float dx = bb_max.getX()-bb_min.getX();
|
||||
float dz = bb_max.getZ()-bb_min.getZ();
|
||||
|
||||
// Set the scaling correctly. Also the center point (which is used
|
||||
// as the camera position) needs to be adjusted: the track must
|
||||
// be aligned to the left/top of the texture which is used (otherwise
|
||||
// mapPoint2MiniMap doesn't work), so adjust the camera position
|
||||
// that the track is properly aligned (view from the side):
|
||||
// c camera
|
||||
// / \ .
|
||||
// / \ <--- camera angle
|
||||
// / \ .
|
||||
// { [-] } <--- track flat (viewed from the side)
|
||||
// If [-] is the shorter side of the track, then the camera will
|
||||
// actually render the area in { } - which is the length of the
|
||||
// longer side of the track.
|
||||
// To align the [-] side to the left, the camera must be moved
|
||||
// the distance betwwen '{' and '[' to the right. This distance
|
||||
// is exacly (longer_side - shorter_side) / 2.
|
||||
// So, adjust the center point by this amount:
|
||||
if(dz > dx)
|
||||
{
|
||||
center.setX(center.getX() + (dz-dx)*0.5f);
|
||||
m_scaling = dimension.Width / dz;
|
||||
}
|
||||
else
|
||||
{
|
||||
center.setZ(center.getZ() + (dx-dz)*0.5f);
|
||||
m_scaling = dimension.Width / dx;
|
||||
}
|
||||
|
||||
float range = (dx>dz) ? dx : dz;
|
||||
|
||||
core::matrix4 projection;
|
||||
projection.buildProjectionMatrixOrthoLH(range /* width */,
|
||||
range /* height */,
|
||||
-1, bb_max.getY()-bb_min.getY()+1);
|
||||
camera->setProjectionMatrix(projection, true);
|
||||
|
||||
irr_driver->suppressSkyBox();
|
||||
irr_driver->clearLights();
|
||||
|
||||
// Adjust Y position by +1 for max, -1 for min - this helps in case that
|
||||
// the maximum Y coordinate is negative (otherwise the minimap is mirrored)
|
||||
// and avoids problems for tracks which have a flat (max Y = min Y) minimap.
|
||||
camera->setPosition(core::vector3df(center.getX(), bb_min.getY() + 1.0f, center.getZ()));
|
||||
//camera->setPosition(core::vector3df(center.getX() - 5.0f, bb_min.getY() - 1 - 5.0f, center.getZ() - 15.0f));
|
||||
camera->setUpVector(core::vector3df(0, 0, 1));
|
||||
camera->setTarget(core::vector3df(center.getX(),bb_min.getY()-1,center.getZ()));
|
||||
//camera->setAspectRatio(1.0f);
|
||||
camera->updateAbsolutePosition();
|
||||
|
||||
video::ITexture* texture = NULL;
|
||||
FrameBuffer* frame_buffer = NULL;
|
||||
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
frame_buffer = newRttProvider->render(camera, GUIEngine::getLatestDt());
|
||||
}
|
||||
else
|
||||
{
|
||||
texture = oldRttProvider->renderToTexture();
|
||||
delete oldRttProvider;
|
||||
}
|
||||
|
||||
cleanupDebugMesh();
|
||||
irr_driver->removeCameraSceneNode(camera);
|
||||
m_min_coord = bb_min;
|
||||
|
||||
|
||||
if (texture == NULL && frame_buffer == NULL)
|
||||
{
|
||||
Log::error("BattleGraph", "[makeMiniMap] WARNING: RTT does not appear to work,"
|
||||
"mini-map will not be available.");
|
||||
}
|
||||
|
||||
*oldRttMinimap = texture;
|
||||
*newRttMinimap = frame_buffer;
|
||||
World::getWorld()->setClearbackBufferColor(oldClearColor);
|
||||
World::getWorld()->forceFogDisabled(false);
|
||||
|
||||
irr_driver->getSceneManager()->clear();
|
||||
VAOManager::kill();
|
||||
irr_driver->clearGlowingNodes();
|
||||
irr_driver->clearLights();
|
||||
irr_driver->clearForcedBloom();
|
||||
irr_driver->clearBackgroundNodes();
|
||||
} // makeMiniMap
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Returns the 2d coordinates of a point when drawn on the mini map
|
||||
* texture.
|
||||
* \param xyz Coordinates of the point to map.
|
||||
* \param draw_at The coordinates in pixel on the mini map of the point,
|
||||
* only the first two coordinates will be used.
|
||||
*/
|
||||
void BattleGraph::mapPoint2MiniMap(const Vec3 &xyz,Vec3 *draw_at) const
|
||||
{
|
||||
draw_at->setX((xyz.getX()-m_min_coord.getX())*m_scaling);
|
||||
draw_at->setY((xyz.getZ()-m_min_coord.getZ())*m_scaling);
|
||||
|
||||
} // mapPoint
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Creates the debug mesh to display the quad graph on top of the track
|
||||
* model. */
|
||||
void BattleGraph::createDebugMesh()
|
||||
{
|
||||
if(getNumNodes()<=0) return; // no debug output if not graph
|
||||
|
||||
createMesh(/*enable_transparency*/true);
|
||||
|
||||
// Now colour the quads red/blue/red ...
|
||||
video::SColor c( 128, 255, 0, 0);
|
||||
video::S3DVertex *v = (video::S3DVertex*)m_mesh_buffer->getVertices();
|
||||
for(unsigned int i=0; i<m_mesh_buffer->getVertexCount(); i++)
|
||||
{
|
||||
// Swap the colours from red to blue and back
|
||||
c.setRed ((i%2) ? 255 : 0);
|
||||
c.setBlue((i%2) ? 0 : 255);
|
||||
v[i].Color = c;
|
||||
}
|
||||
m_node = irr_driver->addMesh(m_mesh, "track-debug-mesh");
|
||||
#ifdef DEBUG
|
||||
m_node->setName("track-debug-mesh");
|
||||
#endif
|
||||
|
||||
} // createDebugMesh
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Cleans up the debug mesh */
|
||||
void BattleGraph::cleanupDebugMesh()
|
||||
{
|
||||
if(m_node != NULL)
|
||||
irr_driver->removeNode(m_node);
|
||||
|
||||
m_node = NULL;
|
||||
// No need to call irr_driber->removeMeshFromCache, since the mesh
|
||||
// was manually made and so never added to the mesh cache.
|
||||
m_mesh->drop();
|
||||
m_mesh = NULL;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Maps items on battle graph */
|
||||
void BattleGraph::findItemsOnGraphNodes()
|
||||
{
|
||||
@ -407,11 +138,7 @@ void BattleGraph::findItemsOnGraphNodes()
|
||||
for (unsigned int j = 0; j < this->getNumNodes(); ++j)
|
||||
{
|
||||
if (NavMesh::get()->getNavPoly(j).pointInPoly(xyz))
|
||||
{
|
||||
float dist = xyz.getY() - NavMesh::get()->getCenterOfPoly(j).getY();
|
||||
if (fabsf(dist) < 1.0f )
|
||||
polygon = j;
|
||||
}
|
||||
polygon = j;
|
||||
}
|
||||
|
||||
if (polygon != BattleGraph::UNKNOWN_POLY)
|
||||
|
@ -23,21 +23,13 @@
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include <dimension2d.h>
|
||||
#include "tracks/graph_structure.hpp"
|
||||
#include "tracks/navmesh.hpp"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class ISceneNode; class IMesh; class IMeshBuffer; }
|
||||
namespace video { class ITexture; }
|
||||
}
|
||||
using namespace irr;
|
||||
|
||||
class FrameBuffer;
|
||||
class GraphStructure;
|
||||
class Item;
|
||||
class ItemManager;
|
||||
class Navmesh;
|
||||
class RTT;
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
@ -49,30 +41,16 @@ class RTT;
|
||||
* design pattern to create an instance).
|
||||
\ingroup tracks
|
||||
*/
|
||||
class BattleGraph
|
||||
class BattleGraph : public GraphStructure
|
||||
{
|
||||
|
||||
private:
|
||||
static BattleGraph *m_battle_graph;
|
||||
|
||||
RTT* m_new_rtt;
|
||||
|
||||
/** The actual graph data structure, it is an adjacency matrix */
|
||||
std::vector< std::vector< float > > m_distance_matrix;
|
||||
/** The matrix that is used to store computed shortest paths */
|
||||
std::vector< std::vector< int > > m_parent_poly;
|
||||
/** For debug mode only: the node of the debug mesh. */
|
||||
scene::ISceneNode *m_node;
|
||||
/** For debug only: the mesh of the debug mesh. */
|
||||
scene::IMesh *m_mesh;
|
||||
/** For debug only: the actual mesh buffer storing the quads. */
|
||||
scene::IMeshBuffer *m_mesh_buffer;
|
||||
|
||||
/** The minimum coordinates of the quad graph. */
|
||||
Vec3 m_min_coord;
|
||||
|
||||
/** Scaling for mini map. */
|
||||
float m_scaling;
|
||||
|
||||
/** Stores the name of the file containing the NavMesh data */
|
||||
std::string m_navmesh_file;
|
||||
@ -81,12 +59,27 @@ private:
|
||||
|
||||
void buildGraph(NavMesh*);
|
||||
void computeFloydWarshall();
|
||||
void createMesh(bool enable_transparency=false,
|
||||
const video::SColor *track_color=NULL);
|
||||
|
||||
BattleGraph(const std::string &navmesh_file_name);
|
||||
~BattleGraph(void);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void set3DVerticesOfGraph(int i, video::S3DVertex *v,
|
||||
const video::SColor &color) const
|
||||
{ NavMesh::get()->setVertices(i, v, color); }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void getGraphBoundingBox(Vec3 *min, Vec3 *max) const
|
||||
{ NavMesh::get()->getBoundingBox(min, max); }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const bool isNodeInvisible(int n) const
|
||||
{ return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const bool isNodeInvalid(int n) const
|
||||
{ return (NavMesh::get()->getNavPoly(n).getVerticesIndex()).size()!=4; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const bool hasLapLine() const
|
||||
{ return false; }
|
||||
|
||||
public:
|
||||
static const int UNKNOWN_POLY;
|
||||
|
||||
@ -115,12 +108,13 @@ public:
|
||||
// ----------------------------------------------------------------------
|
||||
/** Returns the number of nodes in the BattleGraph (equal to the number of
|
||||
* polygons in the NavMesh */
|
||||
unsigned int getNumNodes() const { return m_distance_matrix.size(); }
|
||||
virtual const unsigned int getNumNodes() const
|
||||
{ return m_distance_matrix.size(); }
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Returns the NavPoly corresponding to the i-th node of the BattleGraph */
|
||||
const NavPoly& getPolyOfNode(int i) const
|
||||
{ return NavMesh::get()->getNavPoly(i); }
|
||||
{ return NavMesh::get()->getNavPoly(i); }
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Returns the next polygon on the shortest path from i to j.
|
||||
@ -129,17 +123,9 @@ public:
|
||||
const int & getNextShortestPathPoly(int i, int j) const;
|
||||
|
||||
const std::vector < std::pair<const Item*, int> >& getItemList()
|
||||
{ return m_items_on_graph; }
|
||||
{ return m_items_on_graph; }
|
||||
|
||||
void createDebugMesh();
|
||||
void cleanupDebugMesh();
|
||||
void findItemsOnGraphNodes();
|
||||
void makeMiniMap(const core::dimension2du &where,
|
||||
const std::string &name,
|
||||
const video::SColor &fill_color,
|
||||
video::ITexture** oldRttMinimap,
|
||||
FrameBuffer** newRttMinimap);
|
||||
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
|
||||
}; //BattleGraph
|
||||
|
||||
#endif
|
||||
|
384
src/tracks/graph_structure.cpp
Normal file
384
src/tracks/graph_structure.cpp
Normal file
@ -0,0 +1,384 @@
|
||||
//
|
||||
// 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 "tracks/graph_structure.hpp"
|
||||
|
||||
#include <IMesh.h>
|
||||
#include <ICameraSceneNode.h>
|
||||
#include <IMeshSceneNode.h>
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/glwrap.hpp"
|
||||
#include "graphics/shaders.hpp"
|
||||
#include "graphics/rtts.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
GraphStructure::GraphStructure()
|
||||
{
|
||||
m_min_coord = 0;
|
||||
m_scaling = 0;
|
||||
m_node = NULL;
|
||||
m_mesh = NULL;
|
||||
m_mesh_buffer = NULL;
|
||||
m_new_rtt = NULL;
|
||||
} // GraphStructure
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void GraphStructure::destroyRTT()
|
||||
{
|
||||
if (m_new_rtt != NULL)
|
||||
{
|
||||
delete m_new_rtt;
|
||||
m_new_rtt = NULL;
|
||||
}
|
||||
} // destroyRTT
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Cleans up the debug mesh */
|
||||
void GraphStructure::cleanupDebugMesh()
|
||||
{
|
||||
if (m_node != NULL)
|
||||
irr_driver->removeNode(m_node);
|
||||
|
||||
m_node = NULL;
|
||||
// No need to call irr_driber->removeMeshFromCache, since the mesh
|
||||
// was manually made and so never added to the mesh cache.
|
||||
m_mesh->drop();
|
||||
m_mesh = NULL;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Creates the debug mesh to display the graph on top of the track
|
||||
* model. */
|
||||
void GraphStructure::createDebugMesh()
|
||||
{
|
||||
if (getNumNodes() <= 0) return; // no debug output if not graph
|
||||
|
||||
createMesh(/*show_invisible*/true,
|
||||
/*enable_transparency*/true);
|
||||
|
||||
// Now colour the quads red/blue/red ...
|
||||
video::SColor c( 128, 255, 0, 0);
|
||||
video::S3DVertex *v = (video::S3DVertex*)m_mesh_buffer->getVertices();
|
||||
for (unsigned int i = 0; i < m_mesh_buffer->getVertexCount(); i++)
|
||||
{
|
||||
// Swap the colours from red to blue and back
|
||||
c.setRed ((i%2) ? 255 : 0);
|
||||
c.setBlue((i%2) ? 0 : 255);
|
||||
v[i].Color = c;
|
||||
}
|
||||
m_node = irr_driver->addMesh(m_mesh, "track-debug-mesh");
|
||||
#ifdef DEBUG
|
||||
m_node->setName("track-debug-mesh");
|
||||
#endif
|
||||
|
||||
} // createDebugMesh
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Creates the actual mesh that is used by createDebugMesh() or makeMiniMap() */
|
||||
void GraphStructure::createMesh(bool show_invisible,
|
||||
bool enable_transparency,
|
||||
const video::SColor *track_color)
|
||||
{
|
||||
// The debug track will not be lighted or culled.
|
||||
video::SMaterial m;
|
||||
m.BackfaceCulling = false;
|
||||
m.Lighting = false;
|
||||
if (enable_transparency)
|
||||
m.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
m.setTexture(0, getUnicolorTexture(video::SColor(255, 255, 255, 255)));
|
||||
m.setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0)));
|
||||
m_mesh = irr_driver->createQuadMesh(&m);
|
||||
m_mesh_buffer = m_mesh->getMeshBuffer(0);
|
||||
assert(m_mesh_buffer->getVertexType()==video::EVT_STANDARD);
|
||||
|
||||
unsigned int n = 0;
|
||||
const unsigned int total_nodes = getNumNodes();
|
||||
|
||||
// Count the number of quads to display (some quads might be invisible)
|
||||
for (unsigned int i = 0; i < total_nodes; i++)
|
||||
{
|
||||
if (show_invisible || !isNodeInvisible(i))
|
||||
n++;
|
||||
}
|
||||
|
||||
// Four vertices for each of the n-1 remaining quads
|
||||
video::S3DVertex *new_v = new video::S3DVertex[4*n];
|
||||
// Each quad consists of 2 triangles with 3 elements, so
|
||||
// we need 2*3 indices for each quad.
|
||||
irr::u16 *ind = new irr::u16[6*n];
|
||||
video::SColor c(255, 255, 0, 0);
|
||||
|
||||
if (track_color)
|
||||
c = *track_color;
|
||||
|
||||
// Now add all quads
|
||||
int i = 0;
|
||||
for (unsigned int count = 0; count < total_nodes; count++)
|
||||
{
|
||||
// Ignore invisible quads
|
||||
if (!show_invisible && isNodeInvisible(count))
|
||||
continue;
|
||||
else if (isNodeInvalid(count))
|
||||
{
|
||||
// There should not be a node which isn't made of 4 vertices
|
||||
Log::warn("Graph Structure", "There is an invalid node!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Swap the colours from red to blue and back
|
||||
if (!track_color)
|
||||
{
|
||||
c.setRed ((i%2) ? 255 : 0);
|
||||
c.setBlue((i%2) ? 0 : 255);
|
||||
}
|
||||
|
||||
// Transfer the 4 points of the current quad to the list of vertices
|
||||
set3DVerticesOfGraph(count, new_v+4*i, c);
|
||||
|
||||
// Set up the indices for the triangles
|
||||
// (note, afaik with opengl we could use quads directly, but the code
|
||||
// would not be portable to directx anymore).
|
||||
ind[6*i ] = 4*i+2; // First triangle: vertex 0, 1, 2
|
||||
ind[6*i+1] = 4*i+1;
|
||||
ind[6*i+2] = 4*i;
|
||||
ind[6*i+3] = 4*i+3; // second triangle: vertex 0, 1, 3
|
||||
ind[6*i+4] = 4*i+2;
|
||||
ind[6*i+5] = 4*i;
|
||||
i++;
|
||||
}
|
||||
|
||||
m_mesh_buffer->append(new_v, n*4, ind, n*6);
|
||||
|
||||
if (hasLapLine())
|
||||
{
|
||||
video::S3DVertex lap_v[4];
|
||||
irr::u16 lap_ind[6];
|
||||
video::SColor lap_color(128, 255, 0, 0);
|
||||
set3DVerticesOfGraph(0, lap_v, lap_color);
|
||||
|
||||
// Now scale the length (distance between vertix 0 and 3
|
||||
// and between 1 and 2) to be 'length':
|
||||
Vec3 bb_min, bb_max;
|
||||
getGraphBoundingBox(&bb_min, &bb_max);
|
||||
// Length of the lap line about 3% of the 'height'
|
||||
// of the track.
|
||||
const float length = (bb_max.getZ()-bb_min.getZ())*0.03f;
|
||||
|
||||
core::vector3df dl = lap_v[3].Pos-lap_v[0].Pos;
|
||||
float ll2 = dl.getLengthSQ();
|
||||
if (ll2 < 0.001)
|
||||
lap_v[3].Pos = lap_v[0].Pos+core::vector3df(0, 0, 1);
|
||||
else
|
||||
lap_v[3].Pos = lap_v[0].Pos+dl*length/sqrt(ll2);
|
||||
|
||||
core::vector3df dr = lap_v[2].Pos-lap_v[1].Pos;
|
||||
float lr2 = dr.getLengthSQ();
|
||||
if (lr2 < 0.001)
|
||||
lap_v[2].Pos = lap_v[1].Pos+core::vector3df(0, 0, 1);
|
||||
else
|
||||
lap_v[2].Pos = lap_v[1].Pos+dr*length/sqrt(lr2);
|
||||
lap_ind[0] = 2;
|
||||
lap_ind[1] = 1;
|
||||
lap_ind[2] = 0;
|
||||
lap_ind[3] = 3;
|
||||
lap_ind[4] = 2;
|
||||
lap_ind[5] = 0;
|
||||
// Set it a bit higher to avoid issued with z fighting,
|
||||
// i.e. part of the lap line might not be visible.
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
lap_v[i].Pos.Y += 0.1f;
|
||||
#ifndef USE_TEXTURED_LINE
|
||||
m_mesh_buffer->append(lap_v, 4, lap_ind, 6);
|
||||
#else
|
||||
lap_v[0].TCoords = core::vector2df(0,0);
|
||||
lap_v[1].TCoords = core::vector2df(3,0);
|
||||
lap_v[2].TCoords = core::vector2df(3,1);
|
||||
lap_v[3].TCoords = core::vector2df(0,1);
|
||||
m_mesh_buffer->append(lap_v, 4, lap_ind, 6);
|
||||
video::SMaterial &m = m_mesh_buffer->getMaterial();
|
||||
video::ITexture *t = irr_driver->getTexture("chess.png");
|
||||
m.setTexture(0, t);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Instead of setting the bounding boxes, we could just disable culling,
|
||||
// since the debug track should always be drawn.
|
||||
//m_node->setAutomaticCulling(scene::EAC_OFF);
|
||||
m_mesh_buffer->recalculateBoundingBox();
|
||||
m_mesh->setBoundingBox(m_mesh_buffer->getBoundingBox());
|
||||
|
||||
m_mesh_buffer->getMaterial().setTexture(0, irr_driver->getTexture("unlit.png"));
|
||||
|
||||
delete[] ind;
|
||||
delete[] new_v;
|
||||
} // createMesh
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Takes a snapshot of the graph so they can be used as minimap.
|
||||
*/
|
||||
void GraphStructure::makeMiniMap(const core::dimension2du &dimension,
|
||||
const std::string &name,
|
||||
const video::SColor &fill_color,
|
||||
video::ITexture** oldRttMinimap,
|
||||
FrameBuffer** newRttMinimap)
|
||||
{
|
||||
const video::SColor oldClearColor = World::getWorld()->getClearColor();
|
||||
World::getWorld()->setClearbackBufferColor(video::SColor(0, 255, 255, 255));
|
||||
World::getWorld()->forceFogDisabled(true);
|
||||
*oldRttMinimap = NULL;
|
||||
*newRttMinimap = NULL;
|
||||
|
||||
RTT* newRttProvider = NULL;
|
||||
IrrDriver::RTTProvider* oldRttProvider = NULL;
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
m_new_rtt = newRttProvider = new RTT(dimension.Width, dimension.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldRttProvider = new IrrDriver::RTTProvider(dimension, name, true);
|
||||
}
|
||||
|
||||
irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 255, 255, 255));
|
||||
|
||||
createMesh(/*show_invisible part of the track*/ false,
|
||||
/*enable_transparency*/ false,
|
||||
/*track_color*/ &fill_color);
|
||||
|
||||
m_node = irr_driver->addMesh(m_mesh, "mini_map");
|
||||
#ifdef DEBUG
|
||||
m_node->setName("minimap-mesh");
|
||||
#endif
|
||||
|
||||
m_node->setAutomaticCulling(0);
|
||||
m_node->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||
|
||||
// Add the camera:
|
||||
// ---------------
|
||||
scene::ICameraSceneNode *camera = irr_driver->addCameraSceneNode();
|
||||
Vec3 bb_min, bb_max;
|
||||
getGraphBoundingBox(&bb_min, &bb_max);
|
||||
Vec3 center = (bb_max+bb_min)*0.5f;
|
||||
|
||||
float dx = bb_max.getX()-bb_min.getX();
|
||||
float dz = bb_max.getZ()-bb_min.getZ();
|
||||
|
||||
// Set the scaling correctly. Also the center point (which is used
|
||||
// as the camera position) needs to be adjusted: the track must
|
||||
// be aligned to the left/top of the texture which is used (otherwise
|
||||
// mapPoint2MiniMap doesn't work), so adjust the camera position
|
||||
// that the track is properly aligned (view from the side):
|
||||
// c camera
|
||||
// / \ .
|
||||
// / \ <--- camera angle
|
||||
// / \ .
|
||||
// { [-] } <--- track flat (viewed from the side)
|
||||
// If [-] is the shorter side of the track, then the camera will
|
||||
// actually render the area in { } - which is the length of the
|
||||
// longer side of the track.
|
||||
// To align the [-] side to the left, the camera must be moved
|
||||
// the distance betwwen '{' and '[' to the right. This distance
|
||||
// is exacly (longer_side - shorter_side) / 2.
|
||||
// So, adjust the center point by this amount:
|
||||
if (dz > dx)
|
||||
{
|
||||
center.setX(center.getX() + (dz-dx)*0.5f);
|
||||
m_scaling = dimension.Width / dz;
|
||||
}
|
||||
else
|
||||
{
|
||||
center.setZ(center.getZ() + (dx-dz)*0.5f);
|
||||
m_scaling = dimension.Width / dx;
|
||||
}
|
||||
|
||||
float range = (dx>dz) ? dx : dz;
|
||||
|
||||
core::matrix4 projection;
|
||||
projection.buildProjectionMatrixOrthoLH(range /* width */,
|
||||
range /* height */,
|
||||
-1, bb_max.getY()-bb_min.getY()+1);
|
||||
camera->setProjectionMatrix(projection, true);
|
||||
|
||||
irr_driver->suppressSkyBox();
|
||||
irr_driver->clearLights();
|
||||
|
||||
// Adjust Y position by +1 for max, -1 for min - this helps in case that
|
||||
// the maximum Y coordinate is negative (otherwise the minimap is mirrored)
|
||||
// and avoids problems for tracks which have a flat (max Y = min Y) minimap.
|
||||
camera->setPosition(core::vector3df(center.getX(), bb_min.getY() + 1.0f, center.getZ()));
|
||||
//camera->setPosition(core::vector3df(center.getX() - 5.0f, bb_min.getY() - 1 - 5.0f, center.getZ() - 15.0f));
|
||||
camera->setUpVector(core::vector3df(0, 0, 1));
|
||||
camera->setTarget(core::vector3df(center.getX(),bb_min.getY()-1,center.getZ()));
|
||||
//camera->setAspectRatio(1.0f);
|
||||
camera->updateAbsolutePosition();
|
||||
|
||||
video::ITexture* texture = NULL;
|
||||
FrameBuffer* frame_buffer = NULL;
|
||||
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
frame_buffer = newRttProvider->render(camera, GUIEngine::getLatestDt());
|
||||
}
|
||||
else
|
||||
{
|
||||
texture = oldRttProvider->renderToTexture();
|
||||
delete oldRttProvider;
|
||||
}
|
||||
|
||||
cleanupDebugMesh();
|
||||
irr_driver->removeCameraSceneNode(camera);
|
||||
m_min_coord = bb_min;
|
||||
|
||||
|
||||
if (texture == NULL && frame_buffer == NULL)
|
||||
{
|
||||
Log::error("Graph Structure", "[makeMiniMap] WARNING: RTT does not"
|
||||
"appear to work, mini-map will not be available.");
|
||||
}
|
||||
|
||||
*oldRttMinimap = texture;
|
||||
*newRttMinimap = frame_buffer;
|
||||
World::getWorld()->setClearbackBufferColor(oldClearColor);
|
||||
World::getWorld()->forceFogDisabled(false);
|
||||
|
||||
irr_driver->getSceneManager()->clear();
|
||||
VAOManager::kill();
|
||||
irr_driver->clearGlowingNodes();
|
||||
irr_driver->clearLights();
|
||||
irr_driver->clearForcedBloom();
|
||||
irr_driver->clearBackgroundNodes();
|
||||
} // makeMiniMap
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Returns the 2d coordinates of a point when drawn on the mini map
|
||||
* texture.
|
||||
* \param xyz Coordinates of the point to map.
|
||||
* \param draw_at The coordinates in pixel on the mini map of the point,
|
||||
* only the first two coordinates will be used.
|
||||
*/
|
||||
void GraphStructure::mapPoint2MiniMap(const Vec3 &xyz,Vec3 *draw_at) const
|
||||
{
|
||||
draw_at->setX((xyz.getX()-m_min_coord.getX())*m_scaling);
|
||||
draw_at->setY((xyz.getZ()-m_min_coord.getZ())*m_scaling);
|
||||
|
||||
} // mapPoint
|
94
src/tracks/graph_structure.hpp
Normal file
94
src/tracks/graph_structure.hpp
Normal file
@ -0,0 +1,94 @@
|
||||
//
|
||||
// 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_GRAPH_STRUCTURE_HPP
|
||||
#define HEADER_GRAPH_STRUCTURE_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <dimension2d.h>
|
||||
#include <SColor.h>
|
||||
#include "utils/vec3.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class ISceneNode; class IMesh; class IMeshBuffer; }
|
||||
namespace video { class ITexture; struct S3DVertex; }
|
||||
}
|
||||
using namespace irr;
|
||||
|
||||
class FrameBuffer;
|
||||
class RTT;
|
||||
|
||||
/**
|
||||
* \brief Virtual base class for a graph structure.
|
||||
* This is mainly used for drawing minimap in game.
|
||||
*
|
||||
* \ingroup tracks
|
||||
*/
|
||||
class GraphStructure : public NoCopy
|
||||
{
|
||||
protected:
|
||||
|
||||
void cleanupDebugMesh();
|
||||
void destroyRTT();
|
||||
|
||||
private:
|
||||
RTT* m_new_rtt;
|
||||
|
||||
/** The node of the graph mesh. */
|
||||
scene::ISceneNode *m_node;
|
||||
|
||||
/** The mesh of the graph mesh. */
|
||||
scene::IMesh *m_mesh;
|
||||
|
||||
/** The actual mesh buffer storing the graph. */
|
||||
scene::IMeshBuffer *m_mesh_buffer;
|
||||
|
||||
/** The minimum coordinates of the graph. */
|
||||
Vec3 m_min_coord;
|
||||
|
||||
/** Scaling for mini map. */
|
||||
float m_scaling;
|
||||
|
||||
void createMesh(bool show_invisible=true,
|
||||
bool enable_transparency=false,
|
||||
const video::SColor *track_color=NULL);
|
||||
|
||||
virtual void set3DVerticesOfGraph(int i, video::S3DVertex *v,
|
||||
const video::SColor &color) const = 0;
|
||||
virtual void getGraphBoundingBox(Vec3 *min, Vec3 *max) const = 0;
|
||||
virtual const bool isNodeInvisible(int n) const = 0;
|
||||
virtual const bool isNodeInvalid(int n) const = 0;
|
||||
virtual const bool hasLapLine() const = 0;
|
||||
|
||||
public:
|
||||
GraphStructure();
|
||||
virtual ~GraphStructure() {};
|
||||
void createDebugMesh();
|
||||
void makeMiniMap(const core::dimension2du &where,
|
||||
const std::string &name,
|
||||
const video::SColor &fill_color,
|
||||
video::ITexture** oldRttMinimap,
|
||||
FrameBuffer** newRttMinimap);
|
||||
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
|
||||
virtual const unsigned int getNumNodes() const = 0;
|
||||
}; // GraphStructure
|
||||
|
||||
#endif
|
@ -70,6 +70,10 @@ bool NavPoly::pointInPoly(const Vec3& p) const
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for vertical distance too
|
||||
const float dist = p.getY() - m_center.getY();
|
||||
if (fabsf(dist) > 1.0f )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,11 +51,7 @@ QuadGraph::QuadGraph(const std::string &quad_file_name,
|
||||
const std::string &graph_file_name,
|
||||
const bool reverse) : m_reverse(reverse)
|
||||
{
|
||||
m_node = NULL;
|
||||
m_mesh = NULL;
|
||||
m_mesh_buffer = NULL;
|
||||
m_lap_length = 0;
|
||||
m_new_rtt = NULL;
|
||||
QuadSet::create();
|
||||
QuadSet::get()->init(quad_file_name);
|
||||
m_quad_filename = quad_file_name;
|
||||
@ -73,8 +69,7 @@ QuadGraph::~QuadGraph()
|
||||
}
|
||||
if(UserConfigParams::m_track_debug)
|
||||
cleanupDebugMesh();
|
||||
if (m_new_rtt != NULL)
|
||||
delete m_new_rtt;
|
||||
GraphStructure::destroyRTT();
|
||||
} // ~QuadGraph
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -394,186 +389,6 @@ void QuadGraph::setDefaultStartPositions(AlignedArray<btTransform>
|
||||
} // for i<stk_config->m_max_karts
|
||||
} // setStartPositions
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Creates a mesh for this graph. The mesh is not added to a scene node and
|
||||
* is stored in m_mesh.
|
||||
* \param show_invisble If true, also create a mesh for parts of the
|
||||
* driveline that are invisible.
|
||||
* \param enable_transparency Enable alpha blending to make the mesh
|
||||
* semi transparent.
|
||||
* \param track_color Colour of the actual quads.
|
||||
* \param lap_color If defined, show the lap counting line in that colour.
|
||||
*/
|
||||
void QuadGraph::createMesh(bool show_invisible,
|
||||
bool enable_transparency,
|
||||
const video::SColor *track_color,
|
||||
const video::SColor *lap_color)
|
||||
{
|
||||
// The debug track will not be lighted or culled.
|
||||
video::SMaterial m;
|
||||
m.BackfaceCulling = false;
|
||||
m.Lighting = false;
|
||||
if(enable_transparency)
|
||||
m.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
m.setTexture(0, getUnicolorTexture(SColor(255, 255, 255, 255)));
|
||||
m.setTexture(1, getUnicolorTexture(SColor(0, 0, 0, 0)));
|
||||
m_mesh = irr_driver->createQuadMesh(&m);
|
||||
m_mesh_buffer = m_mesh->getMeshBuffer(0);
|
||||
assert(m_mesh_buffer->getVertexType()==video::EVT_STANDARD);
|
||||
|
||||
// Count the number of quads to display (some quads might be invisible
|
||||
unsigned int n = 0;
|
||||
for(unsigned int i=0; i<m_all_nodes.size(); i++)
|
||||
{
|
||||
if(show_invisible || !m_all_nodes[i]->getQuad().isInvisible())
|
||||
n++;
|
||||
}
|
||||
|
||||
// Four vertices for each of the n-1 remaining quads
|
||||
video::S3DVertex *new_v = new video::S3DVertex[4*n];
|
||||
// Each quad consists of 2 triangles with 3 elements, so
|
||||
// we need 2*3 indices for each quad.
|
||||
irr::u16 *ind = new irr::u16[6*n];
|
||||
video::SColor c(255, 255, 0, 0);
|
||||
|
||||
if(track_color)
|
||||
c = *track_color;
|
||||
|
||||
// Now add all quads
|
||||
int i=0;
|
||||
for(unsigned int count=0; count<m_all_nodes.size(); count++)
|
||||
{
|
||||
// Ignore invisible quads
|
||||
if(!show_invisible && m_all_nodes[count]->getQuad().isInvisible())
|
||||
continue;
|
||||
// Swap the colours from red to blue and back
|
||||
if(!track_color)
|
||||
{
|
||||
c.setRed ((i%2) ? 255 : 0);
|
||||
c.setBlue((i%2) ? 0 : 255);
|
||||
}
|
||||
// Transfer the 4 points of the current quad to the list of vertices
|
||||
m_all_nodes[count]->getQuad().getVertices(new_v+4*i, c);
|
||||
|
||||
// Set up the indices for the triangles
|
||||
// (note, afaik with opengl we could use quads directly, but the code
|
||||
// would not be portable to directx anymore).
|
||||
ind[6*i ] = 4*i+2; // First triangle: vertex 0, 1, 2
|
||||
ind[6*i+1] = 4*i+1;
|
||||
ind[6*i+2] = 4*i;
|
||||
ind[6*i+3] = 4*i+3; // second triangle: vertex 0, 1, 3
|
||||
ind[6*i+4] = 4*i+2;
|
||||
ind[6*i+5] = 4*i;
|
||||
i++;
|
||||
} // for i=1; i<QuadSet::get()
|
||||
|
||||
m_mesh_buffer->append(new_v, n*4, ind, n*6);
|
||||
|
||||
if(lap_color)
|
||||
{
|
||||
video::S3DVertex lap_v[4];
|
||||
irr::u16 lap_ind[6];
|
||||
video::SColor c(128, 255, 0, 0);
|
||||
m_all_nodes[0]->getQuad().getVertices(lap_v, *lap_color);
|
||||
|
||||
// Now scale the length (distance between vertix 0 and 3
|
||||
// and between 1 and 2) to be 'length':
|
||||
Vec3 bb_min, bb_max;
|
||||
QuadSet::get()->getBoundingBox(&bb_min, &bb_max);
|
||||
// Length of the lap line about 3% of the 'height'
|
||||
// of the track.
|
||||
const float length=(bb_max.getZ()-bb_min.getZ())*0.03f;
|
||||
|
||||
core::vector3df dl = lap_v[3].Pos-lap_v[0].Pos;
|
||||
float ll2 = dl.getLengthSQ();
|
||||
if(ll2<0.001)
|
||||
lap_v[3].Pos = lap_v[0].Pos+core::vector3df(0, 0, 1);
|
||||
else
|
||||
lap_v[3].Pos = lap_v[0].Pos+dl*length/sqrt(ll2);
|
||||
|
||||
core::vector3df dr = lap_v[2].Pos-lap_v[1].Pos;
|
||||
float lr2 = dr.getLengthSQ();
|
||||
if(lr2<0.001)
|
||||
lap_v[2].Pos = lap_v[1].Pos+core::vector3df(0, 0, 1);
|
||||
else
|
||||
lap_v[2].Pos = lap_v[1].Pos+dr*length/sqrt(lr2);
|
||||
lap_ind[0] = 2;
|
||||
lap_ind[1] = 1;
|
||||
lap_ind[2] = 0;
|
||||
lap_ind[3] = 3;
|
||||
lap_ind[4] = 2;
|
||||
lap_ind[5] = 0;
|
||||
// Set it a bit higher to avoid issued with z fighting,
|
||||
// i.e. part of the lap line might not be visible.
|
||||
for(unsigned int i=0; i<4; i++)
|
||||
lap_v[i].Pos.Y += 0.1f;
|
||||
#ifndef USE_TEXTURED_LINE
|
||||
m_mesh_buffer->append(lap_v, 4, lap_ind, 6);
|
||||
#else
|
||||
lap_v[0].TCoords = core::vector2df(0,0);
|
||||
lap_v[1].TCoords = core::vector2df(3,0);
|
||||
lap_v[2].TCoords = core::vector2df(3,1);
|
||||
lap_v[3].TCoords = core::vector2df(0,1);
|
||||
m_mesh_buffer->append(lap_v, 4, lap_ind, 6);
|
||||
video::SMaterial &m = m_mesh_buffer->getMaterial();
|
||||
video::ITexture *t = irr_driver->getTexture("chess.png");
|
||||
m.setTexture(0, t);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Instead of setting the bounding boxes, we could just disable culling,
|
||||
// since the debug track should always be drawn.
|
||||
//m_node->setAutomaticCulling(scene::EAC_OFF);
|
||||
m_mesh_buffer->recalculateBoundingBox();
|
||||
m_mesh->setBoundingBox(m_mesh_buffer->getBoundingBox());
|
||||
|
||||
m_mesh_buffer->getMaterial().setTexture(0, irr_driver->getTexture("unlit.png"));
|
||||
|
||||
delete[] ind;
|
||||
delete[] new_v;
|
||||
} // createMesh
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/** Creates the debug mesh to display the quad graph on top of the track
|
||||
* model. */
|
||||
void QuadGraph::createDebugMesh()
|
||||
{
|
||||
if(m_all_nodes.size()<=0) return; // no debug output if not graph
|
||||
|
||||
createMesh(/*show_invisible*/true,
|
||||
/*enable_transparency*/true);
|
||||
|
||||
// Now colour the quads red/blue/red ...
|
||||
video::SColor c( 128, 255, 0, 0);
|
||||
video::S3DVertex *v = (video::S3DVertex*)m_mesh_buffer->getVertices();
|
||||
for(unsigned int i=0; i<m_mesh_buffer->getVertexCount(); i++)
|
||||
{
|
||||
// Swap the colours from red to blue and back
|
||||
c.setRed ((i%2) ? 255 : 0);
|
||||
c.setBlue((i%2) ? 0 : 255);
|
||||
v[i].Color = c;
|
||||
}
|
||||
m_node = irr_driver->addMesh(m_mesh, "quad_graph_debug");
|
||||
#ifdef DEBUG
|
||||
m_node->setName("track-debug-mesh");
|
||||
#endif
|
||||
|
||||
} // createDebugMesh
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Removes the debug mesh from the scene.
|
||||
*/
|
||||
void QuadGraph::cleanupDebugMesh()
|
||||
{
|
||||
irr_driver->removeNode(m_node);
|
||||
m_node = NULL;
|
||||
// No need to call irr_driber->removeMeshFromCache, since the mesh
|
||||
// was manually made and so never added to the mesh cache.
|
||||
m_mesh->drop();
|
||||
m_mesh = NULL;
|
||||
} // cleanupDebugMesh
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Returns the list of successors or a node.
|
||||
* \param node_number The number of the node.
|
||||
@ -974,155 +789,3 @@ int QuadGraph::findOutOfRoadSector(const Vec3& xyz,
|
||||
}
|
||||
return min_sector;
|
||||
} // findOutOfRoadSector
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Takes a snapshot of the driveline quads so they can be used as minimap.
|
||||
*/
|
||||
void QuadGraph::makeMiniMap(const core::dimension2du &dimension,
|
||||
const std::string &name,
|
||||
const video::SColor &fill_color,
|
||||
video::ITexture** oldRttMinimap,
|
||||
FrameBuffer** newRttMinimap)
|
||||
{
|
||||
const SColor oldClearColor = World::getWorld()->getClearColor();
|
||||
World::getWorld()->setClearbackBufferColor(SColor(0, 255, 255, 255));
|
||||
World::getWorld()->forceFogDisabled(true);
|
||||
*oldRttMinimap = NULL;
|
||||
*newRttMinimap = NULL;
|
||||
|
||||
RTT* newRttProvider = NULL;
|
||||
IrrDriver::RTTProvider* oldRttProvider = NULL;
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
m_new_rtt = newRttProvider = new RTT(dimension.Width, dimension.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldRttProvider = new IrrDriver::RTTProvider(dimension, name, true);
|
||||
}
|
||||
|
||||
irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 255, 255, 255));
|
||||
|
||||
video::SColor red(128, 255, 0, 0);
|
||||
createMesh(/*show_invisible part of the track*/ false,
|
||||
/*enable_transparency*/ false,
|
||||
/*track_color*/ &fill_color,
|
||||
/*lap line color*/ &red );
|
||||
|
||||
m_node = irr_driver->addMesh(m_mesh, "mini_map");
|
||||
#ifdef DEBUG
|
||||
m_node->setName("minimap-mesh");
|
||||
#endif
|
||||
|
||||
m_node->setAutomaticCulling(0);
|
||||
m_node->setMaterialFlag(video::EMF_LIGHTING, false);
|
||||
|
||||
// Add the camera:
|
||||
// ---------------
|
||||
scene::ICameraSceneNode *camera = irr_driver->addCameraSceneNode();
|
||||
Vec3 bb_min, bb_max;
|
||||
QuadSet::get()->getBoundingBox(&bb_min, &bb_max);
|
||||
Vec3 center = (bb_max+bb_min)*0.5f;
|
||||
|
||||
float dx = bb_max.getX()-bb_min.getX();
|
||||
float dz = bb_max.getZ()-bb_min.getZ();
|
||||
|
||||
// Set the scaling correctly. Also the center point (which is used
|
||||
// as the camera position) needs to be adjusted: the track must
|
||||
// be aligned to the left/top of the texture which is used (otherwise
|
||||
// mapPoint2MiniMap doesn't work), so adjust the camera position
|
||||
// that the track is properly aligned (view from the side):
|
||||
// c camera
|
||||
// / \ .
|
||||
// / \ <--- camera angle
|
||||
// / \ .
|
||||
// { [-] } <--- track flat (viewed from the side)
|
||||
// If [-] is the shorter side of the track, then the camera will
|
||||
// actually render the area in { } - which is the length of the
|
||||
// longer side of the track.
|
||||
// To align the [-] side to the left, the camera must be moved
|
||||
// the distance betwwen '{' and '[' to the right. This distance
|
||||
// is exacly (longer_side - shorter_side) / 2.
|
||||
// So, adjust the center point by this amount:
|
||||
if(dz > dx)
|
||||
{
|
||||
center.setX(center.getX() + (dz-dx)*0.5f);
|
||||
m_scaling = dimension.Width / dz;
|
||||
}
|
||||
else
|
||||
{
|
||||
center.setZ(center.getZ() + (dx-dz)*0.5f);
|
||||
m_scaling = dimension.Width / dx;
|
||||
}
|
||||
|
||||
float range = (dx>dz) ? dx : dz;
|
||||
|
||||
core::matrix4 projection;
|
||||
projection.buildProjectionMatrixOrthoLH(range /* width */,
|
||||
range /* height */,
|
||||
-1, bb_max.getY()-bb_min.getY()+1);
|
||||
camera->setProjectionMatrix(projection, true);
|
||||
|
||||
irr_driver->suppressSkyBox();
|
||||
irr_driver->clearLights();
|
||||
|
||||
// Adjust Y position by +1 for max, -1 for min - this helps in case that
|
||||
// the maximum Y coordinate is negative (otherwise the minimap is mirrored)
|
||||
// and avoids problems for tracks which have a flat (max Y = min Y) minimap.
|
||||
camera->setPosition(core::vector3df(center.getX(), bb_min.getY() + 1.0f, center.getZ()));
|
||||
//camera->setPosition(core::vector3df(center.getX() - 5.0f, bb_min.getY() - 1 - 5.0f, center.getZ() - 15.0f));
|
||||
camera->setUpVector(core::vector3df(0, 0, 1));
|
||||
camera->setTarget(core::vector3df(center.getX(),bb_min.getY()-1,center.getZ()));
|
||||
//camera->setAspectRatio(1.0f);
|
||||
camera->updateAbsolutePosition();
|
||||
|
||||
video::ITexture* texture = NULL;
|
||||
FrameBuffer* frame_buffer = NULL;
|
||||
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
frame_buffer = newRttProvider->render(camera, GUIEngine::getLatestDt());
|
||||
}
|
||||
else
|
||||
{
|
||||
texture = oldRttProvider->renderToTexture();
|
||||
delete oldRttProvider;
|
||||
}
|
||||
|
||||
cleanupDebugMesh();
|
||||
irr_driver->removeCameraSceneNode(camera);
|
||||
m_min_coord = bb_min;
|
||||
|
||||
|
||||
if (texture == NULL && frame_buffer == NULL)
|
||||
{
|
||||
Log::error("Quad Graph", "[makeMiniMap] WARNING: RTT does not appear to work,"
|
||||
"mini-map will not be available.");
|
||||
}
|
||||
|
||||
*oldRttMinimap = texture;
|
||||
*newRttMinimap = frame_buffer;
|
||||
World::getWorld()->setClearbackBufferColor(oldClearColor);
|
||||
World::getWorld()->forceFogDisabled(false);
|
||||
|
||||
irr_driver->getSceneManager()->clear();
|
||||
VAOManager::kill();
|
||||
irr_driver->clearGlowingNodes();
|
||||
irr_driver->clearLights();
|
||||
irr_driver->clearForcedBloom();
|
||||
irr_driver->clearBackgroundNodes();
|
||||
} // makeMiniMap
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the 2d coordinates of a point when drawn on the mini map
|
||||
* texture.
|
||||
* \param xyz Coordinates of the point to map.
|
||||
* \param draw_at The coordinates in pixel on the mini map of the point,
|
||||
* only the first two coordinates will be used.
|
||||
*/
|
||||
void QuadGraph::mapPoint2MiniMap(const Vec3 &xyz,Vec3 *draw_at) const
|
||||
{
|
||||
draw_at->setX((xyz.getX()-m_min_coord.getX())*m_scaling);
|
||||
draw_at->setY((xyz.getZ()-m_min_coord.getZ())*m_scaling);
|
||||
|
||||
} // mapPoint
|
||||
|
@ -24,21 +24,12 @@
|
||||
#include <set>
|
||||
|
||||
#include "tracks/graph_node.hpp"
|
||||
#include "tracks/graph_structure.hpp"
|
||||
#include "tracks/quad_set.hpp"
|
||||
#include "utils/aligned_array.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
#include <dimension2d.h>
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class ISceneNode; class IMesh; class IMeshBuffer; }
|
||||
namespace video { class ITexture; }
|
||||
}
|
||||
using namespace irr;
|
||||
|
||||
class CheckLine;
|
||||
class RTT;
|
||||
class FrameBuffer;
|
||||
class GraphStructure;
|
||||
|
||||
/**
|
||||
* \brief This class stores a graph of quads. It uses a 'simplified singleton'
|
||||
@ -50,32 +41,18 @@ class FrameBuffer;
|
||||
* returns NULL in this case, and this is tested where necessary.
|
||||
* \ingroup tracks
|
||||
*/
|
||||
class QuadGraph : public NoCopy
|
||||
class QuadGraph : public GraphStructure
|
||||
{
|
||||
|
||||
private:
|
||||
static QuadGraph *m_quad_graph;
|
||||
|
||||
RTT* m_new_rtt;
|
||||
|
||||
/** The actual graph data structure. */
|
||||
std::vector<GraphNode*> m_all_nodes;
|
||||
/** For debug mode only: the node of the debug mesh. */
|
||||
scene::ISceneNode *m_node;
|
||||
/** For debug only: the mesh of the debug mesh. */
|
||||
scene::IMesh *m_mesh;
|
||||
/** For debug only: the actual mesh buffer storing the quads. */
|
||||
scene::IMeshBuffer *m_mesh_buffer;
|
||||
|
||||
/** The length of the first loop. */
|
||||
float m_lap_length;
|
||||
|
||||
/** The minimum coordinates of the quad graph. */
|
||||
Vec3 m_min_coord;
|
||||
|
||||
/** Scaling for mini map. */
|
||||
float m_scaling;
|
||||
|
||||
/** Stores the filename - just used for error messages. */
|
||||
std::string m_quad_filename;
|
||||
|
||||
@ -91,20 +68,32 @@ private:
|
||||
void addSuccessor(unsigned int from, unsigned int to);
|
||||
void load (const std::string &filename);
|
||||
void computeDistanceFromStart(unsigned int start_node, float distance);
|
||||
void createMesh(bool show_invisible=true,
|
||||
bool enable_transparency=false,
|
||||
const video::SColor *track_color=NULL,
|
||||
const video::SColor *lap_color=NULL);
|
||||
unsigned int getStartNode() const;
|
||||
QuadGraph (const std::string &quad_file_name,
|
||||
const std::string &graph_file_name,
|
||||
const bool reverse);
|
||||
~QuadGraph ();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void set3DVerticesOfGraph(int i, video::S3DVertex *v,
|
||||
const video::SColor &color) const
|
||||
{ m_all_nodes[i]->getQuad().getVertices(v, color); }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void getGraphBoundingBox(Vec3 *min, Vec3 *max) const
|
||||
{ QuadSet::get()->getBoundingBox(min, max); }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const bool isNodeInvisible(int n) const
|
||||
{ return m_all_nodes[n]->getQuad().isInvisible(); }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const bool isNodeInvalid(int n) const
|
||||
{ return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const bool hasLapLine() const
|
||||
{ return true; }
|
||||
|
||||
public:
|
||||
static const int UNKNOWN_SECTOR;
|
||||
|
||||
void createDebugMesh();
|
||||
void cleanupDebugMesh();
|
||||
void getSuccessors(int node_number,
|
||||
std::vector<unsigned int>& succ,
|
||||
bool for_ai=false) const;
|
||||
@ -122,12 +111,6 @@ public:
|
||||
float forwards_distance=1.5f,
|
||||
float sidewards_distance=1.5f,
|
||||
float upwards_distance=0.0f) const;
|
||||
void makeMiniMap(const core::dimension2du &where,
|
||||
const std::string &name,
|
||||
const video::SColor &fill_color,
|
||||
video::ITexture** oldRttMinimap,
|
||||
FrameBuffer** newRttMinimap);
|
||||
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
|
||||
void updateDistancesForAllSuccessors(unsigned int indx,
|
||||
float delta,
|
||||
unsigned int count);
|
||||
@ -164,7 +147,8 @@ public:
|
||||
} // destroy
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of nodes in the graph. */
|
||||
unsigned int getNumNodes() const { return (unsigned int)m_all_nodes.size();}
|
||||
virtual const unsigned int getNumNodes() const
|
||||
{ return (unsigned int)m_all_nodes.size();}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the distance to the j-th successor of node n. */
|
||||
float getDistanceToNext(int n, int j) const
|
||||
@ -193,9 +177,7 @@ public:
|
||||
/** Returns the length of the main driveline. */
|
||||
float getLapLength() const {return m_lap_length; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if the graph is to be reversed. */
|
||||
bool isReverse() const {return m_reverse; }
|
||||
|
||||
}; // QuadGraph
|
||||
|
||||
#endif
|
||||
|
@ -115,6 +115,7 @@ Track::Track(const std::string &filename)
|
||||
m_enable_push_back = true;
|
||||
m_reverse_available = false;
|
||||
m_is_arena = false;
|
||||
m_max_arena_players = 0;
|
||||
m_has_easter_eggs = false;
|
||||
m_has_navmesh = false;
|
||||
m_is_soccer = false;
|
||||
@ -510,6 +511,7 @@ void Track::loadTrackInfo()
|
||||
root->get("gravity", &m_gravity);
|
||||
root->get("soccer", &m_is_soccer);
|
||||
root->get("arena", &m_is_arena);
|
||||
root->get("max-arena-players", &m_max_arena_players);
|
||||
root->get("cutscene", &m_is_cutscene);
|
||||
root->get("groups", &m_groups);
|
||||
root->get("internal", &m_internal);
|
||||
@ -672,35 +674,7 @@ void Track::loadBattleGraph()
|
||||
}
|
||||
else
|
||||
{
|
||||
//Check whether the hardware can do nonsquare or
|
||||
// non power-of-two textures
|
||||
video::IVideoDriver* const video_driver = irr_driver->getVideoDriver();
|
||||
bool nonpower = false; //video_driver->queryFeature(video::EVDF_TEXTURE_NPOT);
|
||||
bool nonsquare =
|
||||
video_driver->queryFeature(video::EVDF_TEXTURE_NSQUARE);
|
||||
|
||||
//Create the minimap resizing it as necessary.
|
||||
m_mini_map_size = World::getWorld()->getRaceGUI()->getMiniMapSize();
|
||||
core::dimension2du size = m_mini_map_size
|
||||
.getOptimalSize(!nonpower,!nonsquare);
|
||||
|
||||
BattleGraph::get()->makeMiniMap(size, "minimap::" + m_ident, video::SColor(127, 255, 255, 255),
|
||||
&m_old_rtt_mini_map, &m_new_rtt_mini_map);
|
||||
if (m_old_rtt_mini_map)
|
||||
{
|
||||
m_minimap_x_scale = float(m_mini_map_size.Width) / float(m_old_rtt_mini_map->getSize().Width);
|
||||
m_minimap_y_scale = float(m_mini_map_size.Height) / float(m_old_rtt_mini_map->getSize().Height);
|
||||
}
|
||||
else if (m_new_rtt_mini_map)
|
||||
{
|
||||
m_minimap_x_scale = float(m_mini_map_size.Width) / float(m_new_rtt_mini_map->getWidth());
|
||||
m_minimap_y_scale = float(m_mini_map_size.Height) / float(m_new_rtt_mini_map->getHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_minimap_x_scale = 0;
|
||||
m_minimap_y_scale = 0;
|
||||
}
|
||||
loadMinimap();
|
||||
}
|
||||
} // loadBattleGraph
|
||||
|
||||
@ -734,35 +708,7 @@ void Track::loadQuadGraph(unsigned int mode_id, const bool reverse)
|
||||
}
|
||||
else
|
||||
{
|
||||
//Check whether the hardware can do nonsquare or
|
||||
// non power-of-two textures
|
||||
video::IVideoDriver* const video_driver = irr_driver->getVideoDriver();
|
||||
bool nonpower = false; //video_driver->queryFeature(video::EVDF_TEXTURE_NPOT);
|
||||
bool nonsquare =
|
||||
video_driver->queryFeature(video::EVDF_TEXTURE_NSQUARE);
|
||||
|
||||
//Create the minimap resizing it as necessary.
|
||||
m_mini_map_size = World::getWorld()->getRaceGUI()->getMiniMapSize();
|
||||
core::dimension2du size = m_mini_map_size
|
||||
.getOptimalSize(!nonpower,!nonsquare);
|
||||
|
||||
QuadGraph::get()->makeMiniMap(size, "minimap::" + m_ident, video::SColor(127, 255, 255, 255),
|
||||
&m_old_rtt_mini_map, &m_new_rtt_mini_map);
|
||||
if (m_old_rtt_mini_map)
|
||||
{
|
||||
m_minimap_x_scale = float(m_mini_map_size.Width) / float(m_old_rtt_mini_map->getSize().Width);
|
||||
m_minimap_y_scale = float(m_mini_map_size.Height) / float(m_old_rtt_mini_map->getSize().Height);
|
||||
}
|
||||
else if (m_new_rtt_mini_map)
|
||||
{
|
||||
m_minimap_x_scale = float(m_mini_map_size.Width) / float(m_new_rtt_mini_map->getWidth());
|
||||
m_minimap_y_scale = float(m_mini_map_size.Height) / float(m_new_rtt_mini_map->getHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_minimap_x_scale = 0;
|
||||
m_minimap_y_scale = 0;
|
||||
}
|
||||
loadMinimap();
|
||||
}
|
||||
} // loadQuadGraph
|
||||
|
||||
@ -1070,6 +1016,50 @@ void Track::convertTrackToBullet(scene::ISceneNode *node)
|
||||
|
||||
} // convertTrackToBullet
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Track::loadMinimap()
|
||||
{
|
||||
//Check whether the hardware can do nonsquare or
|
||||
// non power-of-two textures
|
||||
video::IVideoDriver* const video_driver = irr_driver->getVideoDriver();
|
||||
bool nonpower = false; //video_driver->queryFeature(video::EVDF_TEXTURE_NPOT);
|
||||
bool nonsquare =
|
||||
video_driver->queryFeature(video::EVDF_TEXTURE_NSQUARE);
|
||||
|
||||
//Create the minimap resizing it as necessary.
|
||||
m_mini_map_size = World::getWorld()->getRaceGUI()->getMiniMapSize();
|
||||
core::dimension2du size = m_mini_map_size
|
||||
.getOptimalSize(!nonpower,!nonsquare);
|
||||
|
||||
if (m_is_arena && m_has_navmesh)
|
||||
{
|
||||
BattleGraph::get()->makeMiniMap(size, "minimap::" + m_ident, video::SColor(127, 255, 255, 255),
|
||||
&m_old_rtt_mini_map, &m_new_rtt_mini_map);
|
||||
}
|
||||
else
|
||||
{
|
||||
QuadGraph::get()->makeMiniMap(size, "minimap::" + m_ident, video::SColor(127, 255, 255, 255),
|
||||
&m_old_rtt_mini_map, &m_new_rtt_mini_map);
|
||||
}
|
||||
|
||||
if (m_old_rtt_mini_map)
|
||||
{
|
||||
m_minimap_x_scale = float(m_mini_map_size.Width) / float(m_old_rtt_mini_map->getSize().Width);
|
||||
m_minimap_y_scale = float(m_mini_map_size.Height) / float(m_old_rtt_mini_map->getSize().Height);
|
||||
}
|
||||
else if (m_new_rtt_mini_map)
|
||||
{
|
||||
m_minimap_x_scale = float(m_mini_map_size.Width) / float(m_new_rtt_mini_map->getWidth());
|
||||
m_minimap_y_scale = float(m_mini_map_size.Height) / float(m_new_rtt_mini_map->getHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_minimap_x_scale = 0;
|
||||
m_minimap_y_scale = 0;
|
||||
}
|
||||
} // loadMinimap
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Loads the main track model (i.e. all other objects contained in the
|
||||
* scene might use raycast on this track model to determine the actual
|
||||
|
@ -204,6 +204,8 @@ private:
|
||||
Vec3 m_aabb_max;
|
||||
/** True if this track is an arena. */
|
||||
bool m_is_arena;
|
||||
/** Max players supported by an arena. */
|
||||
unsigned int m_max_arena_players;
|
||||
/** True if this track has easter eggs. */
|
||||
bool m_has_easter_eggs;
|
||||
/** True if this track has navmesh. */
|
||||
@ -382,6 +384,7 @@ private:
|
||||
void loadBattleGraph();
|
||||
void convertTrackToBullet(scene::ISceneNode *node);
|
||||
bool loadMainTrack(const XMLNode &node);
|
||||
void loadMinimap();
|
||||
void createWater(const XMLNode &node);
|
||||
void getMusicInformation(std::vector<std::string>& filenames,
|
||||
std::vector<MusicInformation*>& m_music );
|
||||
@ -543,6 +546,10 @@ public:
|
||||
/** Returns the graphical effect mesh for this track. */
|
||||
const TriangleMesh& getGFXEffectMesh() const {return *m_gfx_effect_mesh;}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get the max players supported for this track, for arena only. */
|
||||
unsigned int getMaxArenaPlayers() const
|
||||
{ return m_max_arena_players; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get the number of start positions defined in the scene file. */
|
||||
unsigned int getNumberOfStartPositions() const
|
||||
{ return (unsigned int)m_start_transforms.size(); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user