submodel opacity parameter, additional light blinking modes, scenario event queue filtering

This commit is contained in:
tmj-fstate
2018-10-09 18:48:24 +02:00
parent 06abe187c6
commit 9cacf191c6
9 changed files with 195 additions and 68 deletions

View File

@@ -444,8 +444,9 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable
// tekstura nieprzezroczysta - nie renderować w cyklu przezroczystych
m_materialdata.textures_alpha = 0x30300030;
}
fBlinkTimer = double( Random( 1000 * fOffTime ) ) / ( 1000 * fOffTime );
// TODO: redo the random timer initialization
// fBlinkTimer = Random() * ( fOnTime + fOffTime );
pModel = TModelsManager::GetModel( asName );
return ( pModel != nullptr );
@@ -547,9 +548,73 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
if( Framestamp == m_framestamp ) { return; }
fBlinkTimer -= Timer::GetDeltaTime();
if( fBlinkTimer <= 0 )
fBlinkTimer += fOffTime;
auto const timedelta { Timer::GetDeltaTime() };
// interpretacja ułamka zależnie od typu
// case ls_Off: ustalenie czasu migotania, t<1s (f>1Hz), np. 0.1 => t=0.1 (f=10Hz)
// case ls_On: ustalenie wypełnienia ułamkiem, np. 1.25 => zapalony przez 1/4 okresu
// case ls_Blink: ustalenie częstotliwości migotania, f<1Hz (t>1s), np. 2.2 => f=0.2Hz (t=5s)
float modeintegral, modefractional;
for( int idx = 0; idx < iNumLights; ++idx ) {
modefractional = std::modf( std::abs( lsLights[ idx ] ), &modeintegral );
if( modeintegral >= ls_Dark ) {
// light threshold modes don't use timers
continue;
}
auto const mode { static_cast<int>( modeintegral ) };
auto &opacity { m_lightopacities[ idx ] };
auto &timer { m_lighttimers[ idx ] };
if( ( modeintegral < ls_Blink ) && ( modefractional < 0.01f ) ) {
// simple flip modes
switch( mode ) {
case ls_Off: {
// reduce to zero
timer = std::max<float>( 0.f, timer - timedelta );
break;
}
case ls_On: {
// increase to max value
timer = std::min<float>( fTransitionTime, timer + timedelta );
break;
}
default: {
break;
}
}
opacity = timer / fTransitionTime;
}
else {
// blink modes
auto const ontime { (
( mode == ls_Blink ) ? ( ( modefractional < 0.01f ) ? fOnTime : ( 1.f / modefractional ) * 0.5f ) :
( mode == ls_Off ) ? modefractional * 0.5f :
( mode == ls_On ) ? modefractional * ( fOnTime + fOffTime ) :
fOnTime ) }; // fallback
auto const offtime { (
( mode == ls_Blink ) ? ( ( modefractional < 0.01f ) ? fOffTime : ontime ) :
( mode == ls_Off ) ? ontime :
( mode == ls_On ) ? ( fOnTime + fOffTime ) - ontime :
fOffTime ) }; // fallback
auto const transitiontime {
std::min(
1.f,
std::min( ontime, offtime ) * 0.9f ) };
timer = clamp_circular<float>( timer + timedelta * ( lsLights[ idx ] > 0.f ? 1.f : -1.f ), ontime + offtime );
// set opacity depending on blink stage
if( timer < ontime ) {
// blink on
opacity = clamp( timer / transitiontime, 0.f, 1.f );
}
else {
// blink off
opacity = 1.f - clamp( ( timer - ontime ) / transitiontime, 0.f, 1.f );
}
}
}
// Ra 2F1I: to by można pomijać dla modeli bez animacji, których jest większość
TAnimContainer *pCurrent;
@@ -568,17 +633,19 @@ void TAnimModel::RaPrepare()
bool state; // stan światła
for (int i = 0; i < iNumLights; ++i)
{
auto const lightmode { static_cast<int>( lsLights[ i ] ) };
auto const lightmode { static_cast<int>( std::abs( lsLights[ i ] ) ) };
switch( lightmode ) {
case ls_On:
case ls_Off: {
// zapalony albo zgaszony
state = ( lightmode == ls_On );
break;
}
case ls_Off:
case ls_Blink: {
// migotanie
state = ( fBlinkTimer < fOnTime );
if (LightsOn[i]) {
LightsOn[i]->iVisible = ( m_lightopacities[i] > 0.f );
LightsOn[i]->SetVisibilityLevel( m_lightopacities[i], true, false );
}
if (LightsOff[i]) {
LightsOff[i]->iVisible = ( m_lightopacities[i] < 1.f );
LightsOff[i]->SetVisibilityLevel( 1.f, true, false );
}
break;
}
case ls_Dark: {
@@ -606,10 +673,16 @@ void TAnimModel::RaPrepare()
break;
}
}
if (LightsOn[i])
LightsOn[i]->iVisible = state;
if (LightsOff[i])
LightsOff[i]->iVisible = !state;
if( lightmode >= ls_Dark ) {
// crude as hell but for test will do :x
if (LightsOn[i]) {
LightsOn[i]->iVisible = state;
// TODO: set visibility for the entire submodel's children as well
LightsOn[i]->fVisible = m_lightopacities[i];
}
if (LightsOff[i])
LightsOff[i]->iVisible = !state;
}
}
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( this ); //żeby nie robić cudzych animacji
TSubModel::pasText = &asText; // przekazanie tekstu do wyświetlacza (!!!! do przemyślenia)
@@ -774,8 +847,9 @@ void TAnimModel::AnimationVND(void *pData, double a, double b, double c, double
//---------------------------------------------------------------------------
void TAnimModel::LightSet(int const n, float const v)
{ // ustawienie światła (n) na wartość (v)
if (n >= iMaxNumLights)
if( n >= iMaxNumLights ) {
return; // przekroczony zakres
}
lsLights[ n ] = v;
};

View File

@@ -179,7 +179,7 @@ private:
// members
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli
TModel3d *pModel { nullptr };
double fBlinkTimer { 0.0 };
// double fBlinkTimer { 0.0 };
int iNumLights { 0 };
TSubModel *LightsOn[ iMaxNumLights ]; // Ra: te wskaźniki powinny być w ramach TModel3d
TSubModel *LightsOff[ iMaxNumLights ];
@@ -188,10 +188,13 @@ private:
std::string asText; // tekst dla wyświetlacza znakowego
TAnimAdvanced *pAdvanced { nullptr };
// TODO: wrap into a light state struct
float lsLights[ iMaxNumLights ];
// float fDark { DefaultDarkThresholdLevel }; // poziom zapalanie światła (powinno być chyba powiązane z danym światłem?)
float fOnTime { 0.66f };
float fOffTime { 0.66f + 0.66f }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
std::array<float, iMaxNumLights> m_lighttimers { 0.f };
std::array<float, iMaxNumLights> m_lightopacities { 1.f };
float fOnTime { 1.f / 2 };// { 60.f / 45.f / 2 };
float fOffTime { 1.f / 2 };// { 60.f / 45.f / 2 }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
float fTransitionTime { fOnTime * 0.9f }; // time
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
};

