mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 17:29:18 +02:00
build 181128. coupler sounds enhancement, minor ai logic tweaks, minor bug fixes
This commit is contained in:
@@ -44,6 +44,7 @@ struct light_array;
|
||||
namespace scene {
|
||||
struct node_data;
|
||||
class basic_node;
|
||||
using group_handle = std::size_t;
|
||||
}
|
||||
|
||||
namespace Mtable
|
||||
|
||||
10
Driver.cpp
10
Driver.cpp
@@ -2072,6 +2072,14 @@ bool TController::CheckVehicles(TOrders user)
|
||||
p = pVehicles[0];
|
||||
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")
|
||||
p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeśli nie było
|
||||
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)
|
||||
auto *vehicle = pVehicles[0]; // pojazd na czole składu
|
||||
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
|
||||
if( vehicle->MoverParameters->DoorOpenCtrl != control_t::passenger ) {
|
||||
// if the door are controlled by the driver, we let the user operate them...
|
||||
|
||||
46
DynObj.cpp
46
DynObj.cpp
@@ -1374,8 +1374,6 @@ TDynamicObject::couple( int const Side ) {
|
||||
Side, 2,
|
||||
MoverParameters->Couplers[ Side ].Connected,
|
||||
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
|
||||
return;
|
||||
}
|
||||
@@ -1393,9 +1391,6 @@ TDynamicObject::couple( int const Side ) {
|
||||
Side, 2,
|
||||
MoverParameters->Couplers[ Side ].Connected,
|
||||
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::brakehose ) ) ) {
|
||||
// TODO: dedicated sound for connecting cable-type connections
|
||||
m_couplersounds[ Side ].dsbCouplerDetach.play();
|
||||
|
||||
SetPneumatic( Side != 0, true );
|
||||
if( Side == side::front ) {
|
||||
PrevConnected->SetPneumatic( Side != 0, true );
|
||||
@@ -1417,9 +1412,6 @@ TDynamicObject::couple( int const Side ) {
|
||||
Side, 2,
|
||||
MoverParameters->Couplers[ Side ].Connected,
|
||||
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::mainhose ) ) ) {
|
||||
// TODO: dedicated sound for connecting cable-type connections
|
||||
m_couplersounds[ Side ].dsbCouplerDetach.play();
|
||||
|
||||
SetPneumatic( Side != 0, false );
|
||||
if( Side == side::front ) {
|
||||
PrevConnected->SetPneumatic( Side != 0, false );
|
||||
@@ -1441,8 +1433,6 @@ TDynamicObject::couple( int const Side ) {
|
||||
Side, 2,
|
||||
MoverParameters->Couplers[ Side ].Connected,
|
||||
( 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
|
||||
return;
|
||||
}
|
||||
@@ -1457,8 +1447,6 @@ TDynamicObject::couple( int const Side ) {
|
||||
Side, 2,
|
||||
MoverParameters->Couplers[ Side ].Connected,
|
||||
( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::gangway ) ) ) {
|
||||
// TODO: dedicated gangway sound
|
||||
m_couplersounds[ Side ].dsbCouplerAttach.play();
|
||||
// one coupling type per key press
|
||||
return;
|
||||
}
|
||||
@@ -1473,9 +1461,6 @@ TDynamicObject::couple( int const Side ) {
|
||||
Side, 2,
|
||||
MoverParameters->Couplers[ Side ].Connected,
|
||||
( 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
|
||||
return;
|
||||
}
|
||||
@@ -1494,11 +1479,6 @@ TDynamicObject::uncouple( int const Side ) {
|
||||
}
|
||||
// jeżeli sprzęg niezablokowany, jest co odczepić i się da
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2565,9 +2545,9 @@ void TDynamicObject::AttachPrev(TDynamicObject *Object, int iType)
|
||||
loc.Z=Object->vPosition.y;
|
||||
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;
|
||||
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
|
||||
if (iDirection)
|
||||
{ //łączenie standardowe
|
||||
@@ -4503,6 +4483,11 @@ void TDynamicObject::RenderSounds() {
|
||||
|
||||
auto &coupler { MoverParameters->Couplers[ couplerindex ] };
|
||||
|
||||
if( coupler.sounds == sound::none ) {
|
||||
++couplerindex;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( true == TestFlag( coupler.sounds, sound::bufferclash ) ) {
|
||||
// zderzaki uderzaja o siebie
|
||||
if( true == TestFlag( coupler.sounds, sound::loud ) ) {
|
||||
@@ -4527,6 +4512,7 @@ void TDynamicObject::RenderSounds() {
|
||||
.play( sound_flags::exclusive );
|
||||
}
|
||||
}
|
||||
|
||||
if( true == TestFlag( coupler.sounds, sound::couplerstretch ) ) {
|
||||
// sprzegi sie rozciagaja
|
||||
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;
|
||||
coupler.sounds = 0;
|
||||
}
|
||||
|
||||
MoverParameters->SoundFlag = 0;
|
||||
|
||||
@@ -1019,7 +1019,7 @@ multi_event::init() {
|
||||
|
||||
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
|
||||
init_targets( simulation::Memory, "memory cell", ( false == conditiontchecksmemcell ) );
|
||||
init_targets( simulation::Memory, "memory cell", conditiontchecksmemcell );
|
||||
if( m_ignored ) {
|
||||
// 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 );
|
||||
|
||||
@@ -209,13 +209,20 @@ static int const s_CAtest = 128;
|
||||
/*dzwieki*/
|
||||
enum sound {
|
||||
none,
|
||||
loud = 0x1,
|
||||
couplerstretch = 0x2,
|
||||
bufferclash = 0x4,
|
||||
relay = 0x10,
|
||||
parallel = 0x20,
|
||||
shuntfield = 0x40,
|
||||
pneumatic = 0x80
|
||||
loud = 1 << 0,
|
||||
couplerstretch = 1 << 1,
|
||||
bufferclash = 1 << 2,
|
||||
relay = 1 << 3,
|
||||
parallel = 1 << 4,
|
||||
shuntfield = 1 << 5,
|
||||
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
|
||||
@@ -1245,7 +1252,7 @@ public:
|
||||
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);
|
||||
*/ //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);
|
||||
bool Dettach(int ConnectNo);
|
||||
void SetCoupleDist();
|
||||
|
||||
@@ -406,7 +406,7 @@ double TMoverParameters::CouplerDist(int Coupler)
|
||||
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)
|
||||
// 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
|
||||
@@ -433,12 +433,32 @@ bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *
|
||||
coupler.Render = true; // tego rysować
|
||||
othercoupler.Render = false; // a tego nie
|
||||
};
|
||||
auto const couplingchange { CouplingType ^ coupler.CouplingFlag };
|
||||
coupler.CouplingFlag = CouplingType; // ustawienie typu sprzęgu
|
||||
// if (CouplingType!=ctrain_virtual) //Ra: wirtualnego nie łączymy zwrotnie!
|
||||
//{//jeśli łączenie sprzęgiem niewirtualnym, ustawiamy połączenie zwrotne
|
||||
othercoupler.CouplingFlag = CouplingType;
|
||||
othercoupler.Connected = this;
|
||||
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;
|
||||
//}
|
||||
// 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 =
|
||||
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;
|
||||
}
|
||||
else if (i > 0)
|
||||
@@ -4395,7 +4419,8 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt)
|
||||
// sprzeganie wagonow z samoczynnymi sprzegami}
|
||||
// CouplingFlag:=ctrain_coupler+ctrain_pneumatic+ctrain_controll+ctrain_passenger+ctrain_scndpneumatic;
|
||||
// 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;
|
||||
/*
|
||||
// NOTE: this part is experimentally disabled, as it generated early traction force drop for undetermined purpose
|
||||
if ((tmpV > 2) && (EnginePower < tmp))
|
||||
Ft = Ft * EnginePower / tmp;
|
||||
// power curve drop
|
||||
// NOTE: disabled for the time being due to side-effects
|
||||
if( ( tmpV > 1 ) && ( EnginePower < tmp ) ) {
|
||||
Ft = interpolate(
|
||||
Ft, EnginePower / tmp,
|
||||
clamp( tmpV - 1.0, 0.0, 1.0 ) );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,13 @@ openal_source::update( double const Deltatime, glm::vec3 const &Listenervelocity
|
||||
if( sound_range < 0.0 ) {
|
||||
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 ) {
|
||||
|
||||
sound_change = false;
|
||||
@@ -314,7 +320,6 @@ openal_renderer::erase( sound_source const *Controller ) {
|
||||
// updates state of all active emitters
|
||||
void
|
||||
openal_renderer::update( double const Deltatime ) {
|
||||
|
||||
// update listener
|
||||
// gain
|
||||
::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;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,11 @@ struct openal_source {
|
||||
|
||||
private:
|
||||
// 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 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_velocity; // sound movement vector
|
||||
glm::vec3 sound_distance { 0.f }; // cached distance between sound and the listener
|
||||
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_multipart { false }; // multi-part sounds are kept alive at longer ranges
|
||||
};
|
||||
|
||||
@@ -75,12 +75,12 @@ private:
|
||||
bool
|
||||
mode_snap() const;
|
||||
// members
|
||||
state_backup m_statebackup; // helper, cached variables to be restored on mode exit
|
||||
editormode_input m_input;
|
||||
TCamera Camera;
|
||||
double fTime50Hz { 0.0 }; // bufor czasu dla komunikacji z PoKeys
|
||||
scene::basic_editor m_editor;
|
||||
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
|
||||
state_backup m_statebackup; // helper, cached variables to be restored on mode exit
|
||||
|
||||
};
|
||||
|
||||
@@ -27,6 +27,8 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
|
||||
if( false == is_open ) { return; }
|
||||
|
||||
text_lines.clear();
|
||||
m_grouplines.clear();
|
||||
|
||||
std::string textline;
|
||||
|
||||
// scenario inspector
|
||||
@@ -41,7 +43,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
|
||||
}
|
||||
|
||||
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 ) + "]"
|
||||
+ " (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 );
|
||||
@@ -65,7 +67,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
|
||||
textline += ']';
|
||||
}
|
||||
else {
|
||||
textline += "none";
|
||||
textline += "(none)";
|
||||
}
|
||||
text_lines.emplace_back( textline, Global.UITextColor );
|
||||
|
||||
@@ -73,7 +75,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
|
||||
auto modelfile { (
|
||||
( subnode->pModel != nullptr ) ?
|
||||
subnode->pModel->NameGet() :
|
||||
"none" ) };
|
||||
"(none)" ) };
|
||||
if( modelfile.find( szModelPath ) == 0 ) {
|
||||
// don't include 'models/' in the path
|
||||
modelfile.erase( 0, std::string{ szModelPath }.size() );
|
||||
@@ -82,7 +84,7 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
|
||||
auto texturefile { (
|
||||
( subnode->Material()->replacable_skins[ 1 ] != null_handle ) ?
|
||||
GfxRenderer.Material( subnode->Material()->replacable_skins[ 1 ] ).name :
|
||||
"none" ) };
|
||||
"(none)" ) };
|
||||
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||
// don't include 'textures/' in the path
|
||||
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 );
|
||||
// basic attributes
|
||||
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 )
|
||||
+ "\nwidth: " + to_string( subnode->fTrackWidth ) + " m"
|
||||
+ "\nfriction: " + to_string( subnode->fFriction, 2 )
|
||||
@@ -105,14 +107,14 @@ itemproperties_panel::update( scene::basic_node const *Node ) {
|
||||
auto texturefile { (
|
||||
( subnode->m_material1 != null_handle ) ?
|
||||
GfxRenderer.Material( subnode->m_material1 ).name :
|
||||
"none" ) };
|
||||
"(none)" ) };
|
||||
if( texturefile.find( szTexturePath ) == 0 ) {
|
||||
texturefile.erase( 0, std::string{ szTexturePath }.size() );
|
||||
}
|
||||
auto texturefile2{ (
|
||||
( subnode->m_material2 != null_handle ) ?
|
||||
GfxRenderer.Material( subnode->m_material2 ).name :
|
||||
"none" ) };
|
||||
"(none)" ) };
|
||||
if( texturefile2.find( szTexturePath ) == 0 ) {
|
||||
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->Value2(), 2 ) + "]";
|
||||
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 );
|
||||
}
|
||||
|
||||
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
|
||||
itemproperties_panel::render() {
|
||||
|
||||
@@ -209,16 +272,13 @@ bool
|
||||
itemproperties_panel::render_group() {
|
||||
|
||||
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; }
|
||||
|
||||
auto const &nodegroup { scene::Groups.group( m_node->group() ) };
|
||||
auto const &linecolor { Global.UITextColor };
|
||||
|
||||
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() );
|
||||
for( auto const &line : m_grouplines ) {
|
||||
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,12 @@ public:
|
||||
|
||||
private:
|
||||
// methods
|
||||
void update_group();
|
||||
bool render_group();
|
||||
|
||||
// members
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -64,7 +64,7 @@ struct bounding_area {
|
||||
deserialize( std::istream &Input );
|
||||
};
|
||||
|
||||
using group_handle = std::size_t;
|
||||
//using group_handle = std::size_t;
|
||||
|
||||
struct node_data {
|
||||
|
||||
|
||||
@@ -323,6 +323,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
||||
>> nodedata.range_min
|
||||
>> nodedata.name
|
||||
>> nodedata.type;
|
||||
if( nodedata.name == "none" ) { nodedata.name.clear(); }
|
||||
// type-based deserialization. not elegant but it'll do
|
||||
if( nodedata.type == "dynamic" ) {
|
||||
|
||||
|
||||
@@ -466,7 +466,7 @@ sound_source::stop( bool const Skipend ) {
|
||||
if( ( false == Skipend )
|
||||
&& ( 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 ).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
|
||||
insert( sound_id::end );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
// TODO: review and clean up the helper routines, there's likely some redundant ones
|
||||
glm::dvec3 LoadPoint( cParser &Input ) {
|
||||
|
||||
@@ -200,6 +200,9 @@ replace_slashes( std::string &Filename );
|
||||
// returns potential path part from provided file name
|
||||
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_>
|
||||
void SafeDelete( Type_ &Pointer ) {
|
||||
delete Pointer;
|
||||
|
||||
Reference in New Issue
Block a user