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

build 170708. cursor-based item picking, mouse support for cab controls, rudimentary render modes support in renderer

This commit is contained in:
tmj-fstate
2017-07-09 16:45:40 +02:00
parent d3b812ee9f
commit 9a008ecff5
26 changed files with 1931 additions and 931 deletions

View File

@@ -447,7 +447,7 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable
m_materialdata.replacable_skins[1] = m_materialdata.replacable_skins[1] =
GfxRenderer.GetTextureId( asReplacableTexture, "" ); GfxRenderer.GetTextureId( asReplacableTexture, "" );
if( ( m_materialdata.replacable_skins[ 1 ] != 0 ) if( ( m_materialdata.replacable_skins[ 1 ] != 0 )
&& ( GfxRenderer.Texture( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) ) { && ( GfxRenderer.Texture( m_materialdata.replacable_skins[ 1 ] ).has_alpha ) ) {
// tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych // tekstura z kanałem alfa - nie renderować w cyklu nieprzezroczystych
m_materialdata.textures_alpha = 0x31310031; m_materialdata.textures_alpha = 0x31310031;
} }
@@ -470,7 +470,7 @@ bool TAnimModel::Load(cParser *parser, bool ter)
if (ter) // jeśli teren if (ter) // jeśli teren
{ {
if( name.substr( name.rfind( '.' ) ) == ".t3d" ) { if( name.substr( name.rfind( '.' ) ) == ".t3d" ) {
name[ name.length() - 2 ] = 'e'; name[ name.length() - 3 ] = 'e';
} }
Global::asTerrainModel = name; Global::asTerrainModel = name;
WriteLog("Terrain model \"" + name + "\" will be created."); WriteLog("Terrain model \"" + name + "\" will be created.");

View File

@@ -419,29 +419,18 @@ bool TCamera::SetMatrix( glm::dmat4 &Matrix ) {
if( Type == tp_Follow ) { if( Type == tp_Follow ) {
Matrix *= glm::lookAt( Matrix *= glm::lookAt(
glm::dvec3( Pos.x, Pos.y, Pos.z ), glm::dvec3{ Pos },
glm::dvec3( LookAt.x, LookAt.y, LookAt.z ), glm::dvec3{ LookAt },
glm::dvec3( vUp.x, vUp.y, vUp.z ) ); glm::dvec3{ vUp } );
} }
else { else {
Matrix = glm::translate( Matrix, glm::dvec3( -Pos.x, -Pos.y, -Pos.z ) ); // nie zmienia kierunku patrzenia Matrix = glm::translate( Matrix, glm::dvec3{ -Pos } ); // nie zmienia kierunku patrzenia
} }
Global::SetCameraPosition( Pos ); // było +pOffset Global::SetCameraPosition( Pos ); // było +pOffset
return true; return true;
} }
void TCamera::SetCabMatrix(vector3 &p)
{ // ustawienie widoku z kamery bez przesunięcia robionego przez OpenGL - nie powinno tak trząść
glRotated(-Roll * 180.0 / M_PI, 0.0, 0.0, 1.0);
glRotated(-Pitch * 180.0 / M_PI, 1.0, 0.0, 0.0);
glRotated(-Yaw * 180.0 / M_PI, 0.0, 1.0, 0.0); // w zewnętrznym widoku: kierunek patrzenia
if (Type == tp_Follow)
gluLookAt(Pos.x - p.x, Pos.y - p.y, Pos.z - p.z, LookAt.x - p.x, LookAt.y - p.y,
LookAt.z - p.z, vUp.x, vUp.y, vUp.z); // Ra: pOffset is zero
}
void TCamera::RaLook() void TCamera::RaLook()
{ // zmiana kierunku patrzenia - przelicza Yaw { // zmiana kierunku patrzenia - przelicza Yaw
vector3 where = LookAt - Pos + vector3(0, 3, 0); // trochę w górę od szyn vector3 where = LookAt - Pos + vector3(0, 3, 0); // trochę w górę od szyn

View File

@@ -59,7 +59,6 @@ class TCamera
vector3 GetDirection(); vector3 GetDirection();
bool SetMatrix(); bool SetMatrix();
bool SetMatrix(glm::dmat4 &Matrix); bool SetMatrix(glm::dmat4 &Matrix);
void SetCabMatrix( vector3 &p );
void RaLook(); void RaLook();
void Stop(); void Stop();
// bool GetMatrix(matrix4x4 &Matrix); // bool GetMatrix(matrix4x4 &Matrix);

View File

@@ -66,6 +66,7 @@ namespace input {
keyboard_input Keyboard; keyboard_input Keyboard;
gamepad_input Gamepad; gamepad_input Gamepad;
glm::dvec2 mouse_pos; // stores last mouse position in control picking mode
} }
@@ -122,11 +123,22 @@ void window_resize_callback(GLFWwindow *window, int w, int h)
void cursor_pos_callback(GLFWwindow *window, double x, double y) void cursor_pos_callback(GLFWwindow *window, double x, double y)
{ {
input::Keyboard.mouse( x, y ); if( true == Global::ControlPicking ) {
#ifdef EU07_USE_OLD_COMMAND_SYSTEM glfwSetCursorPos( window, x, y );
World.OnMouseMove(x * 0.005, y * 0.01); }
#endif else {
glfwSetCursorPos(window, 0.0, 0.0); input::Keyboard.mouse( x, y );
glfwSetCursorPos( window, 0, 0 );
}
}
void mouse_button_callback( GLFWwindow* window, int button, int action, int mods ) {
if( ( button == GLFW_MOUSE_BUTTON_LEFT )
|| ( button == GLFW_MOUSE_BUTTON_RIGHT ) ) {
// we don't care about other mouse buttons at the moment
input::Keyboard.mouse( button, action );
}
} }
void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods ) void key_callback( GLFWwindow *window, int key, int scancode, int action, int mods )
@@ -136,6 +148,27 @@ void key_callback( GLFWwindow *window, int key, int scancode, int action, int mo
Global::shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false; Global::shiftState = ( mods & GLFW_MOD_SHIFT ) ? true : false;
Global::ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false; Global::ctrlState = ( mods & GLFW_MOD_CONTROL ) ? true : false;
if( ( key == GLFW_KEY_LEFT_ALT )
|| ( key == GLFW_KEY_RIGHT_ALT ) ) {
// if the alt key was pressed toggle control picking mode and set matching cursor behaviour
if( action == GLFW_RELEASE ) {
if( Global::ControlPicking ) {
// switch off
glfwGetCursorPos( window, &input::mouse_pos.x, &input::mouse_pos.y );
glfwSetInputMode( window, GLFW_CURSOR, GLFW_CURSOR_DISABLED );
glfwSetCursorPos( window, 0, 0 );
}
else {
// enter picking mode
glfwSetInputMode( window, GLFW_CURSOR, GLFW_CURSOR_NORMAL );
glfwSetCursorPos( window, input::mouse_pos.x, input::mouse_pos.y );
}
// actually toggle the mode
Global::ControlPicking = !Global::ControlPicking;
}
}
if( ( key == GLFW_KEY_LEFT_SHIFT ) if( ( key == GLFW_KEY_LEFT_SHIFT )
|| ( key == GLFW_KEY_LEFT_CONTROL ) || ( key == GLFW_KEY_LEFT_CONTROL )
|| ( key == GLFW_KEY_LEFT_ALT ) || ( key == GLFW_KEY_LEFT_ALT )
@@ -340,6 +373,7 @@ int main(int argc, char *argv[])
glfwSetCursorPos(window, 0.0, 0.0); glfwSetCursorPos(window, 0.0, 0.0);
glfwSetFramebufferSizeCallback(window, window_resize_callback); glfwSetFramebufferSizeCallback(window, window_resize_callback);
glfwSetCursorPosCallback(window, cursor_pos_callback); glfwSetCursorPosCallback(window, cursor_pos_callback);
glfwSetMouseButtonCallback( window, mouse_button_callback );
glfwSetKeyCallback(window, key_callback); glfwSetKeyCallback(window, key_callback);
glfwSetScrollCallback( window, scroll_callback ); glfwSetScrollCallback( window, scroll_callback );
glfwSetWindowFocusCallback(window, focus_callback); glfwSetWindowFocusCallback(window, focus_callback);
@@ -417,6 +451,7 @@ int main(int argc, char *argv[])
&& ( true == World.Update() ) && ( true == World.Update() )
&& ( true == GfxRenderer.Render() ) ) { && ( true == GfxRenderer.Render() ) ) {
glfwPollEvents(); glfwPollEvents();
input::Keyboard.poll();
if( true == Global::InputGamepad ) { if( true == Global::InputGamepad ) {
input::Gamepad.poll(); input::Gamepad.poll();
} }

View File

@@ -38,7 +38,6 @@ double Global::ABuDebug = 0;
std::string Global::asSky = "1"; std::string Global::asSky = "1";
double Global::fLuminance = 1.0; // jasność światła do automatycznego zapalania double Global::fLuminance = 1.0; // jasność światła do automatycznego zapalania
float Global::SunAngle = 0.0f; float Global::SunAngle = 0.0f;
int Global::iReCompile = 0; // zwiększany, gdy trzeba odświeżyć siatki
int Global::ScreenWidth = 1; int Global::ScreenWidth = 1;
int Global::ScreenHeight = 1; int Global::ScreenHeight = 1;
float Global::ZoomFactor = 1.0f; float Global::ZoomFactor = 1.0f;
@@ -48,6 +47,7 @@ bool Global::shiftState;
bool Global::ctrlState; bool Global::ctrlState;
int Global::iCameraLast = -1; int Global::iCameraLast = -1;
std::string Global::asVersion = "couldn't retrieve version string"; std::string Global::asVersion = "couldn't retrieve version string";
bool Global::ControlPicking = false; // indicates controls pick mode is enabled
int Global::iTextMode = 0; // tryb pracy wyświetlacza tekstowego int Global::iTextMode = 0; // tryb pracy wyświetlacza tekstowego
int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // numer ekranu wyświetlacza tekstowego int Global::iScreenMode[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // numer ekranu wyświetlacza tekstowego
double Global::fSunDeclination = 0.0; // deklinacja Słońca double Global::fSunDeclination = 0.0; // deklinacja Słońca

View File

@@ -238,7 +238,6 @@ class Global
static int iBallastFiltering; // domyślne rozmywanie tekstury podsypki static int iBallastFiltering; // domyślne rozmywanie tekstury podsypki
static int iRailProFiltering; // domyślne rozmywanie tekstury szyn static int iRailProFiltering; // domyślne rozmywanie tekstury szyn
static int iDynamicFiltering; // domyślne rozmywanie tekstur pojazdów static int iDynamicFiltering; // domyślne rozmywanie tekstur pojazdów
static int iReCompile; // zwiększany, gdy trzeba odświeżyć siatki
static bool bUseVBO; // czy jest VBO w karcie graficznej static bool bUseVBO; // czy jest VBO w karcie graficznej
static std::string LastGLError; static std::string LastGLError;
static int iFeedbackMode; // tryb pracy informacji zwrotnej static int iFeedbackMode; // tryb pracy informacji zwrotnej
@@ -257,6 +256,7 @@ class Global
static int iCameraLast; static int iCameraLast;
static std::string asVersion; // z opisem static std::string asVersion; // z opisem
static GLint iMaxTextureSize; // maksymalny rozmiar tekstury static GLint iMaxTextureSize; // maksymalny rozmiar tekstury
static bool ControlPicking; // indicates controls pick mode is enabled
static int iTextMode; // tryb pracy wyświetlacza tekstowego static int iTextMode; // tryb pracy wyświetlacza tekstowego
static int iScreenMode[12]; // numer ekranu wyświetlacza tekstowego static int iScreenMode[12]; // numer ekranu wyświetlacza tekstowego
static bool bDoubleAmbient; // podwójna jasność ambient static bool bDoubleAmbient; // podwójna jasność ambient

View File

@@ -49,8 +49,14 @@ extern "C"
bool bCondition; // McZapkie: do testowania warunku na event multiple bool bCondition; // McZapkie: do testowania warunku na event multiple
std::string LogComment; std::string LogComment;
// TODO: switch to the new unified code after we have in place merging of individual triangle nodes into material-based soups // tests whether provided points form a degenerate triangle
#define EU07_USE_OLD_RENDERCODE bool
degenerate( glm::dvec3 const &Vertex1, glm::dvec3 const &Vertex2, glm::dvec3 const &Vertex3 ) {
return ( ( Vertex1 == Vertex2 )
|| ( Vertex2 == Vertex3 )
|| ( Vertex3 == Vertex1 ) );
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Obiekt renderujący siatkę jest sztucznie tworzonym obiektem pomocniczym, // Obiekt renderujący siatkę jest sztucznie tworzonym obiektem pomocniczym,
@@ -692,6 +698,21 @@ TGroundNode * TGround::FindGroundNode(std::string asNameToFind, TGroundNodeType
return NULL; return NULL;
} }
TGroundRect *
TGround::GetRect( double x, double z ) {
auto const column = GetColFromX( x ) / iNumSubRects;
auto const row = GetRowFromZ( z ) / iNumSubRects;
if( ( column >= 0 ) && ( column < iNumRects )
&& ( row >= 0 ) && ( row < iNumRects ) ) {
return &Rects[ column ][ row ];
}
else {
return nullptr;
}
};
double fTrainSetVel = 0; double fTrainSetVel = 0;
double fTrainSetDir = 0; double fTrainSetDir = 0;
double fTrainSetDist = 0; // odległość składu od punktu 1 w stronę punktu 2 double fTrainSetDist = 0; // odległość składu od punktu 1 w stronę punktu 2
@@ -934,25 +955,25 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
>> tmp->hvTraction->pPoint1.x >> tmp->hvTraction->pPoint1.x
>> tmp->hvTraction->pPoint1.y >> tmp->hvTraction->pPoint1.y
>> tmp->hvTraction->pPoint1.z; >> tmp->hvTraction->pPoint1.z;
tmp->hvTraction->pPoint1 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); tmp->hvTraction->pPoint1 += glm::dvec3{ pOrigin };
parser->getTokens(3); parser->getTokens(3);
*parser *parser
>> tmp->hvTraction->pPoint2.x >> tmp->hvTraction->pPoint2.x
>> tmp->hvTraction->pPoint2.y >> tmp->hvTraction->pPoint2.y
>> tmp->hvTraction->pPoint2.z; >> tmp->hvTraction->pPoint2.z;
tmp->hvTraction->pPoint2 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); tmp->hvTraction->pPoint2 += glm::dvec3{ pOrigin };
parser->getTokens(3); parser->getTokens(3);
*parser *parser
>> tmp->hvTraction->pPoint3.x >> tmp->hvTraction->pPoint3.x
>> tmp->hvTraction->pPoint3.y >> tmp->hvTraction->pPoint3.y
>> tmp->hvTraction->pPoint3.z; >> tmp->hvTraction->pPoint3.z;
tmp->hvTraction->pPoint3 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); tmp->hvTraction->pPoint3 += glm::dvec3{ pOrigin };
parser->getTokens(3); parser->getTokens(3);
*parser *parser
>> tmp->hvTraction->pPoint4.x >> tmp->hvTraction->pPoint4.x
>> tmp->hvTraction->pPoint4.y >> tmp->hvTraction->pPoint4.y
>> tmp->hvTraction->pPoint4.z; >> tmp->hvTraction->pPoint4.z;
tmp->hvTraction->pPoint4 += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); tmp->hvTraction->pPoint4 += glm::dvec3{ pOrigin };
parser->getTokens(); parser->getTokens();
*parser >> tf1; *parser >> tf1;
tmp->hvTraction->fHeightDifference = tmp->hvTraction->fHeightDifference =
@@ -1238,6 +1259,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
{ // jeśli model jest terenem, trzeba utworzyć dodatkowe obiekty { // jeśli model jest terenem, trzeba utworzyć dodatkowe obiekty
// po wczytaniu model ma już utworzone DL albo VBO // po wczytaniu model ma już utworzone DL albo VBO
Global::pTerrainCompact = tmp->Model; // istnieje co najmniej jeden obiekt terenu Global::pTerrainCompact = tmp->Model; // istnieje co najmniej jeden obiekt terenu
tmp->pCenter = Math3D::vector3( 0.0, 0.0, 0.0 ); // enforce placement in the world center
tmp->iCount = Global::pTerrainCompact->TerrainCount() + 1; // zliczenie submodeli tmp->iCount = Global::pTerrainCompact->TerrainCount() + 1; // zliczenie submodeli
tmp->nNode = new TGroundNode[tmp->iCount]; // sztuczne node dla kwadratów tmp->nNode = new TGroundNode[tmp->iCount]; // sztuczne node dla kwadratów
tmp->nNode[0].iType = TP_MODEL; // pierwszy zawiera model (dla delete) tmp->nNode[0].iType = TP_MODEL; // pierwszy zawiera model (dla delete)
@@ -1245,7 +1267,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
tmp->nNode[0].iFlags = 0x200; // nie wyświetlany, ale usuwany tmp->nNode[0].iFlags = 0x200; // nie wyświetlany, ale usuwany
for (int i = 1; i < tmp->iCount; ++i) for (int i = 1; i < tmp->iCount; ++i)
{ // a reszta to submodele { // a reszta to submodele
tmp->nNode[i].iType = TP_SUBMODEL; // tmp->nNode[i].iType = TP_SUBMODEL;
tmp->nNode[i].smTerrain = Global::pTerrainCompact->TerrainSquare(i - 1); tmp->nNode[i].smTerrain = Global::pTerrainCompact->TerrainSquare(i - 1);
tmp->nNode[i].iFlags = 0x10; // nieprzezroczyste; nie usuwany tmp->nNode[i].iFlags = 0x10; // nieprzezroczyste; nie usuwany
tmp->nNode[i].bVisible = true; tmp->nNode[i].bVisible = true;
@@ -1264,27 +1286,24 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
// case TP_GEOMETRY : // case TP_GEOMETRY :
case GL_TRIANGLES: case GL_TRIANGLES:
case GL_TRIANGLE_STRIP: case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN: case GL_TRIANGLE_FAN: {
parser->getTokens(); parser->getTokens();
*parser >> token; *parser >> token;
// McZapkie-050702: opcjonalne wczytywanie parametrow materialu (ambient,diffuse,specular) // McZapkie-050702: opcjonalne wczytywanie parametrow materialu (ambient,diffuse,specular)
if (token.compare("material") == 0) if( token.compare( "material" ) == 0 ) {
{
parser->getTokens(); parser->getTokens();
*parser >> token; *parser >> token;
while (token.compare("endmaterial") != 0) while( token.compare( "endmaterial" ) != 0 ) {
{ if( token.compare( "ambient:" ) == 0 ) {
if (token.compare("ambient:") == 0) parser->getTokens( 3 );
{
parser->getTokens(3);
*parser *parser
>> tmp->Ambient.r >> tmp->Ambient.r
>> tmp->Ambient.g >> tmp->Ambient.g
>> tmp->Ambient.b; >> tmp->Ambient.b;
tmp->Ambient /= 255.0f; tmp->Ambient /= 255.0f;
} }
else if (token.compare("diffuse:") == 0) else if( token.compare( "diffuse:" ) == 0 ) { // Ra: coś jest nie tak, bo w jednej linijce nie działa
{ // Ra: coś jest nie tak, bo w jednej linijce nie działa
parser->getTokens( 3 ); parser->getTokens( 3 );
*parser *parser
>> tmp->Diffuse.r >> tmp->Diffuse.r
@@ -1292,8 +1311,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
>> tmp->Diffuse.b; >> tmp->Diffuse.b;
tmp->Diffuse /= 255.0f; tmp->Diffuse /= 255.0f;
} }
else if (token.compare("specular:") == 0) else if( token.compare( "specular:" ) == 0 ) {
{
parser->getTokens( 3 ); parser->getTokens( 3 );
*parser *parser
>> tmp->Specular.r >> tmp->Specular.r
@@ -1302,18 +1320,25 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
tmp->Specular /= 255.0f; tmp->Specular /= 255.0f;
} }
else else
Error("Scene material failure!"); Error( "Scene material failure!" );
parser->getTokens(); parser->getTokens();
*parser >> token; *parser >> token;
} }
} }
if (token.compare("endmaterial") == 0) if( token.compare( "endmaterial" ) == 0 ) {
{
parser->getTokens(); parser->getTokens();
*parser >> token; *parser >> token;
} }
str = token; str = token;
tmp->TextureID = GfxRenderer.GetTextureId( str, szTexturePath ); tmp->TextureID = GfxRenderer.GetTextureId( str, szTexturePath );
bool const clamps = (
tmp->TextureID ?
GfxRenderer.Texture( tmp->TextureID ).traits.find( 's' ) != std::string::npos :
false );
bool const clampt = (
tmp->TextureID ?
GfxRenderer.Texture( tmp->TextureID ).traits.find( 't' ) != std::string::npos :
false );
tmp->iFlags |= 200; // z usuwaniem tmp->iFlags |= 200; // z usuwaniem
// remainder of legacy 'problend' system -- geometry assigned a texture with '@' in its name is treated as translucent, opaque otherwise // remainder of legacy 'problend' system -- geometry assigned a texture with '@' in its name is treated as translucent, opaque otherwise
@@ -1322,49 +1347,76 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
&& ( true == GfxRenderer.Texture( tmp->TextureID ).has_alpha ) ) ? && ( true == GfxRenderer.Texture( tmp->TextureID ).has_alpha ) ) ?
0x20 : 0x20 :
0x10 ); 0x10 );
{
TGroundVertex vertex, vertex1, vertex2; TGroundVertex vertex, vertex1, vertex2;
std::size_t vertexcount { 0 }; std::size_t vertexcount{ 0 };
do { do {
parser->getTokens( 8, false ); parser->getTokens( 8, false );
*parser *parser
>> vertex.position.x >> vertex.position.x
>> vertex.position.y >> vertex.position.y
>> vertex.position.z >> vertex.position.z
>> vertex.normal.x >> vertex.normal.x
>> vertex.normal.y >> vertex.normal.y
>> vertex.normal.z >> vertex.normal.z
>> vertex.texture.s >> vertex.texture.s
>> vertex.texture.t; >> vertex.texture.t;
vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI ); vertex.position = glm::rotateZ( vertex.position, aRotate.z / 180 * M_PI );
vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI ); vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI );
vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI );
vertex.normal = glm::rotateZ( vertex.normal, static_cast<float>( aRotate.z / 180 * M_PI ) ); vertex.normal = glm::rotateZ( vertex.normal, static_cast<float>( aRotate.z / 180 * M_PI ) );
vertex.normal = glm::rotateX( vertex.normal, static_cast<float>( aRotate.x / 180 * M_PI ) ); vertex.normal = glm::rotateX( vertex.normal, static_cast<float>( aRotate.x / 180 * M_PI ) );
vertex.normal = glm::rotateY( vertex.normal, static_cast<float>( aRotate.y / 180 * M_PI ) ); vertex.normal = glm::rotateY( vertex.normal, static_cast<float>( aRotate.y / 180 * M_PI ) );
vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); vertex.position += glm::dvec3{ pOrigin };
// convert all data to gl_triangles to allow data merge for matching nodes if( true == clamps ) { vertex.texture.s = clamp( vertex.texture.s, 0.001f, 0.999f ); }
switch( tmp->iType ) { if( true == clampt ) { vertex.texture.t = clamp( vertex.texture.t, 0.001f, 0.999f ); }
case GL_TRIANGLES: { // convert all data to gl_triangles to allow data merge for matching nodes
importedvertices.emplace_back( vertex ); switch( tmp->iType ) {
break; case GL_TRIANGLES: {
if( vertexcount == 0 ) { vertex1 = vertex; }
else if( vertexcount == 1 ) { vertex2 = vertex; }
else if( vertexcount >= 2 ) {
if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) {
importedvertices.emplace_back( vertex1 );
importedvertices.emplace_back( vertex2 );
importedvertices.emplace_back( vertex );
}
else {
ErrorLog(
"Bad geometry: degenerate triangle encountered"
+ ( tmp->asName != "" ? " in node \"" + tmp->asName + "\"" : "" )
+ " (vertices: " + to_string( vertex1.position ) + " + " + to_string( vertex2.position ) + " + " + to_string( vertex.position ) + ")" );
}
} }
case GL_TRIANGLE_FAN: { ++vertexcount;
if( vertexcount == 0 ) { vertex1 = vertex; } if( vertexcount > 2 ) { vertexcount = 0; } // start new triangle if needed
else if( vertexcount == 1 ) { vertex2 = vertex; } break;
else if( vertexcount >= 2 ) { }
case GL_TRIANGLE_FAN: {
if( vertexcount == 0 ) { vertex1 = vertex; }
else if( vertexcount == 1 ) { vertex2 = vertex; }
else if( vertexcount >= 2 ) {
if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) {
importedvertices.emplace_back( vertex1 ); importedvertices.emplace_back( vertex1 );
importedvertices.emplace_back( vertex2 ); importedvertices.emplace_back( vertex2 );
importedvertices.emplace_back( vertex ); importedvertices.emplace_back( vertex );
vertex2 = vertex; vertex2 = vertex;
} }
++vertexcount; else {
break; ErrorLog(
"Bad geometry: degenerate triangle encountered"
+ ( tmp->asName != "" ? " in node \"" + tmp->asName + "\"" : "" )
+ " (vertices: " + to_string( vertex1.position ) + " + " + to_string( vertex2.position ) + " + " + to_string( vertex.position ) + ")" );
}
} }
case GL_TRIANGLE_STRIP: { ++vertexcount;
if( vertexcount == 0 ) { vertex1 = vertex; } break;
else if( vertexcount == 1 ) { vertex2 = vertex; } }
else if( vertexcount >= 2 ) { case GL_TRIANGLE_STRIP: {
if( vertexcount == 0 ) { vertex1 = vertex; }
else if( vertexcount == 1 ) { vertex2 = vertex; }
else if( vertexcount >= 2 ) {
if( false == degenerate( vertex1.position, vertex2.position, vertex.position ) ) {
// swap order every other triangle, to maintain consistent winding // swap order every other triangle, to maintain consistent winding
if( vertexcount % 2 == 0 ) { if( vertexcount % 2 == 0 ) {
importedvertices.emplace_back( vertex1 ); importedvertices.emplace_back( vertex1 );
@@ -1379,40 +1431,47 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
vertex1 = vertex2; vertex1 = vertex2;
vertex2 = vertex; vertex2 = vertex;
} }
++vertexcount; else {
break; ErrorLog(
"Bad geometry: degenerate triangle encountered"
+ ( tmp->asName != "" ? " in node \"" + tmp->asName + "\"" : "" )
+ " (vertices: " + to_string( vertex1.position ) + " + " + to_string( vertex2.position ) + " + " + to_string( vertex.position ) + ")" );
}
} }
default: { break; } ++vertexcount;
break;
} }
parser->getTokens(); default: { break; }
*parser >> token;
} while (token.compare("endtri") != 0);
tmp->iType = GL_TRIANGLES;
tmp->Piece = new piece_node();
tmp->iNumVerts = importedvertices.size();
if( tmp->iNumVerts > 0 ) {
tmp->Piece->vertices.swap( importedvertices );
for( auto const &vertex : tmp->Piece->vertices ) {
tmp->pCenter += vertex.position;
}
tmp->pCenter /= tmp->iNumVerts;
r = 0;
for( auto const &vertex : tmp->Piece->vertices ) {
tf = SquareMagnitude( vertex.position - tmp->pCenter );
if( tf > r )
r = tf;
}
tmp->fSquareRadius += r;
RaTriangleDivider( tmp ); // Ra: dzielenie trójkątów jest teraz całkiem wydajne
} }
parser->getTokens();
*parser >> token;
} while( token.compare( "endtri" ) != 0 );
tmp->iType = GL_TRIANGLES;
tmp->Piece = new piece_node();
tmp->iNumVerts = importedvertices.size();
if( tmp->iNumVerts > 0 ) {
tmp->Piece->vertices.swap( importedvertices );
for( auto const &vertex : tmp->Piece->vertices ) {
tmp->pCenter += vertex.position;
}
tmp->pCenter /= tmp->iNumVerts;
r = 0;
for( auto const &vertex : tmp->Piece->vertices ) {
tf = glm::length2( vertex.position - glm::dvec3{ tmp->pCenter } );
if( tf > r )
r = tf;
}
tmp->fSquareRadius += r;
RaTriangleDivider( tmp ); // Ra: dzielenie trójkątów jest teraz całkiem wydajne
} // koniec wczytywania trójkątów } // koniec wczytywania trójkątów
break; break;
}
case GL_LINES: case GL_LINES:
case GL_LINE_STRIP: case GL_LINE_STRIP:
case GL_LINE_LOOP: { case GL_LINE_LOOP: {
@@ -1440,7 +1499,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI ); vertex.position = glm::rotateX( vertex.position, aRotate.x / 180 * M_PI );
vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI ); vertex.position = glm::rotateY( vertex.position, aRotate.y / 180 * M_PI );
vertex.position += glm::dvec3( pOrigin.x, pOrigin.y, pOrigin.z ); vertex.position += glm::dvec3{ pOrigin };
// convert all data to gl_lines to allow data merge for matching nodes // convert all data to gl_lines to allow data merge for matching nodes
switch( tmp->iType ) { switch( tmp->iType ) {
case GL_LINES: { case GL_LINES: {
@@ -1578,11 +1637,11 @@ void TGround::FirstInit()
// dodanie do globalnego obiektu // dodanie do globalnego obiektu
srGlobal.NodeAdd( Current ); srGlobal.NodeAdd( Current );
} }
else if (type == TP_TERRAIN) else if (type == TP_TERRAIN) {
{ // specjalne przetwarzanie terenu wczytanego z pliku E3D // specjalne przetwarzanie terenu wczytanego z pliku E3D
TGroundRect *gr; TGroundRect *gr;
for (int j = 1; j < Current->iCount; ++j) for (int j = 1; j < Current->iCount; ++j) {
{ // od 1 do końca są zestawy trójkątów // od 1 do końca są zestawy trójkątów
std::string xxxzzz = Current->nNode[j].smTerrain->pName; // pobranie nazwy std::string xxxzzz = Current->nNode[j].smTerrain->pName; // pobranie nazwy
gr = GetRect( gr = GetRect(
( std::stoi( xxxzzz.substr( 0, 3 )) - 500 ) * 1000, ( std::stoi( xxxzzz.substr( 0, 3 )) - 500 ) * 1000,
@@ -1590,16 +1649,30 @@ void TGround::FirstInit()
gr->nTerrain = Current->nNode + j; // zapamiętanie gr->nTerrain = Current->nNode + j; // zapamiętanie
} }
} }
else if( ( Current->iType != GL_TRIANGLES )
|| ( Current->iFlags & 0x20 )
|| ( Current->fSquareMinRadius != 0.0 )
|| ( Current->fSquareRadius <= 90000.0 ) ) {
// add to sub-rectangle
GetSubRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current );
}
else { else {
// dodajemy do kwadratu kilometrowego TSubRect *targetcell { nullptr };
GetRect( Current->pCenter.x, Current->pCenter.z )->NodeAdd( Current ); // test whether we can add the node to a ground cell, or a subcell
if( ( Current->iType != GL_TRIANGLES )
|| ( Current->iFlags & 0x20 )
|| ( Current->fSquareMinRadius != 0.0 )
|| ( Current->fSquareRadius <= 90000.0 ) ) {
// add to sub-rectangle
targetcell = GetSubRect( Current->pCenter.x, Current->pCenter.z );
}
else {
// dodajemy do kwadratu kilometrowego
targetcell = GetRect( Current->pCenter.x, Current->pCenter.z );
}
if( targetcell != nullptr ) {
targetcell->NodeAdd( Current );
}
else {
ErrorLog( "Scenery node" + (
Current->asName == "" ?
"" :
" \"" + Current->asName + "\"" )
+ " placed in location outside of map bounds (location: " + to_string( glm::dvec3{ Current->pCenter } ) + ")" );
}
} }
} }
} }
@@ -2900,7 +2973,7 @@ TTraction * TGround::TractionNearestFind(glm::dvec3 &p, int dir, TGroundNode *n)
if (nCurrent->hvTraction->fResistance[k] >= if (nCurrent->hvTraction->fResistance[k] >=
0.0) //żeby się nie propagowały jakieś ujemne 0.0) //żeby się nie propagowały jakieś ujemne
{ // znaleziony kandydat do połączenia { // znaleziony kandydat do połączenia
d = SquareMagnitude( p - nCurrent->pCenter ); // kwadrat odległości środków d = glm::length2( p - glm::dvec3{ nCurrent->pCenter } ); // kwadrat odległości środków
if (dist > d) if (dist > d)
{ // zapamiętanie nowego najbliższego { // zapamiętanie nowego najbliższego
dist = d; // nowy rekord odległości dist = d; // nowy rekord odległości
@@ -3568,10 +3641,10 @@ bool TGround::GetTraction(TDynamicObject *model)
vParam = vParam =
node->hvTraction node->hvTraction
->vParametric; // współczynniki równania parametrycznego ->vParametric; // współczynniki równania parametrycznego
fRaParam = -DotProduct(pant0, vFront); fRaParam = -glm::dot(pant0, vFront);
auto const paramfrontdot = DotProduct( vParam, vFront ); auto const paramfrontdot = glm::dot( vParam, vFront );
fRaParam = fRaParam =
-( DotProduct( node->hvTraction->pPoint1, vFront ) + fRaParam ) -( glm::dot( node->hvTraction->pPoint1, vFront ) + fRaParam )
/ ( paramfrontdot != 0.0 ? paramfrontdot : 0.001 ); // div0 trap / ( paramfrontdot != 0.0 ? paramfrontdot : 0.001 ); // div0 trap
if ((fRaParam >= -0.001) ? (fRaParam <= 1.001) : false) if ((fRaParam >= -0.001) ? (fRaParam <= 1.001) : false)
{ // jeśli tylko jest w przedziale, wyznaczyć odległość wzdłuż { // jeśli tylko jest w przedziale, wyznaczyć odległość wzdłuż

View File

@@ -313,27 +313,21 @@ class TGround
TGroundNode * DynamicFind(std::string const &Name); TGroundNode * DynamicFind(std::string const &Name);
void DynamicList(bool all = false); void DynamicList(bool all = false);
TGroundNode * FindGroundNode(std::string asNameToFind, TGroundNodeType iNodeType); TGroundNode * FindGroundNode(std::string asNameToFind, TGroundNodeType iNodeType);
TGroundRect * GetRect(double x, double z) TGroundRect * GetRect( double x, double z );
{
return &Rects[GetColFromX(x) / iNumSubRects][GetRowFromZ(z) / iNumSubRects];
};
TSubRect * GetSubRect( int iCol, int iRow ); TSubRect * GetSubRect( int iCol, int iRow );
TSubRect * GetSubRect(double x, double z) inline
{ TSubRect * GetSubRect(double x, double z) {
return GetSubRect(GetColFromX(x), GetRowFromZ(z)); return GetSubRect(GetColFromX(x), GetRowFromZ(z)); };
};
TSubRect * FastGetSubRect( int iCol, int iRow ); TSubRect * FastGetSubRect( int iCol, int iRow );
inline
TSubRect * FastGetSubRect( double x, double z ) { TSubRect * FastGetSubRect( double x, double z ) {
return FastGetSubRect( GetColFromX( x ), GetRowFromZ( z ) ); return FastGetSubRect( GetColFromX( x ), GetRowFromZ( z ) ); };
}; inline
int GetRowFromZ(double z) int GetRowFromZ(double z) {
{ return (int)(z / fSubRectSize + fHalfTotalNumSubRects); };
return (int)(z / fSubRectSize + fHalfTotalNumSubRects); inline
}; int GetColFromX(double x) {
int GetColFromX(double x) return (int)(x / fSubRectSize + fHalfTotalNumSubRects); };
{
return (int)(x / fSubRectSize + fHalfTotalNumSubRects);
};
TEvent * FindEvent(const std::string &asEventName); TEvent * FindEvent(const std::string &asEventName);
TEvent * FindEventScan(const std::string &asEventName); TEvent * FindEventScan(const std::string &asEventName);
void TrackJoin(TGroundNode *Current); void TrackJoin(TGroundNode *Current);

View File

@@ -814,9 +814,11 @@ void TMoverParameters::UpdateBatteryVoltage(double dt)
sn3 = 0.0, sn3 = 0.0,
sn4 = 0.0, sn4 = 0.0,
sn5 = 0.0; // Ra: zrobić z tego amperomierz NN sn5 = 0.0; // Ra: zrobić z tego amperomierz NN
if ((BatteryVoltage > 0) && (EngineType != DieselEngine) && (EngineType != WheelsDriven) && if( ( BatteryVoltage > 0 )
(NominalBatteryVoltage > 0)) && ( EngineType != DieselEngine )
{ && ( EngineType != WheelsDriven )
&& ( NominalBatteryVoltage > 0 ) ) {
if ((NominalBatteryVoltage / BatteryVoltage < 1.22) && Battery) if ((NominalBatteryVoltage / BatteryVoltage < 1.22) && Battery)
{ // 110V { // 110V
if (!ConverterFlag) if (!ConverterFlag)
@@ -884,10 +886,10 @@ void TMoverParameters::UpdateBatteryVoltage(double dt)
if (BatteryVoltage < 0.01) if (BatteryVoltage < 0.01)
BatteryVoltage = 0.01; BatteryVoltage = 0.01;
} }
else if (NominalBatteryVoltage == 0) else {
BatteryVoltage = 0; // TODO: check and implement proper way to handle this for diesel engines
else BatteryVoltage = NominalBatteryVoltage;
BatteryVoltage = 90; }
}; };
/* Ukrotnienie EN57: /* Ukrotnienie EN57:

View File

@@ -121,11 +121,16 @@ std::string to_string(double _Val, int precision);
std::string to_string(double _Val, int precision, int width); std::string to_string(double _Val, int precision, int width);
std::string to_hex_str( int const _Val, int const width = 4 ); std::string to_hex_str( int const _Val, int const width = 4 );
inline std::string to_string(bool _Val) inline std::string to_string(bool _Val) {
{
return _Val == true ? "true" : "false"; return _Val == true ? "true" : "false";
} }
template <typename Type_, glm::precision Precision_ = glm::defaultp>
std::string to_string( glm::tvec3<Type_, Precision_> const &Value ) {
return to_string( Value.x, 2 ) + ", " + to_string( Value.y, 2 ) + ", " + to_string( Value.z, 2 );
}
int stol_def(const std::string & str, const int & DefaultValue); int stol_def(const std::string & str, const int & DefaultValue);
std::string ToLower(std::string const &text); std::string ToLower(std::string const &text);

View File

@@ -381,11 +381,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
if( ( std::abs( scale.x - 1.0f ) > 0.01 ) if( ( std::abs( scale.x - 1.0f ) > 0.01 )
|| ( std::abs( scale.y - 1.0f ) > 0.01 ) || ( std::abs( scale.y - 1.0f ) > 0.01 )
|| ( std::abs( scale.z - 1.0f ) > 0.01 ) ) { || ( std::abs( scale.z - 1.0f ) > 0.01 ) ) {
ErrorLog( ErrorLog( "Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: " + to_string( scale ) + ")" );
"Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: "
+ to_string( scale.x, 2 ) + ", "
+ to_string( scale.y, 2 ) + ", "
+ to_string( scale.z, 2 ) + ")" );
m_normalizenormals = ( m_normalizenormals = (
( ( std::abs( scale.x - scale.y ) < 0.01f ) && ( std::abs( scale.y - scale.z ) < 0.01f ) ) ? ( ( std::abs( scale.x - scale.y ) < 0.01f ) && ( std::abs( scale.y - scale.z ) < 0.01f ) ) ?
rescale : rescale :
@@ -1719,11 +1715,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector<std::string> *t,
if( ( std::abs( scale.x - 1.0f ) > 0.01 ) if( ( std::abs( scale.x - 1.0f ) > 0.01 )
|| ( std::abs( scale.y - 1.0f ) > 0.01 ) || ( std::abs( scale.y - 1.0f ) > 0.01 )
|| ( std::abs( scale.z - 1.0f ) > 0.01 ) ) { || ( std::abs( scale.z - 1.0f ) > 0.01 ) ) {
ErrorLog( ErrorLog( "Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: " + to_string( scale ) + ")" );
"Bad model: transformation matrix for sub-model \"" + pName + "\" imposes geometry scaling (factors: "
+ to_string( scale.x, 2 ) + ", "
+ to_string( scale.y, 2 ) + ", "
+ to_string( scale.z, 2 ) + ")" );
m_normalizenormals = ( m_normalizenormals = (
( ( std::abs( scale.x - scale.y ) < 0.01f ) && ( std::abs( scale.y - scale.z ) < 0.01f ) ) ? ( ( std::abs( scale.x - scale.y ) < 0.01f ) && ( std::abs( scale.y - scale.z ) < 0.01f ) ) ?
rescale : rescale :

View File

@@ -19,10 +19,6 @@ http://mozilla.org/MPL/2.0/.
// 101206 Ra: trapezoidalne drogi // 101206 Ra: trapezoidalne drogi
// 110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0 // 110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0
std::string Where(vector3 p)
{ // zamiana współrzędnych na tekst, używana w błędach
return std::to_string(p.x) + " " + std::to_string(p.y) + " " + std::to_string(p.z);
};
TSegment::TSegment(TTrack *owner) : TSegment::TSegment(TTrack *owner) :
pOwner( owner ) pOwner( owner )
@@ -112,7 +108,7 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI
fStep = fNewStep; fStep = fNewStep;
if (fLength <= 0) if (fLength <= 0)
{ {
ErrorLog( "Bad geometry (zero length) for spline \"" + pOwner->NameGet() + "\" at " + Where( Point1 ) ); ErrorLog( "Bad geometry: zero length spline \"" + pOwner->NameGet() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
// MessageBox(0,"Length<=0","TSegment::Init",MB_OK); // MessageBox(0,"Length<=0","TSegment::Init",MB_OK);
fLength = 0.01; // crude workaround TODO: fix this properly fLength = 0.01; // crude workaround TODO: fix this properly
/* /*
@@ -215,7 +211,7 @@ double TSegment::GetTFromS(double s)
// Newton's method failed. If this happens, increase iterations or // Newton's method failed. If this happens, increase iterations or
// tolerance or integration accuracy. // tolerance or integration accuracy.
// return -1; //Ra: tu nigdy nie dojdzie // return -1; //Ra: tu nigdy nie dojdzie
ErrorLog( "Bad geometry (shape estimation failed) for spline \"" + pOwner->NameGet() + "\" at " + Where( Point1 ) ); ErrorLog( "Bad geometry: shape estimation failed for spline \"" + pOwner->NameGet() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
// MessageBox(0,"Too many iterations","GetTFromS",MB_OK); // MessageBox(0,"Too many iterations","GetTFromS",MB_OK);
return fTime; return fTime;
}; };

View File

@@ -307,10 +307,12 @@ TTrack * TTrack::NullCreate(int dir)
tmp2->pCenter = tmp->pCenter; // ten sam środek jest tmp2->pCenter = tmp->pCenter; // ten sam środek jest
// Ra: to poniżej to porażka, ale na razie się nie da inaczej // Ra: to poniżej to porażka, ale na razie się nie da inaczej
TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z); TSubRect *r = Global::pGround->GetSubRect(tmp->pCenter.x, tmp->pCenter.z);
r->NodeAdd(tmp); // dodanie toru do segmentu if( r != nullptr ) {
if (tmp2) r->NodeAdd( tmp ); // dodanie toru do segmentu
r->NodeAdd(tmp2); // drugiego też if( tmp2 )
r->Sort(); //żeby wyświetlał tabor z dodanego toru r->NodeAdd( tmp2 ); // drugiego t
r->Sort(); //żeby wyświetlał tabor z dodanego toru
}
return trk; return trk;
}; };

408
Train.cpp
View File

@@ -22,6 +22,27 @@ http://mozilla.org/MPL/2.0/.
#include "Driver.h" #include "Driver.h"
#include "Console.h" #include "Console.h"
void
control_mapper::insert( TGauge const &Gauge, std::string const &Label ) {
auto const submodel = Gauge.SubModel;
if( submodel != nullptr ) {
m_controlnames.emplace( submodel, Label );
}
}
std::string
control_mapper::find( TSubModel const *Control ) const {
auto const lookup = m_controlnames.find( Control );
if( lookup != m_controlnames.end() ) {
return lookup->second;
}
else {
return "";
}
}
TCab::TCab() TCab::TCab()
{ {
CabPos1.x = -1.0; CabPos1.x = -1.0;
@@ -5943,13 +5964,16 @@ bool TTrain::Update( double const Deltatime )
// TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement // TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement
if( ( mvControlled->Battery ) if( ( mvControlled->Battery )
|| ( mvControlled->ConverterFlag ) ) { || ( mvControlled->ConverterFlag ) ) {
if( ( false == mvControlled->PantFrontUp ) if( ggPantAllDownButton.GetValue() == 0.0 ) {
&& ( ggPantFrontButton.GetValue() >= 1.0 ) ) { // the 'lower all' button overrides state of switches, while active itself
mvControlled->PantFront( true ); if( ( false == mvControlled->PantFrontUp )
} && ( ggPantFrontButton.GetValue() >= 1.0 ) ) {
if( ( false == mvControlled->PantRearUp ) mvControlled->PantFront( true );
&& ( ggPantRearButton.GetValue() >= 1.0 ) ) { }
mvControlled->PantRear( true ); if( ( false == mvControlled->PantRearUp )
&& ( ggPantRearButton.GetValue() >= 1.0 ) ) {
mvControlled->PantRear( true );
}
} }
} }
/* /*
@@ -6309,6 +6333,7 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
{ {
m_controlmapper.clear();
pyScreens.reset(this); pyScreens.reset(this);
pyScreens.setLookupPath(DynamicObject->asBaseDir); pyScreens.setLookupPath(DynamicObject->asBaseDir);
bool parse = false; bool parse = false;
@@ -7195,309 +7220,78 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co
// otherwise // otherwise
// NOTE: this is temporary work-around for compiler else-if limit // NOTE: this is temporary work-around for compiler else-if limit
// TODO: refactor the cabin controls into some sensible structure // TODO: refactor the cabin controls into some sensible structure
bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex) bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex) {
{
TGauge *gg; // roboczy wskaźnik na obiekt animujący gałkę TGauge *gg { nullptr }; // roboczy wskaźnik na obiekt animujący gałkę
std::unordered_map<std::string, TGauge &> gauges = {
/* sanity check { "mainctrl:", ggMainCtrl },
if( !DynamicObject->mdKabina ) { { "scndctrl:", ggScndCtrl },
WriteLog( "Cab not initialised!" ); { "dirkey:" , ggDirKey },
return false; { "brakectrl:", ggBrakeCtrl },
} { "localbrake:", ggLocalBrake },
*/ { "manualbrake:", ggManualBrake },
// SEKCJA REGULATOROW { "brakeprofile_sw:", ggBrakeProfileCtrl },
if (Label == "mainctrl:") { "brakeprofileg_sw:", ggBrakeProfileG },
{ { "brakeprofiler_sw:", ggBrakeProfileR },
// nastawnik { "maxcurrent_sw:", ggMaxCurrentCtrl },
ggMainCtrl.Load(Parser, DynamicObject->mdKabina); { "main_off_bt:", ggMainOffButton },
} { "main_on_bt:", ggMainOnButton },
else if (Label == "mainctrlact:") { "security_reset_bt:", ggSecurityResetButton },
{ { "releaser_bt:", ggReleaserButton },
// zabek pozycji aktualnej { "sand_bt:", ggSandButton },
ggMainCtrlAct.Load(Parser, DynamicObject->mdKabina); { "antislip_bt:", ggAntiSlipButton },
} { "horn_bt:", ggHornButton },
else if (Label == "scndctrl:") { "hornlow_bt:", ggHornLowButton },
{ { "hornhigh_bt:", ggHornHighButton },
// bocznik { "fuse_bt:", ggFuseButton },
ggScndCtrl.Load(Parser, DynamicObject->mdKabina); { "converterfuse_bt:", ggConverterFuseButton },
} { "stlinoff_bt:", ggStLinOffButton },
else if (Label == "dirkey:") { "door_left_sw:", ggDoorLeftButton },
{ { "door_right_sw:", ggDoorRightButton },
// klucz kierunku { "departure_signal_bt:", ggDepartureSignalButton },
ggDirKey.Load(Parser, DynamicObject->mdKabina); { "upperlight_sw:", ggUpperLightButton },
} { "leftlight_sw:", ggLeftLightButton },
else if (Label == "brakectrl:") { "rightlight_sw:", ggRightLightButton },
{ { "dimheadlights_sw:", ggDimHeadlightsButton },
// hamulec zasadniczy { "leftend_sw:", ggLeftEndLightButton },
ggBrakeCtrl.Load(Parser, DynamicObject->mdKabina); { "rightend_sw:", ggRightEndLightButton },
} { "lights_sw:", ggLightsButton },
else if (Label == "localbrake:") { "rearupperlight_sw:", ggRearUpperLightButton },
{ { "rearleftlight_sw:", ggRearLeftLightButton },
// hamulec pomocniczy { "rearrightlight_sw:", ggRearRightLightButton },
ggLocalBrake.Load(Parser, DynamicObject->mdKabina); { "rearleftend_sw:", ggRearLeftEndLightButton },
} { "rearrightend_sw:", ggRearRightEndLightButton },
else if (Label == "manualbrake:") { "compressor_sw:", ggCompressorButton },
{ { "compressorlocal_sw:", ggCompressorLocalButton },
// hamulec reczny { "converter_sw:", ggConverterButton },
ggManualBrake.Load(Parser, DynamicObject->mdKabina); { "converterlocal_sw:", ggConverterLocalButton },
} { "converteroff_sw:", ggConverterOffButton },
// sekcja przelacznikow obrotowych { "main_sw:", ggMainButton },
else if (Label == "brakeprofile_sw:") { "radio_sw:", ggRadioButton },
{ { "pantfront_sw:", ggPantFrontButton },
// przelacznik tow/osob/posp { "pantrear_sw:", ggPantRearButton },
ggBrakeProfileCtrl.Load(Parser, DynamicObject->mdKabina); { "pantfrontoff_sw:", ggPantFrontButtonOff },
} { "pantrearoff_sw:", ggPantRearButtonOff },
else if (Label == "brakeprofileg_sw:") { "pantalloff_sw:", ggPantAllDownButton },
{ { "pantselected_sw:", ggPantSelectedButton },
// przelacznik tow/osob { "pantselectedoff_sw:", ggPantSelectedDownButton },
ggBrakeProfileG.Load(Parser, DynamicObject->mdKabina); { "trainheating_sw:", ggTrainHeatingButton },
} { "signalling_sw:", ggSignallingButton },
else if (Label == "brakeprofiler_sw:") { "door_signalling_sw:", ggDoorSignallingButton },
{ { "nextcurrent_sw:", ggNextCurrentButton },
// przelacznik osob/posp { "cablight_sw:", ggCabLightButton },
ggBrakeProfileR.Load(Parser, DynamicObject->mdKabina); { "cablightdim_sw:", ggCabLightDimButton },
} { "battery_sw:", ggBatteryButton }
else if (Label == "maxcurrent_sw:") };
{ auto lookup = gauges.find( Label );
// przelacznik rozruchu if( lookup != gauges.end() ) {
ggMaxCurrentCtrl.Load(Parser, DynamicObject->mdKabina); lookup->second.Load( Parser, DynamicObject->mdKabina );
} m_controlmapper.insert( lookup->second, lookup->first );
// SEKCJA przyciskow sprezynujacych
else if (Label == "main_off_bt:")
{
// przycisk wylaczajacy (w EU07 wyl szybki czerwony)
ggMainOffButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "main_on_bt:")
{
// przycisk wlaczajacy (w EU07 wyl szybki zielony)
ggMainOnButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "security_reset_bt:")
{
// przycisk zbijajacy SHP/czuwak
ggSecurityResetButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "releaser_bt:")
{
// przycisk odluzniacza
ggReleaserButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "sand_bt:")
{
// przycisk piasecznicy
ggSandButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "antislip_bt:")
{
// przycisk antyposlizgowy
ggAntiSlipButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "horn_bt:")
{
// dzwignia syreny
ggHornButton.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "hornlow_bt:" ) {
// dzwignia syreny
ggHornLowButton.Load( Parser, DynamicObject->mdKabina );
}
else if( Label == "hornhigh_bt:" ) {
// dzwignia syreny
ggHornHighButton.Load( Parser, DynamicObject->mdKabina );
}
else if( Label == "fuse_bt:" )
{
// bezp. nadmiarowy
ggFuseButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "converterfuse_bt:")
{
// hunter-261211:
// odblokowanie przekaznika nadm. przetw. i ogrz.
ggConverterFuseButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "stlinoff_bt:")
{
// st. liniowe
ggStLinOffButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "door_left_sw:")
{
// drzwi lewe
ggDoorLeftButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "door_right_sw:")
{
// drzwi prawe
ggDoorRightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "departure_signal_bt:")
{
// sygnal odjazdu
ggDepartureSignalButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "upperlight_sw:")
{
// swiatlo
ggUpperLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "leftlight_sw:")
{
// swiatlo
ggLeftLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "rightlight_sw:")
{
// swiatlo
ggRightLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "dimheadlights_sw:" ) {
// swiatlo
ggDimHeadlightsButton.Load( Parser, DynamicObject->mdKabina );
}
else if( Label == "leftend_sw:" )
{
// swiatlo
ggLeftEndLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "rightend_sw:")
{
// swiatlo
ggRightEndLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "lights_sw:")
{
// swiatla wszystkie
ggLightsButton.Load(Parser, DynamicObject->mdKabina);
}
//---------------------
// hunter-230112: przelaczniki swiatel tylnich
else if (Label == "rearupperlight_sw:")
{
// swiatlo
ggRearUpperLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "rearleftlight_sw:")
{
// swiatlo
ggRearLeftLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "rearrightlight_sw:")
{
// swiatlo
ggRearRightLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "rearleftend_sw:")
{
// swiatlo
ggRearLeftEndLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "rearrightend_sw:")
{
// swiatlo
ggRearRightEndLightButton.Load(Parser, DynamicObject->mdKabina);
}
//------------------
else if (Label == "compressor_sw:")
{
// sprezarka
ggCompressorButton.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "compressorlocal_sw:" ) {
// sprezarka
ggCompressorLocalButton.Load( Parser, DynamicObject->mdKabina );
}
else if (Label == "converter_sw:")
{
// przetwornica
ggConverterButton.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "converterlocal_sw:" ) {
// przetwornica
ggConverterLocalButton.Load( Parser, DynamicObject->mdKabina );
}
else if (Label == "converteroff_sw:")
{
// przetwornica wyl
ggConverterOffButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "main_sw:")
{
// wyl szybki (ezt)
ggMainButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "radio_sw:")
{
// radio
ggRadioButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "pantfront_sw:")
{
// patyk przedni
ggPantFrontButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "pantrear_sw:")
{
// patyk tylny
ggPantRearButton.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "pantfrontoff_sw:" )
{
// patyk przedni w dol
ggPantFrontButtonOff.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "pantrearoff_sw:" ) {
// rear pant down
ggPantRearButtonOff.Load( Parser, DynamicObject->mdKabina );
}
else if( Label == "pantalloff_sw:" ) {
// both pantographs down
ggPantAllDownButton.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "pantselected_sw:" ) {
// operate selected pantograph(s)
ggPantSelectedButton.Load( Parser, DynamicObject->mdKabina );
}
else if( Label == "pantselectedoff_sw:" ) {
// operate selected pantograph(s)
ggPantSelectedDownButton.Load( Parser, DynamicObject->mdKabina );
}
else if (Label == "trainheating_sw:") {
// grzanie skladu
ggTrainHeatingButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "signalling_sw:")
{
// Sygnalizacja hamowania
ggSignallingButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "door_signalling_sw:")
{
// Sygnalizacja blokady drzwi
ggDoorSignallingButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "nextcurrent_sw:")
{
// prąd drugiego członu
ggNextCurrentButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "cablight_sw:")
{
// hunter-091012: swiatlo w kabinie
ggCabLightButton.Load(Parser, DynamicObject->mdKabina);
}
else if (Label == "cablightdim_sw:")
{
// hunter-091012: przyciemnienie swiatla w kabinie
ggCabLightDimButton.Load(Parser, DynamicObject->mdKabina);
}
else if( Label == "battery_sw:" ) {
ggBatteryButton.Load( Parser, DynamicObject->mdKabina );
} }
// ABu 090305: uniwersalne przyciski lub inne rzeczy // ABu 090305: uniwersalne przyciski lub inne rzeczy
else if( Label == "mainctrlact:" ) {
ggMainCtrlAct.Load( Parser, DynamicObject->mdKabina, DynamicObject->mdModel );
}
else if (Label == "universal1:") else if (Label == "universal1:")
{ {
ggUniversal1Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel); ggUniversal1Button.Load(Parser, DynamicObject->mdKabina, DynamicObject->mdModel);

18
Train.h
View File

@@ -57,6 +57,18 @@ class TCab
void Update(); void Update();
}; };
class control_mapper {
typedef std::unordered_map< TSubModel const *, std::string> submodelstring_map;
submodelstring_map m_controlnames;
public:
void
clear() { m_controlnames.clear(); }
void
insert( TGauge const &Gauge, std::string const &Label );
std::string
find( TSubModel const *Control ) const;
};
class TTrain class TTrain
{ {
public: public:
@@ -72,6 +84,7 @@ class TTrain
inline vector3 GetDirection() { return DynamicObject->VectorFront(); }; inline vector3 GetDirection() { return DynamicObject->VectorFront(); };
inline vector3 GetUp() { return DynamicObject->VectorUp(); }; inline vector3 GetUp() { return DynamicObject->VectorUp(); };
inline std::string GetLabel( TSubModel const *Control ) const { return m_controlmapper.find( Control ); }
void UpdateMechPosition(double dt); void UpdateMechPosition(double dt);
vector3 GetWorldMechPosition(); vector3 GetWorldMechPosition();
bool Update( double const Deltatime ); bool Update( double const Deltatime );
@@ -84,7 +97,7 @@ class TTrain
private: private:
// types // types
typedef void( *command_handler )( TTrain *Train, command_data const &Command ); typedef void( *command_handler )( TTrain *Train, command_data const &Command );
typedef std::unordered_map<user_command, command_handler> commandhandler_map; typedef std::unordered_map<user_command, command_handler> commandhandler_map;
// clears state of all cabin controls // clears state of all cabin controls
void clear_cab_controls(); void clear_cab_controls();
@@ -184,8 +197,9 @@ class TTrain
TMoverParameters *mvSecond; // drugi człon (ET40, ET41, ET42, ukrotnienia) TMoverParameters *mvSecond; // drugi człon (ET40, ET41, ET42, ukrotnienia)
TMoverParameters *mvThird; // trzeci człon (SN61) TMoverParameters *mvThird; // trzeci człon (SN61)
// helper variable, to prevent immediate switch between closing and opening line breaker circuit // helper variable, to prevent immediate switch between closing and opening line breaker circuit
int m_linebreakerstate{ 0 }; // -1: freshly open, 0: open, 1: closed, 2: freshly closed (and yes this is awful way to go about it) int m_linebreakerstate { 0 }; // -1: freshly open, 0: open, 1: closed, 2: freshly closed (and yes this is awful way to go about it)
static const commandhandler_map m_commandhandlers; static const commandhandler_map m_commandhandlers;
control_mapper m_controlmapper;
public: // reszta może by?publiczna public: // reszta może by?publiczna

170
World.cpp
View File

@@ -180,6 +180,20 @@ simulation_time::julian_day() const {
return JD; return JD;
} }
namespace locale {
std::string
control( std::string const &Label ) {
auto const lookup = m_controls.find( Label );
return (
lookup != m_controls.end() ?
lookup->second :
"" );
}
}
TWorld::TWorld() TWorld::TWorld()
{ {
// randomize(); // randomize();
@@ -1135,43 +1149,44 @@ void
TWorld::Update_Camera( double const Deltatime ) { TWorld::Update_Camera( double const Deltatime ) {
// Console::Update(); //tu jest zależne od FPS, co nie jest korzystne // Console::Update(); //tu jest zależne od FPS, co nie jest korzystne
if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_LEFT ) == GLFW_PRESS ) { if( false == Global::ControlPicking ) {
Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_LEFT ) == GLFW_PRESS ) {
// if (!FreeFlyModeFlag) //jeśli wewnątrz - patrzymy do tyłu Camera.Reset(); // likwidacja obrotów - patrzy horyzontalnie na południe
// Camera.LookAt=Train->pMechPosition-Normalize(Train->GetDirection())*10; // if (!FreeFlyModeFlag) //jeśli wewnątrz - patrzymy do tyłu
if( Controlled ? LengthSquared3( Controlled->GetPosition() - Camera.Pos ) < 2250000 : // Camera.LookAt=Train->pMechPosition-Normalize(Train->GetDirection())*10;
false ) // gdy bliżej niż 1.5km if( Controlled && LengthSquared3( Controlled->GetPosition() - Camera.Pos ) < ( 1500 * 1500 ) ) // gdy bliżej niż 1.5km
Camera.LookAt = Controlled->GetPosition(); Camera.LookAt = Controlled->GetPosition();
else { else {
TDynamicObject *d = TDynamicObject *d =
Ground.DynamicNearest( Camera.Pos, 300 ); // szukaj w promieniu 300m Ground.DynamicNearest( Camera.Pos, 300 ); // szukaj w promieniu 300m
if( !d ) if( !d )
d = Ground.DynamicNearest( Camera.Pos, d = Ground.DynamicNearest( Camera.Pos,
1000 ); // dalej szukanie, jesli bliżej nie ma 1000 ); // dalej szukanie, jesli bliżej nie ma
if( d && pDynamicNearest ) // jeśli jakiś jest znaleziony wcześniej if( d && pDynamicNearest ) // jeśli jakiś jest znaleziony wcześniej
if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) > if( 100.0 * LengthSquared3( d->GetPosition() - Camera.Pos ) >
LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) ) LengthSquared3( pDynamicNearest->GetPosition() - Camera.Pos ) )
d = pDynamicNearest; // jeśli najbliższy nie jest 10 razy bliżej niż d = pDynamicNearest; // jeśli najbliższy nie jest 10 razy bliżej niż
// poprzedni najbliższy, zostaje poprzedni // poprzedni najbliższy, zostaje poprzedni
if( d ) if( d )
pDynamicNearest = d; // zmiana na nowy, jeśli coś znaleziony niepusty pDynamicNearest = d; // zmiana na nowy, jeśli coś znaleziony niepusty
if( pDynamicNearest ) if( pDynamicNearest )
Camera.LookAt = pDynamicNearest->GetPosition(); Camera.LookAt = pDynamicNearest->GetPosition();
}
if( FreeFlyModeFlag )
Camera.RaLook(); // jednorazowe przestawienie kamery
}
else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_RIGHT ) == GLFW_PRESS ) { //||Console::Pressed(VK_F4))
FollowView( false ); // bez wyciszania dźwięków
}
else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) == GLFW_PRESS ) {
// middle mouse button controls zoom.
Global::ZoomFactor = std::min( 4.5f, Global::ZoomFactor + 15.0f * static_cast<float>( Deltatime ) );
}
else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) != GLFW_PRESS ) {
// reset zoom level if the button is no longer held down.
// NOTE: yes, this is terrible way to go about it. it'll do for now.
Global::ZoomFactor = std::max( 1.0f, Global::ZoomFactor - 15.0f * static_cast<float>( Deltatime ) );
} }
if( FreeFlyModeFlag )
Camera.RaLook(); // jednorazowe przestawienie kamery
}
else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_RIGHT ) == GLFW_PRESS ) { //||Console::Pressed(VK_F4))
FollowView( false ); // bez wyciszania dźwięków
}
else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) == GLFW_PRESS ) {
// middle mouse button controls zoom.
Global::ZoomFactor = std::min( 4.5f, Global::ZoomFactor + 15.0f * static_cast<float>( Deltatime ) );
}
else if( glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_MIDDLE ) != GLFW_PRESS ) {
// reset zoom level if the button is no longer held down.
// NOTE: yes, this is terrible way to go about it. it'll do for now.
Global::ZoomFactor = std::max( 1.0f, Global::ZoomFactor - 15.0f * static_cast<float>( Deltatime ) );
} }
Camera.Update(); // uwzględnienie ruchu wywołanego klawiszami Camera.Update(); // uwzględnienie ruchu wywołanego klawiszami
@@ -1258,74 +1273,28 @@ void TWorld::ResourceSweep()
*/ */
}; };
// rendering kabiny gdy jest oddzielnym modelem i ma byc wyswietlana
void
TWorld::Render_Cab() {
if( Train == nullptr ) {
TSubModel::iInstance = 0;
return;
}
TDynamicObject *dynamic = Train->Dynamic();
TSubModel::iInstance = reinterpret_cast<std::size_t>( dynamic );
if( ( true == FreeFlyModeFlag )
|| ( false == dynamic->bDisplayCab )
|| ( dynamic->mdKabina == dynamic->mdModel ) ) {
// ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka
return;
}
/*
glPushMatrix();
vector3 pos = dynamic->GetPosition(); // wszpółrzędne pojazdu z kabiną
// glTranslatef(pos.x,pos.y,pos.z); //przesunięcie o wektor (tak było i trzęsło)
// aby pozbyć się choć trochę trzęsienia, trzeba by nie przeliczać kabiny do punktu
// zerowego scenerii
glLoadIdentity(); // zacząć od macierzy jedynkowej
Camera.SetCabMatrix( pos ); // widok z kamery po przesunięciu
glMultMatrixd( dynamic->mMatrix.getArray() ); // ta macierz nie ma przesunięcia
*/
::glPushMatrix();
auto const originoffset = dynamic->GetPosition() - Global::pCameraPosition;
::glTranslated( originoffset.x, originoffset.y, originoffset.z );
::glMultMatrixd( dynamic->mMatrix.getArray() );
if( dynamic->mdKabina ) // bo mogła zniknąć przy przechodzeniu do innego pojazdu
{
// setup
if( dynamic->fShade > 0.0f ) {
// change light level based on light level of the occupied track
Global::DayLight.apply_intensity( dynamic->fShade );
}
if( dynamic->InteriorLightLevel > 0.0f ) {
// crude way to light the cabin, until we have something more complete in place
auto const cablight = dynamic->InteriorLight * dynamic->InteriorLightLevel;
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &cablight.x );
}
// render
GfxRenderer.Render( dynamic->mdKabina, dynamic->Material(), 0.0 );
GfxRenderer.Render_Alpha( dynamic->mdKabina, dynamic->Material(), 0.0 );
// post-render restore
if( dynamic->fShade > 0.0f ) {
// change light level based on light level of the occupied track
Global::DayLight.apply_intensity();
}
if( dynamic->InteriorLightLevel > 0.0f ) {
// reset the overall ambient
GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient );
}
}
glPopMatrix();
}
void void
TWorld::Update_UI() { TWorld::Update_UI() {
UITable->text_lines.clear(); UITable->text_lines.clear();
std::string uitextline1, uitextline2, uitextline3, uitextline4; std::string uitextline1, uitextline2, uitextline3, uitextline4;
UILayer.set_tooltip( "" );
if( ( Train != nullptr ) && ( false == FreeFlyModeFlag ) ) {
if( false == DebugModeFlag ) {
// in regular mode show control functions, for defined controls
UILayer.set_tooltip( locale::control( Train->GetLabel( GfxRenderer.Pick_Control() ) ) );
}
else {
// in debug mode show names of submodels, to help with cab setup and/or debugging
auto const cabcontrol = GfxRenderer.Pick_Control();
UILayer.set_tooltip( ( cabcontrol ? cabcontrol->pName : "" ) );
}
}
if( ( true == Global::ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) {
auto const scenerynode = GfxRenderer.Pick_Node();
UILayer.set_tooltip( ( scenerynode ? scenerynode->asName : "" ) );
}
switch( Global::iTextMode ) { switch( Global::iTextMode ) {
@@ -2338,9 +2307,6 @@ world_environment::update() {
Global::FogColor[ 0 ] = skydomecolour.x; Global::FogColor[ 0 ] = skydomecolour.x;
Global::FogColor[ 1 ] = skydomecolour.y; Global::FogColor[ 1 ] = skydomecolour.y;
Global::FogColor[ 2 ] = skydomecolour.z; Global::FogColor[ 2 ] = skydomecolour.z;
::glFogfv( GL_FOG_COLOR, Global::FogColor ); // kolor mgły
::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 1.0f ); // kolor nieba
} }
void void

71
World.h
View File

@@ -60,6 +60,74 @@ extern simulation_time Time;
} }
namespace locale {
std::string
control( std::string const &Label );
static std::unordered_map<std::string, std::string> m_controls = {
{ "mainctrl:", "master controller" },
{ "scndctrl:", "second controller" },
{ "dirkey:" , "reverser" },
{ "brakectrl:", "train brake" },
{ "localbrake:", "independent brake" },
{ "manualbrake:", "manual brake" },
{ "brakeprofile_sw:", "brake acting speed" },
{ "brakeprofileg_sw:", "brake acting speed: cargo" },
{ "brakeprofiler_sw:", "brake acting speed: rapid" },
{ "maxcurrent_sw:", "motor overload relay threshold" },
{ "main_off_bt:", "line breaker" },
{ "main_on_bt:", "line breaker" },
{ "security_reset_bt:", "alerter" },
{ "releaser_bt:", "independent brake releaser" },
{ "sand_bt:", "sandbox" },
{ "antislip_bt:", "wheelspin brake" },
{ "horn_bt:", "horn" },
{ "hornlow_bt:", "low tone horn" },
{ "hornhigh_bt:", "high tone horn" },
{ "fuse_bt:", "motor overload relay reset" },
{ "converterfuse_bt:", "converter overload relay reset" },
{ "stlinoff_bt:", "motor connectors" },
{ "door_left_sw:", "left door" },
{ "door_right_sw:", "right door" },
{ "departure_signal_bt:", "departure signal" },
{ "upperlight_sw:", "upper headlight" },
{ "leftlight_sw:", "left headlight" },
{ "rightlight_sw:", "right headlight" },
{ "dimheadlights_sw:", "headlights dimmer" },
{ "leftend_sw:", "left marker light" },
{ "rightend_sw:", "right marker light" },
{ "lights_sw:", "light pattern" },
{ "rearupperlight_sw:", "rear upper headlight" },
{ "rearleftlight_sw:", "rear left headlight" },
{ "rearrightlight_sw:", "rear right headlight" },
{ "rearleftend_sw:", "rear left marker light" },
{ "rearrightend_sw:", "rear right marker light" },
{ "compressor_sw:", "compressor" },
{ "compressorlocal_sw:", "local compressor" },
{ "converter_sw:", "converter" },
{ "converterlocal_sw:", "local converter" },
{ "converteroff_sw:", "converter" },
{ "main_sw:", "line breaker" },
{ "radio_sw:", "radio" },
{ "pantfront_sw:", "front pantograph" },
{ "pantrear_sw:", "rear pantograph" },
{ "pantfrontoff_sw:", "front pantograph" },
{ "pantrearoff_sw:", "rear pantograph" },
{ "pantalloff_sw:", "all pantographs" },
{ "pantselected_sw:", "selected pantograph" },
{ "pantselectedoff_sw:", "selected pantograph" },
{ "trainheating_sw:", "heating" },
{ "signalling_sw:", "braking indicator" },
{ "door_signalling_sw:", "door locking" },
{ "nextcurrent_sw:", "current indicator source" },
{ "cablight_sw:", "interior light" },
{ "cablightdim_sw:", "interior light dimmer" },
{ "battery_sw:", "battery" }
};
}
// wrapper for environment elements -- sky, sun, stars, clouds etc // wrapper for environment elements -- sky, sun, stars, clouds etc
class world_environment { class world_environment {
@@ -106,6 +174,8 @@ TWorld();
void OnCommandGet(DaneRozkaz *pRozkaz); void OnCommandGet(DaneRozkaz *pRozkaz);
bool Update(); bool Update();
void TrainDelete(TDynamicObject *d = NULL); void TrainDelete(TDynamicObject *d = NULL);
TTrain const *
train() const { return Train; }
// switches between static and dynamic daylight calculation // switches between static and dynamic daylight calculation
void ToggleDaylight(); void ToggleDaylight();
@@ -114,7 +184,6 @@ private:
void Update_Camera( const double Deltatime ); void Update_Camera( const double Deltatime );
void Update_UI(); void Update_UI();
void ResourceSweep(); void ResourceSweep();
void Render_Cab();
TCamera Camera; TCamera Camera;
TGround Ground; TGround Ground;

View File

@@ -120,10 +120,11 @@ const int k_Univ4 = 69;
const int k_EndSign = 70; const int k_EndSign = 70;
const int k_Active = 71; const int k_Active = 71;
*/ */
batterytoggle batterytoggle,
/* /*
const int k_WalkMode = 73; const int k_WalkMode = 73;
*/ */
none = -1
}; };
enum class command_target { enum class command_target {

View File

@@ -64,18 +64,16 @@ class vector3
public: public:
vector3(void) : vector3(void) :
x(0.0), y(0.0), z(0.0) x(0.0), y(0.0), z(0.0)
{ {}
} vector3( scalar_t X, scalar_t Y, scalar_t Z ) :
vector3(scalar_t a, scalar_t b, scalar_t c) x( X ), y( Y ), z( Z )
{ {}
x = a;
y = b;
z = c;
}
vector3( glm::dvec3 const &Vector ) : vector3( glm::dvec3 const &Vector ) :
x( Vector.x ), y( Vector.y ), z( Vector.z ) x( Vector.x ), y( Vector.y ), z( Vector.z )
{} {}
template <glm::precision Precision_>
operator glm::tvec3<double, Precision_>() const {
return glm::tvec3<double, Precision_>{ x, y, z }; }
// The int parameter is the number of elements to copy from initArray (3 or 4) // The int parameter is the number of elements to copy from initArray (3 or 4)
// explicit vector3(scalar_t* initArray, int arraySize = 3) // explicit vector3(scalar_t* initArray, int arraySize = 3)
// { for (int i = 0;i<arraySize;++i) e[i] = initArray[i]; } // { for (int i = 0;i<arraySize;++i) e[i] = initArray[i]; }

View File

@@ -11,6 +11,13 @@ http://mozilla.org/MPL/2.0/.
#include "keyboardinput.h" #include "keyboardinput.h"
#include "logs.h" #include "logs.h"
#include "parser.h" #include "parser.h"
#include "globals.h"
#include "timer.h"
//#include "world.h"
#include "train.h"
#include "renderer.h"
extern TWorld World;
bool bool
keyboard_input::recall_bindings() { keyboard_input::recall_bindings() {
@@ -168,6 +175,78 @@ keyboard_input::mouse( double Mousex, double Mousey ) {
0 ); 0 );
} }
void
keyboard_input::mouse( int const Button, int const Action ) {
if( false == Global::ControlPicking ) { return; }
if( true == FreeFlyModeFlag ) {
// for now we're only interested in cab controls
return;
}
user_command &mousecommand = (
Button == GLFW_MOUSE_BUTTON_LEFT ?
m_mousecommandleft :
m_mousecommandright
);
if( Action == GLFW_RELEASE ) {
if( mousecommand != user_command::none ) {
// NOTE: basic keyboard controls don't have any parameters
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( mousecommand, 0, 0, Action, 0 );
mousecommand = user_command::none;
}
}
else {
// if not release then it's press
auto train = World.train();
if( train != nullptr ) {
auto lookup = m_mousecommands.find( train->GetLabel( GfxRenderer.Update_Pick_Control() ) );
if( lookup != m_mousecommands.end() ) {
mousecommand = (
Button == GLFW_MOUSE_BUTTON_LEFT ?
lookup->second.left :
lookup->second.right
);
if( mousecommand != user_command::none ) {
// NOTE: basic keyboard controls don't have any parameters
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( mousecommand, 0, 0, Action, 0 );
m_updateaccumulator = 0.0; // prevent potential command repeat right after issuing one
}
}
}
}
}
void
keyboard_input::poll() {
m_updateaccumulator += Timer::GetDeltaRenderTime();
if( m_updateaccumulator < 0.2 ) {
// too early for any work
return;
}
m_updateaccumulator -= 0.2;
if( m_mousecommandleft != user_command::none ) {
// NOTE: basic keyboard controls don't have any parameters
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 );
}
if( m_mousecommandright != user_command::none ) {
// NOTE: basic keyboard controls don't have any parameters
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 );
}
}
void void
keyboard_input::default_bindings() { keyboard_input::default_bindings() {
@@ -366,6 +445,183 @@ const int k_WalkMode = 73;
}; };
bind(); bind();
m_mousecommands = {
{ "mainctrl:", {
user_command::mastercontrollerincrease,
user_command::mastercontrollerdecrease } },
{ "scndctrl:", {
user_command::secondcontrollerincrease,
user_command::secondcontrollerdecrease } },
{ "dirkey:", {
user_command::reverserincrease,
user_command::reverserdecrease } },
{ "brakectrl:", {
user_command::trainbrakedecrease,
user_command::trainbrakeincrease } },
{ "localbrake:", {
user_command::independentbrakedecrease,
user_command::independentbrakeincrease } },
{ "manualbrake:", {
user_command::none,
user_command::none } },
{ "brakeprofile_sw:", {
user_command::brakeactingspeedincrease,
user_command::brakeactingspeeddecrease } },
{ "brakeprofileg_sw:", {
user_command::brakeactingspeeddecrease,
user_command::none } },
{ "brakeprofiler_sw:", {
user_command::brakeactingspeedincrease,
user_command::none } },
{ "maxcurrent_sw:", {
user_command::motoroverloadrelaythresholdtoggle,
user_command::none } },
{ "main_off_bt:", {
user_command::linebreakertoggle,
user_command::none } },
{ "main_on_bt:",{
user_command::linebreakertoggle,
user_command::none } }, // TODO: dedicated on and off line breaker commands
{ "security_reset_bt:", {
user_command::alerteracknowledge,
user_command::none } },
{ "releaser_bt:", {
user_command::independentbrakebailoff,
user_command::none } },
{ "sand_bt:", {
user_command::sandboxactivate,
user_command::none } },
{ "antislip_bt:", {
user_command::wheelspinbrakeactivate,
user_command::none } },
{ "horn_bt:", {
user_command::hornhighactivate,
user_command::hornlowactivate } },
{ "hornlow_bt:", {
user_command::hornlowactivate,
user_command::none } },
{ "hornhigh_bt:", {
user_command::hornhighactivate,
user_command::none } },
{ "fuse_bt:", {
user_command::motoroverloadrelayreset,
user_command::none } },
{ "converterfuse_bt:", {
user_command::converteroverloadrelayreset,
user_command::none } },
{ "stlinoff_bt:", {
user_command::motorconnectorsopen,
user_command::none } },
{ "door_left_sw:", {
user_command::doortoggleleft,
user_command::none } },
{ "door_right_sw:", {
user_command::doortoggleright,
user_command::none } },
{ "departure_signal_bt:", {
user_command::departureannounce,
user_command::none } },
{ "upperlight_sw:", {
user_command::headlighttoggleupper,
user_command::none } },
{ "leftlight_sw:", {
user_command::headlighttoggleleft,
user_command::none } },
{ "rightlight_sw:", {
user_command::headlighttoggleright,
user_command::none } },
{ "dimheadlights_sw:", {
user_command::headlightsdimtoggle,
user_command::none } },
{ "leftend_sw:", {
user_command::redmarkertoggleleft,
user_command::none } },
{ "rightend_sw:", {
user_command::redmarkertoggleright,
user_command::none } },
{ "lights_sw:", {
user_command::none,
user_command::none } }, // TODO: implement commands for lights controller
{ "rearupperlight_sw:", {
user_command::headlighttogglerearupper,
user_command::none } },
{ "rearleftlight_sw:", {
user_command::headlighttogglerearleft,
user_command::none } },
{ "rearrightlight_sw:", {
user_command::headlighttogglerearright,
user_command::none } },
{ "rearleftend_sw:", {
user_command::redmarkertogglerearleft,
user_command::none } },
{ "rearrightend_sw:", {
user_command::redmarkertogglerearright,
user_command::none } },
{ "compressor_sw:", {
user_command::compressortoggle,
user_command::none } },
{ "compressorlocal_sw:", {
user_command::compressortogglelocal,
user_command::none } },
{ "converter_sw:", {
user_command::convertertoggle,
user_command::none } },
{ "converterlocal_sw:", {
user_command::convertertogglelocal,
user_command::none } },
{ "converteroff_sw:", {
user_command::convertertoggle,
user_command::none } }, // TODO: dedicated converter shutdown command
{ "main_sw:", {
user_command::linebreakertoggle,
user_command::none } },
{ "radio_sw:", {
user_command::radiotoggle,
user_command::none } },
{ "pantfront_sw:", {
user_command::pantographtogglefront,
user_command::none } },
{ "pantrear_sw:", {
user_command::pantographtogglerear,
user_command::none } },
{ "pantfrontoff_sw:", {
user_command::pantographtogglefront,
user_command::none } }, // TODO: dedicated lower pantograph commands
{ "pantrearoff_sw:", {
user_command::pantographtogglerear,
user_command::none } }, // TODO: dedicated lower pantograph commands
{ "pantalloff_sw:", {
user_command::pantographlowerall,
user_command::none } },
{ "pantselected_sw:", {
user_command::none,
user_command::none } }, // TODO: selected pantograph(s) operation command
{ "pantselectedoff_sw:", {
user_command::none,
user_command::none } }, // TODO: lower selected pantograp(s) command
{ "trainheating_sw:", {
user_command::heatingtoggle,
user_command::none } },
{ "signalling_sw:", {
user_command::mubrakingindicatortoggle,
user_command::none } },
{ "door_signalling_sw:", {
user_command::doorlocktoggle,
user_command::none } },
{ "nextcurrent_sw:", {
user_command::mucurrentindicatorothersourceactivate,
user_command::none } },
{ "cablight_sw:", {
user_command::interiorlighttoggle,
user_command::none } },
{ "cablightdim_sw:", {
user_command::interiorlightdimtoggle,
user_command::none } },
{ "battery_sw:", {
user_command::batterytoggle,
user_command::none } }
};
} }
void void

