16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 20:59:19 +02:00

build 181128. coupler sounds enhancement, minor ai logic tweaks, minor bug fixes

This commit is contained in:
tmj-fstate
2018-11-28 23:29:35 +01:00
parent 1d6f75322b
commit 3fbf5bf894
17 changed files with 199 additions and 63 deletions

View File

@@ -44,6 +44,7 @@ struct light_array;
namespace scene { namespace scene {
struct node_data; struct node_data;
class basic_node; class basic_node;
using group_handle = std::size_t;
} }
namespace Mtable namespace Mtable

View File

@@ -2072,6 +2072,14 @@ bool TController::CheckVehicles(TOrders user)
p = pVehicles[0]; p = pVehicles[0];
while (p) while (p)
{ {
// HACK: wagony muszą mieć baterię załączoną do otwarcia drzwi...
if( ( p != pVehicle )
&& ( ( p->MoverParameters->Couplers[ side::front ].CouplingFlag & ( coupling::control | coupling::permanent ) ) == 0 )
&& ( ( p->MoverParameters->Couplers[ side::rear ].CouplingFlag & ( coupling::control | coupling::permanent ) ) == 0 ) ) {
// NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly
p->MoverParameters->BatterySwitch( true );
}
if (p->asDestination == "none") if (p->asDestination == "none")
p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeśli nie było p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeśli nie było
if (AIControllFlag) // jeśli prowadzi komputer if (AIControllFlag) // jeśli prowadzi komputer
@@ -3212,8 +3220,6 @@ void TController::Doors( bool const Open, int const Side ) {
// tu będzie jeszcze długość peronu zaokrąglona do 10m (20m bezpieczniej, bo nie modyfikuje bitu 1) // tu będzie jeszcze długość peronu zaokrąglona do 10m (20m bezpieczniej, bo nie modyfikuje bitu 1)
auto *vehicle = pVehicles[0]; // pojazd na czole składu auto *vehicle = pVehicles[0]; // pojazd na czole składu
while( vehicle != nullptr ) { while( vehicle != nullptr ) {
// wagony muszą mieć baterię załączoną do otwarcia drzwi...
vehicle->MoverParameters->BatterySwitch( true );
// otwieranie drzwi w pojazdach - flaga zezwolenia była by lepsza // otwieranie drzwi w pojazdach - flaga zezwolenia była by lepsza
if( vehicle->MoverParameters->DoorOpenCtrl != control_t::passenger ) { if( vehicle->MoverParameters->DoorOpenCtrl != control_t::passenger ) {
// if the door are controlled by the driver, we let the user operate them... // if the door are controlled by the driver, we let the user operate them...

View File

@@ -1374,8 +1374,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2, Side, 2,
MoverParameters->Couplers[ Side ].Connected, MoverParameters->Couplers[ Side ].Connected,
coupling::coupler ) ) { coupling::coupler ) ) {
// tmp->MoverParameters->Couplers[CouplNr].Render=true; //podłączony sprzęg będzie widoczny
m_couplersounds[ Side ].dsbCouplerAttach.play();
// one coupling type per key press // one coupling type per key press
return; return;
} }
@@ -1393,9 +1391,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2, Side, 2,
MoverParameters->Couplers[ Side ].Connected, MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::brakehose ) ) ) { ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::brakehose ) ) ) {
// TODO: dedicated sound for connecting cable-type connections
m_couplersounds[ Side ].dsbCouplerDetach.play();
SetPneumatic( Side != 0, true ); SetPneumatic( Side != 0, true );
if( Side == side::front ) { if( Side == side::front ) {
PrevConnected->SetPneumatic( Side != 0, true ); PrevConnected->SetPneumatic( Side != 0, true );
@@ -1417,9 +1412,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2, Side, 2,
MoverParameters->Couplers[ Side ].Connected, MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::mainhose ) ) ) { ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::mainhose ) ) ) {
// TODO: dedicated sound for connecting cable-type connections
m_couplersounds[ Side ].dsbCouplerDetach.play();
SetPneumatic( Side != 0, false ); SetPneumatic( Side != 0, false );
if( Side == side::front ) { if( Side == side::front ) {
PrevConnected->SetPneumatic( Side != 0, false ); PrevConnected->SetPneumatic( Side != 0, false );
@@ -1441,8 +1433,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2, Side, 2,
MoverParameters->Couplers[ Side ].Connected, MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::control ) ) ) { ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::control ) ) ) {
// TODO: dedicated sound for connecting cable-type connections
m_couplersounds[ Side ].dsbCouplerAttach.play();
// one coupling type per key press // one coupling type per key press
return; return;
} }
@@ -1457,8 +1447,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2, Side, 2,
MoverParameters->Couplers[ Side ].Connected, MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::gangway ) ) ) { ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::gangway ) ) ) {
// TODO: dedicated gangway sound
m_couplersounds[ Side ].dsbCouplerAttach.play();
// one coupling type per key press // one coupling type per key press
return; return;
} }
@@ -1473,9 +1461,6 @@ TDynamicObject::couple( int const Side ) {
Side, 2, Side, 2,
MoverParameters->Couplers[ Side ].Connected, MoverParameters->Couplers[ Side ].Connected,
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::heating ) ) ) { ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::heating ) ) ) {
// TODO: dedicated 'click' sound for connecting cable-type connections
m_couplersounds[ Side ].dsbCouplerDetach.play();
// one coupling type per key press // one coupling type per key press
return; return;
} }
@@ -1494,11 +1479,6 @@ TDynamicObject::uncouple( int const Side ) {
} }
// jeżeli sprzęg niezablokowany, jest co odczepić i się da // jeżeli sprzęg niezablokowany, jest co odczepić i się da
auto const couplingflag { Dettach( Side ) }; auto const couplingflag { Dettach( Side ) };
if( couplingflag == coupling::faux ) {
// dźwięk odczepiania
m_couplersounds[ Side ].dsbCouplerAttach.play();
m_couplersounds[ Side ].dsbCouplerDetach.play();
}
return couplingflag; return couplingflag;
} }
@@ -2565,9 +2545,9 @@ void TDynamicObject::AttachPrev(TDynamicObject *Object, int iType)
loc.Z=Object->vPosition.y; loc.Z=Object->vPosition.y;
Object->MoverParameters->Loc=loc; //ustawienie dodawanego pojazdu Object->MoverParameters->Loc=loc; //ustawienie dodawanego pojazdu
*/ */
MoverParameters->Attach(iDirection, Object->iDirection ^ 1, Object->MoverParameters, iType, true); MoverParameters->Attach(iDirection, Object->iDirection ^ 1, Object->MoverParameters, iType, true, false);
MoverParameters->Couplers[iDirection].Render = false; MoverParameters->Couplers[iDirection].Render = false;
Object->MoverParameters->Attach(Object->iDirection ^ 1, iDirection, MoverParameters, iType, true); Object->MoverParameters->Attach(Object->iDirection ^ 1, iDirection, MoverParameters, iType, true, false);
Object->MoverParameters->Couplers[Object->iDirection ^ 1].Render = true; // rysowanie sprzęgu w dołączanym Object->MoverParameters->Couplers[Object->iDirection ^ 1].Render = true; // rysowanie sprzęgu w dołączanym
if (iDirection) if (iDirection)
{ //łączenie standardowe { //łączenie standardowe
@@ -4503,6 +4483,11 @@ void TDynamicObject::RenderSounds() {
auto &coupler { MoverParameters->Couplers[ couplerindex ] }; auto &coupler { MoverParameters->Couplers[ couplerindex ] };
if( coupler.sounds == sound::none ) {
++couplerindex;
continue;
}
if( true == TestFlag( coupler.sounds, sound::bufferclash ) ) { if( true == TestFlag( coupler.sounds, sound::bufferclash ) ) {
// zderzaki uderzaja o siebie // zderzaki uderzaja o siebie
if( true == TestFlag( coupler.sounds, sound::loud ) ) { if( true == TestFlag( coupler.sounds, sound::loud ) ) {
@@ -4527,6 +4512,7 @@ void TDynamicObject::RenderSounds() {
.play( sound_flags::exclusive ); .play( sound_flags::exclusive );
} }
} }
if( true == TestFlag( coupler.sounds, sound::couplerstretch ) ) { if( true == TestFlag( coupler.sounds, sound::couplerstretch ) ) {
// sprzegi sie rozciagaja // sprzegi sie rozciagaja
if( true == TestFlag( coupler.sounds, sound::loud ) ) { if( true == TestFlag( coupler.sounds, sound::loud ) ) {
@@ -4552,8 +4538,22 @@ void TDynamicObject::RenderSounds() {
} }
} }
coupler.sounds = 0; // TODO: dedicated sound for each connection type
// until then, play legacy placeholders:
if( ( coupler.sounds & ( sound::attachcoupler | sound::attachcontrol | sound::attachgangway ) ) != 0 ) {
m_couplersounds[ couplerindex ].dsbCouplerAttach.play();
}
if( ( coupler.sounds & ( sound::attachbrakehose | sound::attachmainhose | sound::attachheating ) ) != 0 ) {
m_couplersounds[ couplerindex ].dsbCouplerDetach.play();
}
if( true == TestFlag( coupler.sounds, sound::detachall ) ) {
// TODO: dedicated disconnect sounds
m_couplersounds[ couplerindex ].dsbCouplerAttach.play();
m_couplersounds[ couplerindex ].dsbCouplerDetach.play();
}
++couplerindex; ++couplerindex;
coupler.sounds = 0;
} }
MoverParameters->SoundFlag = 0; MoverParameters->SoundFlag = 0;

View File

@@ -1019,7 +1019,7 @@ multi_event::init() {
auto const conditiontchecksmemcell { m_conditions.flags & ( flags::text | flags::value_1 | flags::value_2 ) }; auto const conditiontchecksmemcell { m_conditions.flags & ( flags::text | flags::value_1 | flags::value_2 ) };
// not all multi-events have memory cell checks, for the ones which don't we can keep quiet about it // not all multi-events have memory cell checks, for the ones which don't we can keep quiet about it
init_targets( simulation::Memory, "memory cell", ( false == conditiontchecksmemcell ) ); init_targets( simulation::Memory, "memory cell", conditiontchecksmemcell );
if( m_ignored ) { if( m_ignored ) {
// legacy compatibility behaviour, instead of disabling the event we disable the memory cell comparison test // legacy compatibility behaviour, instead of disabling the event we disable the memory cell comparison test
m_conditions.flags &= ~( flags::text | flags::value_1 | flags::value_2 ); m_conditions.flags &= ~( flags::text | flags::value_1 | flags::value_2 );

View File

@@ -209,13 +209,20 @@ static int const s_CAtest = 128;
/*dzwieki*/ /*dzwieki*/
enum sound { enum sound {
none, none,
loud = 0x1, loud = 1 << 0,
couplerstretch = 0x2, couplerstretch = 1 << 1,
bufferclash = 0x4, bufferclash = 1 << 2,
relay = 0x10, relay = 1 << 3,
parallel = 0x20, parallel = 1 << 4,
shuntfield = 0x40, shuntfield = 1 << 5,
pneumatic = 0x80 pneumatic = 1 << 6,
detachall = 1 << 7,
attachcoupler = 1 << 8,
attachbrakehose = 1 << 9,
attachmainhose = 1 << 10,
attachcontrol = 1 << 11,
attachgangway = 1 << 12,
attachheating = 1 << 13
}; };
//szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType //szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType
@@ -1245,7 +1252,7 @@ public:
double Distance(const TLocation &Loc1, const TLocation &Loc2, const TDimension &Dim1, const TDimension &Dim2); double Distance(const TLocation &Loc1, const TLocation &Loc2, const TDimension &Dim1, const TDimension &Dim2);
/* double Distance(const vector3 &Loc1, const vector3 &Loc2, const vector3 &Dim1, const vector3 &Dim2); /* double Distance(const vector3 &Loc1, const vector3 &Loc2, const vector3 &Dim1, const vector3 &Dim2);
*/ //bool AttachA(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false); */ //bool AttachA(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false);
bool Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false); bool Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false, bool Audible = true);
int DettachStatus(int ConnectNo); int DettachStatus(int ConnectNo);
bool Dettach(int ConnectNo); bool Dettach(int ConnectNo);
void SetCoupleDist(); void SetCoupleDist();

View File

@@ -406,7 +406,7 @@ double TMoverParameters::CouplerDist(int Coupler)
return Couplers[ Coupler ].CoupleDist; return Couplers[ Coupler ].CoupleDist;
}; };
bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced) bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced, bool Audible)
{ //łączenie do swojego sprzęgu (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr) { //łączenie do swojego sprzęgu (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr)
// Ra: zwykle wykonywane dwukrotnie, dla każdego pojazdu oddzielnie // Ra: zwykle wykonywane dwukrotnie, dla każdego pojazdu oddzielnie
// Ra: trzeba by odróżnić wymóg dociśnięcia od uszkodzenia sprzęgu przy podczepianiu AI do // Ra: trzeba by odróżnić wymóg dociśnięcia od uszkodzenia sprzęgu przy podczepianiu AI do
@@ -433,12 +433,32 @@ bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *
coupler.Render = true; // tego rysować coupler.Render = true; // tego rysować
othercoupler.Render = false; // a tego nie othercoupler.Render = false; // a tego nie
}; };
auto const couplingchange { CouplingType ^ coupler.CouplingFlag };
coupler.CouplingFlag = CouplingType; // ustawienie typu sprzęgu coupler.CouplingFlag = CouplingType; // ustawienie typu sprzęgu
// if (CouplingType!=ctrain_virtual) //Ra: wirtualnego nie łączymy zwrotnie! // if (CouplingType!=ctrain_virtual) //Ra: wirtualnego nie łączymy zwrotnie!
//{//jeśli łączenie sprzęgiem niewirtualnym, ustawiamy połączenie zwrotne //{//jeśli łączenie sprzęgiem niewirtualnym, ustawiamy połączenie zwrotne
othercoupler.CouplingFlag = CouplingType; othercoupler.CouplingFlag = CouplingType;
othercoupler.Connected = this; othercoupler.Connected = this;
othercoupler.CoupleDist = coupler.CoupleDist; othercoupler.CoupleDist = coupler.CoupleDist;
if( ( true == Audible ) && ( couplingchange != 0 ) ) {
// set sound event flag
int soundflag{ sound::none };
std::vector<std::pair<coupling, sound>> const soundmappings = {
{ coupling::coupler, sound::attachcoupler },
{ coupling::brakehose, sound::attachbrakehose },
{ coupling::mainhose, sound::attachmainhose },
{ coupling::control, sound::attachcontrol},
{ coupling::gangway, sound::attachgangway},
{ coupling::heating, sound::attachheating} };
for( auto const &soundmapping : soundmappings ) {
if( ( couplingchange & soundmapping.first ) != 0 ) {
soundflag |= soundmapping.second;
}
}
SetFlag( coupler.sounds, soundflag );
}
return true; return true;
//} //}
// podłączenie nie udało się - jest wirtualne // podłączenie nie udało się - jest wirtualne
@@ -489,6 +509,10 @@ bool TMoverParameters::Dettach(int ConnectNo)
Couplers[ConnectNo].Connected->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag = Couplers[ConnectNo].Connected->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag =
0; // pozostaje sprzęg wirtualny 0; // pozostaje sprzęg wirtualny
Couplers[ConnectNo].CouplingFlag = 0; // pozostaje sprzęg wirtualny Couplers[ConnectNo].CouplingFlag = 0; // pozostaje sprzęg wirtualny
// set sound event flag
SetFlag( Couplers[ ConnectNo ].sounds, sound::detachall );
return true; return true;
} }
else if (i > 0) else if (i > 0)
@@ -4395,7 +4419,8 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
// sprzeganie wagonow z samoczynnymi sprzegami} // sprzeganie wagonow z samoczynnymi sprzegami}
// CouplingFlag:=ctrain_coupler+ctrain_pneumatic+ctrain_controll+ctrain_passenger+ctrain_scndpneumatic; // CouplingFlag:=ctrain_coupler+ctrain_pneumatic+ctrain_controll+ctrain_passenger+ctrain_scndpneumatic;
// EN57 // EN57
Couplers[ CouplerN ].CouplingFlag = coupling::coupler | coupling::brakehose | coupling::mainhose | coupling::control; Couplers[ CouplerN ].CouplingFlag = coupling::coupler /*| coupling::brakehose | coupling::mainhose | coupling::control*/;
SetFlag( Couplers[ CouplerN ].sounds, sound::attachcoupler );
} }
} }
} }
@@ -4847,9 +4872,13 @@ double TMoverParameters::TractionForce( double dt ) {
EnginePower = Voltage * Im / 1000.0; EnginePower = Voltage * Im / 1000.0;
/* /*
// NOTE: this part is experimentally disabled, as it generated early traction force drop for undetermined purpose // power curve drop
if ((tmpV > 2) && (EnginePower < tmp)) // NOTE: disabled for the time being due to side-effects
Ft = Ft * EnginePower / tmp; if( ( tmpV > 1 ) && ( EnginePower < tmp ) ) {
Ft = interpolate(
Ft, EnginePower / tmp,
clamp( tmpV - 1.0, 0.0, 1.0 ) );
}
*/ */
} }

