Merge branch 'master' of https://github.com/supertuxkart/stk-code
This commit is contained in:
@@ -34,8 +34,6 @@
|
||||
#include "input/input_manager.hpp"
|
||||
#include "modes/demo_world.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "utils/debug.hpp"
|
||||
#include "utils/profiler.hpp"
|
||||
@@ -186,21 +184,6 @@ bool EventHandler::OnEvent (const SEvent &event)
|
||||
SFXManager::get()->resumeAll();
|
||||
}
|
||||
}
|
||||
else if (cmd == APP_CMD_TERM_WINDOW)
|
||||
{
|
||||
if (STKHost::existHost() && NetworkConfig::get()->isWAN())
|
||||
{
|
||||
STKHost::get()->requestShutdownDelayed(10000);
|
||||
}
|
||||
}
|
||||
else if (cmd == APP_CMD_INIT_WINDOW)
|
||||
{
|
||||
if (STKHost::existHost() && NetworkConfig::get()->isWAN() &&
|
||||
!STKHost::get()->requestedShutdown())
|
||||
{
|
||||
STKHost::get()->cancelShutdown();
|
||||
}
|
||||
}
|
||||
else if (cmd == APP_CMD_LOW_MEMORY)
|
||||
{
|
||||
Log::warn("EventHandler", "Low memory event received");
|
||||
|
||||
@@ -388,25 +388,26 @@ void MultitouchDevice::updateAxisY(float value)
|
||||
*/
|
||||
void MultitouchDevice::handleControls(MultitouchButton* button)
|
||||
{
|
||||
if (m_controller == NULL)
|
||||
if (!isGameRunning())
|
||||
return;
|
||||
|
||||
if (button->type == MultitouchButtonType::BUTTON_STEERING)
|
||||
{
|
||||
updateAxisX(button->axis_x);
|
||||
updateAxisY(button->axis_y);
|
||||
}
|
||||
else if (button->type == MultitouchButtonType::BUTTON_UP_DOWN)
|
||||
{
|
||||
updateAxisY(button->axis_y);
|
||||
}
|
||||
else if (button->type == MultitouchButtonType::BUTTON_ESCAPE)
|
||||
|
||||
if (button->type == MultitouchButtonType::BUTTON_ESCAPE)
|
||||
{
|
||||
StateManager::get()->escapePressed();
|
||||
}
|
||||
else
|
||||
|
||||
if (m_controller != NULL && !race_manager->isWatchingReplay())
|
||||
{
|
||||
if (button->action != PA_BEFORE_FIRST)
|
||||
if (button->type == MultitouchButtonType::BUTTON_STEERING)
|
||||
{
|
||||
updateAxisX(button->axis_x);
|
||||
updateAxisY(button->axis_y);
|
||||
}
|
||||
else if (button->type == MultitouchButtonType::BUTTON_UP_DOWN)
|
||||
{
|
||||
updateAxisY(button->axis_y);
|
||||
}
|
||||
else if (button->action != PA_BEFORE_FIRST)
|
||||
{
|
||||
int value = button->pressed ? Input::MAX_VALUE : 0;
|
||||
m_controller->action(button->action, value);
|
||||
@@ -416,6 +417,15 @@ void MultitouchDevice::handleControls(MultitouchButton* button)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool MultitouchDevice::isGameRunning()
|
||||
{
|
||||
return StateManager::get()->getGameState() == GUIEngine::GAME &&
|
||||
!GUIEngine::ModalDialog::isADialogActive() &&
|
||||
!GUIEngine::ScreenKeyboard::isActive();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void MultitouchDevice::updateController()
|
||||
{
|
||||
if (m_player == NULL)
|
||||
@@ -427,10 +437,7 @@ void MultitouchDevice::updateController()
|
||||
// Handle multitouch events only when race is running. It avoids to process
|
||||
// it when pause dialog is active during the race. And there is no reason
|
||||
// to use it for GUI navigation.
|
||||
if (StateManager::get()->getGameState() != GUIEngine::GAME ||
|
||||
GUIEngine::ModalDialog::isADialogActive() ||
|
||||
GUIEngine::ScreenKeyboard::isActive() ||
|
||||
race_manager->isWatchingReplay())
|
||||
if (!isGameRunning())
|
||||
{
|
||||
m_controller = NULL;
|
||||
return;
|
||||
|
||||
@@ -94,6 +94,7 @@ private:
|
||||
|
||||
float getSteeringFactor(float value);
|
||||
void handleControls(MultitouchButton* button);
|
||||
bool isGameRunning();
|
||||
|
||||
public:
|
||||
/** The array that contains data for all multitouch input events */
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
*/
|
||||
ServerLobby::ServerLobby() : LobbyProtocol(NULL)
|
||||
{
|
||||
m_last_success_poll_time.store(StkTime::getRealTimeMs() + 30000);
|
||||
m_waiting_players_counts.store(0);
|
||||
m_server_owner_id.store(-1);
|
||||
m_registered_for_once_only = false;
|
||||
@@ -110,7 +111,7 @@ ServerLobby::ServerLobby() : LobbyProtocol(NULL)
|
||||
m_result_ns = getNetworkString();
|
||||
m_result_ns->setSynchronous(true);
|
||||
m_waiting_for_reset = false;
|
||||
m_server_id_online = 0;
|
||||
m_server_id_online.store(0);
|
||||
} // ServerLobby
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -356,7 +357,7 @@ void ServerLobby::createServerIdFile()
|
||||
if (!sid.empty() && !m_has_created_server_id_file)
|
||||
{
|
||||
std::fstream fs;
|
||||
sid += StringUtils::toString(m_server_id_online) + "_" +
|
||||
sid += StringUtils::toString(m_server_id_online.load()) + "_" +
|
||||
StringUtils::toString(STKHost::get()->getPrivatePort());
|
||||
fs.open(sid, std::ios::out);
|
||||
fs.close();
|
||||
@@ -384,6 +385,13 @@ void ServerLobby::asynchronousUpdate()
|
||||
handlePendingConnection();
|
||||
}
|
||||
|
||||
if (allowJoinedPlayersWaiting() && m_server_recovering.expired() &&
|
||||
StkTime::getRealTimeMs() > m_last_success_poll_time.load() + 30000)
|
||||
{
|
||||
Log::warn("ServerLobby", "Trying auto server recovery.");
|
||||
registerServer(false/*now*/);
|
||||
}
|
||||
|
||||
switch (m_state.load())
|
||||
{
|
||||
case SET_PUBLIC_ADDRESS:
|
||||
@@ -420,7 +428,7 @@ void ServerLobby::asynchronousUpdate()
|
||||
// Register this server with the STK server. This will block
|
||||
// this thread, because there is no need for the protocol manager
|
||||
// to react to any requests before the server is registered.
|
||||
if (registerServer())
|
||||
if (registerServer(true/*now*/))
|
||||
{
|
||||
if (allowJoinedPlayersWaiting())
|
||||
m_registered_for_once_only = true;
|
||||
@@ -690,12 +698,56 @@ void ServerLobby::update(int ticks)
|
||||
* ProtocolManager thread). The information about this client is added
|
||||
* to the table 'server'.
|
||||
*/
|
||||
bool ServerLobby::registerServer()
|
||||
bool ServerLobby::registerServer(bool now)
|
||||
{
|
||||
while (!m_server_unregistered.expired())
|
||||
while (now && !m_server_unregistered.expired())
|
||||
StkTime::sleep(1);
|
||||
|
||||
Online::XMLRequest *request = new Online::XMLRequest();
|
||||
// ========================================================================
|
||||
class RegisterServerRequest : public Online::XMLRequest
|
||||
{
|
||||
private:
|
||||
std::weak_ptr<ServerLobby> m_server_lobby;
|
||||
protected:
|
||||
virtual void afterOperation()
|
||||
{
|
||||
Online::XMLRequest::afterOperation();
|
||||
const XMLNode* result = getXMLData();
|
||||
std::string rec_success;
|
||||
auto sl = m_server_lobby.lock();
|
||||
if (!sl)
|
||||
return;
|
||||
|
||||
if (result->get("success", &rec_success) &&
|
||||
rec_success == "yes")
|
||||
{
|
||||
const XMLNode* server = result->getNode("server");
|
||||
assert(server);
|
||||
const XMLNode* server_info = server->getNode("server-info");
|
||||
assert(server_info);
|
||||
unsigned server_id_online = 0;
|
||||
server_info->get("id", &server_id_online);
|
||||
assert(server_id_online != 0);
|
||||
Log::info("ServerLobby",
|
||||
"Server %d is now online.", server_id_online);
|
||||
sl->m_server_id_online.store(server_id_online);
|
||||
sl->m_last_success_poll_time.store(StkTime::getRealTimeMs());
|
||||
return;
|
||||
}
|
||||
Log::error("ServerLobby", "%s",
|
||||
StringUtils::wideToUtf8(getInfo()).c_str());
|
||||
// For auto server recovery wait 3 seconds for next try
|
||||
// This sleep only the request manager thread
|
||||
if (manageMemory())
|
||||
StkTime::sleep(3000);
|
||||
}
|
||||
public:
|
||||
RegisterServerRequest(bool now, std::shared_ptr<ServerLobby> sl)
|
||||
: XMLRequest(!now/*manage memory*/), m_server_lobby(sl) {}
|
||||
}; // RegisterServerRequest
|
||||
|
||||
RegisterServerRequest *request = new RegisterServerRequest(now,
|
||||
std::dynamic_pointer_cast<ServerLobby>(shared_from_this()));
|
||||
NetworkConfig::get()->setServerDetails(request, "create");
|
||||
request->addParameter("address", m_server_address.getIP() );
|
||||
request->addParameter("port", m_server_address.getPort() );
|
||||
@@ -715,29 +767,19 @@ bool ServerLobby::registerServer()
|
||||
Log::info("ServerLobby", "Public server address %s",
|
||||
m_server_address.toString().c_str());
|
||||
|
||||
request->executeNow();
|
||||
|
||||
const XMLNode* result = request->getXMLData();
|
||||
std::string rec_success;
|
||||
|
||||
if (result->get("success", &rec_success) && rec_success == "yes")
|
||||
if (now)
|
||||
{
|
||||
const XMLNode* server = result->getNode("server");
|
||||
assert(server);
|
||||
const XMLNode* server_info = server->getNode("server-info");
|
||||
assert(server_info);
|
||||
server_info->get("id", &m_server_id_online);
|
||||
assert(m_server_id_online != 0);
|
||||
Log::info("ServerLobby",
|
||||
"Server %d is now online.", m_server_id_online);
|
||||
request->executeNow();
|
||||
delete request;
|
||||
return true;
|
||||
if (m_server_id_online.load() == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
irr::core::stringc error(request->getInfo().c_str());
|
||||
Log::error("ServerLobby", "%s", error.c_str());
|
||||
delete request;
|
||||
return false;
|
||||
else
|
||||
{
|
||||
request->queue();
|
||||
m_server_recovering = request->observeExistence();
|
||||
}
|
||||
return true;
|
||||
} // registerServer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -811,7 +853,7 @@ void ServerLobby::startSelection(const Event *event)
|
||||
if (!allowJoinedPlayersWaiting())
|
||||
{
|
||||
ProtocolManager::lock()->findAndTerminate(PROTOCOL_CONNECTION);
|
||||
if (NetworkConfig::get()->isWAN() )
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
{
|
||||
unregisterServer(false/*now*/);
|
||||
}
|
||||
@@ -903,7 +945,9 @@ void ServerLobby::checkIncomingConnectionRequests()
|
||||
// First poll every 5 seconds. Return if no polling needs to be done.
|
||||
const uint64_t POLL_INTERVAL = 5000;
|
||||
static uint64_t last_poll_time = 0;
|
||||
if (StkTime::getRealTimeMs() < last_poll_time + POLL_INTERVAL)
|
||||
if (StkTime::getRealTimeMs() < last_poll_time + POLL_INTERVAL ||
|
||||
StkTime::getRealTimeMs() > m_last_success_poll_time.load() + 30000 ||
|
||||
m_server_id_online.load() == 0)
|
||||
return;
|
||||
|
||||
// Keep the port open, it can be sent to anywhere as we will send to the
|
||||
@@ -927,12 +971,13 @@ void ServerLobby::checkIncomingConnectionRequests()
|
||||
virtual void afterOperation()
|
||||
{
|
||||
Online::XMLRequest::afterOperation();
|
||||
const XMLNode *result = getXMLData();
|
||||
const XMLNode* result = getXMLData();
|
||||
std::string success;
|
||||
|
||||
if (!result->get("success", &success) || success != "yes")
|
||||
{
|
||||
Log::error("ServerLobby", "Cannot retrieve the list.");
|
||||
Log::error("ServerLobby", "Poll server request failed: %s",
|
||||
StringUtils::wideToUtf8(getInfo()).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -942,6 +987,7 @@ void ServerLobby::checkIncomingConnectionRequests()
|
||||
auto sl = m_server_lobby.lock();
|
||||
if (!sl)
|
||||
return;
|
||||
sl->m_last_success_poll_time.store(StkTime::getRealTimeMs());
|
||||
if (sl->m_state.load() != WAITING_FOR_START_GAME &&
|
||||
!sl->allowJoinedPlayersWaiting())
|
||||
{
|
||||
|
||||
@@ -95,6 +95,8 @@ private:
|
||||
/** It indicates if this server is unregistered with the stk server. */
|
||||
std::weak_ptr<bool> m_server_unregistered;
|
||||
|
||||
std::weak_ptr<bool> m_server_recovering;
|
||||
|
||||
/** Timeout counter for various state. */
|
||||
std::atomic<int64_t> m_timeout;
|
||||
|
||||
@@ -148,9 +150,11 @@ private:
|
||||
|
||||
std::atomic<uint32_t> m_waiting_players_counts;
|
||||
|
||||
std::atomic<uint64_t> m_last_success_poll_time;
|
||||
|
||||
uint64_t m_server_started_at, m_server_delay;
|
||||
|
||||
unsigned m_server_id_online;
|
||||
std::atomic<uint32_t> m_server_id_online;
|
||||
|
||||
bool m_registered_for_once_only;
|
||||
|
||||
@@ -164,7 +168,7 @@ private:
|
||||
// Track(s) votes
|
||||
void playerVote(Event *event);
|
||||
void playerFinishedResult(Event *event);
|
||||
bool registerServer();
|
||||
bool registerServer(bool now);
|
||||
void finishedLoadingWorldClient(Event *event);
|
||||
void kickHost(Event* event);
|
||||
void changeTeam(Event* event);
|
||||
|
||||
@@ -308,7 +308,6 @@ void STKHost::init()
|
||||
{
|
||||
m_network_timer.store(StkTime::getRealTimeMs());
|
||||
m_shutdown = false;
|
||||
m_shutdown_delay = 0;
|
||||
m_authorised = false;
|
||||
m_network = NULL;
|
||||
m_exit_timeout.store(std::numeric_limits<uint64_t>::max());
|
||||
|
||||
@@ -117,9 +117,6 @@ private:
|
||||
* triggers a shutdown of the STKHost (and the Protocolmanager). */
|
||||
std::atomic_bool m_shutdown;
|
||||
|
||||
/** Used as a timeout for shedule shutdown. */
|
||||
std::atomic<uint64_t> m_shutdown_delay;
|
||||
|
||||
/** True if this local host is authorised to control a server. */
|
||||
std::atomic_bool m_authorised;
|
||||
|
||||
@@ -211,21 +208,8 @@ public:
|
||||
void requestShutdown()
|
||||
{
|
||||
m_shutdown.store(true);
|
||||
m_shutdown_delay.store(0);
|
||||
} // requestExit
|
||||
//-------------------------------------------------------------------------
|
||||
void requestShutdownDelayed(int delay)
|
||||
{
|
||||
m_shutdown.store(true);
|
||||
m_shutdown_delay.store(StkTime::getRealTimeMs() + delay);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
void cancelShutdown()
|
||||
{
|
||||
m_shutdown.store(false);
|
||||
m_shutdown_delay.store(0);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
void shutdown();
|
||||
//-------------------------------------------------------------------------
|
||||
void sendPacketToAllPeersInServer(NetworkString *data,
|
||||
@@ -282,11 +266,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if a shutdown of the network infrastructure was
|
||||
* requested. */
|
||||
bool requestedShutdown() const
|
||||
{
|
||||
return m_shutdown.load() &&
|
||||
m_shutdown_delay.load() < StkTime::getRealTimeMs();
|
||||
}
|
||||
bool requestedShutdown() const { return m_shutdown.load(); }
|
||||
// ------------------------------------------------------------------------
|
||||
int receiveRawPacket(char *buffer, int buffer_len,
|
||||
TransportAddress* sender, int max_tries = -1)
|
||||
|
||||
@@ -354,13 +354,6 @@ void PhysicalObject::init(const PhysicalObject::Settings& settings)
|
||||
case MP_EXACT:
|
||||
{
|
||||
extend.setY(0);
|
||||
|
||||
// In case of readonly materials we have to get the material from
|
||||
// the mesh, otherwise from the node. This is esp. important for
|
||||
// water nodes, which only have the material defined in the node,
|
||||
// but not in the mesh at all!
|
||||
bool is_readonly_material = false;
|
||||
|
||||
scene::IMesh* mesh = NULL;
|
||||
switch (presentation->getNode()->getType())
|
||||
{
|
||||
@@ -371,7 +364,6 @@ void PhysicalObject::init(const PhysicalObject::Settings& settings)
|
||||
scene::IMeshSceneNode *node =
|
||||
(scene::IMeshSceneNode*)presentation->getNode();
|
||||
mesh = node->getMesh();
|
||||
is_readonly_material = node->isReadOnlyMaterials();
|
||||
break;
|
||||
}
|
||||
case scene::ESNT_ANIMATED_MESH :
|
||||
@@ -380,7 +372,6 @@ void PhysicalObject::init(const PhysicalObject::Settings& settings)
|
||||
scene::IAnimatedMeshSceneNode *node =
|
||||
(scene::IAnimatedMeshSceneNode*)presentation->getNode();
|
||||
mesh = node->getMesh()->getMesh(0);
|
||||
is_readonly_material = node->isReadOnlyMaterials();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -436,27 +427,27 @@ void PhysicalObject::init(const PhysicalObject::Settings& settings)
|
||||
mb->getVertexType());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle readonly materials correctly: mb->getMaterial can return
|
||||
// NULL if the node is not using readonly materials. E.g. in case
|
||||
// of a water scene node, the mesh (which is the animated copy of
|
||||
// the original mesh) does not contain any material information,
|
||||
// the material is only available in the node.
|
||||
const video::SMaterial &irrMaterial =
|
||||
is_readonly_material ? mb->getMaterial()
|
||||
: presentation->getNode()->getMaterial(i);
|
||||
video::ITexture* t=irrMaterial.getTexture(0);
|
||||
|
||||
const Material* material=0;
|
||||
if(t)
|
||||
const video::SMaterial& irrMaterial = mb->getMaterial();
|
||||
std::string t1_full_path, t2_full_path;
|
||||
video::ITexture* t1 = irrMaterial.getTexture(0);
|
||||
if (t1)
|
||||
{
|
||||
std::string image =
|
||||
std::string(core::stringc(t->getName()).c_str());
|
||||
material = material_manager
|
||||
->getMaterial(StringUtils::getBasename(image));
|
||||
if(material->isIgnore())
|
||||
continue;
|
||||
t1_full_path = t1->getName().getPtr();
|
||||
t1_full_path = file_manager->getFileSystem()->getAbsolutePath(
|
||||
t1_full_path.c_str()).c_str();
|
||||
}
|
||||
video::ITexture* t2 = irrMaterial.getTexture(1);
|
||||
if (t2)
|
||||
{
|
||||
t2_full_path = t2->getName().getPtr();
|
||||
t2_full_path = file_manager->getFileSystem()->getAbsolutePath(
|
||||
t2_full_path.c_str()).c_str();
|
||||
}
|
||||
const Material* material = material_manager->getMaterialSPM(
|
||||
t1_full_path, t2_full_path);
|
||||
if (material->isIgnore())
|
||||
continue;
|
||||
|
||||
if (mb->getVertexType() == video::EVT_STANDARD)
|
||||
{
|
||||
irr::video::S3DVertex* mbVertices =
|
||||
|
||||
@@ -918,26 +918,15 @@ void Track::convertTrackToBullet(scene::ISceneNode *node)
|
||||
matrices.push_back(node->getAbsoluteTransformation());
|
||||
|
||||
scene::IMesh *mesh;
|
||||
// In case of readonly materials we have to get the material from
|
||||
// the mesh, otherwise from the node. This is esp. important for
|
||||
// water nodes, which only have the material defined in the node,
|
||||
// but not in the mesh at all!
|
||||
bool is_readonly_material=false;
|
||||
|
||||
|
||||
switch(node->getType())
|
||||
{
|
||||
case scene::ESNT_MESH :
|
||||
case scene::ESNT_WATER_SURFACE :
|
||||
case scene::ESNT_OCTREE :
|
||||
mesh = ((scene::IMeshSceneNode*)node)->getMesh();
|
||||
is_readonly_material =
|
||||
((scene::IMeshSceneNode*)node)->isReadOnlyMaterials();
|
||||
break;
|
||||
case scene::ESNT_ANIMATED_MESH :
|
||||
mesh = ((scene::IAnimatedMeshSceneNode*)node)->getMesh();
|
||||
is_readonly_material =
|
||||
((scene::IAnimatedMeshSceneNode*)node)->isReadOnlyMaterials();
|
||||
break;
|
||||
case scene::ESNT_SKY_BOX :
|
||||
case scene::ESNT_SKY_DOME:
|
||||
@@ -1021,38 +1010,35 @@ void Track::convertTrackToBullet(scene::ISceneNode *node)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Handle readonly materials correctly: mb->getMaterial can return
|
||||
// NULL if the node is not using readonly materials. E.g. in case
|
||||
// of a water scene node, the mesh (which is the animated copy of
|
||||
// the original mesh) does not contain any material information,
|
||||
// the material is only available in the node.
|
||||
const video::SMaterial &irrMaterial =
|
||||
is_readonly_material ? mb->getMaterial()
|
||||
: node->getMaterial(i);
|
||||
video::ITexture* t=irrMaterial.getTexture(0);
|
||||
|
||||
const Material* material=0;
|
||||
TriangleMesh *tmesh = m_track_mesh;
|
||||
if(t)
|
||||
const video::SMaterial& irrMaterial = mb->getMaterial();
|
||||
std::string t1_full_path, t2_full_path;
|
||||
video::ITexture* t1 = irrMaterial.getTexture(0);
|
||||
if (t1)
|
||||
{
|
||||
std::string image = t->getName().getPtr();
|
||||
|
||||
// the third boolean argument is false because at this point we're
|
||||
// dealing physics, so it's useless to warn about missing textures,
|
||||
// we'd just get duplicate/useless warnings
|
||||
material=material_manager->getMaterial(StringUtils::getBasename(image),
|
||||
false, false, false);
|
||||
// Special gfx meshes will not be stored as a normal physics body,
|
||||
// but converted to a collision body only, so that ray tests
|
||||
// against them can be done.
|
||||
if(material->isSurface())
|
||||
tmesh = m_gfx_effect_mesh;
|
||||
// A material which is a surface must be converted,
|
||||
// even if it's marked as ignore. So only ignore
|
||||
// non-surface materials.
|
||||
else if(material->isIgnore())
|
||||
continue;
|
||||
t1_full_path = t1->getName().getPtr();
|
||||
t1_full_path = file_manager->getFileSystem()->getAbsolutePath(
|
||||
t1_full_path.c_str()).c_str();
|
||||
}
|
||||
video::ITexture* t2 = irrMaterial.getTexture(1);
|
||||
if (t2)
|
||||
{
|
||||
t2_full_path = t2->getName().getPtr();
|
||||
t2_full_path = file_manager->getFileSystem()->getAbsolutePath(
|
||||
t2_full_path.c_str()).c_str();
|
||||
}
|
||||
const Material* material = material_manager->getMaterialSPM(
|
||||
t1_full_path, t2_full_path);
|
||||
TriangleMesh *tmesh = m_track_mesh;
|
||||
// Special gfx meshes will not be stored as a normal physics body,
|
||||
// but converted to a collision body only, so that ray tests
|
||||
// against them can be done.
|
||||
if (material->isSurface())
|
||||
tmesh = m_gfx_effect_mesh;
|
||||
// A material which is a surface must be converted,
|
||||
// even if it's marked as ignore. So only ignore
|
||||
// non-surface materials.
|
||||
else if(material->isIgnore())
|
||||
continue;
|
||||
|
||||
if (mb->getVertexType() == video::EVT_STANDARD)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user