View File

@@ -342,8 +342,8 @@ std::string TSpeedPos::TableText() const
{ // pozycja tabelki pr?dko?ci
if (iFlags & spEnabled)
{ // o ile pozycja istotna
return "Flags:" + to_hex_str(iFlags, 8) + ", Dist:" + to_string(fDist, 1, 6) +
", Vel:" + (fVelNext == -1.0 ? " - " : to_string(static_cast<int>(fVelNext), 0, 3)) + ", Name:" + GetName();
return to_hex_str(iFlags, 8) + " " + to_string(fDist, 1, 6) +
" " + (fVelNext == -1.0 ? " -" : to_string(static_cast<int>(fVelNext), 0, 3)) + " " + GetName();
}
return "Empty";
}

View File

@@ -71,6 +71,23 @@ void TSubModel::Name(std::string const &Name)
pName = Name;
};
// sets visibility level (alpha component) to specified value
void
TSubModel::SetVisibilityLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
fVisible = Level;
if( true == Includesiblings ) {
auto sibling { this };
while( ( sibling = sibling->Next ) != nullptr ) {
sibling->SetVisibilityLevel( Level, Includechildren, false ); // no need for all siblings to duplicate the work
}
}
if( ( true == Includechildren )
&& ( Child != nullptr ) ) {
Child->SetVisibilityLevel( Level, Includechildren, true ); // node's children include child's siblings and children
}
}
// sets light level (alpha component of illumination color) to specified value
void
TSubModel::SetLightLevel( float const Level, bool const Includechildren, bool const Includesiblings ) {
@@ -1313,7 +1330,8 @@ void TSubModel::serialize(std::ostream &s,
else
sn_utils::ls_int32(s, (int32_t)get_container_pos(textures, m_materialname));
sn_utils::ls_float32(s, fVisible);
// sn_utils::ls_float32(s, fVisible);
sn_utils::ls_float32(s, 1.f);
sn_utils::ls_float32(s, fLight);
sn_utils::s_vec4(s, f4Ambient);
@@ -1433,7 +1451,8 @@ void TSubModel::deserialize(std::istream &s)
tVboPtr = sn_utils::ld_int32(s);
iTexture = sn_utils::ld_int32(s);
fVisible = sn_utils::ld_float32(s);
// fVisible = sn_utils::ld_float32(s);
auto discard = sn_utils::ld_float32(s);
fLight = sn_utils::ld_float32(s);
f4Ambient = sn_utils::d_vec4(s);

View File

@@ -98,7 +98,6 @@ private:
int iNumVerts { -1 }; // ilość wierzchołków (1 dla FreeSpotLight)
int tVboPtr; // początek na liście wierzchołków albo indeksów
int iTexture { 0 }; // numer nazwy tekstury, -1 wymienna, 0 brak
float fVisible { 0.0f }; // próg jasności światła do załączenia submodelu
float fLight { -1.0f }; // próg jasności światła do zadziałania selfillum
glm::vec4
f4Ambient { 1.0f,1.0f,1.0f,1.0f },
@@ -140,7 +139,8 @@ public: // chwilowo
float4x4 *mAnimMatrix{ nullptr }; // macierz do animacji kwaternionowych (należy do AnimContainer)
TSubModel **smLetter{ nullptr }; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D)
TSubModel *Parent{ nullptr }; // nadrzędny, np. do wymnażania macierzy
int iVisible{ 1 }; // roboczy stan widoczności
int iVisible { 1 }; // roboczy stan widoczności
float fVisible { 1.f }; // visibility level
std::string m_materialname; // robocza nazwa tekstury do zapisania w pliku binarnym
std::string pName; // robocza nazwa
private:
@@ -192,6 +192,8 @@ public:
int Flags() const { return iFlags; };
void UnFlagNext() { iFlags &= 0x00FFFFFF; };
void ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular );
// sets visibility level (alpha component) to specified value
void SetVisibilityLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
// sets light level (alpha component of illumination color) to specified value
void SetLightLevel( float const Level, bool const Includechildren = false, bool const Includesiblings = false );
inline float3 Translation1Get() {

View File

@@ -565,7 +565,7 @@ TTraction::wire_color() const {
color.r *= Global.DayLight.ambient[ 0 ];
color.g *= Global.DayLight.ambient[ 1 ];
color.b *= Global.DayLight.ambient[ 2 ];
color *= 0.5f;
color *= 0.35f;
}
else {
// tymczasowo pokazanie zasilanych odcinków

View File

@@ -356,7 +356,10 @@ debug_panel::render() {
render_section( "Vehicle AI", m_ailines );
render_section( "Vehicle Scan Table", m_scantablelines );
render_section( "Scenario", m_scenariolines );
render_section( "Scenario Event Queue", m_eventqueuelines );
if( true == render_section( "Scenario Event Queue", m_eventqueuelines ) ) {
// event queue filter
ImGui::Checkbox( "By This Vehicle Only", &m_eventqueueactivevehicleonly );
}
render_section( "Camera", m_cameralines );
render_section( "Gfx Renderer", m_rendererlines );
// toggles
@@ -764,6 +767,8 @@ debug_panel::update_section_scantable( std::vector<text_line> &Output ) {
if( m_input.mechanik == nullptr ) { return; }
Output.emplace_back( "Flags: Dist: Vel: Name:", Global.UITextColor );
auto const &mechanik{ *m_input.mechanik };
std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast<int>( mechanik.TableSize() ) - 1, 0, 30 );
@@ -773,8 +778,8 @@ debug_panel::update_section_scantable( std::vector<text_line> &Output ) {
Output.emplace_back( Bezogonkow( scanline ), Global.UITextColor );
++i;
} while( i < speedtablesize );
if( Output.empty() ) {
Output.emplace_back( "(no points of interest)", Global.UITextColor );
if( Output.size() == 1 ) {
Output.front().data = "(no points of interest)";
}
}
@@ -787,7 +792,8 @@ debug_panel::update_section_scenario( std::vector<text_line> &Output ) {
Output.emplace_back( textline, Global.UITextColor );
// current luminance level
textline = "Light level: " + to_string( Global.fLuminance, 3 );
textline = "Cloud cover: " + to_string( Global.Overcast, 3 );
textline += "\nLight level: " + to_string( Global.fLuminance, 3 );
if( Global.FakeLight ) { textline += "(*)"; }
textline += "\nAir temperature: " + to_string( Global.AirTemperature, 1 ) + " deg C";
@@ -799,32 +805,33 @@ debug_panel::update_section_eventqueue( std::vector<text_line> &Output ) {
std::string textline;
// current event queue
auto const time { Timer::GetTime() };
auto const *event { simulation::Events.begin() };
auto eventtableindex{ 0 };
while( ( event != nullptr )
&& ( eventtableindex < 30 ) ) {
// current event queue
auto const time { Timer::GetTime() };
auto const *event { simulation::Events.begin() };
if( ( false == event->m_ignored )
&& ( false == event->m_passive ) ) {
Output.emplace_back( "Delay: Event:", Global.UITextColor );
auto const delay { " " + to_string( std::max( 0.0, event->m_launchtime - time ), 1 ) };
textline =
"Delay: " + delay.substr( delay.length() - 6 )
+ ", Event: " + event->m_name
+ ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" )
+ ( event->m_sibling ? " (joint event)" : "" );
while( ( event != nullptr )
&& ( Output.size() < 30 ) ) {
Output.emplace_back( textline, Global.UITextColor );
++eventtableindex;
}
event = event->m_next;
}
if( Output.empty() ) {
textline = "(no queued events)";
Output.emplace_back( textline, Global.UITextColor );
}
if( ( false == event->m_ignored )
&& ( false == event->m_passive )
&& ( ( false == m_eventqueueactivevehicleonly )
|| ( event->m_activator == m_input.vehicle ) ) ) {
auto const delay { " " + to_string( std::max( 0.0, event->m_launchtime - time ), 1 ) };
textline = delay.substr( delay.length() - 6 )
+ " " + event->m_name
+ ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" )
+ ( event->m_sibling ? " (joint event)" : "" );
Output.emplace_back( textline, Global.UITextColor );
}
event = event->m_next;
}
if( Output.size() == 1 ) {
Output.front().data = "(no queued events)";
}
}
void
@@ -888,15 +895,16 @@ debug_panel::update_section_renderer( std::vector<text_line> &Output ) {
Output.emplace_back( GfxRenderer.info_stats(), Global.UITextColor );
}
void
bool
debug_panel::render_section( std::string const &Header, std::vector<text_line> const &Lines ) {
if( Lines.empty() ) { return; }
if( false == ImGui::CollapsingHeader( Header.c_str() ) ) { return; }
if( true == Lines.empty() ) { return false; }
if( false == ImGui::CollapsingHeader( Header.c_str() ) ) { return false; }
for( auto const &line : Lines ) {
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
}
return true;
}
void

View File

@@ -76,7 +76,7 @@ private:
std::string update_vehicle_coupler( int const Side );
std::string update_vehicle_brake() const;
// renders provided lines, under specified collapsing header
void render_section( std::string const &Header, std::vector<text_line> const &Lines );
bool render_section( std::string const &Header, std::vector<text_line> const &Lines );
// members
std::array<char, 1024> m_buffer;
input_data m_input;
@@ -92,6 +92,7 @@ private:
int tprev { 0 }; // poprzedni czas
double VelPrev { 0.0 }; // poprzednia prędkość
double Acc { 0.0 }; // przyspieszenie styczne
bool m_eventqueueactivevehicleonly { false };
};
class transcripts_panel : public ui_panel {

View File

@@ -2409,7 +2409,20 @@ opengl_renderer::Render( TSubModel *Submodel ) {
Bind_Material( Submodel->m_material );
}
// ...colors...
::glColor3fv( glm::value_ptr( Submodel->f4Diffuse ) ); // McZapkie-240702: zamiast ub
if( Submodel->fVisible < 1.f ) {
// setup
::glAlphaFunc( GL_GREATER, 0.f );
::glEnable( GL_BLEND );
::glColor4f(
Submodel->f4Diffuse.r,
Submodel->f4Diffuse.g,
Submodel->f4Diffuse.b,
Submodel->fVisible );
}
else {
::glColor3fv( glm::value_ptr( Submodel->f4Diffuse ) ); // McZapkie-240702: zamiast ub
}
// ...specular...
if( ( true == m_renderspecular ) && ( m_sunlight.specular.a > 0.01f ) ) {
// specular strength in legacy models is set uniformly to 150, 150, 150 so we scale it down for opaque elements
::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( Submodel->f4Specular * m_sunlight.specular.a * m_specularopaquescalefactor ) );
@@ -2441,6 +2454,10 @@ opengl_renderer::Render( TSubModel *Submodel ) {
}
*/
// post-draw reset
if( Submodel->fVisible < 1.f ) {
::glAlphaFunc( GL_GREATER, 0.5f );
::glDisable( GL_BLEND );
}
if( ( true == m_renderspecular ) && ( m_sunlight.specular.a > 0.01f ) ) {
::glMaterialfv( GL_FRONT, GL_SPECULAR, glm::value_ptr( colors::none ) );
}
@@ -2535,7 +2552,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
// distance attenuation. NOTE: since it's fixed pipeline with built-in gamma correction we're using linear attenuation
// we're capping how much effect the distance attenuation can have, otherwise the lights get too tiny at regular distances
float const distancefactor { std::max( 0.5f, ( Submodel->fSquareMaxDist - TSubModel::fSquareDist ) / Submodel->fSquareMaxDist ) };
float const precipitationfactor { std::max( 1.f, Global.Overcast - 1.f ) };
float const precipitationfactor { std::max( 1.f, 0.5f * ( Global.Overcast - 1.f ) ) };
if( lightlevel > 0.f ) {
// material configuration:
@@ -2543,9 +2560,11 @@ opengl_renderer::Render( TSubModel *Submodel ) {
Bind_Material( null_handle );
::glPointSize( std::max( 3.f, 5.f * distancefactor * anglefactor ) );
::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], std::min( 1.f, lightlevel * anglefactor * precipitationfactor ) );
::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], Submodel->fVisible * std::min( 1.f, lightlevel * anglefactor * precipitationfactor ) );
::glDisable( GL_LIGHTING );
::glDisable( GL_FOG );
::glEnable( GL_BLEND );
::glAlphaFunc( GL_GREATER, 0.f );
::glPushMatrix();
::glLoadIdentity();
@@ -3439,10 +3458,10 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
float glarelevel = 0.6f; // luminosity at night is at level of ~0.1, so the overall resulting transparency in clear conditions is ~0.5 at full 'brightness'
if( Submodel->fCosViewAngle > Submodel->fCosFalloffAngle ) {
// only bother if the viewer is inside the visibility cone
auto glarelevel { clamp<float>(
0.6f
- Global.fLuminance // reduce the glare in bright daylight
+ std::max( 0.f, Global.Overcast - 1.f ), // increase the glare in rainy/foggy conditions
auto glarelevel { clamp(
std::max<float>(
0.6f - Global.fLuminance, // reduce the glare in bright daylight
Global.Overcast - 1.f ), // ensure some glare in rainy/foggy conditions
0.f, 1.f ) };
// scale it down based on view angle
glarelevel *= ( Submodel->fCosViewAngle - Submodel->fCosFalloffAngle ) / ( 1.0f - Submodel->fCosFalloffAngle );
@@ -3452,8 +3471,9 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
::glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT );
Bind_Texture( m_glaretexture );
::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], glarelevel );
::glColor4f( Submodel->f4Diffuse[ 0 ], Submodel->f4Diffuse[ 1 ], Submodel->f4Diffuse[ 2 ], Submodel->fVisible * glarelevel );
::glDisable( GL_LIGHTING );
::glDisable( GL_FOG );
::glDepthMask( GL_FALSE );
::glBlendFunc( GL_SRC_ALPHA, GL_ONE );