View File

@@ -81,7 +81,13 @@ openal_source::update( double const Deltatime, glm::vec3 const &Listenervelocity
if( sound_range < 0.0 ) { if( sound_range < 0.0 ) {
sound_velocity = Listenervelocity; // cached for doppler shift calculation sound_velocity = Listenervelocity; // cached for doppler shift calculation
} }
/*
// HACK: if the application gets stuck for long time loading assets the audio can gone awry.
// terminate all sources when it happens to stay on the safe side
if( Deltatime > 1.0 ) {
stop();
}
*/
if( id != audio::null_resource ) { if( id != audio::null_resource ) {
sound_change = false; sound_change = false;
@@ -314,7 +320,6 @@ openal_renderer::erase( sound_source const *Controller ) {
// updates state of all active emitters // updates state of all active emitters
void void
openal_renderer::update( double const Deltatime ) { openal_renderer::update( double const Deltatime ) {
// update listener // update listener
// gain // gain
::alListenerf( AL_GAIN, clamp( Global.AudioVolume, 0.f, 2.f ) * ( Global.iPause == 0 ? 1.f : 0.15f ) ); ::alListenerf( AL_GAIN, clamp( Global.AudioVolume, 0.f, 2.f ) * ( Global.iPause == 0 ? 1.f : 0.15f ) );
@@ -411,6 +416,14 @@ openal_renderer::fetch_source() {
} }
} }
if( newsource.id == audio::null_resource ) {
// for sources with functional emitter reset emitter parameters from potential last use
::alSourcef( newsource.id, AL_PITCH, 1.f );
::alSourcef( newsource.id, AL_GAIN, 1.f );
::alSourcefv( newsource.id, AL_POSITION, glm::value_ptr( glm::vec3{ 0.f } ) );
::alSourcefv( newsource.id, AL_VELOCITY, glm::value_ptr( glm::vec3{ 0.f } ) );
}
return newsource; return newsource;
} }

View File

@@ -89,11 +89,11 @@ struct openal_source {
private: private:
// members // members
double update_deltatime; // time delta of most current update double update_deltatime { 0.0 }; // time delta of most current update
float pitch_variation { 1.f }; // emitter-specific variation of the base pitch float pitch_variation { 1.f }; // emitter-specific variation of the base pitch
float sound_range { 50.f }; // cached audible range of the emitted samples float sound_range { 50.f }; // cached audible range of the emitted samples
glm::vec3 sound_distance; // cached distance between sound and the listener glm::vec3 sound_distance { 0.f }; // cached distance between sound and the listener
glm::vec3 sound_velocity; // sound movement vector glm::vec3 sound_velocity { 0.f }; // sound movement vector
bool is_in_range { false }; // helper, indicates the source was recently within audible range bool is_in_range { false }; // helper, indicates the source was recently within audible range
bool is_multipart { false }; // multi-part sounds are kept alive at longer ranges bool is_multipart { false }; // multi-part sounds are kept alive at longer ranges
}; };