View File

@@ -28,6 +28,10 @@ public:
key( int const Key, int const Action ); key( int const Key, int const Action );
void void
mouse( double const Mousex, double const Mousey ); mouse( double const Mousex, double const Mousey );
void
mouse( int const Button, int const Action );
void
poll();
private: private:
// types // types
@@ -45,6 +49,18 @@ private:
typedef std::vector<command_setup> commandsetup_sequence; typedef std::vector<command_setup> commandsetup_sequence;
typedef std::unordered_map<int, user_command> usercommand_map; typedef std::unordered_map<int, user_command> usercommand_map;
struct mouse_commands {
user_command left;
user_command right;
mouse_commands( user_command const Left, user_command const Right ):
left(Left), right(Right)
{}
};
typedef std::unordered_map<std::string, mouse_commands> controlcommands_map;
struct bindings_cache { struct bindings_cache {
int forward{ -1 }; int forward{ -1 };
@@ -66,9 +82,13 @@ private:
// members // members
commandsetup_sequence m_commands; commandsetup_sequence m_commands;
usercommand_map m_bindings; usercommand_map m_bindings;
controlcommands_map m_mousecommands;
user_command m_mousecommandleft { user_command::none }; // last if any command issued with mouse
user_command m_mousecommandright { user_command::none };
command_relay m_relay; command_relay m_relay;
bool m_shift{ false }; bool m_shift{ false };
bool m_ctrl{ false }; bool m_ctrl{ false };
double m_updateaccumulator { 0.0 };
bindings_cache m_bindingscache; bindings_cache m_bindingscache;
std::array<char, GLFW_KEY_LAST + 1> m_keys; std::array<char, GLFW_KEY_LAST + 1> m_keys;
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -134,15 +134,6 @@ public:
Render_Alpha( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle ); Render_Alpha( TModel3d *Model, material_data const *Material, Math3D::vector3 const &Position, Math3D::vector3 const &Angle );
bool bool
Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance ); Render_Alpha( TModel3d *Model, material_data const *Material, double const Squaredistance );
// maintenance jobs
void
Update( double const Deltatime );
// debug performance string
std::string const &
Info() const;
// light methods
void
Disable_Lights();
// geometry methods // geometry methods
// NOTE: hands-on geometry management is exposed as a temporary measure; ultimately all visualization data should be generated/handled automatically by the renderer itself // NOTE: hands-on geometry management is exposed as a temporary measure; ultimately all visualization data should be generated/handled automatically by the renderer itself
// creates a new geometry bank. returns: handle to the bank or NULL // creates a new geometry bank. returns: handle to the bank or NULL
@@ -167,6 +158,24 @@ public:
Bind( texture_handle const Texture ); Bind( texture_handle const Texture );
opengl_texture const & opengl_texture const &
Texture( texture_handle const Texture ); Texture( texture_handle const Texture );
// light methods
void
Disable_Lights();
// utility methods
TSubModel const *
Pick_Control() const { return m_pickcontrolitem; }
TGroundNode const *
Pick_Node() const { return m_picksceneryitem; }
// maintenance jobs
void
Update( double const Deltatime );
TSubModel const *
Update_Pick_Control();
TGroundNode const *
Update_Pick_Node();
// debug performance string
std::string const &
Info() const;
// members // members
GLenum static const sunlight{ GL_LIGHT0 }; GLenum static const sunlight{ GL_LIGHT0 };
@@ -175,16 +184,37 @@ public:
private: private:
// types // types
enum class rendermode { enum class rendermode {
color color,
shadows,
pickcontrols,
pickscenery
};
typedef std::pair< double, TSubRect * > distancesubcell_pair;
struct renderpass_config {
opengl_camera camera;
rendermode draw_mode { rendermode::color };
float draw_range { 0.0f };
std::vector<distancesubcell_pair> draw_queue; // list of subcells to be drawn in current render pass
}; };
typedef std::vector<opengl_light> opengllight_array; typedef std::vector<opengl_light> opengllight_array;
typedef std::pair< double, TSubRect * > distancesubcell_pair;
// methods // methods
bool bool
Init_caps(); Init_caps();
// runs jobs needed to generate graphics for specified render pass
void
Render_pass( rendermode const Mode );
// configures projection matrix for the current render pass
void
Render_projection();
// configures camera for the current render pass
void
Render_camera();
void
Render_setup( bool const Alpha = false );
bool bool
Render( world_environment *Environment ); Render( world_environment *Environment );
bool bool
@@ -197,6 +227,8 @@ private:
Render( TGroundNode *Node ); Render( TGroundNode *Node );
void void
Render( TTrack *Track ); Render( TTrack *Track );
bool
Render_cab( TDynamicObject *Dynamic );
void void
Render( TMemCell *Memcell ); Render( TMemCell *Memcell );
bool bool
@@ -209,29 +241,43 @@ private:
Render_Alpha( TSubModel *Submodel ); Render_Alpha( TSubModel *Submodel );
void void
Update_Lights( light_array const &Lights ); Update_Lights( light_array const &Lights );
glm::vec3
pick_color( std::size_t const Index );
std::size_t
pick_index( glm::ivec3 const &Color );
// members // members
opengllight_array m_lights;
geometrybank_manager m_geometry; geometrybank_manager m_geometry;
texture_manager m_textures; texture_manager m_textures;
opengl_camera m_camera; opengllight_array m_lights;
rendermode renderpass { rendermode::color };
float m_drawrange { 2500.0f }; // current drawing range
float m_drawtime { 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps
double m_updateaccumulator { 0.0 };
std::string m_debuginfo;
GLFWwindow *m_window { nullptr }; GLFWwindow *m_window { nullptr };
#ifdef EU07_USE_PICKING_FRAMEBUFFER
GLuint m_pickframebuffer { 0 }; // TODO: refactor pick framebuffer stuff into an object
GLuint m_picktexture { 0 };
GLuint m_pickdepthbuffer { 0 };
#endif
GLUquadricObj *m_quadric { nullptr }; // helper object for drawing debug mode scene elements
geometry_handle m_billboardgeometry { 0, 0 };
texture_handle m_glaretexture { -1 }; texture_handle m_glaretexture { -1 };
texture_handle m_suntexture { -1 }; texture_handle m_suntexture { -1 };
texture_handle m_moontexture { -1 }; texture_handle m_moontexture { -1 };
geometry_handle m_billboardgeometry { 0, 0 };
GLUquadricObj *m_quadric; // helper object for drawing debug mode scene elements float m_drawtime { 1000.0f / 30.0f * 20.0f }; // start with presumed 'neutral' average of 30 fps
std::vector<distancesubcell_pair> m_drawqueue; // list of subcells to be drawn in current render pass double m_updateaccumulator { 0.0 };
std::string m_debuginfo;
glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f }; glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f };
bool m_renderspecular{ false }; // controls whether to include specular component in the calculations
float m_specularopaquescalefactor { 1.0f }; float m_specularopaquescalefactor { 1.0f };
float m_speculartranslucentscalefactor { 1.0f }; float m_speculartranslucentscalefactor { 1.0f };
bool m_framebuffersupport { false };
rendermode m_texenvmode { rendermode::color }; // last configured texture environment
renderpass_config m_renderpass;
bool m_renderspecular { false }; // controls whether to include specular component in the calculations
std::vector<TGroundNode const *> m_picksceneryitems;
std::vector<TSubModel const *> m_pickcontrolsitems;
TSubModel const *m_pickcontrolitem { nullptr };
TGroundNode const *m_picksceneryitem { nullptr };
}; };
extern opengl_renderer GfxRenderer; extern opengl_renderer GfxRenderer;

