From 493340e6027118c08af8ec440ac21d08d934b4cf Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 25 Feb 2017 21:02:27 +0100 Subject: [PATCH] working vehicle spotlights --- EU07.cpp | 6 + Globals.cpp | 2 + Globals.h | 4 + Model3d.cpp | 3 +- Segment.cpp | 95 +++++++++++++ World.cpp | 399 +++++++++++++++++++++++++++++----------------------- World.h | 1 + dumb3d.h | 5 + renderer.h | 12 +- sky.cpp | 2 +- sun.cpp | 8 +- 11 files changed, 353 insertions(+), 184 deletions(-) diff --git a/EU07.cpp b/EU07.cpp index b02ef876..4265784f 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -511,6 +511,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, // handle for this window if (DebugModeFlag) { // siatki wyświetlane tyko w trybie testowym Global::bWireFrame = !Global::bWireFrame; + if( true == Global::bWireFrame ) { + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + } + else { + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + } ++Global::iReCompile; // odświeżyć siatki // Ra: jeszcze usunąć siatki ze skompilowanych obiektów! } diff --git a/Globals.cpp b/Globals.cpp index 3e68f5e7..996b6936 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -104,6 +104,8 @@ GLfloat Global::diffuseLight[] = {0.85f, 0.85f, 0.80f, 1.0f}; GLfloat Global::specularLight[] = {0.95f, 0.94f, 0.90f, 1.0f}; #else opengl_light Global::DayLight; +opengl_light Global::VehicleLight; +opengl_light Global::VehicleLightRear; #endif GLfloat Global::whiteLight[] = {1.00f, 1.00f, 1.00f, 1.0f}; GLfloat Global::noLight[] = {0.00f, 0.00f, 0.00f, 1.0f}; diff --git a/Globals.h b/Globals.h index c46932e1..f2b1650b 100644 --- a/Globals.h +++ b/Globals.h @@ -231,7 +231,11 @@ class Global static GLfloat diffuseLight[]; static GLfloat specularLight[]; #else + // TODO: put these things in the renderer static opengl_light DayLight; + // TODO: possibly create a pool of few lights which can be attached to nearby vehicles + static opengl_light VehicleLight; + static opengl_light VehicleLightRear; #endif static GLfloat whiteLight[]; static GLfloat noLight[]; diff --git a/Model3d.cpp b/Model3d.cpp index 3ac52358..994862b5 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -278,7 +278,8 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) if (dynamic) { // dla pojazdu, blokujemy załączone submodele, które mogą być // nieobsługiwane - if (token.find("_on") + 3 == token.length()) // jeśli nazwa kończy się na "_on" + if ( (token.size() >= 3) + && (token.find("_on") + 3 == token.length())) // jeśli nazwa kończy się na "_on" iVisible = 0; // to domyślnie wyłączyć, żeby się nie nakładało z obiektem "_off" } else // dla pozostałych modeli blokujemy zapalone światła, które mogą być diff --git a/Segment.cpp b/Segment.cpp index 21f66a41..9ed6dbfe 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -21,6 +21,11 @@ http://mozilla.org/MPL/2.0/. // 101206 Ra: trapezoidalne drogi // 110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0 +float Interpolate( float const First, float const Second, float const Factor ) { + + return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); +} + 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); @@ -116,7 +121,11 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI fStoop = atan2((Point2.y - Point1.y), fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie SafeDeleteArray(fTsBuffer); +/* if ((bCurve) && (fStep > 0)) +*/ + // we're enforcing sub-division of even straight track, to have dense enough mesh for the spotlight to work with + if( fStep > 0 ) { // Ra: prosty dostanie podział, jak ma różną przechyłkę na końcach double s = 0; int i = 0; @@ -454,6 +463,7 @@ void TSegment::RenderLoft(const vector6 *ShapePoints, int iNumShapePoints, doubl } } else +#ifdef EU07_USE_OLD_LIGHTING_MODEL { // gdy prosty, nie modyfikujemy wektora kierunkowego i poprzecznego pos1 = FastGetPoint((fStep * iSkip) / fLength); pos2 = FastGetPoint_1(); @@ -498,6 +508,91 @@ void TSegment::RenderLoft(const vector6 *ShapePoints, int iNumShapePoints, doubl } glEnd(); } +#else +{ + Math3D::vector3 const pos0 = FastGetPoint( ( fStep * iSkip ) / fLength ); + Math3D::vector3 const pos1 = FastGetPoint_1(); + dir = GetDirection(); + Math3D::vector3 const parallel = Normalize( vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny + + Math3D::vector3 startnormal0, startnormal1, endnormal0, endnormal1; + Math3D::vector3 startvertex0, startvertex1, endvertex0, endvertex1; + float startuv0, startuv1, enduv0, enduv1; + + for( j = 0; j < iNumShapePoints - 1; ++j ) { + + startnormal0 = ShapePoints[ j ].n.x * parallel; + startnormal0.y += ShapePoints[ j ].n.y; + startvertex0 = parallel * ShapePoints[ j ].x + pos0; + startvertex0.y += ShapePoints[ j ].y; + startuv0 = ShapePoints[ j ].z; + startnormal1 = ShapePoints[ j + 1 ].n.x * parallel; + startnormal1.y += ShapePoints[ j + 1 ].n.y; + startvertex1 = parallel * ShapePoints[ j + 1 ].x + pos0; + startvertex1.y += ShapePoints[ j + 1 ].y; + startuv1 = ShapePoints[ j + 1 ].z; + + if( trapez == false ) { + // single profile throughout + endnormal0 = startnormal0; + endvertex0 = startvertex0 + ( pos1 - pos0 ); + enduv0 = startuv0; + endnormal1 = startnormal1; + endvertex1 = startvertex1 + ( pos1 - pos0 ); + enduv1 = startuv1; + } + else { + // end profile is different + endnormal0 = ShapePoints[ j + iNumShapePoints ].n.x * parallel; + endnormal0.y += ShapePoints[ j + iNumShapePoints ].n.y; + endvertex0 = parallel * ShapePoints[ j + iNumShapePoints ].x + pos1; // odsunięcie + endvertex0.y += ShapePoints[ j + iNumShapePoints ].y; // wysokość + enduv0 = ShapePoints[ j + iNumShapePoints ].z; + endnormal1 = ShapePoints[ j + iNumShapePoints + 1 ].n.x * parallel; + endnormal1.y += ShapePoints[ j + iNumShapePoints + 1 ].n.y; + endvertex1 = parallel * ShapePoints[ j + iNumShapePoints + 1 ].x + pos1; // odsunięcie + endvertex1.y += ShapePoints[ j + iNumShapePoints + 1 ].y; // wysokość + enduv1 = ShapePoints[ j + iNumShapePoints + 1 ].z; + } + // now build strips, lerping from start to endpoint + step = 10.0; // arbitrary segment size for straights + float s = 0.0, + t = 0.0, + uv = 0.0; + glBegin( GL_TRIANGLE_STRIP ); + while( s < fLength ) { + + t = s / fLength; + uv = s / fTextureLength; + + auto const normal1lerp = Interpolate( startnormal1, endnormal1, t ); + glNormal3dv( &normal1lerp.x ); + auto const uv1lerp = Interpolate( startuv1, enduv1, t ); + glTexCoord2f( uv1lerp, uv ); + auto const vertex1lerp = Interpolate( startvertex1, endvertex1, t ); + glVertex3dv( &vertex1lerp.x ); + + auto const normal0lerp = Interpolate( startnormal0, endnormal0, t ); + glNormal3dv( &normal0lerp.x ); + auto const uv0lerp = Interpolate( startuv0, enduv0, t ); + glTexCoord2f( uv0lerp, uv ); + auto const vertex0lerp = Interpolate( startvertex0, endvertex0, t ); + glVertex3dv( &vertex0lerp.x ); + + s += step; + } + // add ending vertex pair if needed + glNormal3dv( &endnormal1.x ); + glTexCoord2f( enduv1, fLength / fTextureLength ); + glVertex3dv( &endvertex1.x ); + glNormal3dv( &endnormal0.x ); + glTexCoord2f( enduv0, fLength / fTextureLength ); + glVertex3dv( &endvertex0.x ); + + glEnd(); + } +} +#endif }; void TSegment::RenderSwitchRail(const vector6 *ShapePoints1, const vector6 *ShapePoints2, diff --git a/World.cpp b/World.cpp index e216d765..9839e026 100644 --- a/World.cpp +++ b/World.cpp @@ -264,89 +264,34 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) WriteLog("Max texture size: " + std::to_string(Global::iMaxTextureSize)); } /*-----------------------Render Initialization----------------------*/ - if (Global::fOpenGL >= 1.2) // poniższe nie działa w 1.1 - glTexEnvf(TEXTURE_FILTER_CONTROL_EXT, TEXTURE_LOD_BIAS_EXT, -1); - GLfloat FogColor[] = {1.0f, 1.0f, 1.0f, 1.0f}; - glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear screen and depth buffer + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); - // WriteLog("glClearColor (FogColor[0], FogColor[1], FogColor[2], 0.0); "); - // glClearColor (1.0, 0.0, 0.0, 0.0); // Background Color - // glClearColor (FogColor[0], FogColor[1], FogColor[2], 0.0); - // Background // Color - glClearColor(Global::Background[0], Global::Background[1], Global::Background[2], 1.0); // Background Color - WriteLog("glFogfv(GL_FOG_COLOR, FogColor);"); - glFogfv(GL_FOG_COLOR, FogColor); // Set Fog Color + glClearDepth( 1.0f ); // ZBuffer Value + glClearColor( 51.0f / 255.0f, 106.0f / 255.0f, 85.0f / 255.0f, 1.0f ); // Background Color + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Clear screen and depth buffer - WriteLog("glClearDepth(1.0f); "); - glClearDepth(1.0f); // ZBuffer Value - - // glEnable(GL_NORMALIZE); - // glEnable(GL_RESCALE_NORMAL); - - // glEnable(GL_CULL_FACE); - WriteLog("glEnable(GL_TEXTURE_2D);"); glEnable(GL_TEXTURE_2D); // Enable Texture Mapping - WriteLog("glShadeModel(GL_SMOOTH);"); glShadeModel(GL_SMOOTH); // Enable Smooth Shading - WriteLog("glEnable(GL_DEPTH_TEST);"); glEnable(GL_DEPTH_TEST); // McZapkie:261102-uruchomienie polprzezroczystosci (na razie linie) pod kierunkiem Marcina // if (Global::bRenderAlpha) //Ra: wywalam tę flagę { - WriteLog("glEnable(GL_BLEND);"); glEnable(GL_BLEND); - WriteLog("glEnable(GL_ALPHA_TEST);"); glEnable(GL_ALPHA_TEST); - WriteLog("glAlphaFunc(GL_GREATER,0.04);"); glAlphaFunc(GL_GREATER, 0.04); - WriteLog("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);"); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - WriteLog("glDepthFunc(GL_LEQUAL);"); glDepthFunc(GL_LEQUAL); } - /* - else - { - WriteLog("glEnable(GL_ALPHA_TEST);"); - glEnable(GL_ALPHA_TEST); - WriteLog("glAlphaFunc(GL_GREATER,0.5);"); - glAlphaFunc(GL_GREATER,0.5); - WriteLog("glDepthFunc(GL_LEQUAL);"); - glDepthFunc(GL_LEQUAL); - WriteLog("glDisable(GL_BLEND);"); - glDisable(GL_BLEND); - } - */ - /* zakomentowanie to co bylo kiedys mieszane - WriteLog("glEnable(GL_ALPHA_TEST);"); - glEnable(GL_ALPHA_TEST);//glGetIntegerv() - WriteLog("glAlphaFunc(GL_GREATER,0.5);"); - // glAlphaFunc(GL_LESS,0.5); - glAlphaFunc(GL_GREATER,0.5); - // glBlendFunc(GL_SRC_ALPHA,GL_ONE); - WriteLog("glDepthFunc(GL_LEQUAL);"); - glDepthFunc(GL_LEQUAL);//EQUAL); - // The Type Of Depth Testing To Do - // glEnable(GL_BLEND); - // glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - */ - WriteLog("glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);"); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations - - WriteLog("glPolygonMode(GL_FRONT, GL_FILL);"); glPolygonMode(GL_FRONT, GL_FILL); - WriteLog("glFrontFace(GL_CCW);"); glFrontFace(GL_CCW); // Counter clock-wise polygons face out - WriteLog("glEnable(GL_CULL_FACE); "); glEnable(GL_CULL_FACE); // Cull back-facing triangles - WriteLog("glLineWidth(1.0f);"); glLineWidth(1.0f); - // glLineWidth(2.0f); - WriteLog("glPointSize(3.0f);"); glPointSize(3.0f); #ifdef EU07_USE_OLD_LIGHTING_MODEL // ----------- LIGHTING SETUP ----------- @@ -378,39 +323,18 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) glEnable(GL_LIGHT0); #endif // glColor() ma zmieniać kolor wybrany w glColorMaterial() - WriteLog("glEnable(GL_COLOR_MATERIAL);"); glEnable(GL_COLOR_MATERIAL); - WriteLog("glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);"); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + glColor4fv(Global::whiteLight); - // WriteLog("glMaterialfv( GL_FRONT, GL_AMBIENT, whiteLight );"); - // glMaterialfv( GL_FRONT, GL_AMBIENT, Global::whiteLight ); - - WriteLog("glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, whiteLight );"); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Global::whiteLight); - - /* - WriteLog("glMaterialfv( GL_FRONT, GL_SPECULAR, noLight );"); - glMaterialfv( GL_FRONT, GL_SPECULAR, Global::noLight ); - */ - - WriteLog("glEnable(GL_LIGHTING);"); glEnable(GL_LIGHTING); - WriteLog("glFogi(GL_FOG_MODE, GL_LINEAR);"); glFogi(GL_FOG_MODE, GL_LINEAR); // Fog Mode - WriteLog("glFogfv(GL_FOG_COLOR, FogColor);"); + GLfloat FogColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glFogfv(GL_FOG_COLOR, FogColor); // Set Fog Color - // glFogf(GL_FOG_DENSITY, 0.594f); // How Dense Will The - //Fog - // Be - // glHint(GL_FOG_HINT, GL_NICEST); // Fog Hint Value - WriteLog("glFogf(GL_FOG_START, 1000.0f);"); glFogf(GL_FOG_START, 10.0f); // Fog Start Depth - WriteLog("glFogf(GL_FOG_END, 2000.0f);"); glFogf(GL_FOG_END, 200.0f); // Fog End Depth - WriteLog("glEnable(GL_FOG);"); glEnable(GL_FOG); // Enables GL_FOG // Ra: ustawienia testowe @@ -480,7 +404,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) glLoadIdentity(); // glColor4f(0.3f,0.0f,0.0f,0.0f); - glTranslatef(0.0f, 0.0f, -0.50f); +// glTranslatef(0.0f, 0.0f, -0.50f); // glRasterPos2f(-0.25f, -0.10f); #ifdef EU07_USE_OLD_LIGHTING_MODEL glColor3f( 3.0f, 3.0f, 3.0f ); @@ -491,23 +415,25 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) auto logo = GfxRenderer.GetTextureId( "logo", szTexturePath, 6 ); GfxRenderer.Bind(logo); // Select our texture + float const widthratio = ( 4.0f / 3.0f ) / ( (float)Global::iWindowWidth / Global::iWindowHeight ); + glBegin(GL_QUADS); // Drawing using triangles glTexCoord2f(0.0f, 0.0f); - glVertex3f(-1.0f, -1.0f, 0.0f); // bottom left of the texture and quad + glVertex2f( -widthratio, -1.0f ); // bottom left of the texture and quad glTexCoord2f(1.0f, 0.0f); - glVertex3f(1.0f, -1.0f, 0.0f); // bottom right of the texture and quad + glVertex2f(widthratio, -1.0f); // bottom right of the texture and quad glTexCoord2f(1.0f, 1.0f); - glVertex3f(1.0f, 1.0f, 0.0f); // top right of the texture and quad + glVertex2f(widthratio, 1.0f); // top right of the texture and quad glTexCoord2f(0.0f, 1.0f); - glVertex3f(-1.0f, 1.0f, 0.0f); // top left of the texture and quad + glVertex2f( -widthratio, 1.0f ); // top left of the texture and quad glEnd(); //~logo; Ra: to jest bez sensu zapis glColor3f(0.0f, 0.0f, 1.0f); if (Global::detonatoryOK) { - glRasterPos2f(-0.85f, -0.25f); + glRasterPos2f(-0.85f * widthratio, -0.25f); glPrint("Uruchamianie / Initializing..."); - glRasterPos2f(-0.85f, -0.30f); + glRasterPos2f(-0.85f * widthratio, -0.30f); glPrint("Dzwiek / Sound..."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -519,7 +445,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) WriteLog("Sound Init OK"); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.30f); + glRasterPos2f(-0.25f * widthratio, -0.30f); glPrint("OK."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -530,7 +456,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) WriteLog("Textures init"); if (Global::detonatoryOK) { - glRasterPos2f(-0.85f, -0.35f); + glRasterPos2f(-0.85f * widthratio, -0.35f); glPrint("Tekstury / Textures..."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -540,7 +466,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) WriteLog("Textures init OK"); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.35f); + glRasterPos2f( -0.25f * widthratio, -0.35f ); glPrint("OK."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -548,7 +474,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) WriteLog("Models init"); if (Global::detonatoryOK) { - glRasterPos2f(-0.85f, -0.40f); + glRasterPos2f( -0.85f * widthratio, -0.40f ); glPrint("Modele / Models..."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -558,7 +484,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) WriteLog("Models init OK"); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.40f); + glRasterPos2f( -0.25f * widthratio, -0.40f ); glPrint("OK."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -566,7 +492,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) WriteLog("Ground init"); if (Global::detonatoryOK) { - glRasterPos2f(-0.85f, -0.45f); + glRasterPos2f( -0.85f * widthratio, -0.45f ); glPrint("Sceneria / Scenery (please wait)..."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -586,6 +512,25 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) Global::DayLight.diffuse[ 0 ] = 255.0 / 255.0; Global::DayLight.diffuse[ 1 ] = 242.0 / 255.0; Global::DayLight.diffuse[ 2 ] = 231.0 / 255.0; + + Global::VehicleLight.id = opengl_renderer::vehiclelight; + // directional light + Global::VehicleLight.position[ 3 ] = 1.0f; + ::glLightf( opengl_renderer::vehiclelight, GL_SPOT_CUTOFF, 20.0f ); + ::glLightf( opengl_renderer::vehiclelight, GL_SPOT_EXPONENT, 10.0f ); + ::glLightf( opengl_renderer::vehiclelight, GL_CONSTANT_ATTENUATION, 0.0f ); + ::glLightf( opengl_renderer::vehiclelight, GL_LINEAR_ATTENUATION, 0.035f ); + // halogen light. TODO: allow light type definition + Global::VehicleLight.diffuse[ 0 ] = 255.0 / 255.0; + Global::VehicleLight.diffuse[ 1 ] = 241.0 / 255.0; + Global::VehicleLight.diffuse[ 2 ] = 224.0 / 255.0; + // rear light + Global::VehicleLightRear = Global::VehicleLight; + Global::VehicleLightRear.id = opengl_renderer::vehiclelightrear; + ::glLightf( opengl_renderer::vehiclelightrear, GL_SPOT_CUTOFF, 20.0f ); + ::glLightf( opengl_renderer::vehiclelightrear, GL_SPOT_EXPONENT, 10.0f ); + ::glLightf( opengl_renderer::vehiclelightrear, GL_CONSTANT_ATTENUATION, 0.0f ); + ::glLightf( opengl_renderer::vehiclelightrear, GL_LINEAR_ATTENUATION, 0.035f ); #endif Ground.Init(Global::SceneryFile, hDC); @@ -594,7 +539,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) WriteLog("Ground init OK"); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.45f); + glRasterPos2f( -0.25f * widthratio, -0.45f ); glPrint("OK."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -611,7 +556,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) char buff[255] = "Player train init: "; if (Global::detonatoryOK) { - glRasterPos2f(-0.85f, -0.50f); + glRasterPos2f( -0.85f * widthratio, -0.50f ); glPrint("Przygotowanie kabiny do sterowania..."); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -632,7 +577,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) WriteLog("Player train init OK"); if (Global::detonatoryOK) { - glRasterPos2f(-0.25f, -0.50f); + glRasterPos2f( -0.25f * widthratio, -0.50f ); glPrint("OK."); } FollowView(); @@ -644,7 +589,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) FreeFlyModeFlag = true; // Ra: automatycznie włączone latanie if (Global::detonatoryOK) { - glRasterPos2f(-0.85f, -0.50f); + glRasterPos2f( -0.85f * widthratio, -0.50f ); glPrint("Blad inicjalizacji sterowanego pojazdu!"); } SwapBuffers(hDC); // Swap Buffers (Double Buffering) @@ -660,7 +605,7 @@ bool TWorld::Init(HWND NhWnd, HDC hDC) Error("Player train not exist!"); if (Global::detonatoryOK) { - glRasterPos2f(-0.85f, -0.55f); + glRasterPos2f( -0.85f * widthratio, -0.55f ); glPrint("Wybrany pojazd nie istnieje w scenerii!"); } } @@ -790,59 +735,97 @@ void TWorld::OnKeyDown(int cKey) } else if ((cKey >= VK_F1) ? (cKey <= VK_F12) : false) { - switch (cKey) - { - case VK_F1: // czas i relacja - case VK_F3: - case VK_F5: // przesiadka do innego pojazdu - case VK_F8: // FPS - case VK_F9: // wersja, typ wyświetlania, błędy OpenGL - case VK_F10: - if (Global::iTextMode == cKey) - Global::iTextMode = - (Global::iPause && (cKey != VK_F1) ? VK_F1 : - 0); // wyłączenie napisów, chyba że pauza - else - Global::iTextMode = cKey; - break; - case VK_F2: // parametry pojazdu - if (Global::iTextMode == cKey) // jeśli kolejne naciśnięcie - ++Global::iScreenMode[cKey - VK_F1]; // kolejny ekran - else - { // pierwsze naciśnięcie daje pierwszy (tzn. zerowy) ekran - Global::iTextMode = cKey; - Global::iScreenMode[cKey - VK_F1] = 0; - } - break; - case VK_F12: // coś tam jeszcze - if (Console::Pressed(VK_CONTROL) && Console::Pressed(VK_SHIFT)) - DebugModeFlag = !DebugModeFlag; // taka opcjonalna funkcja, może się czasem przydać - /* //Ra 2F1P: teraz włączanie i wyłączanie klawiszami cyfrowymi po użyciu [F12] - else if (Console::Pressed(VK_SHIFT)) - {//odpalenie logu w razie "W" - if ((Global::iWriteLogEnabled&2)==0) //nie było okienka - {//otwarcie okna - AllocConsole(); - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN); - } - Global::iWriteLogEnabled|=3; - } */ - else - Global::iTextMode = cKey; - break; - case VK_F4: - InOutKey(); - break; - case VK_F6: - if (DebugModeFlag) - { // przyspieszenie symulacji do testowania scenerii... uwaga na FPS! - // Global::iViewMode=VK_F6; - if (Console::Pressed(VK_CONTROL)) - Global::fTimeSpeed = (Console::Pressed(VK_SHIFT) ? 10.0 : 5.0); + switch (cKey) { + + case VK_F1: { + // czas i relacja + if( Global::iTextMode == cKey ) + Global::iTextMode = + ( Global::iPause && ( cKey != VK_F1 ) ? + VK_F1 : + 0 ); // wyłączenie napisów, chyba że pauza else - Global::fTimeSpeed = (Console::Pressed(VK_SHIFT) ? 2.0 : 1.0); + Global::iTextMode = cKey; + // advance world clock in debug mode + if( DebugModeFlag ) { + if( Console::Pressed( VK_CONTROL ) ) { + // ctrl-f3 + GlobalTime->UpdateMTableTime( 20.0 * 60.0 ); + } + else if( Console::Pressed( VK_SHIFT ) ) { + // shift-f3 + GlobalTime->UpdateMTableTime( 5.0 * 60.0 ); + } + } + break; + } + case VK_F2: { + // parametry pojazdu + if( Global::iTextMode == cKey ) { + // jeśli kolejne naciśnięcie + ++Global::iScreenMode[ cKey - VK_F1 ]; // kolejny ekran + } + else { + // pierwsze naciśnięcie daje pierwszy (tzn. zerowy) ekran + Global::iTextMode = cKey; + Global::iScreenMode[ cKey - VK_F1 ] = 0; + } + break; + } + case VK_F3: { + Global::iTextMode = cKey; + break; + } + case VK_F4: { + InOutKey(); + break; + } + case VK_F5: { + // przesiadka do innego pojazdu + Global::iTextMode = cKey; + break; + } + case VK_F6: { + Global::iTextMode = cKey; + // przyspieszenie symulacji do testowania scenerii... uwaga na FPS! + if( DebugModeFlag ) { + + if( Console::Pressed( VK_CONTROL ) ) { Global::fTimeSpeed = ( Console::Pressed( VK_SHIFT ) ? 60.0 : 20.0 ); } + else { Global::fTimeSpeed = ( Console::Pressed( VK_SHIFT ) ? 5.0 : 1.0 ); } + } + break; + } + case VK_F8: { + Global::iTextMode = cKey; + // FPS + break; + } + case VK_F9: { + Global::iTextMode = cKey; + // wersja, typ wyświetlania, błędy OpenGL + break; + } + case VK_F10: { + if( Global::iTextMode == cKey ) { + Global::iTextMode = + ( Global::iPause && ( cKey != VK_F1 ) ? + VK_F1 : + 0 ); // wyłączenie napisów, chyba że pauza + } + else { + Global::iTextMode = cKey; + } + break; + } + case VK_F12: { + // coś tam jeszcze + if( Console::Pressed( VK_CONTROL ) + && Console::Pressed( VK_SHIFT ) ) + DebugModeFlag = !DebugModeFlag; // taka opcjonalna funkcja, może się czasem przydać + else + Global::iTextMode = cKey; + break; } - break; } // if (cKey!=VK_F4) return; // nie są przekazywane do pojazdu wcale @@ -1181,7 +1164,8 @@ bool TWorld::Update() iCheckFPS = 0.25 * Timer::GetFPS(); // tak za 0.25 sekundy sprawdzić ponownie (jeszcze przycina?) } Timer::UpdateTimers(Global::iPause); - if (!Global::iPause) + if( (Global::iPause == false) + || (m_init == false) ) { // jak pauza, to nie ma po co tego przeliczać GlobalTime->UpdateMTableTime(Timer::GetDeltaTime()); // McZapkie-300302: czas rozkladowy // Ra 2014-07: przeliczenie kąta czasu (do animacji zależnych od czasu) @@ -1278,13 +1262,24 @@ bool TWorld::Update() // przy 0.25 smuga gaśnie o 6:37 w Quarku, a mogłaby już 5:40 // Ra 2014-12: przy 0.15 się skarżyli, że nie widać smug => zmieniłem na 0.25 // changed light activation threshold to 0.5, paired with strength reduction in daylight - if (Train) // jeśli nie usunięty + if( Train ) { + // jeśli nie usunięty Global::bSmudge = ( FreeFlyModeFlag ? false : ( Train->Dynamic()->fShade <= 0.0 ? - (Global::fLuminance <= 0.5) : - (Train->Dynamic()->fShade * Global::fLuminance <= 0.5) ) ); + ( Global::fLuminance <= 0.5 ) : + ( Train->Dynamic()->fShade * Global::fLuminance <= 0.5 ) ) ); + + // match the vehicle light position with new position of the vehicle + Global::VehicleLight.set_position( Train->Dynamic()->GetPosition() + ( Train->Dynamic()->VectorFront() * Train->Dynamic()->GetLength() * 0.45 ) ); + Global::VehicleLight.direction = Train->Dynamic()->VectorFront(); + Global::VehicleLightRear.set_position( Train->Dynamic()->GetPosition() - ( Train->Dynamic()->VectorFront() * Train->Dynamic()->GetLength() * 0.45 ) ); + Global::VehicleLightRear.direction = Train->Dynamic()->VectorFront(); + Global::VehicleLightRear.direction.RotateY( M_PI ); + } + + m_init = true; if (!Render()) return false; @@ -1556,6 +1551,51 @@ bool TWorld::Render() Environment.render(); } + // enable vehicle light, if it's present and on + if( nullptr != Train ) { + + auto const &frontlights = Train->Controlled()->iLights[ 0 ]; + int const frontlightcount = 0 + + ( ( frontlights & 1 ) ? 1 : 0 ) + + ( ( frontlights & 4 ) ? 1 : 0 ) + + ( ( frontlights & 16 ) ? 1 : 0 ); + + if( frontlightcount > 0 ) { + // halogen light. TODO: allow light type definition + Global::VehicleLight.ambient[ 0 ] = 0.15f * 255.0 * frontlightcount / 255.0; + Global::VehicleLight.ambient[ 1 ] = 0.15f * 241.0 * frontlightcount / 255.0; + Global::VehicleLight.ambient[ 2 ] = 0.15f * 224.0 * frontlightcount / 255.0; + + ::glLightf( opengl_renderer::vehiclelight, GL_LINEAR_ATTENUATION, 0.3f / pow(frontlightcount, 2) ); + glEnable( GfxRenderer.vehiclelight ); + Global::VehicleLight.apply_intensity(); + Global::VehicleLight.apply_angle(); + } + else { + glDisable( GfxRenderer.vehiclelight ); + } + auto const &rearlights = Train->Controlled()->iLights[ 1 ]; + int const rearlightcount = 0 + + ( ( rearlights & 1 ) ? 1 : 0 ) + + ( ( rearlights & 4 ) ? 1 : 0 ) + + ( ( rearlights & 16 ) ? 1 : 0 ); + + if( rearlightcount > 0 ) { + // halogen light. TODO: allow light type definition + Global::VehicleLightRear.ambient[ 0 ] = 0.15f * 255.0 * rearlightcount / 255.0; + Global::VehicleLightRear.ambient[ 1 ] = 0.15f * 241.0 * rearlightcount / 255.0; + Global::VehicleLightRear.ambient[ 2 ] = 0.15f * 224.0 * rearlightcount / 255.0; + + ::glLightf( opengl_renderer::vehiclelightrear, GL_LINEAR_ATTENUATION, 0.3f / pow( rearlightcount, 2 ) ); + glEnable( GfxRenderer.vehiclelightrear ); + Global::VehicleLightRear.apply_intensity(); + Global::VehicleLightRear.apply_angle(); + } + else { + glDisable( GfxRenderer.vehiclelightrear ); + } + } + if (Global::bUseVBO) { // renderowanie przez VBO if (!Ground.RenderVBO(Camera.Pos)) @@ -1618,10 +1658,11 @@ TWorld::Render_Cab() { glLoadIdentity(); // zacząć od macierzy jedynkowej Camera.SetCabMatrix( pos ); // widok z kamery po przesunięciu glMultMatrixd( dynamic->mMatrix.getArray() ); // ta macierz nie ma przesunięcia - +/* //*yB: moje smuuugi 1 if( Global::bSmudge ) { // Ra: uwzględniłem zacienienie pojazdu przy zapalaniu smug - // 1. warunek na smugę wyznaczyc wcześniej + + // 1. warunek na smugę wyznaczyc wcześniej // 2. jeśli smuga włączona, nie renderować pojazdu użytkownika w DynObj // 3. jeśli smuga właczona, wyrenderować pojazd użytkownia po dodaniu smugi do sceny auto const &frontlights = Train->Controlled()->iLights[ 0 ]; @@ -1694,24 +1735,25 @@ TWorld::Render_Cab() { //float ddl = (0.15*Global::diffuseDayLight[0]+0.295*Global::diffuseDayLight[1]+0.055*Global::diffuseDayLight[2]); //0.24:0 glBegin( GL_QUADS ); float fSmudge = dynamic->MoverParameters->DimHalf.y + 7; // gdzie zaczynać smugę - if( frontlightstrength > 0.f ) { // wystarczy jeden zapalony z przodu - + if( frontlightstrength > 0.f ) { + // wystarczy jeden zapalony z przodu for( int i = 15; i <= 35; i++ ) { float z = i * i * i * 0.01f;//25/4; //float C = (36 - i*0.5)*0.005*(1.5 - sqrt(ddl)); float C = ( 36 - i*0.5 )*0.005*sqrt( ( 1 / sqrt( Global::fLuminance + 0.015 ) ) - 1 ) * frontlightstrength; glColor4f( C, C, C, 1.0f );// *frontlightstrength ); - glTexCoord2f( 0, 0 ); glVertex3f( -10 / 2 - 2 * i / 4, 6.0 + 0.3*z, 13 + 1.7*z / 3 ); - glTexCoord2f( 1, 0 ); glVertex3f( 10 / 2 + 2 * i / 4, 6.0 + 0.3*z, 13 + 1.7*z / 3 ); - glTexCoord2f( 1, 1 ); glVertex3f( 10 / 2 + 2 * i / 4, -5.0 - 0.5*z, 13 + 1.7*z / 3 ); + glTexCoord2f( 0, 0 ); glVertex3f( -10 / 2 - 2 * i / 4, 6.0 + 0.3*z, 13 + 1.7*z / 3 ); + glTexCoord2f( 1, 0 ); glVertex3f( 10 / 2 + 2 * i / 4, 6.0 + 0.3*z, 13 + 1.7*z / 3 ); + glTexCoord2f( 1, 1 ); glVertex3f( 10 / 2 + 2 * i / 4, -5.0 - 0.5*z, 13 + 1.7*z / 3 ); glTexCoord2f( 0, 1 ); glVertex3f( -10 / 2 - 2 * i / 4, -5.0 - 0.5*z, 13 + 1.7*z / 3 ); } } - if( rearlightstrength > 0.f ) { // wystarczy jeden zapalony z tyłu + if( rearlightstrength > 0.f ) { + // wystarczy jeden zapalony z tyłu for( int i = 15; i <= 35; i++ ) { float z = i * i * i * 0.01f;//25/4; float C = ( 36 - i*0.5 )*0.005*sqrt( ( 1 / sqrt( Global::fLuminance + 0.015 ) ) - 1 ) * rearlightstrength; - glColor4f( C, C, C, 0.35f );// *rearlightstrength ); + glColor4f( C, C, C, 1.0f );// *rearlightstrength ); glTexCoord2f( 0, 0 ); glVertex3f( 10 / 2 + 2 * i / 4, 6.0 + 0.3*z, -13 - 1.7*z / 3 ); glTexCoord2f( 1, 0 ); glVertex3f( -10 / 2 - 2 * i / 4, 6.0 + 0.3*z, -13 - 1.7*z / 3 ); glTexCoord2f( 1, 1 ); glVertex3f( -10 / 2 - 2 * i / 4, -5.0 - 0.5*z, -13 - 1.7*z / 3 ); @@ -1728,15 +1770,18 @@ TWorld::Render_Cab() { glEnable( GL_FOG ); } } +*/ glEnable( GL_LIGHTING ); // po renderowaniu smugi jest to wyłączone // Ra: pojazd użytkownika należało by renderować po smudze, aby go nie rozświetlała + Global::bSmudge = false; // aby model użytkownika się teraz wyrenderował dynamic->Render(); dynamic->RenderAlpha(); // przezroczyste fragmenty pojazdów na torach - } // yB: moje smuuugi 1 - koniec*/ +/* + } // yB: moje smuuugi 1 - koniec else - glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone - + glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit +*/ if( dynamic->mdKabina ) // bo mogła zniknąć przy przechodzeniu do innego pojazdu { #ifdef EU07_USE_OLD_LIGHTING_MODEL @@ -1822,6 +1867,10 @@ TWorld::Render_Cab() { glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseCabLight ); glLightfv( GL_LIGHT0, GL_SPECULAR, specularCabLight ); #else + // cab shouldn't get affected by the vehicle light, so we disable it here + ::glDisable( GfxRenderer.vehiclelight ); + ::glDisable( GfxRenderer.vehiclelightrear ); + if( dynamic->InteriorLightLevel > 0.0f ) { // crude way to light the cabin, until we have something more complete in place @@ -1866,9 +1915,9 @@ TWorld::Render_UI() { glLoadIdentity(); if( DebugModeFlag && !Global::iTextMode ) { - OutText1 = " FPS: "; + OutText1 = "FPS: "; OutText1 += to_string( Timer::GetFPS(), 2 ); - OutText1 += Global::iSlowMotion ? "s" : "n"; + OutText1 += Global::iSlowMotion ? "(s)" : "(n)"; OutText1 += ( Timer::GetDeltaTime() >= 0.2 ) ? "!" : " "; // if (GetDeltaTime()>=0.2) //Ra: to za bardzo miota tekstem! @@ -1883,7 +1932,7 @@ TWorld::Render_UI() { if( Global::iTextMode == VK_F8 ) { Global::iViewMode = VK_F8; - OutText1 = " FPS: "; + OutText1 = "FPS: "; OutText1 += to_string( Timer::GetFPS(), 2 ); //OutText1 += sprintf(); if( Global::iSlowMotion ) @@ -2318,7 +2367,7 @@ TWorld::Render_UI() { OutText1 += " " + std::string( "S SEE NEN NWW SW" ) - .substr( 1 + 2 * floor( fmod( 8 + ( Camera.Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); + .substr( 0 + 2 * floor( fmod( 8 + ( Camera.Yaw + 0.5 * M_PI_4 ) / M_PI_4, 8 ) ), 2 ); // current luminance level OutText2 = "Light level: " + to_string( Global::fLuminance, 3 ); } @@ -3033,9 +3082,7 @@ world_environment::update() { auto const position = m_sun.getPosition(); // ...update the global data to match new sun state... Global::SunAngle = m_sun.getAngle(); - Global::DayLight.position[ 0 ] = position.x; - Global::DayLight.position[ 1 ] = position.y; - Global::DayLight.position[ 2 ] = position.z; + Global::DayLight.set_position( position ); Global::DayLight.direction = -1.0 * m_sun.getDirection(); // ...update skydome to match the current sun position as well... m_skydome.Update( position ); diff --git a/World.h b/World.h index eb5f3dde..cfdff5b5 100644 --- a/World.h +++ b/World.h @@ -81,6 +81,7 @@ class TWorld double VelPrev; // poprzednia prędkość int tprev; // poprzedni czas double Acc; // przyspieszenie styczne + bool m_init{ false }; // indicates whether initial update of the world was performed public: void ModifyTGA(std::string const &dir = ""); void CreateE3D(std::string const &dir = "", bool dyn = false); diff --git a/dumb3d.h b/dumb3d.h index 0ed4f67f..0d93b8e3 100644 --- a/dumb3d.h +++ b/dumb3d.h @@ -415,6 +415,11 @@ inline vector3 CrossProduct(const vector3 &v1, const vector3 &v2) return vector3(v1.y * v2.z - v1.z * v2.y, v2.x * v1.z - v2.z * v1.x, v1.x * v2.y - v1.y * v2.x); } +inline vector3 Interpolate( vector3 const &First, vector3 const &Second, float const Factor ) { + + return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); +} + inline vector3 operator*(const matrix4x4 &m, const vector3 &v) { return vector3(v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + m[3][0], diff --git a/renderer.h b/renderer.h index deabb54e..69e39ca7 100644 --- a/renderer.h +++ b/renderer.h @@ -24,7 +24,7 @@ struct opengl_light { opengl_light() { position[ 0 ] = position[ 1 ] = position[ 2 ] = 0.0f; position[ 3 ] = 1.0f; - ambient[ 0 ] = ambient[ 1 ] = ambient[ 2 ] = ambient[ 3 ] = 1.0f; + ambient[ 0 ] = ambient[ 1 ] = ambient[ 2 ] = 0.0f; ambient[ 3 ] = 1.0f; diffuse[ 0 ] = diffuse[ 1 ] = diffuse[ 2 ] = diffuse[ 3 ] = 1.0f; specular[ 0 ] = specular[ 1 ] = specular[ 2 ] = specular[ 3 ] = 1.0f; } @@ -45,6 +45,13 @@ struct opengl_light { glLightfv( id, GL_SPOT_DIRECTION, directionarray ); } } + inline + void set_position( Math3D::vector3 const &Position ) { + + position[ 0 ] = Position.x; + position[ 1 ] = Position.y; + position[ 2 ] = Position.z; + } }; // encapsulates basic rendering setup. @@ -66,7 +73,8 @@ class opengl_renderer { public: GLenum static const sunlight{ GL_LIGHT0 }; -// GLenum static const ambientlight{ GL_LIGHT1 }; + GLenum static const vehiclelight{ GL_LIGHT1 }; + GLenum static const vehiclelightrear{ GL_LIGHT2 }; texture_manager::size_type GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ) { diff --git a/sky.cpp b/sky.cpp index 710adbdb..c6766f44 100644 --- a/sky.cpp +++ b/sky.cpp @@ -48,8 +48,8 @@ void TSky::Render() mdCloud->Render(100, 0); mdCloud->RenderAlpha(100, 0); } - glPopMatrix(); #ifdef EU07_USE_OLD_LIGHTING_MODEL + glPopMatrix(); // TODO: re-implement this glLightfv(GL_LIGHT0, GL_POSITION, Global::lightPos); #endif diff --git a/sun.cpp b/sun.cpp index 78fd9e4f..b21ef312 100644 --- a/sun.cpp +++ b/sun.cpp @@ -32,8 +32,8 @@ cSun::update() { move(); Math3D::vector3 position( 0.0f, 0.0f, -2000.0f ); - position.RotateX( (float)( m_body.elevref * ( M_PI / 180.0 ) ) ); - position.RotateY( (float)( ( 90.0 - m_body.hrang ) * ( M_PI / 180.0 ) ) ); + position.RotateX( (float)( m_body.elevref * ( M_PI / 180.0 ) ) ); + position.RotateY( (float)( -m_body.hrang * ( M_PI / 180.0 ) ) ); m_position = position; } @@ -69,8 +69,8 @@ Math3D::vector3 cSun::getDirection() { Math3D::vector3 position( 0.f, 0.f, -1.f ); - position.RotateX( (float)(m_body.elevref * (M_PI/180.0)) ); - position.RotateY( (float)((90.0 - m_body.hrang) * (M_PI/180.0)) ); + position.RotateX( (float)( m_body.elevref * (M_PI/180.0)) ); + position.RotateY( (float)( -m_body.hrang * (M_PI/180.0)) ); position.Normalize(); return position; }