View File

@@ -75,12 +75,12 @@ private:
bool bool
mode_snap() const; mode_snap() const;
// members // members
state_backup m_statebackup; // helper, cached variables to be restored on mode exit
editormode_input m_input; editormode_input m_input;
TCamera Camera; TCamera Camera;
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys
scene::basic_editor m_editor; scene::basic_editor m_editor;
scene::basic_node *m_node; // currently selected scene node scene::basic_node *m_node; // currently selected scene node
bool m_takesnapshot { true }; // helper, hints whether snapshot of selected node(s) should be taken before modification bool m_takesnapshot { true }; // helper, hints whether snapshot of selected node(s) should be taken before modification
state_backup m_statebackup; // helper, cached variables to be restored on mode exit
}; };

View File

@@ -27,6 +27,8 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
if( false == is_open ) { return; } if( false == is_open ) { return; }
text_lines.clear(); text_lines.clear();
m_grouplines.clear();
std::string textline; std::string textline;
// scenario inspector // scenario inspector
@@ -41,7 +43,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
} }
textline = textline =
"node name: " + node->name() "name: " + ( node->name().empty() ? "(none)" : node->name() )
+ "\nlocation: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]" + "\nlocation: [" + to_string( node->location().x, 2 ) + ", " + to_string( node->location().y, 2 ) + ", " + to_string( node->location().z, 2 ) + "]"
+ " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)"; + " (distance: " + to_string( glm::length( glm::dvec3{ node->location().x, 0.0, node->location().z } -glm::dvec3{ camera.Pos.x, 0.0, camera.Pos.z } ), 1 ) + " m)";
text_lines.emplace_back( textline, Global.UITextColor ); text_lines.emplace_back( textline, Global.UITextColor );
@@ -65,7 +67,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
textline += ']'; textline += ']';
} }
else { else {
textline += "none"; textline += "(none)";
} }
text_lines.emplace_back( textline, Global.UITextColor ); text_lines.emplace_back( textline, Global.UITextColor );
@@ -73,7 +75,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
auto modelfile { ( auto modelfile { (
( subnode->pModel != nullptr ) ? ( subnode->pModel != nullptr ) ?
subnode->pModel->NameGet() : subnode->pModel->NameGet() :
"none" ) }; "(none)" ) };
if( modelfile.find( szModelPath ) == 0 ) { if( modelfile.find( szModelPath ) == 0 ) {
// don't include 'models/' in the path // don't include 'models/' in the path
modelfile.erase( 0, std::string{ szModelPath }.size() ); modelfile.erase( 0, std::string{ szModelPath }.size() );
@@ -82,7 +84,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
auto texturefile { ( auto texturefile { (
( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ? ( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ?
GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name : GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name :
"none" ) }; "(none)" ) };
if( texturefile.find( szTexturePath ) == 0 ) { if( texturefile.find( szTexturePath ) == 0 ) {
// don't include 'textures/' in the path // don't include 'textures/' in the path
texturefile.erase( 0, std::string{ szTexturePath }.size() ); texturefile.erase( 0, std::string{ szTexturePath }.size() );
@@ -95,7 +97,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
auto const *subnode = static_cast<TTrack const *>( node ); auto const *subnode = static_cast<TTrack const *>( node );
// basic attributes // basic attributes
textline = textline =
"isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "none" ) "isolated: " + ( ( subnode->pIsolated != nullptr ) ? subnode->pIsolated->asName : "(none)" )
+ "\nvelocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity ) + "\nvelocity: " + to_string( subnode->SwitchExtension ? subnode->SwitchExtension->fVelocity : subnode->fVelocity )
+ "\nwidth: " + to_string( subnode->fTrackWidth ) + " m" + "\nwidth: " + to_string( subnode->fTrackWidth ) + " m"
+ "\nfriction: " + to_string( subnode->fFriction, 2 ) + "\nfriction: " + to_string( subnode->fFriction, 2 )
@@ -105,14 +107,14 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
auto texturefile { ( auto texturefile { (
( subnode->m_material1 != null_handle ) ? ( subnode->m_material1 != null_handle ) ?
GfxRenderer.Material( subnode->m_material1 ).name : GfxRenderer.Material( subnode->m_material1 ).name :
"none" ) }; "(none)" ) };
if( texturefile.find( szTexturePath ) == 0 ) { if( texturefile.find( szTexturePath ) == 0 ) {
texturefile.erase( 0, std::string{ szTexturePath }.size() ); texturefile.erase( 0, std::string{ szTexturePath }.size() );
} }
auto texturefile2{ ( auto texturefile2{ (
( subnode->m_material2 != null_handle ) ? ( subnode->m_material2 != null_handle ) ?
GfxRenderer.Material( subnode->m_material2 ).name : GfxRenderer.Material( subnode->m_material2 ).name :
"none" ) }; "(none)" ) };
if( texturefile2.find( szTexturePath ) == 0 ) { if( texturefile2.find( szTexturePath ) == 0 ) {
texturefile2.erase( 0, std::string{ szTexturePath }.size() ); texturefile2.erase( 0, std::string{ szTexturePath }.size() );
} }
@@ -167,11 +169,72 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
+ " [" + to_string( subnode->Value1(), 2 ) + "]" + " [" + to_string( subnode->Value1(), 2 ) + "]"
+ " [" + to_string( subnode->Value2(), 2 ) + "]"; + " [" + to_string( subnode->Value2(), 2 ) + "]";
text_lines.emplace_back( textline, Global.UITextColor ); text_lines.emplace_back( textline, Global.UITextColor );
textline = "track: " + ( subnode->asTrackName.empty() ? "none" : subnode->asTrackName ); textline = "track: " + ( subnode->asTrackName.empty() ? "(none)" : subnode->asTrackName );
text_lines.emplace_back( textline, Global.UITextColor ); text_lines.emplace_back( textline, Global.UITextColor );
} }
update_group();
} }
void
itemproperties_panel::update_group() {
auto const grouphandle { m_node->group() };
if( grouphandle == null_handle ) {
m_grouphandle = null_handle;
m_groupprefix.clear();
return;
}
auto const &nodegroup { scene::Groups.group( grouphandle ) };
if( m_grouphandle != grouphandle ) {
// calculate group name from shared prefix of item names
std::vector<std::reference_wrapper<std::string const>> names;
// build list of custom item and event names
for( auto const *node : nodegroup.nodes ) {
auto const &name { node->name() };
if( name.empty() || name == "none" ) { continue; }
names.emplace_back( name );
}
for( auto const *event : nodegroup.events ) {
auto const &name { event->m_name };
if( name.empty() || name == "none" ) { continue; }
names.emplace_back( name );
}
// find the common prefix
if( names.size() > 1 ) {
m_groupprefix = names.front();
for( auto const &name : names ) {
// NOTE: first calculation runs over two instances of the same name, but, eh
auto const prefixlength{ len_common_prefix( m_groupprefix, name ) };
if( prefixlength > 0 ) {
m_groupprefix = m_groupprefix.substr( 0, prefixlength );
}
else {
m_groupprefix.clear();
break;
}
}
}
else {
// less than two names to compare means no prefix
m_groupprefix.clear();
}
m_grouphandle = grouphandle;
}
m_grouplines.emplace_back(
"nodes: " + to_string( static_cast<int>( nodegroup.nodes.size() ) )
+ "\nevents: " + to_string( static_cast<int>( nodegroup.events.size() ) ),
Global.UITextColor );
m_grouplines.emplace_back(
"names prefix: " + ( m_groupprefix.empty() ? "(none)" : m_groupprefix ),
Global.UITextColor );
}
void void
itemproperties_panel::render() { itemproperties_panel::render() {
@@ -209,16 +272,13 @@ bool
itemproperties_panel::render_group() { itemproperties_panel::render_group() {
if( m_node == nullptr ) { return false; } if( m_node == nullptr ) { return false; }
if( m_node->group() == null_handle ) { return false; } if( m_grouplines.empty() ) { return false; }
if( false == ImGui::CollapsingHeader( "Parent Group" ) ) { return false; } if( false == ImGui::CollapsingHeader( "Parent Group" ) ) { return false; }
auto const &nodegroup { scene::Groups.group( m_node->group() ) }; for( auto const &line : m_grouplines ) {
auto const &linecolor { Global.UITextColor }; ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
}
ImGui::TextColored( ImVec4( linecolor.r, linecolor.g, linecolor.b, linecolor.a ),
( "Nodes: " + to_string( static_cast<int>( nodegroup.nodes.size() ) )
+ "\nEvents: " + to_string( static_cast<int>( nodegroup.events.size() ) ) ).c_str() );
return true; return true;
} }

View File

@@ -24,8 +24,12 @@ public:
private: private:
// methods // methods
void update_group();
bool render_group(); bool render_group();
// members // members
scene::basic_node const *m_node { nullptr }; // scene node bound to the panel scene::basic_node const *m_node { nullptr }; // scene node bound to the panel
scene::group_handle m_grouphandle { null_handle }; // scene group bound to the panel
std::string m_groupprefix;
std::vector<text_line> m_grouplines;
}; };

View File

@@ -64,7 +64,7 @@ struct bounding_area {
deserialize( std::istream &Input ); deserialize( std::istream &Input );
}; };
using group_handle = std::size_t; //using group_handle = std::size_t;
struct node_data { struct node_data {

View File

@@ -323,6 +323,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
>> nodedata.range_min >> nodedata.range_min
>> nodedata.name >> nodedata.name
>> nodedata.type; >> nodedata.type;
if( nodedata.name == "none" ) { nodedata.name.clear(); }
// type-based deserialization. not elegant but it'll do // type-based deserialization. not elegant but it'll do
if( nodedata.type == "dynamic" ) { if( nodedata.type == "dynamic" ) {

View File

@@ -466,7 +466,7 @@ sound_source::stop( bool const Skipend ) {
if( ( false == Skipend ) if( ( false == Skipend )
&& ( sound( sound_id::end ).buffer != null_handle ) && ( sound( sound_id::end ).buffer != null_handle )
/* && ( sound( sound_id::end ).buffer != sound( sound_id::main ).buffer ) */ // end == main can happen in malformed legacy cases /* && ( sound( sound_id::end ).buffer != sound( sound_id::main ).buffer ) */ // end == main can happen in malformed legacy cases
/* && ( sound( sound_id::end ).playing == 0 ) */ ) { && ( sound( sound_id::end ).playing < 2 ) ) { // allows potential single extra instance to account for longer overlapping sounds
// spawn potentially defined sound end sample, if the emitter is currently active // spawn potentially defined sound end sample, if the emitter is currently active
insert( sound_id::end ); insert( sound_id::end );
} }

View File

@@ -411,6 +411,18 @@ substr_path( std::string const &Filename ) {
"" ); "" );
} }
// returns length of common prefix between two provided strings
std::ptrdiff_t
len_common_prefix( std::string const &Left, std::string const &Right ) {
auto const *left { Left.data() };
auto const *right { Right.data() };
// compare up to the length of the shorter string
return ( Right.size() <= Left.size() ?
std::distance( right, std::mismatch( right, right + Right.size(), left ).first ) :
std::distance( left, std::mismatch( left, left + Left.size(), right ).first ) );
}
// helper, restores content of a 3d vector from provided input stream // helper, restores content of a 3d vector from provided input stream
// TODO: review and clean up the helper routines, there's likely some redundant ones // TODO: review and clean up the helper routines, there's likely some redundant ones
glm::dvec3 LoadPoint( cParser &Input ) { glm::dvec3 LoadPoint( cParser &Input ) {

View File

@@ -200,6 +200,9 @@ replace_slashes( std::string &Filename );
// returns potential path part from provided file name // returns potential path part from provided file name
std::string substr_path( std::string const &Filename ); std::string substr_path( std::string const &Filename );
// returns common prefix of two provided strings
std::ptrdiff_t len_common_prefix( std::string const &Left, std::string const &Right );
template <typename Type_> template <typename Type_>
void SafeDelete( Type_ &Pointer ) { void SafeDelete( Type_ &Pointer ) {
delete Pointer; delete Pointer;

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#define VERSION_MAJOR 18 #define VERSION_MAJOR 18
#define VERSION_MINOR 1117 #define VERSION_MINOR 1128
#define VERSION_REVISION 0 #define VERSION_REVISION 0