View File

@@ -25,9 +25,10 @@ ui_layer::~ui_layer() {
bool bool
ui_layer::init( GLFWwindow *Window ) { ui_layer::init( GLFWwindow *Window ) {
m_window = Window;
HFONT font; // Windows Font ID HFONT font; // Windows Font ID
m_fontbase = ::glGenLists(96); // storage for 96 characters m_fontbase = ::glGenLists(96); // storage for 96 characters
HDC hDC = ::GetDC( glfwGetWin32Window( Window ) ); HDC hDC = ::GetDC( glfwGetWin32Window( m_window ) );
font = ::CreateFont( -MulDiv( 10, ::GetDeviceCaps( hDC, LOGPIXELSY ), 72 ), // height of font font = ::CreateFont( -MulDiv( 10, ::GetDeviceCaps( hDC, LOGPIXELSY ), 72 ), // height of font
0, // width of font 0, // width of font
0, // angle of escapement 0, // angle of escapement
@@ -79,6 +80,7 @@ ui_layer::render() {
render_background(); render_background();
render_progress(); render_progress();
render_panels(); render_panels();
render_tooltip();
glPopAttrib(); glPopAttrib();
} }
@@ -94,12 +96,14 @@ void
ui_layer::set_background( std::string const &Filename ) { ui_layer::set_background( std::string const &Filename ) {
if( false == Filename.empty() ) { if( false == Filename.empty() ) {
m_background = GfxRenderer.GetTextureId( Filename, szTexturePath ); m_background = GfxRenderer.GetTextureId( Filename, szTexturePath );
} }
else { else {
m_background = NULL;
m_background = 0; }
if( m_background != NULL ) {
auto const &texture = GfxRenderer.Texture( m_background );
m_progressbottom = ( texture.width() != texture.height() );
} }
} }
/* /*
@@ -115,17 +119,27 @@ ui_layer::render_progress() {
glPushAttrib( GL_ENABLE_BIT ); glPushAttrib( GL_ENABLE_BIT );
glDisable( GL_TEXTURE_2D ); glDisable( GL_TEXTURE_2D );
quad( float4( 75.0f, 640.0f, 75.0f + 320.0f, 640.0f + 16.0f ), float4(0.0f, 0.0f, 0.0f, 0.25f) ); glm::vec2 origin, size;
if( m_progressbottom == true ) {
origin = glm::vec2{ 0.0f, 768.0f - 20.0f };
size = glm::vec2{ 1024.0f, 20.0f };
}
else {
origin = glm::vec2{ 75.0f, 640.0f };
size = glm::vec2{ 320.0f, 16.0f };
}
quad( float4( origin.x, origin.y, origin.x + size.x, origin.y + size.y ), float4(0.0f, 0.0f, 0.0f, 0.25f) );
// secondary bar // secondary bar
if( m_subtaskprogress ) { if( m_subtaskprogress ) {
quad( quad(
float4( 75.0f, 640.0f, 75.0f + 320.0f * m_subtaskprogress, 640.0f + 16.0f), float4( origin.x, origin.y, origin.x + size.x * m_subtaskprogress, origin.y + size.y),
float4( 8.0f/255.0f, 160.0f/255.0f, 8.0f/255.0f, 0.35f ) ); float4( 8.0f/255.0f, 160.0f/255.0f, 8.0f/255.0f, 0.35f ) );
} }
// primary bar // primary bar
if( m_progress ) { if( m_progress ) {
quad( quad(
float4( 75.0f, 640.0f, 75.0f + 320.0f * m_progress, 640.0f + 16.0f ), float4( origin.x, origin.y, origin.x + size.x * m_progress, origin.y + size.y ),
float4( 8.0f / 255.0f, 160.0f / 255.0f, 8.0f / 255.0f, 1.0f ) ); float4( 8.0f / 255.0f, 160.0f / 255.0f, 8.0f / 255.0f, 1.0f ) );
} }
@@ -160,6 +174,23 @@ ui_layer::render_panels() {
glPopAttrib(); glPopAttrib();
} }
void
ui_layer::render_tooltip() {
if( m_tooltip.empty() ) { return; }
glm::dvec2 mousepos;
glfwGetCursorPos( m_window, &mousepos.x, &mousepos.y );
glPushAttrib( GL_ENABLE_BIT );
glDisable( GL_TEXTURE_2D );
::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
::glRasterPos2f( mousepos.x + 20.0f, mousepos.y + 25.0f );
print( m_tooltip );
glPopAttrib();
}
void void
ui_layer::render_background() { ui_layer::render_background() {

View File

@@ -50,6 +50,8 @@ public:
// sets the ui background texture, if any // sets the ui background texture, if any
void void
set_background( std::string const &Filename = "" ); set_background( std::string const &Filename = "" );
void
set_tooltip( std::string const &Tooltip ) { m_tooltip = Tooltip; }
void void
clear_texts() { m_panels.clear(); } clear_texts() { m_panels.clear(); }
void void
@@ -67,6 +69,8 @@ private:
render_progress(); render_progress();
void void
render_panels(); render_panels();
void
render_tooltip();
// prints specified text, using display lists font // prints specified text, using display lists font
void void
print( std::string const &Text ); print( std::string const &Text );
@@ -76,11 +80,18 @@ private:
// members: // members:
GLuint m_fontbase{ (GLuint)-1 }; // numer DL dla znaków w napisach GLFWwindow *m_window { nullptr };
float m_progress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. GLuint m_fontbase { (GLuint)-1 }; // numer DL dla znaków w napisach
float m_subtaskprogress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations.
texture_handle m_background; // path to texture used as the background. size depends on mAspect. // progress bar config. TODO: put these together into an object
float m_progress { 0.0f }; // percentage of filled progres bar, to indicate lengthy operations.
float m_subtaskprogress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations.
std::string m_progresstext; // label placed over the progress bar
bool m_progressbottom { false }; // location of the progress bar
texture_handle m_background { NULL }; // path to texture used as the background. size depends on mAspect.
std::vector<std::shared_ptr<ui_panel> > m_panels; std::vector<std::shared_ptr<ui_panel> > m_panels;
std::string m_tooltip;
}; };
extern ui_layer UILayer; extern ui_layer UILayer;

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#define VERSION_MAJOR 17 #define VERSION_MAJOR 17
#define VERSION_MINOR 701 #define VERSION_MINOR 708
#define VERSION_REVISION 0 #define VERSION_REVISION 0