From 5544ed33e9c5eddd6a9cbfaa2cff3c797185d251 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 12 May 2017 00:10:40 +0200 Subject: [PATCH 1/5] build 170511. crossroad generation for vbo render path. partial unification of generation and render functions for tracks and ground nodes --- Driver.cpp | 4 +- Ground.cpp | 205 ++------ Ground.h | 45 +- Segment.cpp | 887 ++++++++-------------------------- Segment.h | 23 +- Track.cpp | 1298 ++++++++++++++++++++++++++++---------------------- dumb3d.h | 8 +- renderer.cpp | 305 +++++++++++- renderer.h | 4 + 9 files changed, 1250 insertions(+), 1529 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 6cde0078..cf192ad7 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -230,9 +230,7 @@ bool TSpeedPos::Update(vector3 *p, vector3 *dir, double &len) if( fDist < 50.0 ) { // old sceneries use trick of placing 'helper' semaphores underground, which can lead to vehicles running over them instead of stopping in front of them // to account for it at short distances we redo distance calculation on 2d plane - fDist = glm::dot( - glm::vec3( v.x, 0.0, v.z ), - glm::vec3( dir->x, 0.0, dir->z ) ); + fDist = glm::length( glm::vec3( v.x, 0.0, v.z ) ); } } } diff --git a/Ground.cpp b/Ground.cpp index 4fd4ff9e..e8d6a2dc 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -290,16 +290,13 @@ void TGroundNode::RaRenderVBO() glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójkąty } +#ifdef EU07_USE_OLD_RENDERCODE void TGroundNode::RenderVBO() { // renderowanie obiektu z VBO - faza nieprzezroczystych switch( iType ) { // obiekty renderowane niezależnie od odległości case TP_SUBMODEL: TSubModel::fSquareDist = 0; -#ifdef EU07_USE_OLD_RENDERCODE - return smTerrain->RenderDL(); -#else GfxRenderer.Render( smTerrain ); -#endif } double distancesquared = SquareMagnitude( pCenter - Global::pCameraPosition ) / Global::ZoomFactor; @@ -334,15 +331,9 @@ void TGroundNode::RenderVBO() { // renderowanie obiektu z VBO - faza nieprzezroc if( linealpha > 255 ) linealpha = 255; float r, g, b; -#ifdef EU07_USE_OLD_LIGHTING_MODEL - r = floor( Diffuse[ 0 ] * Global::ambientDayLight[ 0 ] ); // w zaleznosci od koloru swiatla - g = floor( Diffuse[ 1 ] * Global::ambientDayLight[ 1 ] ); - b = floor( Diffuse[ 2 ] * Global::ambientDayLight[ 2 ] ); -#else r = floor( Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ); // w zaleznosci od koloru swiatla g = floor( Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ] ); b = floor( Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ] ); -#endif glColor4ub( r, g, b, linealpha ); // przezroczystosc dalekiej linii GfxRenderer.Bind( 0 ); @@ -436,6 +427,8 @@ void TGroundNode::RenderAlphaVBO() #endif } +#endif + void TGroundNode::Compile(bool many) { // tworzenie skompilowanej listy w wyświetlaniu DL if (!many) @@ -451,49 +444,28 @@ void TGroundNode::Compile(bool many) } if ((iType == GL_LINES) || (iType == GL_LINE_STRIP) || (iType == GL_LINE_LOOP)) { -#ifdef USE_VERTEX_ARRAYS - glVertexPointer(3, GL_DOUBLE, sizeof(vector3), &Points[0].x); - glDrawArrays(iType, 0, iNumPts); -#else glBegin(iType); for (int i = 0; i < iNumPts; i++) glVertex3dv(&Points[i].x); glEnd(); -#endif } else if (iType == GL_TRIANGLE_STRIP || iType == GL_TRIANGLE_FAN || iType == GL_TRIANGLES) { // jak nie linie, to trójkąty TGroundNode *tri = this; do { // pętla po obiektach w grupie w celu połączenia siatek -#ifdef USE_VERTEX_ARRAYS - glVertexPointer(3, GL_DOUBLE, sizeof(TGroundVertex), &tri->Vertices[0].Point.x); - glNormalPointer(GL_DOUBLE, sizeof(TGroundVertex), &tri->Vertices[0].Normal.x); - glTexCoordPointer(2, GL_FLOAT, sizeof(TGroundVertex), &tri->Vertices[0].tu); -#endif + // TODO: eliminate these calls, they're duplicated by setup part in the unified render function glColor3ub(tri->Diffuse[0], tri->Diffuse[1], tri->Diffuse[2]); GfxRenderer.Bind(Global::bWireFrame ? 0 : tri->TextureID); -#ifdef USE_VERTEX_ARRAYS - glDrawArrays(Global::bWireFrame ? GL_LINE_LOOP : tri->iType, 0, tri->iNumVerts); -#else + glBegin(Global::bWireFrame ? GL_LINE_LOOP : tri->iType); for (int i = 0; i < tri->iNumVerts; i++) { - glNormal3d(tri->Vertices[i].Normal.x, tri->Vertices[i].Normal.y, - tri->Vertices[i].Normal.z); + glNormal3dv(&tri->Vertices[i].Normal.x); glTexCoord2f(tri->Vertices[i].tu, tri->Vertices[i].tv); glVertex3dv(&tri->Vertices[i].Point.x); }; glEnd(); -#endif - /* - if (tri->pTriGroup) //jeśli z grupy - {tri=tri->pNext2; //następny w sektorze - while (tri?!tri->pTriGroup:false) tri=tri->pNext2; //szukamy kolejnego należącego do - grupy - } - else - */ tri = NULL; // a jak nie, to koniec } while (tri); } @@ -552,17 +524,14 @@ void TGroundNode::RenderHidden() } }; +#ifdef EU07_USE_OLD_RENDERCODE void TGroundNode::RenderDL() { // wyświetlanie obiektu przez Display List switch (iType) { // obiekty renderowane niezależnie od odległości case TP_SUBMODEL: TSubModel::fSquareDist = 0; -#ifdef EU07_USE_OLD_RENDERCODE - return smTerrain->RenderDL(); -#else GfxRenderer.Render( smTerrain ); -#endif } double distancesquared = SquareMagnitude(pCenter - Global::pCameraPosition) / Global::ZoomFactor; @@ -605,15 +574,9 @@ void TGroundNode::RenderDL() if( linealpha > 255 ) linealpha = 255; float r, g, b; -#ifdef EU07_USE_OLD_LIGHTING_MODEL - r = floor( Diffuse[ 0 ] * Global::ambientDayLight[ 0 ] ); // w zaleznosci od koloru swiatla - g = floor( Diffuse[ 1 ] * Global::ambientDayLight[ 1 ] ); - b = floor( Diffuse[ 2 ] * Global::ambientDayLight[ 2 ] ); -#else r = floor( Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ); // w zaleznosci od koloru swiatla g = floor( Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ] ); b = floor( Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ] ); -#endif glColor4ub( r, g, b, linealpha ); // przezroczystosc dalekiej linii GfxRenderer.Bind( 0 ); @@ -689,15 +652,9 @@ void TGroundNode::RenderAlphaDL() float linealpha = 255000 * fLineThickness / ( distancesquared + 1.0 ); if (linealpha > 255) linealpha = 255; -#ifdef EU07_USE_OLD_LIGHTING_MODEL - r = Diffuse[ 0 ] * Global::ambientDayLight[ 0 ]; // w zaleznosci od koloru swiatla - g = Diffuse[ 1 ] * Global::ambientDayLight[ 1 ]; - b = Diffuse[ 2 ] * Global::ambientDayLight[ 2 ]; -#else float r = Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ]; // w zaleznosci od koloru swiatla float g = Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ]; float b = Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ]; -#endif glColor4ub( r, g, b, linealpha ); // przezroczystosc dalekiej linii GfxRenderer.Bind( 0 ); @@ -720,6 +677,7 @@ void TGroundNode::RenderAlphaDL() } #endif } +#endif //------------------------------------------------------------------------------ //------------------ Podstawowy pojemnik terenu - sektor ----------------------- @@ -1093,8 +1051,7 @@ void TSubRect::LoadNodes() case GL_LINE_STRIP: case GL_LINE_LOOP: n->iVboPtr = m_nVertexCount; // nowy początek - m_nVertexCount += - n->iNumPts; // miejsce w tablicach normalnych i teksturowania się zmarnuje... + m_nVertexCount += n->iNumPts; // miejsce w tablicach normalnych i teksturowania się zmarnuje... break; case TP_TRACK: n->iVboPtr = m_nVertexCount; // nowy początek @@ -1180,10 +1137,10 @@ void TSubRect::RenderDL() { // renderowanie nieprzezroczystych (DL) TGroundNode *node; RaAnimate(); // przeliczenia animacji torów w sektorze - for (node = nRender; node; node = node->nNext3) - node->RenderDL(); // nieprzezroczyste obiekty (oprócz pojazdów) + for( node = nRender; node; node = node->nNext3 ) + GfxRenderer.Render( node ); // nieprzezroczyste obiekty (oprócz pojazdów) for (node = nRenderMixed; node; node = node->nNext3) - node->RenderDL(); // nieprzezroczyste z mieszanych modeli + GfxRenderer.Render( node ); // nieprzezroczyste z mieszanych modeli for (int j = 0; j < iTracks; ++j) tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach #ifdef EU07_SCENERY_EDITOR @@ -1237,13 +1194,10 @@ void TSubRect::RenderDL() void TSubRect::RenderAlphaDL() { // renderowanie przezroczystych modeli oraz pojazdów (DL) TGroundNode *node; - for (node = nRenderMixed; node; node = node->nNext3) - node->RenderAlphaDL(); // przezroczyste z mieszanych modeli - for (node = nRenderAlpha; node; node = node->nNext3) - node->RenderAlphaDL(); // przezroczyste modele - // for (node=tmp->nRender;node;node=node->nNext3) - // if (node->iType==TP_TRACK) - // node->pTrack->RenderAlpha(); //przezroczyste fragmenty pojazdów na torach + for( node = nRenderMixed; node; node = node->nNext3 ) + GfxRenderer.Render_Alpha( node ); // przezroczyste z mieszanych modeli + for( node = nRenderAlpha; node; node = node->nNext3 ) + GfxRenderer.Render_Alpha( node ); // przezroczyste modele for (int j = 0; j < iTracks; ++j) tTracks[j]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach }; @@ -1255,15 +1209,15 @@ void TSubRect::RenderVBO() LoadNodes(); // czemu tutaj? if (StartVBO()) { - for (node = nRenderRect; node; node = node->nNext3) - if (node->iVboPtr >= 0) - node->RenderVBO(); // nieprzezroczyste obiekty terenu + for( node = nRenderRect; node; node = node->nNext3 ) + if( node->iVboPtr >= 0 ) + GfxRenderer.Render( node ); // nieprzezroczyste obiekty terenu EndVBO(); } - for (node = nRender; node; node = node->nNext3) - node->RenderVBO(); // nieprzezroczyste obiekty (oprócz pojazdów) + for( node = nRender; node; node = node->nNext3 ) + GfxRenderer.Render( node ); // nieprzezroczyste obiekty (oprócz pojazdów) for (node = nRenderMixed; node; node = node->nNext3) - node->RenderVBO(); // nieprzezroczyste z mieszanych modeli + GfxRenderer.Render( node ); // nieprzezroczyste z mieszanych modeli for (int j = 0; j < iTracks; ++j) tTracks[j]->RenderDyn(); // nieprzezroczyste fragmenty pojazdów na torach #ifdef EU07_SCENERY_EDITOR @@ -1279,13 +1233,10 @@ void TSubRect::RenderVBO() void TSubRect::RenderAlphaVBO() { // renderowanie przezroczystych modeli oraz pojazdów (VBO) TGroundNode *node; - for (node = nRenderMixed; node; node = node->nNext3) - node->RenderAlphaVBO(); // przezroczyste z mieszanych modeli - for (node = nRenderAlpha; node; node = node->nNext3) - node->RenderAlphaVBO(); // przezroczyste modele - // for (node=tmp->nRender;node;node=node->nNext3) - // if (node->iType==TP_TRACK) - // node->pTrack->RenderAlpha(); //przezroczyste fragmenty pojazdów na torach + for( node = nRenderMixed; node; node = node->nNext3 ) + GfxRenderer.Render_Alpha( node ); // przezroczyste z mieszanych modeli + for( node = nRenderAlpha; node; node = node->nNext3 ) + GfxRenderer.Render_Alpha( node ); // przezroczyste modele for (int j = 0; j < iTracks; ++j) tTracks[j]->RenderDynAlpha(); // przezroczyste fragmenty pojazdów na torach }; @@ -1300,8 +1251,6 @@ void TSubRect::RenderSounds() //--------------------------------------------------------------------------- int TGroundRect::iFrameNumber = 0; // licznik wyświetlanych klatek -//TGroundRect::TGroundRect( float3 const &Position, float const Radius = 1000.0f * M_SQRT2 ) : - TGroundRect::~TGroundRect() { SafeDeleteArray(pSubRects); @@ -1343,50 +1292,12 @@ void TGroundRect::RenderDL() node->Compile(true); glEndList(); } - nRender->RenderDL(); // nieprzezroczyste trójkąty kwadratu kilometrowego + GfxRenderer.Render( nRender ); // nieprzezroczyste trójkąty kwadratu kilometrowego } - if (nRootMesh) - nRootMesh->RenderDL(); + if( nRootMesh ) + GfxRenderer.Render( nRootMesh ); iLastDisplay = iFrameNumber; // drugi raz nie potrzeba } -/* - float width = 500.0f; - float height = 50.0f; - float3 vTopLeftFront( m_area.center.x - width, m_area.center.y + height, m_area.center.z + width ); - float3 vTopLeftBack( m_area.center.x - width, m_area.center.y + height, m_area.center.z - width ); - float3 vTopRightBack( m_area.center.x + width, m_area.center.y + height, m_area.center.z - width ); - float3 vTopRightFront( m_area.center.x + width, m_area.center.y + height, m_area.center.z + width ); - - float3 vBottom_LeftFront( m_area.center.x - width, m_area.center.y - height, m_area.center.z + width ); - float3 vBottom_LeftBack( m_area.center.x - width, m_area.center.y - height, m_area.center.z - width ); - float3 vBottomRightBack( m_area.center.x + width, m_area.center.y - height, m_area.center.z - width ); - float3 vBottomRightFront( m_area.center.x + width, m_area.center.y - height, m_area.center.z + width ); - - glDisable( GL_LIGHTING ); - glDisable( GL_TEXTURE_2D ); - glColor3ub( 0, 255, 255 ); - glBegin( GL_LINE_LOOP ); - glVertex3fv( &vTopLeftFront.x ); - glVertex3fv( &vTopLeftBack.x ); - glVertex3fv( &vTopRightBack.x ); - glVertex3fv( &vTopRightFront.x ); - glEnd(); - glBegin( GL_LINE_LOOP ); - glVertex3fv( &vBottom_LeftFront.x ); - glVertex3fv( &vBottom_LeftBack.x ); - glVertex3fv( &vBottomRightBack.x ); - glVertex3fv( &vBottomRightFront.x ); - glEnd(); - glBegin( GL_LINES ); - glVertex3fv( &vTopLeftFront.x ); glVertex3fv( &vBottom_LeftFront.x ); - glVertex3fv( &vTopLeftBack.x ); glVertex3fv( &vBottom_LeftBack.x ); - glVertex3fv( &vTopRightBack.x ); glVertex3fv( &vBottomRightBack.x ); - glVertex3fv( &vTopRightFront.x ); glVertex3fv( &vBottomRightFront.x ); - glEnd(); - glColor3ub( 255, 255, 255 ); - glEnable( GL_TEXTURE_2D ); - glEnable( GL_LIGHTING ); -*/ }; void TGroundRect::RenderVBO() @@ -1410,46 +1321,8 @@ void TGroundRect::RenderVBO() //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- -void TGround::MoveGroundNode(vector3 pPosition) -{ // Ra: to wymaga gruntownej reformy - /* - TGroundNode *Current; - for (Current=RootNode;Current!=NULL;Current=Current->Next) - Current->MoveMe(pPosition); - - TGroundRect *Rectx=new TGroundRect; //kwadrat kilometrowy - for(int i=0;iNext) - {//rozłożenie obiektów na mapie - if (Current->iType!=TP_DYNAMIC) - {//pojazdów to w ogóle nie dotyczy - if ((Current->iType!=GL_TRIANGLES)&&(Current->iType!=GL_TRIANGLE_STRIP)?true //~czy trójkąt? - :(Current->iFlags&0x20)?true //~czy teksturę ma nieprzezroczystą? - //:(Current->iNumVerts!=3)?true //~czy tylko jeden trójkąt? - :(Current->fSquareMinRadius!=0.0)?true //~czy widoczny z bliska? - :(Current->fSquareRadius<=90000.0)) //~czy widoczny z daleka? - GetSubRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current); - else //dodajemy do kwadratu kilometrowego - GetRect(Current->pCenter.x,Current->pCenter.z)->AddNode(Current); - } - } - for (Current=RootDynamic;Current!=NULL;Current=Current->Next) - { - Current->pCenter+=pPosition; - Current->DynamicObject->UpdatePos(); - } - for (Current=RootDynamic;Current!=NULL;Current=Current->Next) - Current->DynamicObject->MoverParameters->Physic_ReActivation(); - */ -} - std::vector TempVerts; -/* -TGroundVertex TempVerts[ 10000 ]; // tu wczytywane s¹ trójk¹ty -*/ + BYTE TempConnectionType[ 200 ]; // Ra: sprzêgi w sk³adzie; ujemne, gdy odwrotnie TGround::TGround() @@ -4856,8 +4729,8 @@ bool TGround::RenderAlphaDL(vector3 pPosition) for (i = iRendered - 1; i >= 0; --i) // od najdalszych { // przezroczyste trójkąty w oddzielnym cyklu przed modelami tmp = pRendered[i]; - for (node = tmp->nRenderRectAlpha; node; node = node->nNext3) - node->RenderAlphaDL(); // przezroczyste modele + for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) + GfxRenderer.Render_Alpha( node ); // przezroczyste modele } for (i = iRendered - 1; i >= 0; --i) // od najdalszych { // renderowanie przezroczystych modeli oraz pojazdów @@ -4867,8 +4740,8 @@ bool TGround::RenderAlphaDL(vector3 pPosition) for (i = iRendered - 1; i >= 0; --i) // od najdalszych { // druty na końcu, żeby się nie robiły białe plamy na tle lasu tmp = pRendered[i]; - for (node = tmp->nRenderWires; node; node = node->nNext3) - node->RenderAlphaDL(); // druty + for( node = tmp->nRenderWires; node; node = node->nNext3 ) + GfxRenderer.Render_Alpha( node ); // druty } return true; } @@ -4954,9 +4827,9 @@ bool TGround::RenderAlphaVBO(vector3 pPosition) tmp->LoadNodes(); // ewentualne tworzenie siatek if (tmp->StartVBO()) { - for (node = tmp->nRenderRectAlpha; node; node = node->nNext3) - if (node->iVboPtr >= 0) - node->RenderAlphaVBO(); // nieprzezroczyste obiekty terenu + for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) + if( node->iVboPtr >= 0 ) + GfxRenderer.Render_Alpha( node ); // nieprzezroczyste obiekty terenu tmp->EndVBO(); } } @@ -4968,8 +4841,8 @@ bool TGround::RenderAlphaVBO(vector3 pPosition) tmp = pRendered[i]; if (tmp->StartVBO()) { - for (node = tmp->nRenderWires; node; node = node->nNext3) - node->RenderAlphaVBO(); // przezroczyste modele + for( node = tmp->nRenderWires; node; node = node->nNext3 ) + GfxRenderer.Render_Alpha( node ); // przezroczyste modele tmp->EndVBO(); } } diff --git a/Ground.h b/Ground.h index 707c127f..1a87a442 100644 --- a/Ground.h +++ b/Ground.h @@ -101,8 +101,11 @@ class TSubRect; // sektor (aktualnie 200m×200m, ale może być zmieniony) class TGroundNode : public Resource { // obiekt scenerii - private: - public: + + friend class opengl_renderer; + +private: +public: TGroundNodeType iType; // typ obiektu union { // Ra: wskażniki zależne od typu - zrobić klasy dziedziczone zamiast @@ -130,12 +133,7 @@ class TGroundNode : public Resource }; vector3 pCenter; // współrzędne środka do przydzielenia sektora - union - { - // double fAngle; //kąt obrotu dla modelu - double fLineThickness; // McZapkie-120702: grubosc linii - // int Status; //McZapkie-170303: status dzwieku - }; + double fLineThickness; // McZapkie-120702: grubosc linii double fSquareRadius; // kwadrat widoczności do double fSquareMinRadius; // kwadrat widoczności od // TGroundNode *nMeshGroup; //Ra: obiekt grupujący trójkąty w TSubRect dla tekstury @@ -174,12 +172,8 @@ class TGroundNode : public Resource void Release(); void RenderHidden(); // obsługa dźwięków i wyzwalaczy zdarzeń - void RenderDL(); // renderowanie nieprzezroczystych w Display Lists - void RenderAlphaDL(); // renderowanie przezroczystych w Display Lists // (McZapkie-131202) void RaRenderVBO(); // renderowanie (nieprzezroczystych) ze wspólnego VBO - void RenderVBO(); // renderowanie nieprzezroczystych z własnego VBO - void RenderAlphaVBO(); // renderowanie przezroczystych z (własnego) VBO }; @@ -313,9 +307,6 @@ class TGround public: bool bDynamicRemove = false; // czy uruchomić procedurę usuwania pojazdów TDynamicObject *LastDyn = nullptr; // ABu: paskudnie, ale na bardzo szybko moze jakos przejdzie... - // TTrain *pTrain; - // double fVDozwolona; - // bool bTrabil; TGround(); ~TGround(); @@ -329,7 +320,6 @@ class TGround TTrack * FindTrack(vector3 Point, int &iConnection, TGroundNode *Exclude); TTraction * FindTraction(vector3 *Point, int &iConnection, TGroundNode *Exclude); TTraction * TractionNearestFind(vector3 &p, int dir, TGroundNode *n); - // TGroundNode* CreateGroundNode(); TGroundNode * AddGroundNode(cParser *parser); bool AddGroundNode(double x, double z, TGroundNode *Node) { @@ -342,11 +332,6 @@ class TGround else return false; }; - // bool Include(TQueryParserComp *Parser); - // TGroundNode* GetVisible(AnsiString asName); - TGroundNode * GetNode(std::string asName); - bool AddDynamic(TGroundNode *Node); - void MoveGroundNode(vector3 pPosition); void UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS void Update_Lights(); // updates scene lights array @@ -358,23 +343,6 @@ class TGround bool RenderVBO(vector3 pPosition); bool RenderAlphaVBO(vector3 pPosition); bool CheckQuery(); - // GetRect(double x, double z) { return - // &(Rects[int(x/fSubRectSize+fHalfNumRects)][int(z/fSubRectSize+fHalfNumRects)]); }; - /* - int GetRowFromZ(double z) { return (z/fRectSize+fHalfNumRects); }; - int GetColFromX(double x) { return (x/fRectSize+fHalfNumRects); }; - int GetSubRowFromZ(double z) { return (z/fSubRectSize+fHalfNumSubRects); }; - int GetSubColFromX(double x) { return (x/fSubRectSize+fHalfNumSubRects); }; - */ - /* - inline TGroundNode* FindGroundNode(const AnsiString &asNameToFind ) - { - if (RootNode) - return (RootNode->Find( asNameToFind )); - else - return NULL; - } - */ TGroundNode * DynamicFindAny(std::string asNameToFind); TGroundNode * DynamicFind(std::string asNameToFind); void DynamicList(bool all = false); @@ -419,7 +387,6 @@ class TGround void WyslijNamiary(TGroundNode *t); void WyslijParam(int nr, int fl); void WyslijUszkodzenia(const std::string &t, char fl); - void WyslijPojazdy(int nr); // -> skladanie wielu pojazdow void WyslijObsadzone(); // -> skladanie wielu pojazdow void RadioStop(vector3 pPosition); TDynamicObject * DynamicNearest(vector3 pPosition, double distance = 20.0, diff --git a/Segment.cpp b/Segment.cpp index 27c133a0..1455414b 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -19,12 +19,6 @@ 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); @@ -122,15 +116,14 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI // MessageBox(0,"Length<=0","TSegment::Init",MB_OK); return false; // zerowe nie mogą być } - fStoop = atan2((Point2.y - Point1.y), - fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie + fStoop = std::atan2((Point2.y - Point1.y), fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie SafeDeleteArray(fTsBuffer); if( ( bCurve ) && ( fStep > 0 ) ) { if( fStep > 0 ) { // Ra: prosty dostanie podział, jak ma różną przechyłkę na końcach double s = 0; int i = 0; - iSegCount = ceil( fLength / fStep ); // potrzebne do VBO + iSegCount = static_cast( std::ceil( fLength / fStep )); // potrzebne do VBO // fStep=fLength/(double)(iSegCount-1); //wyrównanie podziału fTsBuffer = new double[ iSegCount + 1 ]; fTsBuffer[ 0 ] = 0; /* TODO : fix fTsBuffer */ @@ -324,408 +317,213 @@ vector3 TSegment::FastGetPoint(double t) return (bCurve ? RaInterpolate(t) : ((1.0 - t) * Point1 + (t)*Point2)); } -void TSegment::RenderLoft(const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, - int iSkip, int iQualityFactor, vector3 **p, bool bRender) +void TSegment::RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, bool Onlypositions, vector3 **p, bool bRender) { // generowanie trójkątów dla odcinka trajektorii ruchu // standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli // podany jest przekrój końcowy // podsypka toru jest robiona za pomocą 6 punktów, szyna 12, drogi i rzeki na 3+2+3 - if (iQualityFactor < 1) - iQualityFactor = 1; // co który segment ma być uwzględniony + if( !fTsBuffer ) + return; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę + vector3 pos1, pos2, dir, parallel1, parallel2, pt, norm; - double s, step, fOffset, tv1, tv2, t; - int i, j; - bool trapez = iNumShapePoints < 0; // sygnalizacja trapezowatości - iNumShapePoints = abs(iNumShapePoints); - if (bCurve) - { - double m1, jmm1, m2, jmm2; // pozycje względne na odcinku 0...1 (ale nie parametr Beziera) - tv1 = 1.0; // Ra: to by można było wyliczać dla odcinka, wyglądało by lepiej - step = fStep * iQualityFactor; - s = fStep * iSkip; // iSkip - ile odcinków z początku pominąć - i = iSkip; // domyślnie 0 - if (!fTsBuffer) - return; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę - if (i > iSegCount) - return; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę - t = fTsBuffer[i]; // tabela watości t dla segmentów - fOffset = 0.1 / fLength; // pierwsze 10cm - pos1 = FastGetPoint(t); // wektor początku segmentu - dir = FastGetDirection(t, fOffset); // wektor kierunku - // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); //wektor poprzeczny - parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - m2 = s / fLength; - jmm2 = 1.0 - m2; - while (s < fLength) - { - // step=SquareMagnitude(Global::GetCameraPosition()+pos); - i += iQualityFactor; // kolejny punkt łamanej - s += step; // końcowa pozycja segmentu [m] - m1 = m2; - jmm1 = jmm2; // stara pozycja - m2 = s / fLength; - jmm2 = 1.0 - m2; // nowa pozycja - if (s > fLength - 0.5) // Ra: -0.5 żeby nie robiło cieniasa na końcu - { // gdy przekroczyliśmy koniec - stąd dziury w torach... - step -= (s - fLength); // jeszcze do wyliczenia mapowania potrzebny - s = fLength; - i = iSegCount; // 20/5 ma dawać 4 - m2 = 1.0; - jmm2 = 0.0; - } - while (tv1 < 0.0) - tv1 += 1.0; // przestawienie mapowania - tv2 = tv1 - step / fTextureLength; // mapowanie na końcu segmentu - t = fTsBuffer[i]; // szybsze od GetTFromS(s); - pos2 = FastGetPoint(t); - dir = FastGetDirection(t, fOffset); // nowy wektor kierunku - // parallel2=CrossProduct(dir,vector3(0,1,0)); //wektor poprzeczny - parallel2 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - glBegin(GL_TRIANGLE_STRIP); - if (trapez) - for (j = 0; j < iNumShapePoints; j++) - { - norm = (jmm1 * ShapePoints[j].n.x + m1 * ShapePoints[j + iNumShapePoints].n.x) * - parallel1; - norm.y += jmm1 * ShapePoints[j].n.y + m1 * ShapePoints[j + iNumShapePoints].n.y; - pt = parallel1 * - (jmm1 * ShapePoints[j].x + m1 * ShapePoints[j + iNumShapePoints].x) + - pos1; - pt.y += jmm1 * ShapePoints[j].y + m1 * ShapePoints[j + iNumShapePoints].y; - if (bRender) - { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale - // potrzebować punktów - glNormal3f(norm.x, norm.y, norm.z); - glTexCoord2f( - jmm1 * ShapePoints[j].z + m1 * ShapePoints[j + iNumShapePoints].z, tv1); - glVertex3f(pt.x, pt.y, pt.z); // pt nie mamy gdzie zapamiętać? - } - // BUG: things blow up badly in the following part in 64bit version on baltyk.scn - // TODO: sort this mess out when the time comes to reorganize spline generation - if( p ) // jeśli jest wskaźnik do tablicy - if (*p) - if (!j) // to dla pierwszego punktu - { - *(*p) = pt; - (*p)++; - } // zapamiętanie brzegu jezdni - // dla trapezu drugi koniec ma inne współrzędne - norm = (jmm1 * ShapePoints[j].n.x + m1 * ShapePoints[j + iNumShapePoints].n.x) * - parallel2; - norm.y += jmm1 * ShapePoints[j].n.y + m1 * ShapePoints[j + iNumShapePoints].n.y; - pt = parallel2 * - (jmm2 * ShapePoints[j].x + m2 * ShapePoints[j + iNumShapePoints].x) + - pos2; - pt.y += jmm2 * ShapePoints[j].y + m2 * ShapePoints[j + iNumShapePoints].y; - if (bRender) - { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale - // potrzebować punktów - glNormal3f(norm.x, norm.y, norm.z); - glTexCoord2f( - jmm2 * ShapePoints[j].z + m2 * ShapePoints[j + iNumShapePoints].z, tv2); - glVertex3f(pt.x, pt.y, pt.z); - } - if (p) // jeśli jest wskaźnik do tablicy - if (*p) - if (!j) // to dla pierwszego punktu - if (i == iSegCount) - { - *(*p) = pt; - (*p)++; - } // zapamiętanie brzegu jezdni - } - else - for (j = 0; j < iNumShapePoints; j++) - { //łuk z jednym profilem - norm = ShapePoints[j].n.x * parallel1; - norm.y += ShapePoints[j].n.y; - pt = parallel1 * ShapePoints[j].x + pos1; - pt.y += ShapePoints[j].y; - glNormal3f(norm.x, norm.y, norm.z); - glTexCoord2f(ShapePoints[j].z, tv1); - glVertex3f(pt.x, pt.y, pt.z); // punkt na początku odcinka - norm = ShapePoints[j].n.x * parallel2; - norm.y += ShapePoints[j].n.y; - pt = parallel2 * ShapePoints[j].x + pos2; - pt.y += ShapePoints[j].y; - glNormal3f(norm.x, norm.y, norm.z); - glTexCoord2f(ShapePoints[j].z, tv2); - glVertex3f(pt.x, pt.y, pt.z); // punkt na końcu odcinka - } - glEnd(); - pos1 = pos2; - parallel1 = parallel2; - tv1 = tv2; + double s, step, fOffset, tv1, tv2, t, fEnd; + bool const trapez = iNumShapePoints < 0; // sygnalizacja trapezowatości + iNumShapePoints = std::abs( iNumShapePoints ); + fTextureLength *= Texturescale; + + double m1, jmm1, m2, jmm2; // pozycje względne na odcinku 0...1 (ale nie parametr Beziera) + step = fStep; + tv1 = 1.0; // Ra: to by można było wyliczać dla odcinka, wyglądało by lepiej + s = fStep * iSkip; // iSkip - ile odcinków z początku pominąć + int i = iSkip; // domyślnie 0 + t = fTsBuffer[ i ]; // tabela wattości t dla segmentów + // BUG: length of spline can be 0, we should skip geometry generation for such cases + fOffset = 0.1 / fLength; // pierwsze 10cm + pos1 = FastGetPoint( t ); // wektor początku segmentu + dir = FastGetDirection( t, fOffset ); // wektor kierunku + parallel1 = Normalize( vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny + if( iEnd == 0 ) + iEnd = iSegCount; + fEnd = fLength * double( iEnd ) / double( iSegCount ); + m2 = s / fEnd; + jmm2 = 1.0 - m2; + while( i < iEnd ) { + + ++i; // kolejny punkt łamanej + s += step; // końcowa pozycja segmentu [m] + m1 = m2; + jmm1 = jmm2; // stara pozycja + m2 = s / fEnd; + jmm2 = 1.0 - m2; // nowa pozycja + if( i == iEnd ) { // gdy przekroczyliśmy koniec - stąd dziury w torach... + step -= ( s - fEnd ); // jeszcze do wyliczenia mapowania potrzebny + s = fEnd; + m2 = 1.0; + jmm2 = 0.0; } - } - else -#ifdef EU07_USE_OLD_LIGHTING_MODEL - { // gdy prosty, nie modyfikujemy wektora kierunkowego i poprzecznego - pos1 = FastGetPoint((fStep * iSkip) / fLength); - pos2 = FastGetPoint_1(); - dir = GetDirection(); - // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); - parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - glBegin(GL_TRIANGLE_STRIP); - if (trapez) - for (j = 0; j < iNumShapePoints; j++) - { - norm = ShapePoints[j].n.x * parallel1; - norm.y += ShapePoints[j].n.y; - pt = parallel1 * ShapePoints[j].x + pos1; - pt.y += ShapePoints[j].y; - glNormal3f(norm.x, norm.y, norm.z); - glTexCoord2f(ShapePoints[j].z, 0); - glVertex3f(pt.x, pt.y, pt.z); - // dla trapezu drugi koniec ma inne współrzędne względne - norm = ShapePoints[j + iNumShapePoints].n.x * parallel1; - norm.y += ShapePoints[j + iNumShapePoints].n.y; - pt = parallel1 * ShapePoints[j + iNumShapePoints].x + pos2; // odsunięcie - pt.y += ShapePoints[j + iNumShapePoints].y; // wysokość - glNormal3f(norm.x, norm.y, norm.z); - glTexCoord2f(ShapePoints[j + iNumShapePoints].z, fLength / fTextureLength); - glVertex3f(pt.x, pt.y, pt.z); + + if( false == Onlypositions ) { + while( tv1 < 0.0 ) { + tv1 += 1.0; } - else - for (j = 0; j < iNumShapePoints; j++) - { - norm = ShapePoints[j].n.x * parallel1; - norm.y += ShapePoints[j].n.y; - pt = parallel1 * ShapePoints[j].x + pos1; - pt.y += ShapePoints[j].y; - glNormal3f(norm.x, norm.y, norm.z); - glTexCoord2f(ShapePoints[j].z, 0); - glVertex3f(pt.x, pt.y, pt.z); - pt = parallel1 * ShapePoints[j].x + pos2; - pt.y += ShapePoints[j].y; - glNormal3f(norm.x, norm.y, norm.z); - glTexCoord2f(ShapePoints[j].z, fLength / fTextureLength); - glVertex3f(pt.x, pt.y, pt.z); + tv2 = tv1 - step / fTextureLength; // mapowanie na końcu segmentu + } + + t = fTsBuffer[ i ]; // szybsze od GetTFromS(s); + pos2 = FastGetPoint( t ); + dir = FastGetDirection( t, fOffset ); // nowy wektor kierunku + parallel2 = Normalize( vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny + + if( Output == nullptr ) { + // immediate mode + ::glBegin( GL_TRIANGLE_STRIP ); + } + + if( trapez ) { + for( int j = 0; j < iNumShapePoints; ++j ) { + pt = parallel1 * ( jmm1 * ( ShapePoints[ j ].x - fOffsetX ) + m1 * ShapePoints[ j + iNumShapePoints ].x ) + pos1; + pt.y += jmm1 * ShapePoints[ j ].y + m1 * ShapePoints[ j + iNumShapePoints ].y; + if( false == Onlypositions ) { + norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel1; + norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y; + } + if( bRender ) { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów + if( Output == nullptr ) { + // immediate mode + if( false == Onlypositions ) { + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv1 ); + } + ::glVertex3f( pt.x, pt.y, pt.z ); // pt nie mamy gdzie zapamiętać? + } + else { + Output->x = pt.x; + Output->y = pt.y; + Output->z = pt.z; + if( false == Onlypositions ) { + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = (jmm1 * ShapePoints[ j ].z + m1 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; + Output->v = tv1; + } + ++Output; + } + } + if( p ) // jeśli jest wskaźnik do tablicy + if( *p ) + if( !j ) // to dla pierwszego punktu + { + *( *p ) = pt; + ( *p )++; + } // zapamiętanie brzegu jezdni + // dla trapezu drugi koniec ma inne współrzędne + pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].x - fOffsetX ) + m2 * ShapePoints[ j + iNumShapePoints ].x ) + pos2; + pt.y += jmm2 * ShapePoints[ j ].y + m2 * ShapePoints[ j + iNumShapePoints ].y; + if( false == Onlypositions ) { + norm = ( jmm1 * ShapePoints[ j ].n.x + m1 * ShapePoints[ j + iNumShapePoints ].n.x ) * parallel2; + norm.y += jmm1 * ShapePoints[ j ].n.y + m1 * ShapePoints[ j + iNumShapePoints ].n.y; + } + if( bRender ) { // skrzyżowania podczas łączenia siatek mogą nie renderować poboczy, ale potrzebować punktów + if( Output == nullptr ) { + // immediate mode + if( false == Onlypositions ) { + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale, tv2 ); + } + ::glVertex3f( pt.x, pt.y, pt.z ); + } + else { + Output->x = pt.x; + Output->y = pt.y; + Output->z = pt.z; + if( false == Onlypositions ) { + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = (jmm2 * ShapePoints[ j ].z + m2 * ShapePoints[ j + iNumShapePoints ].z) / Texturescale; + Output->v = tv2; + } + ++Output; + } + } + if( p ) // jeśli jest wskaźnik do tablicy + if( *p ) + if( !j ) // to dla pierwszego punktu + if( i == iSegCount ) { + *( *p ) = pt; + ( *p )++; + } // zapamiętanie brzegu jezdni } - 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, - int iNumShapePoints, double fTextureLength, int iSkip, - double fOffsetX) -{ // tworzenie siatki trójkątów dla iglicy - vector3 pos1, pos2, dir, parallel1, parallel2, pt; - double a1, a2, s, step, offset, tv1, tv2, t, t2step, oldt2; - int i, j; - if (bCurve) - { // dla toru odchylonego - // t2= 0; - t2step = 1 / double(iSkip); // przesunięcie tekstury? - oldt2 = 1; - tv1 = 1.0; - step = fStep; // długść segmentu - s = 0; - i = 0; - t = fTsBuffer[i]; // wartość t krzywej Beziera dla początku - a1 = 0; - // step= fStep/fLength; - offset = 0.1 / fLength; // około 10cm w sensie parametru t - pos1 = FastGetPoint(t); // współrzędne dla parmatru t - // dir= GetDirection1(); - dir = FastGetDirection(t, offset); // wektor wzdłużny - // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); //poprzeczny? - parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - - while (s < fLength && i < iSkip) - { - // step= SquareMagnitude(Global::GetCameraPosition()+pos); - // t2= oldt2+t2step; - i++; - s += step; - - if (s > fLength) - { - step -= (s - fLength); - s = fLength; - } - - while (tv1 < 0.0) - tv1 += 1.0; - tv2 = tv1 - step / fTextureLength; - - t = fTsBuffer[i]; - pos2 = FastGetPoint(t); - dir = FastGetDirection(t, offset); - // parallel2=Normalize(CrossProduct(dir,vector3(0,1,0))); - parallel2 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - - a2 = double(i) / (iSkip); - glBegin(GL_TRIANGLE_STRIP); - for (j = 0; j < iNumShapePoints; j++) - { // po dwa punkty trapezu - pt = parallel1 * - (ShapePoints1[j].x * a1 + (ShapePoints2[j].x - fOffsetX) * (1.0 - a1)) + - pos1; - pt.y += ShapePoints1[j].y * a1 + ShapePoints2[j].y * (1.0 - a1); - glNormal3f(0.0f, 1.0f, 0.0f); - glTexCoord2f(ShapePoints1[j].z * a1 + ShapePoints2[j].z * (1.0 - a1), tv1); - glVertex3f(pt.x, pt.y, pt.z); - - pt = parallel2 * - (ShapePoints1[j].x * a2 + (ShapePoints2[j].x - fOffsetX) * (1.0 - a2)) + - pos2; - pt.y += ShapePoints1[j].y * a2 + ShapePoints2[j].y * (1.0 - a2); - glNormal3f(0.0f, 1.0f, 0.0f); - glTexCoord2f(ShapePoints1[j].z * a2 + ShapePoints2[j].z * (1.0 - a2), tv2); - glVertex3f(pt.x, pt.y, pt.z); + for( int j = 0; j < iNumShapePoints; ++j ) { + //łuk z jednym profilem + pt = parallel1 * ( ShapePoints[ j ].x - fOffsetX ) + pos1; + pt.y += ShapePoints[ j ].y; + if( false == Onlypositions ) { + norm = ShapePoints[ j ].n.x * parallel1; + norm.y += ShapePoints[ j ].n.y; + } + if( Output == nullptr ) { + // immediate mode + if( false == Onlypositions ) { + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv1 ); + } + ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na początku odcinka + } + else { + Output->x = pt.x; + Output->y = pt.y; + Output->z = pt.z; + if( false == Onlypositions ) { + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = ShapePoints[ j ].z / Texturescale; + Output->v = tv1; + } + ++Output; + } + pt = parallel2 * ShapePoints[ j ].x + pos2; + pt.y += ShapePoints[ j ].y; + if( false == Onlypositions ) { + norm = ShapePoints[ j ].n.x * parallel2; + norm.y += ShapePoints[ j ].n.y; + } + if( Output == nullptr ) { + // immediate mode + if( false == Onlypositions ) { + ::glNormal3f( norm.x, norm.y, norm.z ); + ::glTexCoord2f( ShapePoints[ j ].z / Texturescale, tv2 ); + } + ::glVertex3f( pt.x, pt.y, pt.z ); // punkt na końcu odcinka + } + else { + Output->x = pt.x; + Output->y = pt.y; + Output->z = pt.z; + if( false == Onlypositions ) { + Output->nx = norm.x; + Output->ny = norm.y; + Output->nz = norm.z; + Output->u = ShapePoints[ j ].z / Texturescale; + Output->v = tv2; + } + ++Output; + } } + } + if( Output == nullptr ) { + // immediate mode glEnd(); - pos1 = pos2; - parallel1 = parallel2; - tv1 = tv2; - a1 = a2; } - } - else - { // dla toru prostego - tv1 = 1.0; - s = 0; - i = 0; - // pos1= FastGetPoint( (5*iSkip)/fLength ); - pos1 = FastGetPoint_0(); - dir = GetDirection(); - // parallel1=CrossProduct(dir,vector3(0,1,0)); - parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - - step = 5; - a1 = 0; - - while (i < iSkip) - { - // step= SquareMagnitude(Global::GetCameraPosition()+pos); - i++; - s += step; - - if (s > fLength) - { - step -= (s - fLength); - s = fLength; - } - - while (tv1 < 0.0) - tv1 += 1.0; - - tv2 = tv1 - step / fTextureLength; - - t = s / fLength; - pos2 = FastGetPoint(t); - - a2 = double(i) / (iSkip); - glBegin(GL_TRIANGLE_STRIP); - for (j = 0; j < iNumShapePoints; j++) - { - pt = parallel1 * - (ShapePoints1[j].x * a1 + (ShapePoints2[j].x - fOffsetX) * (1.0 - a1)) + - pos1; - pt.y += ShapePoints1[j].y * a1 + ShapePoints2[j].y * (1.0 - a1); - glNormal3f(0.0f, 1.0f, 0.0f); - glTexCoord2f((ShapePoints1[j].z), tv1); - glVertex3f(pt.x, pt.y, pt.z); - - pt = parallel1 * - (ShapePoints1[j].x * a2 + (ShapePoints2[j].x - fOffsetX) * (1.0 - a2)) + - pos2; - pt.y += ShapePoints1[j].y * a2 + ShapePoints2[j].y * (1.0 - a2); - glNormal3f(0.0f, 1.0f, 0.0f); - glTexCoord2f(ShapePoints2[j].z, tv2); - glVertex3f(pt.x, pt.y, pt.z); - } - glEnd(); - pos1 = pos2; + pos1 = pos2; + parallel1 = parallel2; + if( false == Onlypositions ) { tv1 = tv2; - a1 = a2; } } }; @@ -778,301 +576,4 @@ void TSegment::Render() } } -void TSegment::RaRenderLoft(CVertNormTex *&Vert, const vector6 *ShapePoints, int iNumShapePoints, - double fTextureLength, int iSkip, int iEnd, double fOffsetX) -{ // generowanie trójkątów dla odcinka trajektorii ruchu - // standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku - // po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli - // podany jest przekrój końcowy - // podsypka toru jest robiona za pomocą 6 punktów, szyna 12, drogi i rzeki na 3+2+3 - // na użytek VBO strip dla łuków jest tworzony wzdłuż - // dla skróconego odcinka (iEndnx = norm.x; // niekoniecznie tak - Vert->ny = norm.y; - Vert->nz = norm.z; - Vert->u = jmm1 * ShapePoints[j].z + m1 * ShapePoints[j + iNumShapePoints].z; - Vert->v = tv1; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na początku odcinka - Vert++; - // dla trapezu drugi koniec ma inne współrzędne względne - norm = (jmm1 * ShapePoints[j].n.x + m1 * ShapePoints[j + iNumShapePoints].n.x) * - parallel2; - norm.y += jmm1 * ShapePoints[j].n.y + m1 * ShapePoints[j + iNumShapePoints].n.y; - pt = parallel2 * (jmm2 * (ShapePoints[j].x - fOffsetX) + - m2 * ShapePoints[j + iNumShapePoints].x) + - pos2; - pt.y += jmm2 * ShapePoints[j].y + m2 * ShapePoints[j + iNumShapePoints].y; - Vert->nx = norm.x; // niekoniecznie tak - Vert->ny = norm.y; - Vert->nz = norm.z; - Vert->u = jmm2 * ShapePoints[j].z + m2 * ShapePoints[j + iNumShapePoints].z; - Vert->v = tv2; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na końcu odcinka - Vert++; - } - else - for (j = 0; j < iNumShapePoints; j++) - { // współrzędne początku - norm = ShapePoints[j].n.x * parallel1; - norm.y += ShapePoints[j].n.y; - pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos1; - pt.y += ShapePoints[j].y; - Vert->nx = norm.x; // niekoniecznie tak - Vert->ny = norm.y; - Vert->nz = norm.z; - Vert->u = ShapePoints[j].z; - Vert->v = tv1; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na początku odcinka - Vert++; - norm = ShapePoints[j].n.x * parallel2; - norm.y += ShapePoints[j].n.y; - pt = parallel2 * ShapePoints[j].x + pos2; - pt.y += ShapePoints[j].y; - Vert->nx = norm.x; // niekoniecznie tak - Vert->ny = norm.y; - Vert->nz = norm.z; - Vert->u = ShapePoints[j].z; - Vert->v = tv2; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na końcu odcinka - Vert++; - } - pos1 = pos2; - parallel1 = parallel2; - tv1 = tv2; - } - } - else - { // gdy prosty - pos1 = FastGetPoint((fStep * iSkip) / fLength); - pos2 = FastGetPoint_1(); - dir = GetDirection(); - // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); - parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - if (trapez) - for (j = 0; j < iNumShapePoints; j++) - { - norm = ShapePoints[j].n.x * parallel1; - norm.y += ShapePoints[j].n.y; - pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos1; - pt.y += ShapePoints[j].y; - Vert->nx = norm.x; // niekoniecznie tak - Vert->ny = norm.y; - Vert->nz = norm.z; - Vert->u = ShapePoints[j].z; - Vert->v = 0; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na początku odcinka - Vert++; - // dla trapezu drugi koniec ma inne współrzędne - norm = ShapePoints[j + iNumShapePoints].n.x * parallel1; - norm.y += ShapePoints[j + iNumShapePoints].n.y; - pt = parallel1 * (ShapePoints[j + iNumShapePoints].x - fOffsetX) + - pos2; // odsunięcie - pt.y += ShapePoints[j + iNumShapePoints].y; // wysokość - Vert->nx = norm.x; // niekoniecznie tak - Vert->ny = norm.y; - Vert->nz = norm.z; - Vert->u = ShapePoints[j + iNumShapePoints].z; - Vert->v = fLength / fTextureLength; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na końcu odcinka - Vert++; - } - else - for (j = 0; j < iNumShapePoints; j++) - { - norm = ShapePoints[j].n.x * parallel1; - norm.y += ShapePoints[j].n.y; - pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos1; - pt.y += ShapePoints[j].y; - Vert->nx = norm.x; // niekoniecznie tak - Vert->ny = norm.y; - Vert->nz = norm.z; - Vert->u = ShapePoints[j].z; - Vert->v = 0; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na początku odcinka - Vert++; - pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos2; - pt.y += ShapePoints[j].y; - Vert->nx = norm.x; // niekoniecznie tak - Vert->ny = norm.y; - Vert->nz = norm.z; - Vert->u = ShapePoints[j].z; - Vert->v = fLength / fTextureLength; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na końcu odcinka - Vert++; - } - } -}; - -void TSegment::RaAnimate(CVertNormTex *&Vert, const vector6 *ShapePoints, int iNumShapePoints, - double fTextureLength, int iSkip, int iEnd, double fOffsetX) -{ // jak wyżej, tylko z pominięciem mapowania i braku trapezowania - vector3 pos1, pos2, dir, parallel1, parallel2, pt; - double s, step, fOffset, t, fEnd; - int i, j; - bool trapez = iNumShapePoints < 0; // sygnalizacja trapezowatości - iNumShapePoints = abs(iNumShapePoints); - if (bCurve) - { - double m1, jmm1, m2, jmm2; // pozycje względne na odcinku 0...1 (ale nie parametr Beziera) - step = fStep; - s = fStep * iSkip; // iSkip - ile odcinków z początku pominąć - i = iSkip; // domyślnie 0 - t = fTsBuffer[i]; // tabela wattości t dla segmentów - fOffset = 0.1 / fLength; // pierwsze 10cm - pos1 = FastGetPoint(t); // wektor początku segmentu - dir = FastGetDirection(t, fOffset); // wektor kierunku - // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); //wektor prostopadły - parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - if (iEnd == 0) - iEnd = iSegCount; - fEnd = fLength * double(iEnd) / double(iSegCount); - m2 = s / fEnd; - jmm2 = 1.0 - m2; - while (i < iEnd) - { - ++i; // kolejny punkt łamanej - s += step; // końcowa pozycja segmentu [m] - m1 = m2; - jmm1 = jmm2; // stara pozycja - m2 = s / fEnd; - jmm2 = 1.0 - m2; // nowa pozycja - if (i == iEnd) - { // gdy przekroczyliśmy koniec - stąd dziury w torach... - step -= (s - fEnd); // jeszcze do wyliczenia mapowania potrzebny - s = fEnd; - // i=iEnd; //20/5 ma dawać 4 - m2 = 1.0; - jmm2 = 0.0; - } - t = fTsBuffer[i]; // szybsze od GetTFromS(s); - pos2 = FastGetPoint(t); - dir = FastGetDirection(t, fOffset); // nowy wektor kierunku - // parallel2=Normalize(CrossProduct(dir,vector3(0,1,0))); - parallel2 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - if (trapez) - for (j = 0; j < iNumShapePoints; j++) - { // współrzędne początku - pt = parallel1 * (jmm1 * (ShapePoints[j].x - fOffsetX) + - m1 * ShapePoints[j + iNumShapePoints].x) + - pos1; - pt.y += jmm1 * ShapePoints[j].y + m1 * ShapePoints[j + iNumShapePoints].y; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na początku odcinka - Vert++; - // dla trapezu drugi koniec ma inne współrzędne - pt = parallel2 * (jmm2 * (ShapePoints[j].x - fOffsetX) + - m2 * ShapePoints[j + iNumShapePoints].x) + - pos2; - pt.y += jmm2 * ShapePoints[j].y + m2 * ShapePoints[j + iNumShapePoints].y; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na końcu odcinka - Vert++; - } - pos1 = pos2; - parallel1 = parallel2; - } - } - else - { // gdy prosty - pos1 = FastGetPoint((fStep * iSkip) / fLength); - pos2 = FastGetPoint_1(); - dir = GetDirection(); - // parallel1=Normalize(CrossProduct(dir,vector3(0,1,0))); - parallel1 = Normalize(vector3(-dir.z, 0.0, dir.x)); // wektor poprzeczny - if (trapez) - for (j = 0; j < iNumShapePoints; j++) - { - pt = parallel1 * (ShapePoints[j].x - fOffsetX) + pos1; - pt.y += ShapePoints[j].y; - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na początku odcinka - Vert++; - pt = parallel1 * (ShapePoints[j + iNumShapePoints].x - fOffsetX) + - pos2; // odsunięcie - pt.y += ShapePoints[j + iNumShapePoints].y; // wysokość - Vert->x = pt.x; - Vert->y = pt.y; - Vert->z = pt.z; // punkt na końcu odcinka - Vert++; - } - } -}; //--------------------------------------------------------------------------- diff --git a/Segment.h b/Segment.h index 380744e1..aa303484 100644 --- a/Segment.h +++ b/Segment.h @@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "VBO.h" #include "dumb3d.h" #include "Classes.h" +#include "usefull.h" using namespace Math3D; @@ -61,8 +62,6 @@ class TSegment double fDirection = 0.0; // Ra: kąt prostego w planie; dla łuku kąt od Point1 double fStoop = 0.0; // Ra: kąt wzniesienia; dla łuku od Point1 vector3 vA, vB, vC; // współczynniki wielomianów trzeciego stopnia vD==Point1 - // TSegment *pPrev; //odcinek od strony punktu 1 - w segmencie, żeby nie skakać na zwrotnicach - // TSegment *pNext; //odcinek od strony punktu 2 TTrack *pOwner = nullptr; // wskaźnik na właściciela double fAngle[2]; // kąty zakończenia drogi na przejazdach @@ -71,12 +70,8 @@ class TSegment double GetTFromS(double s); vector3 RaInterpolate(double t); vector3 RaInterpolate0(double t); - // TSegment *segNeightbour[2]; //sąsiednie odcinki - musi być przeniesione z Track - // int iNeightbour[2]; //do którego końca doczepiony public: bool bCurve = false; - // int iShape; //Ra: flagi kształtu dadzą więcej możliwości optymalizacji - // (0-Bezier,1-prosty,2/3-łuk w lewo/prawo,6/7-przejściowa w lewo/prawo) TSegment(TTrack *owner); ~TSegment(); bool Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, double fNewRoll1 = 0, @@ -109,21 +104,16 @@ class TSegment { return Point2; }; - inline double GetRoll(double s) + inline double GetRoll(double const Distance) { - s /= fLength; - return ((1.0 - s) * fRoll1 + s * fRoll2); + return interpolate( fRoll1, fRoll2, Distance / fLength ); } void GetRolls(double &r1, double &r2) { // pobranie przechyłek (do generowania trójkątów) r1 = fRoll1; r2 = fRoll2; } - void RenderLoft(const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, - int iSkip = 0, int iQualityFactor = 1, vector3 **p = NULL, bool bRender = true); - void RenderSwitchRail(const vector6 *ShapePoints1, const vector6 *ShapePoints2, - int iNumShapePoints, double fTextureLength, int iSkip = 0, - double fOffsetX = 0.0f); + void RenderLoft( CVertNormTex* &Output, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, bool Onlypositions = false, vector3 **p = nullptr, bool bRender = true); void Render(); inline double GetLength() { @@ -143,15 +133,10 @@ class TSegment { return fTsBuffer ? iSegCount : 1; }; - void RaRenderLoft(CVertNormTex *&Vert, const vector6 *ShapePoints, int iNumShapePoints, - double fTextureLength, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0); - void RaAnimate(CVertNormTex *&Vert, const vector6 *ShapePoints, int iNumShapePoints, - double fTextureLength, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0); void AngleSet(int i, double a) { fAngle[i] = a; }; - void Rollment(double w1, double w2); // poprawianie przechyłki }; //--------------------------------------------------------------------------- diff --git a/Track.cpp b/Track.cpp index 7c77ea1d..2335248c 100644 --- a/Track.cpp +++ b/Track.cpp @@ -732,8 +732,8 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) parser->getTokens(); *parser >> fVelocity; //*0.28; McZapkie-010602 if (SwitchExtension) // jeśli tor ruchomy - if (fabs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio - SwitchExtension->fVelocity = fVelocity; // zapamiętanie głównego ograniczenia; a + if (std::fabs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio + SwitchExtension->fVelocity = static_cast(fVelocity); // zapamiętanie głównego ograniczenia; a // np. -40 ogranicza tylko na bok } else if (str == "isolated") @@ -1076,7 +1076,10 @@ const vector6 iglica[nnumPts] = // iglica - vextor3(x,y,mapowanie tekstury) }; void TTrack::Compile(GLuint tex) -{ // generowanie treści dla Display Lists - model proceduralny +{ + CVertNormTex *immediate{ nullptr }; + + // generowanie treści dla Display Lists - model proceduralny if (!tex) { // jeśli nie podana tekstura, to każdy tor ma wlasne DL if (DisplayListID) @@ -1134,26 +1137,42 @@ void TTrack::Compile(GLuint tex) int i; for (i = 0; i < 12; ++i) { - rpts1[i] = vector6((fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1, - -(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z, - +szyna[i].n.x * cos1 + szyna[i].n.y * sin1, - -szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0); - rpts2[11 - i] = vector6((-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1, - -(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, szyna[i].z, - -szyna[i].n.x * cos1 + szyna[i].n.y * sin1, - +szyna[i].n.x * sin1 + szyna[i].n.y * cos1, 0.0); + rpts1[i] = + vector6( + (fHTW + szyna[i].x) * cos1 + szyna[i].y * sin1, + -(fHTW + szyna[i].x) * sin1 + szyna[i].y * cos1, + szyna[i].z, + +szyna[i].n.x * cos1 + szyna[i].n.y * sin1, + -szyna[i].n.x * sin1 + szyna[i].n.y * cos1, + 0.0); + rpts2[11 - i] = + vector6( + (-fHTW - szyna[i].x) * cos1 + szyna[i].y * sin1, + -(-fHTW - szyna[i].x) * sin1 + szyna[i].y * cos1, + szyna[i].z, + -szyna[i].n.x * cos1 + szyna[i].n.y * sin1, + +szyna[i].n.x * sin1 + szyna[i].n.y * cos1, + 0.0); } if (iTrapezoid) // jak trapez albo przechyłki, to oddzielne punkty na końcu for (i = 0; i < 12; ++i) { - rpts1[12 + i] = vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, - -(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2, - szyna[i].z, +szyna[i].n.x * cos2 + szyna[i].n.y * sin2, - -szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0); - rpts2[23 - i] = vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, - -(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2, - szyna[i].z, -szyna[i].n.x * cos2 + szyna[i].n.y * sin2, - +szyna[i].n.x * sin2 + szyna[i].n.y * cos2, 0.0); + rpts1[12 + i] = + vector6( + (fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(fHTW2 + szyna[i].x) * sin2 + szyna[i].y * cos2, + szyna[i].z, + +szyna[i].n.x * cos2 + szyna[i].n.y * sin2, + -szyna[i].n.x * sin2 + szyna[i].n.y * cos2, + 0.0); + rpts2[23 - i] = + vector6( + (-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + szyna[i].y * cos2, + szyna[i].z, + -szyna[i].n.x * cos2 + szyna[i].n.y * sin2, + +szyna[i].n.x * sin2 + szyna[i].n.y * cos2, + 0.0); } switch (eType) // dalej zależnie od typu { @@ -1163,10 +1182,8 @@ void TTrack::Compile(GLuint tex) if (TextureID2) if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex) { // podsypka z podkładami jest tylko dla zwykłego toru - vector6 - bpts1[8]; // punkty głównej płaszczyzny nie przydają się do robienia boków - if (fTexLength == - 4.0) // jeśli stare mapowanie na profil 0.2 0.5 1.1 (również 6-9-9/noil) + vector6 bpts1[8]; // punkty głównej płaszczyzny nie przydają się do robienia boków + if (fTexLength == 4.0) // jeśli stare mapowanie na profil 0.2 0.5 1.1 (również 6-9-9/noil) { // stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy // profil if (iTrapezoid) // trapez albo przechyłki @@ -1174,100 +1191,76 @@ void TTrack::Compile(GLuint tex) // ewentualnie poprawić mapowanie, żeby środek mapował się na // 1.435/4.671 ((0.3464,0.6536) // bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, normal1.x, - -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, - 0.33, 0.0, 1.0, 0.0); // krawędź załamania - bpts1[2] = - vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.67, -normal1.x, - -normal1.y, 0.0); // prawy brzeg początku symetrycznie - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.00, -normal1.x, - -normal1.y, 0.0); // prawy skos + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, normal1.x, -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.33, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.67, -normal1.x, -normal1.y, 0.0); // prawy brzeg początku symetrycznie + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.00, -normal1.x, -normal1.y, 0.0); // prawy skos // przekrój końcowy - bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.00, normal2.x, - -normal2.y, 0.0); // lewy brzeg - bpts1[5] = - vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, - 0.33, 0.0, 1.0, 0.0); // krawędź załamania - bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.67, - 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie - bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 1.00, -normal2.x, - -normal2.y, 0.0); // prawy skos + bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.00, normal2.x, -normal2.y, 0.0); // lewy brzeg + bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, 0.33, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.67, 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 1.00, -normal2.x, -normal2.y, 0.0); // prawy skos } else { - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.0, +normal1.x, - -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6(fHTW + side, -0.18, 0.33, +normal1.x, -normal1.y, - 0.0); // krawędź załamania - bpts1[2] = vector6(-fHTW - side, -0.18, 0.67, -normal1.x, -normal1.y, - 0.0); // druga - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.0, -normal1.x, - -normal1.y, 0.0); // prawy skos + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.0, +normal1.x, -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6(fHTW + side, -0.18, 0.33, +normal1.x, -normal1.y, 0.0); // krawędź załamania + bpts1[2] = vector6(-fHTW - side, -0.18, 0.67, -normal1.x, -normal1.y, 0.0); // druga + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.0, -normal1.x, -normal1.y, 0.0); // prawy skos } } else - { // mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa - // fTexLength - double max = fTexRatio2 * fTexLength; // szerokość proporcjonalna do - // długości - double map11 = - max > 0.0 ? (fHTW + side) / max : 0.25; // załamanie od strony 1 - double map12 = - max > 0.0 ? (fHTW + side + hypot1) / max : 0.5; // brzeg od strony 1 + { // mapowanie proporcjonalne do powierzchni, rozmiar w poprzek określa fTexLength + double max = fTexRatio2 * fTexLength; // szerokość proporcjonalna do długości + double map11 = ( + max > 0.0 ? + (fHTW + side) / max : + 0.25 ); // załamanie od strony 1 + double map12 = ( + max > 0.0 ? + (fHTW + side + hypot1) / max : + 0.5 ); // brzeg od strony 1 if (iTrapezoid) // trapez albo przechyłki { // podsypka z podkladami trapezowata - double map21 = - max > 0.0 ? (fHTW2 + side2) / max : 0.25; // załamanie od strony 2 - double map22 = max > 0.0 ? (fHTW2 + side2 + hypot2) / max : - 0.5; // brzeg od strony 2 - // ewentualnie poprawić mapowanie, żeby środek mapował się na - // 1.435/4.671 ((0.3464,0.6536) + double map21 = ( + max > 0.0 ? + (fHTW2 + side2) / max : + 0.25 ); // załamanie od strony 2 + double map22 = ( + max > 0.0 ? + (fHTW2 + side2 + hypot2) / max : + 0.5 ); // brzeg od strony 2 + // ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 ((0.3464,0.6536) // bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, normal1.x, - -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, - 0.5 - map11, 0.0, 1.0, 0.0); // krawędź załamania - bpts1[2] = - vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.5 + map11, 0.0, - 1.0, 0.0); // prawy brzeg początku symetrycznie - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, - -normal1.y, 0.0); // prawy skos + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, normal1.x, -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.5 - map11, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.5 + map11, 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos // przekrój końcowy - bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.5 - map22, normal2.x, - -normal2.y, 0.0); // lewy brzeg - bpts1[5] = - vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, - 0.5 - map21, 0.0, 1.0, 0.0); // krawędź załamania - bpts1[6] = - vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.5 + map21, - 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie - bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 0.5 + map22, -normal2.x, - -normal2.y, 0.0); // prawy skos + bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.5 - map22, normal2.x, -normal2.y, 0.0); // lewy brzeg + bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, 0.5 - map21, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.5 + map21, 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 0.5 + map22, -normal2.x, -normal2.y, 0.0); // prawy skos } else { - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, +normal1.x, - -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6(fHTW + side, -0.18, 0.5 - map11, +normal1.x, - -normal1.y, 0.0); // krawędź załamania - bpts1[2] = vector6(-fHTW - side, -0.18, 0.5 + map11, -normal1.x, - -normal1.y, 0.0); // druga - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, - -normal1.y, 0.0); // prawy skos + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, +normal1.x, -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6(fHTW + side, -0.18, 0.5 - map11, +normal1.x, -normal1.y, 0.0); // krawędź załamania + bpts1[2] = vector6(-fHTW - side, -0.18, 0.5 + map11, -normal1.x, -normal1.y, 0.0); // druga + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos } } if (!tex) GfxRenderer.Bind( TextureID2 ); - Segment->RenderLoft(bpts1, iTrapezoid ? -4 : 4, fTexLength); + Segment->RenderLoft( immediate, bpts1, iTrapezoid ? -4 : 4, fTexLength); } if (TextureID1) if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) { // szyny if (!tex) GfxRenderer.Bind( TextureID1 ); - Segment->RenderLoft(rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - Segment->RenderLoft(rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft( immediate, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft( immediate, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); } break; case tt_Switch: // dla zwrotnicy dwa razy szyny @@ -1277,70 +1270,43 @@ void TTrack::Compile(GLuint tex) vector6 rpts3[24], rpts4[24]; for (i = 0; i < 12; ++i) { - rpts3[i] = vector6((fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, - -(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, - iglica[i].z, +iglica[i].n.x * cos1 + iglica[i].n.y * sin1, - -iglica[i].n.x * sin1 + iglica[i].n.y * cos1, 0.0); + rpts3[i] = + vector6(+(fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, + -(+fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); + rpts3[i + 12] = + vector6(+(fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(+fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); rpts4[11 - i] = vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, - -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z, - -iglica[i].n.x * cos1 + iglica[i].n.y * sin1, - +iglica[i].n.x * sin1 + iglica[i].n.y * cos1, 0.0); + -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); + rpts4[23 - i] = + vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); } - if (iTrapezoid) // trapez albo przechyłki, to oddzielne punkty na końcu - for (i = 0; i < 12; ++i) - { - rpts3[12 + i] = - vector6((fHTW2 + iglica[i].x) * cos2 + iglica[i].y * sin2, - -(fHTW2 + iglica[i].x) * sin2 + iglica[i].y * cos2, iglica[i].z, - +iglica[i].n.x * cos2 + iglica[i].n.y * sin2, - -iglica[i].n.x * sin2 + iglica[i].n.y * cos2, 0.0); - rpts4[23 - i] = - vector6((-fHTW2 - iglica[i].x) * cos2 + iglica[i].y * sin2, - -(-fHTW2 - iglica[i].x) * sin2 + iglica[i].y * cos2, - iglica[i].z, -iglica[i].n.x * cos2 + iglica[i].n.y * sin2, - +iglica[i].n.x * sin2 + iglica[i].n.y * cos2, 0.0); - } // McZapkie-130302 - poprawione rysowanie szyn if (SwitchExtension->RightSwitch) { // zwrotnica prawa GfxRenderer.Bind( TextureID1 ); - SwitchExtension->Segments[0]->RenderLoft(rpts1, nnumPts, fTexLength, - 2); // prawa szyna za iglicą - SwitchExtension->Segments[0]->RenderSwitchRail( - rpts1, rpts3, nnumPts, fTexLength, 2, - SwitchExtension->fOffset2); // prawa iglica - SwitchExtension->Segments[0]->RenderLoft( - rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała + SwitchExtension->Segments[0]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2); // prawa iglica + SwitchExtension->Segments[0]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2); // prawa szyna za iglicą + SwitchExtension->Segments[0]->RenderLoft( immediate, rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje GfxRenderer.Bind( TextureID2 ); - SwitchExtension->Segments[1]->RenderLoft( - rpts1, nnumPts, fTexLength); // prawa szyna normalna cała - SwitchExtension->Segments[1]->RenderLoft(rpts2, nnumPts, fTexLength, - 2); // lewa szyna za iglicą - SwitchExtension->Segments[1]->RenderSwitchRail( - rpts2, rpts4, nnumPts, fTexLength, 2, - -fMaxOffset + SwitchExtension->fOffset1); // lewa iglica + SwitchExtension->Segments[1]->RenderLoft( immediate, rpts1, nnumPts, fTexLength); // prawa szyna normalna cała + SwitchExtension->Segments[1]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1); // lewa iglica + SwitchExtension->Segments[1]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą } else { // lewa kiedyś działała lepiej niż prawa GfxRenderer.Bind( TextureID1 ); - SwitchExtension->Segments[0]->RenderLoft( - rpts1, nnumPts, fTexLength); // prawa szyna normalna cała - SwitchExtension->Segments[0]->RenderLoft(rpts2, nnumPts, fTexLength, - 2); // lewa szyna za iglicą - SwitchExtension->Segments[0]->RenderSwitchRail( - rpts2, rpts4, nnumPts, fTexLength, 2, - -SwitchExtension->fOffset2); // lewa iglica + SwitchExtension->Segments[0]->RenderLoft( immediate, rpts1, nnumPts, fTexLength); // prawa szyna normalna cała + SwitchExtension->Segments[0]->RenderLoft( immediate, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2); // lewa iglica + SwitchExtension->Segments[0]->RenderLoft( immediate, rpts2, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą if (TextureID2 != TextureID1) // nie wiadomo, czy OpenGL to optymalizuje GfxRenderer.Bind( TextureID2 ); - SwitchExtension->Segments[1]->RenderLoft(rpts1, nnumPts, fTexLength, - 2); // prawa szyna za iglicą - SwitchExtension->Segments[1]->RenderSwitchRail( - rpts1, rpts3, nnumPts, fTexLength, 2, - fMaxOffset - SwitchExtension->fOffset1); // prawa iglica - SwitchExtension->Segments[1]->RenderLoft( - rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała + SwitchExtension->Segments[1]->RenderLoft( immediate, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1); // prawa iglica + SwitchExtension->Segments[1]->RenderLoft( immediate, rpts1, nnumPts, fTexLength, 1.0, 2); // prawa szyna za iglicą + SwitchExtension->Segments[1]->RenderLoft( immediate, rpts2, nnumPts, fTexLength); // lewa szyna normalnie cała } } break; @@ -1362,14 +1328,10 @@ void TTrack::Compile(GLuint tex) if (iTrapezoid) // trapez albo przechyłki { // nawierzchnia trapezowata Segment->GetRolls(roll1, roll2); - bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1, - sin(roll1), cos(roll1), 0.0); // lewy brzeg początku - bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1), - cos(roll1), 0.0); // prawy brzeg początku symetrycznie - bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2, - sin(roll2), cos(roll2), 0.0); // lewy brzeg końca - bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2), - cos(roll2), 0.0); // prawy brzeg początku symetrycznie + bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1, sin(roll1), cos(roll1), 0.0); // lewy brzeg początku + bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1), cos(roll1), 0.0); // prawy brzeg początku symetrycznie + bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2, sin(roll2), cos(roll2), 0.0); // lewy brzeg końca + bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2), cos(roll2), 0.0); // prawy brzeg początku symetrycznie } else { @@ -1382,106 +1344,100 @@ void TTrack::Compile(GLuint tex) { // tworzenie trójkątów nawierzchni szosy if (!tex) GfxRenderer.Bind( TextureID1 ); - Segment->RenderLoft(bpts1, iTrapezoid ? -2 : 2, fTexLength); + Segment->RenderLoft( immediate, bpts1, iTrapezoid ? -2 : 2, fTexLength); } if (TextureID2) if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex) - { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak - // w Midtown Madness 2?) + { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) if (!tex) GfxRenderer.Bind( TextureID2 ); - vector6 rpts1[6], + vector6 + rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony if (fTexHeight1 >= 0.0) { // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy - rpts1[1] = - vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawędź załamania - rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, - 1.0); // lewy brzeg pobocza (mapowanie może być inne + rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawędź załamania + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 1.0); // lewy brzeg pobocza (mapowanie może być inne rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza - rpts2[1] = - vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania + rpts2[1] = vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy if (iTrapezoid) // trapez albo przechyłki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony - // odcinka - rpts1[3] = - vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza - rpts1[4] = - vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź załamania + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka + rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza + rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź załamania rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); - rpts2[5] = - vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza + rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza } } else { // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości // mapowanie propocjonalne do szerokości chodnika // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy - double d = - -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm - double max = - fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości - double map1l = max > 0.0 ? - side / max : - 0.484375; // obcięcie tekstury od lewej strony punktu 1 - double map1r = max > 0.0 ? - slop / max : - 0.484375; // obcięcie tekstury od prawej strony punktu 1 - rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y - fTexHeight1, - 0.515625 + map1r); // prawy brzeg prawego chodnika - rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y - fTexHeight1, - 0.515625); // prawy krawężnik u góry - rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, - 0.515625 - d / 2.56); // prawy krawężnik u dołu - rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, - 0.484375 + d / 2.56); // lewy krawężnik u dołu - rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y - fTexHeight1, - 0.484375); // lewy krawężnik u góry - rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y - fTexHeight1, - 0.484375 - map1l); // lewy brzeg lewego chodnika + double d = -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm + double max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości + double map1l = ( + max > 0.0 ? + side / max : + 0.484375 ); // obcięcie tekstury od lewej strony punktu 1 + double map1r = ( + max > 0.0 ? + slop / max : + 0.484375 ); // obcięcie tekstury od prawej strony punktu 1 + double h1r = ( + slop > d ? + -fTexHeight1 : + 0 ); + double h1l = ( + side > d ? + -fTexHeight1 : + 0 ); + rpts1[ 0 ] = vector6( bpts1[ 0 ].x + slop, bpts1[ 0 ].y + h1r, 0.515625 + map1r ); // prawy brzeg prawego chodnika + rpts1[ 1 ] = vector6( bpts1[ 0 ].x + d, bpts1[ 0 ].y + h1r, 0.515625 ); // prawy krawężnik u góry + rpts1[ 2 ] = vector6( bpts1[ 0 ].x, bpts1[ 0 ].y, 0.515625 - d / 2.56 ); // prawy krawężnik u dołu + rpts2[ 0 ] = vector6( bpts1[ 1 ].x, bpts1[ 1 ].y, 0.484375 + d / 2.56 ); // lewy krawężnik u dołu + rpts2[ 1 ] = vector6( bpts1[ 1 ].x - d, bpts1[ 1 ].y + h1l, 0.484375 ); // lewy krawężnik u góry + rpts2[ 2 ] = vector6( bpts1[ 1 ].x - side, bpts1[ 1 ].y + h1l, 0.484375 - map1l ); // lewy brzeg lewego chodnika if (iTrapezoid) // trapez albo przechyłki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony - // odcinka - slop2 = fabs((iTrapezoid & 2) ? slop2 : - slop); // szerokość chodnika po prawej - double map2l = - max > 0.0 ? side2 / max : - 0.484375; // obcięcie tekstury od lewej strony punktu 2 - double map2r = - max > 0.0 ? slop2 / max : - 0.484375; // obcięcie tekstury od prawej strony punktu 2 - rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y - fTexHeight2, - 0.515625 + map2r); // prawy brzeg prawego chodnika - rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y - fTexHeight2, - 0.515625); // prawy krawężnik u góry - rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, - 0.515625 - d / 2.56); // prawy krawężnik u dołu - rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, - 0.484375 + d / 2.56); // lewy krawężnik u dołu - rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y - fTexHeight2, - 0.484375); // lewy krawężnik u góry - rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y - fTexHeight2, - 0.484375 - map2l); // lewy brzeg lewego chodnika + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka + slop2 = ( + fabs( ( iTrapezoid & 2 ) ? + slop2 : + slop ) ); // szerokość chodnika po prawej + double map2l = ( + max > 0.0 ? + side2 / max : + 0.484375 ); // obcięcie tekstury od lewej strony punktu 2 + double map2r = ( + max > 0.0 ? + slop2 / max : + 0.484375 ); // obcięcie tekstury od prawej strony punktu 2 + double h2r = ( slop2 > d ) ? -fTexHeight2 : 0; + double h2l = ( side2 > d ) ? -fTexHeight2 : 0; + rpts1[ 3 ] = vector6( bpts1[ 2 ].x + slop2, bpts1[ 2 ].y + h2r, 0.515625 + map2r ); // prawy brzeg prawego chodnika + rpts1[ 4 ] = vector6( bpts1[ 2 ].x + d, bpts1[ 2 ].y + h2r, 0.515625 ); // prawy krawężnik u góry + rpts1[ 5 ] = vector6( bpts1[ 2 ].x, bpts1[ 2 ].y, 0.515625 - d / 2.56 ); // prawy krawężnik u dołu + rpts2[ 3 ] = vector6( bpts1[ 3 ].x, bpts1[ 3 ].y, 0.484375 + d / 2.56 ); // lewy krawężnik u dołu + rpts2[ 4 ] = vector6( bpts1[ 3 ].x - d, bpts1[ 3 ].y + h2l, 0.484375 ); // lewy krawężnik u góry + rpts2[ 5 ] = vector6( bpts1[ 3 ].x - side2, bpts1[ 3 ].y + h2l, 0.484375 - map2l ); // lewy brzeg lewego chodnika } } if (iTrapezoid) // trapez albo przechyłki { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony // odcinka if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0)) - Segment->RenderLoft(rpts1, -3, fTexLength); // tylko jeśli jest z prawej + Segment->RenderLoft( immediate, rpts1, -3, fTexLength); // tylko jeśli jest z prawej if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - Segment->RenderLoft(rpts2, -3, fTexLength); // tylko jeśli jest z lewej + Segment->RenderLoft( immediate, rpts2, -3, fTexLength); // tylko jeśli jest z lewej } else { // pobocza zwykłe, brak przechyłki if ((fTexHeight1 >= 0.0) ? true : (slop != 0.0)) - Segment->RenderLoft(rpts1, 3, fTexLength); + Segment->RenderLoft( immediate, rpts1, 3, fTexLength); if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - Segment->RenderLoft(rpts2, 3, fTexLength); + Segment->RenderLoft( immediate, rpts2, 3, fTexLength); } } break; @@ -1493,13 +1449,11 @@ void TTrack::Compile(GLuint tex) // na razie połowa odległości pomiędzy Point1 i Point2, potem się dopracuje a[0] = a[1] = 0.5; // parametr do poszukiwania przecięcia łuków // modyfikować a[0] i a[1] tak, aby trafić na przecięcie odcinka 34 - p[0] = SwitchExtension->Segments[0]->FastGetPoint( - a[0]); // współrzędne środka pierwszego odcinka + p[0] = SwitchExtension->Segments[0]->FastGetPoint(a[0]); // współrzędne środka pierwszego odcinka p[1] = SwitchExtension->Segments[1]->FastGetPoint(a[1]); //-//- drugiego // p[2]=p[1]-p[0]; //jeśli różne od zera, przeliczyć a[0] i a[1] i wyznaczyć nowe punkty vector3 oxz = p[0]; // punkt mapowania środka tekstury skrzyżowania - p[0] = SwitchExtension->Segments[0] - ->GetDirection1(); // Point1 - pobranie wektorów kontrolnych + p[0] = SwitchExtension->Segments[0]->GetDirection1(); // Point1 - pobranie wektorów kontrolnych p[1] = SwitchExtension->Segments[1]->GetDirection2(); // Point3 (bo zamienione) p[2] = SwitchExtension->Segments[0]->GetDirection2(); // Point2 p[3] = SwitchExtension->Segments[1]->GetDirection1(); // Point4 (bo zamienione) @@ -1507,37 +1461,36 @@ void TTrack::Compile(GLuint tex) a[1] = atan2(-p[1].x, p[1].z); a[2] = atan2(-p[2].x, p[2].z); a[3] = atan2(-p[3].x, p[3].z); - p[0] = SwitchExtension->Segments[0] - ->FastGetPoint_0(); // Point1 - pobranie współrzędnych końców + p[0] = SwitchExtension->Segments[0]->FastGetPoint_0(); // Point1 - pobranie współrzędnych końców p[1] = SwitchExtension->Segments[1]->FastGetPoint_1(); // Point3 p[2] = SwitchExtension->Segments[0]->FastGetPoint_1(); // Point2 - p[3] = SwitchExtension->Segments[1] - ->FastGetPoint_0(); // Point4 - przy trzech drogach pokrywa się z Point1 + p[3] = SwitchExtension->Segments[1]->FastGetPoint_0(); // Point4 - przy trzech drogach pokrywa się z Point1 // 2014-07: na początek rysować brzegi jak dla łuków - // punkty brzegu nawierzchni uzyskujemy podczas renderowania boków (bez sensu, ale - // najszybciej było zrobić) + // punkty brzegu nawierzchni uzyskujemy podczas renderowania boków (bez sensu, ale najszybciej było zrobić) int i; // ile punktów (może byc różna ilość punktów między drogami) if (!SwitchExtension->vPoints) { // jeśli tablica punktów nie jest jeszcze utworzona, zliczamy punkty i tworzymy ją - if (SwitchExtension->iRoads == 3) // mogą być tylko 3 drogi zamiast 4 - SwitchExtension->iPoints = 5 + SwitchExtension->Segments[0]->RaSegCount() + - SwitchExtension->Segments[1]->RaSegCount() + - SwitchExtension->Segments[2]->RaSegCount(); - else + if( SwitchExtension->iRoads == 3 ) { + // mogą być tylko 3 drogi zamiast 4 SwitchExtension->iPoints = - 5 + SwitchExtension->Segments[2]->RaSegCount() + - SwitchExtension->Segments[3]->RaSegCount() + - SwitchExtension->Segments[4]->RaSegCount() + - SwitchExtension->Segments[5]->RaSegCount(); // mogą być tylko 3 drogi - SwitchExtension->vPoints = - new vector3[SwitchExtension->iPoints]; // tablica utworzona z zapasem, ale nie - // wypełniona współrzędnymi + 5 + SwitchExtension->Segments[ 0 ]->RaSegCount() + + SwitchExtension->Segments[ 1 ]->RaSegCount() + + SwitchExtension->Segments[ 2 ]->RaSegCount(); + } + else { + SwitchExtension->iPoints = + 5 + SwitchExtension->Segments[ 2 ]->RaSegCount() + + SwitchExtension->Segments[ 3 ]->RaSegCount() + + SwitchExtension->Segments[ 4 ]->RaSegCount() + + SwitchExtension->Segments[ 5 ]->RaSegCount(); // mogą być tylko 3 drogi + } + // tablica utworzona z zapasem, ale nie wypełniona współrzędnymi + SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints]; } vector3 *b = SwitchExtension->bPoints ? - NULL : - SwitchExtension - ->vPoints; // zmienna robocza, NULL gdy tablica punktów już jest wypełniona + nullptr : + SwitchExtension->vPoints; // zmienna robocza, NULL gdy tablica punktów już jest wypełniona vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% @@ -1547,136 +1500,101 @@ void TTrack::Compile(GLuint tex) // if (iTrapezoid) //trapez albo przechyłki { // nawierzchnia trapezowata Segment->GetRolls(roll1, roll2); - bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1, - sin(roll1), cos(roll1), 0.0); // lewy brzeg początku - bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1), - cos(roll1), 0.0); // prawy brzeg początku symetrycznie - bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2, - sin(roll2), cos(roll2), 0.0); // lewy brzeg końca - bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2), - cos(roll2), 0.0); // prawy brzeg początku symetrycznie + bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1, sin(roll1), cos(roll1), 0.0); // lewy brzeg początku + bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1), cos(roll1), 0.0); // prawy brzeg początku symetrycznie + bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2, sin(roll2), cos(roll2), 0.0); // lewy brzeg końca + bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2), cos(roll2), 0.0); // prawy brzeg początku symetrycznie } } // najpierw renderowanie poboczy i zapamiętywanie punktów - // problem ze skrzyżowaniami jest taki, że teren chce się pogrupować wg tekstur, ale - // zaczyna od nawierzchni + // problem ze skrzyżowaniami jest taki, że teren chce się pogrupować wg tekstur, ale zaczyna od nawierzchni // sama nawierzchnia nie wypełni tablicy punktów, bo potrzebne są pobocza - // ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie - // w swoim czasie - // if (TextureID2) - // if (tex?TextureID2==tex:true) //jeśli pasuje do grupy (tex) - { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w - // Midtown Madness 2?) + // ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie w swoim czasie + { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) if (TextureID2) if (!tex) GfxRenderer.Bind( TextureID2 ); vector6 rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony - // Ra 2014-07: trzeba to przerobić na pętlę i pobierać profile (przynajmniej 2..4) z - // sąsiednich dróg + // Ra 2014-07: trzeba to przerobić na pętlę i pobierać profile (przynajmniej 2..4) z sąsiednich dróg if (fTexHeight1 >= 0.0) { // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy - rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawędź - // załamania - rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, - 1.0); // lewy brzeg pobocza (mapowanie może być inne + rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawędź załamania + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 1.0); // lewy brzeg pobocza (mapowanie może być inne rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza - rpts2[1] = - vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania + rpts2[1] = vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy // if (iTrapezoid) //trapez albo przechyłki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony - // odcinka + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza - rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź - // załamania + rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź załamania rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); - rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego - // pobocza + rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza } } else { // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości // mapowanie propocjonalne do szerokości chodnika // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy - double d = - -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm - double max = - fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości + double d = -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm + double max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości double map1l = max > 0.0 ? side / max : 0.484375; // obcięcie tekstury od lewej strony punktu 1 double map1r = max > 0.0 ? slop / max : 0.484375; // obcięcie tekstury od prawej strony punktu 1 - rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y - fTexHeight1, - 0.515625 + map1r); // prawy brzeg prawego chodnika - rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y - fTexHeight1, - 0.515625); // prawy krawężnik u góry - rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, - 0.515625 - d / 2.56); // prawy krawężnik u dołu - rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, - 0.484375 + d / 2.56); // lewy krawężnik u dołu - rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y - fTexHeight1, - 0.484375); // lewy krawężnik u góry - rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y - fTexHeight1, - 0.484375 - map1l); // lewy brzeg lewego chodnika + rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y - fTexHeight1, 0.515625 + map1r); // prawy brzeg prawego chodnika + rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y - fTexHeight1, 0.515625); // prawy krawężnik u góry + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y - fTexHeight1, 0.484375); // lewy krawężnik u góry + rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y - fTexHeight1, 0.484375 - map1l); // lewy brzeg lewego chodnika // if (iTrapezoid) //trapez albo przechyłki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony - // odcinka - slop2 = - fabs((iTrapezoid & 2) ? slop2 : slop); // szerokość chodnika po prawej + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka + slop2 = fabs((iTrapezoid & 2) ? slop2 : slop); // szerokość chodnika po prawej double map2l = max > 0.0 ? side2 / max : 0.484375; // obcięcie tekstury od lewej strony punktu 2 double map2r = max > 0.0 ? slop2 / max : 0.484375; // obcięcie tekstury od prawej strony punktu 2 - rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y - fTexHeight2, - 0.515625 + map2r); // prawy brzeg prawego chodnika - rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y - fTexHeight2, - 0.515625); // prawy krawężnik u góry - rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, - 0.515625 - d / 2.56); // prawy krawężnik u dołu - rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, - 0.484375 + d / 2.56); // lewy krawężnik u dołu - rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y - fTexHeight2, - 0.484375); // lewy krawężnik u góry - rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y - fTexHeight2, - 0.484375 - map2l); // lewy brzeg lewego chodnika + rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y - fTexHeight2, 0.515625 + map2r); // prawy brzeg prawego chodnika + rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y - fTexHeight2, 0.515625); // prawy krawężnik u góry + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y - fTexHeight2, 0.484375); // lewy krawężnik u góry + rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y - fTexHeight2, 0.484375 - map2l); // lewy brzeg lewego chodnika } } - bool render = TextureID2 ? (tex ? TextureID2 == tex : true) : - false; // renderować nie trzeba, ale trzeba wyznaczyć + bool render = ( + TextureID2 ? ( + tex ? + TextureID2 == tex : + true ) : + false ); // renderować nie trzeba, ale trzeba wyznaczyć // punkty brzegowe nawierzchni // if (iTrapezoid) //trapez albo przechyłki if (SwitchExtension->iRoads == 4) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka - if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - SwitchExtension->Segments[2]->RenderLoft( - rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej - if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - SwitchExtension->Segments[3]->RenderLoft( - rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej - if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - SwitchExtension->Segments[4]->RenderLoft( - rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej - if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) - SwitchExtension->Segments[5]->RenderLoft( - rpts2, -3, fTexLength, 0, 1, &b, render); // tylko jeśli jest z lewej + if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { + SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 3 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 4 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 5 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + } } else // to będzie ewentualnie dla prostego na skrzyżowaniu trzech dróg { // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe - if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK - SwitchExtension->Segments[2]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, render); // z P2 do P4 - if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK - SwitchExtension->Segments[1]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, render); // z P4 do P3=P1 (odwrócony) - if ((fTexHeight1 >= 0.0) ? true : (side != 0.0)) // OK - SwitchExtension->Segments[0]->RenderLoft(rpts2, -3, fTexLength, 0, 1, &b, render); // z P1 do P2 + if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { + SwitchExtension->Segments[ 2 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4 + SwitchExtension->Segments[ 1 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony) + SwitchExtension->Segments[ 0 ]->RenderLoft( immediate, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2 + } } } // renderowanie nawierzchni na końcu @@ -1685,24 +1603,23 @@ void TTrack::Compile(GLuint tex) if (!SwitchExtension->bPoints) // jeśli tablica nie wypełniona if (b) // ale jest wskaźnik do tablicy - może nie być? { // coś się gubi w obliczeniach na wskaźnikach - i = (int)(((size_t)(b)) - ((size_t)(SwitchExtension->vPoints))) / - sizeof(vector3); // ustalenie liczby punktów, bo mogło wyjść inaczej niż + // ustalenie liczby punktów, bo mogło wyjść inaczej niż + i = (int)(((size_t)(b)) - ((size_t)(SwitchExtension->vPoints))) / sizeof(vector3); // policzone z góry if (i > 0) { // jeśli zostało to właśnie utworzone if (SwitchExtension->iPoints > i) // jeśli wyszło mniej niż było miejsca SwitchExtension->iPoints = i; // domknięcie wachlarza - else - --SwitchExtension->iPoints; // jak tutaj wejdzie, to błąd jest - zrobić - // miejsce na powtórzenie pierwszego punktu - // na końcu - SwitchExtension->vPoints[SwitchExtension->iPoints++] = - SwitchExtension->vPoints[0]; + else { + // jak tutaj wejdzie, to błąd jest - zrobić miejsce na powtórzenie pierwszego punktu na końcu + --SwitchExtension->iPoints; + } + SwitchExtension->vPoints[SwitchExtension->iPoints++] = SwitchExtension->vPoints[0]; SwitchExtension->bPoints = true; // tablica punktów została wypełniona } } if (TextureID1) // jeśli podana tekstura nawierzchni - if (tex ? TextureID1 == tex : true) // jeśli pasuje do grupy (tex) + if ( (tex == TextureID1) || (tex == 0) ) // jeśli pasuje do grupy (tex) { if (!tex) GfxRenderer.Bind( TextureID1 ); @@ -1711,15 +1628,18 @@ void TTrack::Compile(GLuint tex) glTexCoord2f(0.5, 0.5); //środek tekstury na środku skrzyżowania glVertex3f(oxz.x, oxz.y, oxz.z); for (i = SwitchExtension->iPoints - 1; i >= 0; --i) - // for (i=0;iiPoints;++i) { glNormal3f(0, 1, 0); - u = (SwitchExtension->vPoints[i].x - oxz.x) / - fTexLength; // mapowanie we współrzędnych scenerii + // mapowanie we współrzędnych scenerii + u = (SwitchExtension->vPoints[i].x - oxz.x) / fTexLength; v = (SwitchExtension->vPoints[i].z - oxz.z) / (fTexRatio1 * fTexLength); - glTexCoord2f(cosa0 * u + sina0 * v + 0.5, -sina0 * u + cosa0 * v + 0.5); - glVertex3f(SwitchExtension->vPoints[i].x, SwitchExtension->vPoints[i].y, - SwitchExtension->vPoints[i].z); + glTexCoord2f( + cosa0 * u + sina0 * v + 0.5, + -sina0 * u + cosa0 * v + 0.5); + glVertex3f( + SwitchExtension->vPoints[i].x, + SwitchExtension->vPoints[i].y, + SwitchExtension->vPoints[i].z); } glEnd(); } @@ -1738,7 +1658,7 @@ void TTrack::Compile(GLuint tex) { if (!tex) GfxRenderer.Bind( TextureID1 ); - Segment->RenderLoft(bpts1, numPts, fTexLength); + Segment->RenderLoft( immediate, bpts1, numPts, fTexLength); } if (TextureID2) if (tex ? TextureID2 == tex : true) // jeśli pasuje do grupy (tex) @@ -1750,8 +1670,8 @@ void TTrack::Compile(GLuint tex) vector6(-rozp, -fTexHeight1, 0.0)}; // Ra: po kiego 0.1? if (!tex) GfxRenderer.Bind( TextureID2 ); // brzeg rzeki - Segment->RenderLoft(rpts1, 3, fTexLength); - Segment->RenderLoft(rpts2, 3, fTexLength); + Segment->RenderLoft( immediate, rpts1, 3, fTexLength); + Segment->RenderLoft( immediate, rpts2, 3, fTexLength); } break; } @@ -1918,17 +1838,36 @@ int TTrack::RaArrayPrepare() case 2: // droga if (eType == tt_Cross) // tylko dla skrzyżowania dróg { // specjalny sposób obliczania liczby wierzchołków w skrzyżowaniu - // int n=0; //wierzchołki wewnętrzne do generowania nawierzchni - // int b=0; //wierzchołki do generowania boków - if (fTexHeight1 >= 0) // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być - { // normalne pobocze, na razie się składa z - return (Segment->RaSegCount()) * ((TextureID1 ? 4 : 0) + (TextureID2 ? 12 : 0)); + if( SwitchExtension->iRoads == 3 ) { + // mogą być tylko 3 drogi zamiast 4 + SwitchExtension->iPoints = + 5 + + SwitchExtension->Segments[ 0 ]->RaSegCount() + + SwitchExtension->Segments[ 1 ]->RaSegCount() + + SwitchExtension->Segments[ 2 ]->RaSegCount(); + } + else { + SwitchExtension->iPoints = + 5 + + SwitchExtension->Segments[ 2 ]->RaSegCount() + + SwitchExtension->Segments[ 3 ]->RaSegCount() + + SwitchExtension->Segments[ 4 ]->RaSegCount() + + SwitchExtension->Segments[ 5 ]->RaSegCount(); + } + if (fTexHeight1 >= 0) { + // normalne pobocze, na razie się składa z + // NOTE: for the road part 1x the point amount would be enough, but we provide extra padding + // on account of unexamined issues with geometry data bleeding between vbo chunks + // TODO: sort this out if/when the vbo system is revised + return SwitchExtension->iPoints * ((TextureID1 ? 1 : 0) + (TextureID2 ? 12 : 0)); + } + else { + // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być + // NOTE: for the road part 1x the point amount would be enough, but we provide extra padding + // on account of unexamined issues with geometry data bleeding between vbo chunks + // TODO: sort this out if/when the vbo system is revised + return SwitchExtension->iPoints * ((TextureID1 ? 1 : 0) + (TextureID2 ? 6 : 0 )); } - else - return (Segment->RaSegCount()) * - ((TextureID1 ? 4 : 0) + - (TextureID2 ? (fTexWidth != 0.0 ? 6 : 0) + (fTexSlope != 0.0 ? 6 : 0) : - 0)); } else // standardowo dla zwykłej drogi if (fTexHeight1 >= 0) // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być @@ -2024,40 +1963,27 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) { // podsypka z podkładami jest tylko dla zwykłego toru vector6 bpts1[8]; // punkty głównej płaszczyzny nie przydają się do robienia boków if (fTexLength == 4.0) // jeśli stare mapowanie - { // stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy - // profil + { // stare mapowanie z różną gęstością pikseli i oddzielnymi teksturami na każdy profil if (iTrapezoid) // trapez albo przechyłki { // podsypka z podkladami trapezowata - // ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 - // ((0.3464,0.6536) + // ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 ((0.3464,0.6536) // bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, -0.707, 0.707, - 0.0); // lewy brzeg - bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.33, - -0.707, 0.707, 0.0); // krawędź załamania - bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.67, 0.707, - 0.707, 0.0); // prawy brzeg początku symetrycznie - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.00, 0.707, 0.707, - 0.0); // prawy skos + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, -0.707, 0.707, 0.0); // lewy brzeg + bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.33, -0.707, 0.707, 0.0); // krawędź załamania + bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.67, 0.707, 0.707, 0.0); // prawy brzeg początku symetrycznie + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.00, 0.707, 0.707, 0.0); // prawy skos // końcowy przekrój - bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.00, -0.707, 0.707, - 0.0); // lewy brzeg - bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, - 0.33, -0.707, 0.707, 0.0); // krawędź załamania - bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.67, 0.707, - 0.707, 0.0); // prawy brzeg początku symetrycznie - bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 1.00, 0.707, 0.707, - 0.0); // prawy skos + bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.00, -0.707, 0.707, 0.0); // lewy brzeg + bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, 0.33, -0.707, 0.707, 0.0); // krawędź załamania + bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.67, 0.707, 0.707, 0.0); // prawy brzeg początku symetrycznie + bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 1.00, 0.707, 0.707, 0.0); // prawy skos } else { - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.0, -0.707, 0.707, - 0.0); // lewy brzeg - bpts1[1] = vector6(fHTW + side, -0.18, 0.33, -0.707, 0.707, - 0.0); // krawędź załamania + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.0, -0.707, 0.707, 0.0); // lewy brzeg + bpts1[1] = vector6(fHTW + side, -0.18, 0.33, -0.707, 0.707, 0.0); // krawędź załamania bpts1[2] = vector6(-fHTW - side, -0.18, 0.67, 0.707, 0.707, 0.0); // druga - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.0, 0.707, 0.707, - 0.0); // prawy skos + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 1.0, 0.707, 0.707, 0.0); // prawy skos } } else @@ -2075,42 +2001,30 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) // ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 // ((0.3464,0.6536) // bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, normal1.x, - -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, - 0.5 - map11, 0.0, 1.0, 0.0); // krawędź załamania - bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.5 + map11, - 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, - -normal1.y, 0.0); // prawy skos + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, normal1.x, -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.5 - map11, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[2] = vector6(-bpts1[1].x, +(fHTW + side) * sin1 - 0.18, 0.5 + map11, 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos // przekrój końcowy - bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.5 - map22, normal2.x, - -normal2.y, 0.0); // lewy brzeg - bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, - 0.5 - map21, 0.0, 1.0, 0.0); // krawędź załamania - bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.5 + map21, - 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie - bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 0.5 + map22, -normal2.x, - -normal2.y, 0.0); // prawy skos + bpts1[4] = vector6(rozp2, -fTexHeight2 - 0.18, 0.5 - map22, normal2.x, -normal2.y, 0.0); // lewy brzeg + bpts1[5] = vector6((fHTW2 + side2) * cos2, -(fHTW2 + side2) * sin2 - 0.18, 0.5 - map21, 0.0, 1.0, 0.0); // krawędź załamania + bpts1[6] = vector6(-bpts1[5].x, +(fHTW2 + side2) * sin2 - 0.18, 0.5 + map21, 0.0, 1.0, 0.0); // prawy brzeg początku symetrycznie + bpts1[7] = vector6(-rozp2, -fTexHeight2 - 0.18, 0.5 + map22, -normal2.x, -normal2.y, 0.0); // prawy skos } else { - bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, +normal1.x, - -normal1.y, 0.0); // lewy brzeg - bpts1[1] = vector6(fHTW + side, -0.18, 0.5 - map11, +normal1.x, -normal1.y, - 0.0); // krawędź załamania - bpts1[2] = vector6(-fHTW - side, -0.18, 0.5 + map11, -normal1.x, -normal1.y, - 0.0); // druga - bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, - -normal1.y, 0.0); // prawy skos + bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.5 - map12, +normal1.x, -normal1.y, 0.0); // lewy brzeg + bpts1[1] = vector6(fHTW + side, -0.18, 0.5 - map11, +normal1.x, -normal1.y, 0.0); // krawędź załamania + bpts1[2] = vector6(-fHTW - side, -0.18, 0.5 + map11, -normal1.x, -normal1.y, 0.0); // druga + bpts1[3] = vector6(-rozp, -fTexHeight1 - 0.18, 0.5 + map12, -normal1.x, -normal1.y, 0.0); // prawy skos } } - Segment->RaRenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength); + Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -4 : 4, fTexLength); } if (TextureID1) { // szyny - generujemy dwie, najwyżej rysować się będzie jedną - Segment->RaRenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); - Segment->RaRenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft(Vert, rpts1, iTrapezoid ? -nnumPts : nnumPts, fTexLength); + Segment->RenderLoft(Vert, rpts2, iTrapezoid ? -nnumPts : nnumPts, fTexLength); } break; case tt_Switch: // dla zwrotnicy dwa razy szyny @@ -2135,35 +2049,26 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts3, -nnumPts, fTexLength, 0, - 2, SwitchExtension->fOffset2); - SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts1, nnumPts, fTexLength, 2); - SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts2, nnumPts, fTexLength); - SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts1, nnumPts, fTexLength); + SwitchExtension->Segments[0]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2); + SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2); + SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); + + SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength); SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts4, -nnumPts, fTexLength, 0, - 2, -fMaxOffset + - SwitchExtension->fOffset1); - SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts2, nnumPts, fTexLength, 2); + SwitchExtension->Segments[1]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1); + SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2); } else { // lewa działa lepiej niż prawa - SwitchExtension->Segments[0]->RaRenderLoft( - Vert, rpts1, nnumPts, fTexLength); // lewa szyna normalna cała + SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength); // lewa szyna normalna cała SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - SwitchExtension->Segments[0]->RaRenderLoft( - Vert, rpts4, -nnumPts, fTexLength, 0, 2, - -SwitchExtension->fOffset2); // prawa iglica - SwitchExtension->Segments[0]->RaRenderLoft(Vert, rpts2, nnumPts, fTexLength, - 2); // prawa szyna za iglicą + SwitchExtension->Segments[0]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2); // prawa iglica + SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2); // prawa szyna za iglicą + SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - SwitchExtension->Segments[1]->RaRenderLoft( - Vert, rpts3, -nnumPts, fTexLength, 0, 2, - fMaxOffset - SwitchExtension->fOffset1); // lewa iglica - SwitchExtension->Segments[1]->RaRenderLoft(Vert, rpts1, nnumPts, fTexLength, - 2); // lewa szyna za iglicą - SwitchExtension->Segments[1]->RaRenderLoft( - Vert, rpts2, nnumPts, fTexLength); // prawa szyna normalnie cała + SwitchExtension->Segments[1]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1); // lewa iglica + SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą + SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); // prawa szyna normalnie cała } } break; @@ -2178,136 +2083,312 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% - double max = (iCategoryFlag & 4) ? - 0.0 : - fTexLength; // test: szerokość dróg proporcjonalna do długości + double max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1 double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2 if (iTrapezoid) // trapez albo przechyłki { // nawierzchnia trapezowata Segment->GetRolls(roll1, roll2); - bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), - 0.5 - map1); // lewy brzeg początku - bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, - 0.5 + map1); // prawy brzeg początku symetrycznie - bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), - 0.5 - map2); // lewy brzeg końca - bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, - 0.5 + map2); // prawy brzeg początku symetrycznie + bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1); // lewy brzeg początku + bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1); // prawy brzeg początku symetrycznie + bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2); // lewy brzeg końca + bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2); // prawy brzeg początku symetrycznie } else { - bpts1[0] = vector6(fHTW, 0.0, 0.5 - map1); // zawsze standardowe mapowanie - bpts1[1] = vector6(-fHTW, 0.0, 0.5 + map1); + bpts1[ 0 ] = vector6( fHTW, 0.0, 0.5 - map1, 0.0, 1.0, 0.0 ); + bpts1[ 1 ] = vector6( -fHTW, 0.0, 0.5 + map1, 0.0, 1.0, 0.0 ); } } if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - Segment->RaRenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); } if (TextureID2) - { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w - // Midtown Madness 2?) - vector6 rpts1[6], + { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) + vector6 + rpts1[6], rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony if (fTexHeight1 >= 0.0) { // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy - rpts1[1] = - vector6(bpts1[0].x + side, bpts1[0].y, 0.5), // lewa krawędź załamania - rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, - 1.0); // lewy brzeg pobocza (mapowanie może być inne + rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5), // lewa krawędź załamania + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 1.0); // lewy brzeg pobocza (mapowanie może być inne rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza - rpts2[1] = - vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania + rpts2[1] = vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy if (iTrapezoid) // trapez albo przechyłki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony - // odcinka + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza - rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź - // załamania + rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź załamania rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); - rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego - // pobocza - Segment->RaRenderLoft(Vert, rpts1, -3, fTexLength); - Segment->RaRenderLoft(Vert, rpts2, -3, fTexLength); - } - else - { // pobocza zwykłe, brak przechyłki - Segment->RaRenderLoft(Vert, rpts1, 3, fTexLength); - Segment->RaRenderLoft(Vert, rpts2, 3, fTexLength); + rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza } } else { // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości // mapowanie propocjonalne do szerokości chodnika // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy - double d = - -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm - double max = - fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości + double d = -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm + double max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości + double map1l = ( + max > 0.0 ? + side / max : + 0.484375 ); // obcięcie tekstury od lewej strony punktu 1 + double map1r = ( + max > 0.0 ? + slop / max : + 0.484375 ); // obcięcie tekstury od prawej strony punktu 1 + double h1r = ( + slop > d ? + -fTexHeight1 : + 0 ); + double h1l = ( + side > d ? + -fTexHeight1 : + 0 ); + rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y + h1r, 0.515625 + map1r); // prawy brzeg prawego chodnika + rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y + h1r, 0.515625); // prawy krawężnik u góry + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y + h1l, 0.484375); // lewy krawężnik u góry + rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y + h1l, 0.484375 - map1l); // lewy brzeg lewego chodnika + if (iTrapezoid) // trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka + slop2 = ( + fabs((iTrapezoid & 2) ? + slop2 : + slop) ); // szerokość chodnika po prawej + double map2l = ( + max > 0.0 ? + side2 / max : + 0.484375 ); // obcięcie tekstury od lewej strony punktu 2 + double map2r = ( + max > 0.0 ? + slop2 / max : + 0.484375 ); // obcięcie tekstury od prawej strony punktu 2 + double h2r = (slop2 > d) ? -fTexHeight2 : 0; + double h2l = (side2 > d) ? -fTexHeight2 : 0; + rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y + h2r, 0.515625 + map2r); // prawy brzeg prawego chodnika + rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y + h2r, 0.515625); // prawy krawężnik u góry + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y + h2l, 0.484375); // lewy krawężnik u góry + rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y + h2l, 0.484375 - map2l); // lewy brzeg lewego chodnika + } + } + if( iTrapezoid ) // trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony + // odcinka + if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) + Segment->RenderLoft( Vert, rpts1, -3, fTexLength ); // tylko jeśli jest z prawej + if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) + Segment->RenderLoft( Vert, rpts2, -3, fTexLength ); // tylko jeśli jest z lewej + } + else { // pobocza zwykłe, brak przechyłki + if( ( fTexHeight1 >= 0.0 ) || ( slop != 0.0 ) ) + Segment->RenderLoft( Vert, rpts1, 3, fTexLength ); + if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) + Segment->RenderLoft( Vert, rpts2, 3, fTexLength ); + } + } + break; + } + case tt_Cross: // skrzyżowanie dróg rysujemy inaczej + { // ustalenie współrzędnych środka - przecięcie Point1-Point2 z CV4-Point4 + double a[4]; // kąty osi ulic wchodzących + vector3 p[4]; // punkty się przydadzą do obliczeń + // na razie połowa odległości pomiędzy Point1 i Point2, potem się dopracuje + a[0] = a[1] = 0.5; // parametr do poszukiwania przecięcia łuków + // modyfikować a[0] i a[1] tak, aby trafić na przecięcie odcinka 34 + p[0] = SwitchExtension->Segments[0]->FastGetPoint(a[0]); // współrzędne środka pierwszego odcinka + p[1] = SwitchExtension->Segments[1]->FastGetPoint(a[1]); //-//- drugiego + // p[2]=p[1]-p[0]; //jeśli różne od zera, przeliczyć a[0] i a[1] i wyznaczyć nowe punkty + vector3 oxz = p[0]; // punkt mapowania środka tekstury skrzyżowania + p[0] = SwitchExtension->Segments[0]->GetDirection1(); // Point1 - pobranie wektorów kontrolnych + p[1] = SwitchExtension->Segments[1]->GetDirection2(); // Point3 (bo zamienione) + p[2] = SwitchExtension->Segments[0]->GetDirection2(); // Point2 + p[3] = SwitchExtension->Segments[1]->GetDirection1(); // Point4 (bo zamienione) + a[0] = atan2(-p[0].x, p[0].z); // kąty stycznych osi dróg + a[1] = atan2(-p[1].x, p[1].z); + a[2] = atan2(-p[2].x, p[2].z); + a[3] = atan2(-p[3].x, p[3].z); + p[0] = SwitchExtension->Segments[0]->FastGetPoint_0(); // Point1 - pobranie współrzędnych końców + p[1] = SwitchExtension->Segments[1]->FastGetPoint_1(); // Point3 + p[2] = SwitchExtension->Segments[0]->FastGetPoint_1(); // Point2 + p[3] = SwitchExtension->Segments[1]->FastGetPoint_0(); // Point4 - przy trzech drogach pokrywa się z Point1 + // 2014-07: na początek rysować brzegi jak dla łuków + // punkty brzegu nawierzchni uzyskujemy podczas renderowania boków (bez sensu, ale najszybciej było zrobić) + int i; // ile punktów (może byc różna ilość punktów między drogami) + if (!SwitchExtension->vPoints) + { // jeśli tablica punktów nie jest jeszcze utworzona, zliczamy punkty i tworzymy ją + if( SwitchExtension->iRoads == 3 ) { + // mogą być tylko 3 drogi zamiast 4 + SwitchExtension->iPoints = + 5 + + SwitchExtension->Segments[ 0 ]->RaSegCount() + + SwitchExtension->Segments[ 1 ]->RaSegCount() + + SwitchExtension->Segments[ 2 ]->RaSegCount(); + } + else { + SwitchExtension->iPoints = + 5 + + SwitchExtension->Segments[ 2 ]->RaSegCount() + + SwitchExtension->Segments[ 3 ]->RaSegCount() + + SwitchExtension->Segments[ 4 ]->RaSegCount() + + SwitchExtension->Segments[ 5 ]->RaSegCount(); + } + // tablica utworzona z zapasem, ale nie wypełniona współrzędnymi + SwitchExtension->vPoints = new vector3[SwitchExtension->iPoints]; + } + vector3 *b = + SwitchExtension->bPoints ? + nullptr : + SwitchExtension->vPoints; // zmienna robocza, NULL gdy tablica punktów już jest wypełniona + vector6 bpts1[4]; // punkty głównej płaszczyzny przydają się do robienia boków + if (TextureID1 || TextureID2) // punkty się przydadzą, nawet jeśli nawierzchni nie ma + { // double max=2.0*(fHTW>fHTW2?fHTW:fHTW2); //z szerszej strony jest 100% + double max = fTexRatio1 * fTexLength; // test: szerokość proporcjonalna do długości + double map1 = max > 0.0 ? fHTW / max : 0.5; // obcięcie tekstury od strony 1 + double map2 = max > 0.0 ? fHTW2 / max : 0.5; // obcięcie tekstury od strony 2 + // if (iTrapezoid) //trapez albo przechyłki + { // nawierzchnia trapezowata + Segment->GetRolls(roll1, roll2); + bpts1[0] = vector6(fHTW * cos(roll1), -fHTW * sin(roll1), 0.5 - map1, sin(roll1), cos(roll1), 0.0); // lewy brzeg początku + bpts1[1] = vector6(-bpts1[0].x, -bpts1[0].y, 0.5 + map1, -sin(roll1), cos(roll1), 0.0); // prawy brzeg początku symetrycznie + bpts1[2] = vector6(fHTW2 * cos(roll2), -fHTW2 * sin(roll2), 0.5 - map2, sin(roll2), cos(roll2), 0.0); // lewy brzeg końca + bpts1[3] = vector6(-bpts1[2].x, -bpts1[2].y, 0.5 + map2, -sin(roll2), cos(roll2), 0.0); // prawy brzeg początku symetrycznie + } + } + // najpierw renderowanie poboczy i zapamiętywanie punktów + // problem ze skrzyżowaniami jest taki, że teren chce się pogrupować wg tekstur, ale zaczyna od nawierzchni + // sama nawierzchnia nie wypełni tablicy punktów, bo potrzebne są pobocza + // ale pobocza renderują się później, więc nawierzchnia nie załapuje się na renderowanie w swoim czasie + if( TextureID2 ) + { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w Midtown Madness 2?) + vector6 + rpts1[6], + rpts2[6]; // współrzędne przekroju i mapowania dla prawej i lewej strony + // Ra 2014-07: trzeba to przerobić na pętlę i pobierać profile (przynajmniej 2..4) z sąsiednich dróg + if (fTexHeight1 >= 0.0) + { // standardowo: od zewnątrz pochylenie, a od wewnątrz poziomo + rpts1[0] = vector6(rozp, -fTexHeight1, 0.0); // lewy brzeg podstawy + rpts1[1] = vector6(bpts1[0].x + side, bpts1[0].y, 0.5); // lewa krawędź załamania + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 1.0); // lewy brzeg pobocza (mapowanie może być inne + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 1.0); // prawy brzeg pobocza + rpts2[1] = vector6(bpts1[1].x - side, bpts1[1].y, 0.5); // prawa krawędź załamania + rpts2[2] = vector6(-rozp, -fTexHeight1, 0.0); // prawy brzeg podstawy + // if (iTrapezoid) //trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka + rpts1[3] = vector6(rozp2, -fTexHeight2, 0.0); // lewy brzeg lewego pobocza + rpts1[4] = vector6(bpts1[2].x + side2, bpts1[2].y, 0.5); // krawędź załamania + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 1.0); // brzeg pobocza + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); + rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); + rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza + } + } + else + { // wersja dla chodnika: skos 1:3.75, każdy chodnik innej szerokości + // mapowanie propocjonalne do szerokości chodnika + // krawężnik jest mapowany od 31/64 do 32/64 lewy i od 32/64 do 33/64 prawy + double d = -fTexHeight1 / 3.75; // krawężnik o wysokości 150mm jest pochylony 40mm + double max = fTexRatio2 * fTexLength; // test: szerokość proporcjonalna do długości double map1l = max > 0.0 ? side / max : 0.484375; // obcięcie tekstury od lewej strony punktu 1 double map1r = max > 0.0 ? slop / max : 0.484375; // obcięcie tekstury od prawej strony punktu 1 - double h1r = (slop > d) ? -fTexHeight1 : 0; - double h1l = (side > d) ? -fTexHeight1 : 0; - rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y + h1r, - 0.515625 + map1r); // prawy brzeg prawego chodnika - rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y + h1r, - 0.515625); // prawy krawężnik u góry - rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, - 0.515625 - d / 2.56); // prawy krawężnik u dołu - rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, - 0.484375 + d / 2.56); // lewy krawężnik u dołu - rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y + h1l, - 0.484375); // lewy krawężnik u góry - rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y + h1l, - 0.484375 - map1l); // lewy brzeg lewego chodnika - if (iTrapezoid) // trapez albo przechyłki - { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony - // odcinka - slop2 = - fabs((iTrapezoid & 2) ? slop2 : slop); // szerokość chodnika po prawej + rpts1[0] = vector6(bpts1[0].x + slop, bpts1[0].y - fTexHeight1, 0.515625 + map1r); // prawy brzeg prawego chodnika + rpts1[1] = vector6(bpts1[0].x + d, bpts1[0].y - fTexHeight1, 0.515625); // prawy krawężnik u góry + rpts1[2] = vector6(bpts1[0].x, bpts1[0].y, 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[0] = vector6(bpts1[1].x, bpts1[1].y, 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[1] = vector6(bpts1[1].x - d, bpts1[1].y - fTexHeight1, 0.484375); // lewy krawężnik u góry + rpts2[2] = vector6(bpts1[1].x - side, bpts1[1].y - fTexHeight1, 0.484375 - map1l); // lewy brzeg lewego chodnika + // if (iTrapezoid) //trapez albo przechyłki + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka + slop2 = std::fabs((iTrapezoid & 2) ? slop2 : slop); // szerokość chodnika po prawej double map2l = max > 0.0 ? side2 / max : 0.484375; // obcięcie tekstury od lewej strony punktu 2 double map2r = max > 0.0 ? slop2 / max : 0.484375; // obcięcie tekstury od prawej strony punktu 2 - double h2r = (slop2 > d) ? -fTexHeight2 : 0; - double h2l = (side2 > d) ? -fTexHeight2 : 0; - rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y + h2r, - 0.515625 + map2r); // prawy brzeg prawego chodnika - rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y + h2r, - 0.515625); // prawy krawężnik u góry - rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, - 0.515625 - d / 2.56); // prawy krawężnik u dołu - rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, - 0.484375 + d / 2.56); // lewy krawężnik u dołu - rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y + h2l, - 0.484375); // lewy krawężnik u góry - rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y + h2l, - 0.484375 - map2l); // lewy brzeg lewego chodnika - if (slop != 0.0) - Segment->RaRenderLoft(Vert, rpts1, -3, fTexLength); - if (side != 0.0) - Segment->RaRenderLoft(Vert, rpts2, -3, fTexLength); + rpts1[3] = vector6(bpts1[2].x + slop2, bpts1[2].y - fTexHeight2, 0.515625 + map2r); // prawy brzeg prawego chodnika + rpts1[4] = vector6(bpts1[2].x + d, bpts1[2].y - fTexHeight2, 0.515625); // prawy krawężnik u góry + rpts1[5] = vector6(bpts1[2].x, bpts1[2].y, 0.515625 - d / 2.56); // prawy krawężnik u dołu + rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 0.484375 + d / 2.56); // lewy krawężnik u dołu + rpts2[4] = vector6(bpts1[3].x - d, bpts1[3].y - fTexHeight2, 0.484375); // lewy krawężnik u góry + rpts2[5] = vector6(bpts1[3].x - side2, bpts1[3].y - fTexHeight2, 0.484375 - map2l); // lewy brzeg lewego chodnika } - else - { // pobocza zwykłe, brak przechyłki - if (slop != 0.0) - Segment->RaRenderLoft(Vert, rpts1, 3, fTexLength); - if (side != 0.0) - Segment->RaRenderLoft(Vert, rpts2, 3, fTexLength); + } + bool render = ( TextureID2 != 0 ); // renderować nie trzeba, ale trzeba wyznaczyć punkty brzegowe nawierzchni + // if (iTrapezoid) //trapez albo przechyłki + if (SwitchExtension->iRoads == 4) + { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka + if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { + SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 3 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 4 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + SwitchExtension->Segments[ 5 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); + } + } + else { + // punkt 3 pokrywa się z punktem 1, jak w zwrotnicy; połączenie 1->2 nie musi być prostoliniowe + if( ( fTexHeight1 >= 0.0 ) || ( side != 0.0 ) ) { + SwitchExtension->Segments[ 2 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P2 do P4 + SwitchExtension->Segments[ 1 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P4 do P3=P1 (odwrócony) + SwitchExtension->Segments[ 0 ]->RenderLoft( Vert, rpts2, -3, fTexLength, 1.0, 0, 0, 0.0, false, &b, render ); // z P1 do P2 } } } + // renderowanie nawierzchni na końcu + double sina0 = sin(a[0]), cosa0 = cos(a[0]); + double u, v; + if (!SwitchExtension->bPoints) // jeśli tablica nie wypełniona + if (b) // ale jest wskaźnik do tablicy - może nie być? + { // coś się gubi w obliczeniach na wskaźnikach + // ustalenie liczby punktów, bo mogło wyjść inaczej niż policzone z góry + i = (int)(((size_t)(b)) - ((size_t)(SwitchExtension->vPoints))) / sizeof(vector3); + if (i > 0) + { // jeśli zostało to właśnie utworzone + SwitchExtension->iPoints = std::min( SwitchExtension->iPoints - 2, i ); + SwitchExtension->vPoints[SwitchExtension->iPoints++] = SwitchExtension->vPoints[0]; + ++SwitchExtension->iPoints; // we'll add one extra point in the middle + SwitchExtension->bPoints = true; // tablica punktów została wypełniona + } + } + if (TextureID1) { + // jeśli podana tekstura nawierzchni + Vert->nx = 0.0; + Vert->ny = 1.0; + Vert->nz = 0.0; + Vert->u = 0.5; + Vert->v = 0.5; + Vert->x = oxz.x; + Vert->y = oxz.y; + Vert->z = oxz.z; + ++Vert; + for (i = SwitchExtension->iPoints - 2; i >= 0; --i) + { + Vert->nx = 0.0; + Vert->ny = 1.0; + Vert->nz = 0.0; + // mapowanie we współrzędnych scenerii + u = (SwitchExtension->vPoints[i].x - oxz.x) / fTexLength; + v = (SwitchExtension->vPoints[i].z - oxz.z) / (fTexRatio1 * fTexLength); + Vert->u = cosa0 * u + sina0 * v + 0.5; + Vert->v = -sina0 * u + cosa0 * v + 0.5; + Vert->x = SwitchExtension->vPoints[ i ].x; + Vert->y = SwitchExtension->vPoints[ i ].y; + Vert->z = SwitchExtension->vPoints[ i ].z; + ++Vert; + } + } + break; } } break; @@ -2344,7 +2425,7 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) } if (TextureID1) // jeśli podana była tekstura, generujemy trójkąty { // tworzenie trójkątów nawierzchni szosy - Segment->RaRenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); + Segment->RenderLoft(Vert, bpts1, iTrapezoid ? -2 : 2, fTexLength); } if (TextureID2) { // pobocze drogi - poziome przy przechyłce (a może krawężnik i chodnik zrobić jak w @@ -2366,13 +2447,13 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) rpts2[3] = vector6(bpts1[3].x, bpts1[3].y, 1.0); rpts2[4] = vector6(bpts1[3].x - side2, bpts1[3].y, 0.5); rpts2[5] = vector6(-rozp2, -fTexHeight2, 0.0); // prawy brzeg prawego pobocza - Segment->RaRenderLoft(Vert, rpts1, -3, fTexLength); - Segment->RaRenderLoft(Vert, rpts2, -3, fTexLength); + Segment->RenderLoft(Vert, rpts1, -3, fTexLength); + Segment->RenderLoft(Vert, rpts2, -3, fTexLength); } else { // pobocza zwykłe, brak przechyłki - Segment->RaRenderLoft(Vert, rpts1, 3, fTexLength); - Segment->RaRenderLoft(Vert, rpts2, 3, fTexLength); + Segment->RenderLoft(Vert, rpts1, 3, fTexLength); + Segment->RenderLoft(Vert, rpts2, 3, fTexLength); } } } @@ -2388,7 +2469,8 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO int seg; int i; switch( iCategoryFlag & 15 ) { - case 1: // tor + case 1: { + // tor if( eType == tt_Switch ) // dla zwrotnicy tylko szyny { if( TextureID1 ) @@ -2405,6 +2487,7 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); iPtr += 24 * seg; // pominięcie lewej szyny glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); + iPtr += 24 * seg; } } else // dla toru podsypka plus szyny @@ -2420,36 +2503,86 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); iPtr += 24 * seg; // pominięcie lewej szyny glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); + iPtr += 24 * seg; } } } break; - case 2: // droga - if( ( seg = Segment->RaSegCount() ) > 0 ) { - if( TextureID1 ) { - GfxRenderer.Bind( TextureID1 ); // nawierzchnia - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 4 * seg ); - iPtr += 4 * seg; - } - if( TextureID2 ) { - GfxRenderer.Bind( TextureID2 ); // pobocze - if( fTexHeight1 >= 0.0 ) { // normalna droga z poboczem - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); - iPtr += 6 * seg; // pominięcie lewego pobocza - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); + } + case 2: { + // droga + switch( eType ) { + case tt_Normal: { + if( ( seg = Segment->RaSegCount() ) > 0 ) { + if( TextureID1 ) { + GfxRenderer.Bind( TextureID1 ); // nawierzchnia + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 4 * seg ); + iPtr += 4 * seg; } - else { // z chodnikami o różnych szerokociach - if( fTexWidth != 0.0 ) { - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); + if( TextureID2 ) { + GfxRenderer.Bind( TextureID2 ); // pobocze + if( fTexHeight1 >= 0.0 ) { // normalna droga z poboczem + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); iPtr += 6 * seg; // pominięcie lewego pobocza + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); + iPtr += 6 * seg; + } + else { // z chodnikami o różnych szerokociach + if( fTexWidth != 0.0 ) { + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); + iPtr += 6 * seg; // pominięcie lewego pobocza + } + if( fTexSlope != 0.0 ) { + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); + iPtr += 6 * seg; + } } - if( fTexSlope != 0.0 ) - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); } } + break; } + case tt_Cross: { + if( (seg = SwitchExtension->iPoints) > 0 ) { + if( TextureID2 ) { + // sidewalks + GfxRenderer.Bind( TextureID2 ); + if( fTexHeight1 != 0.0 ) { + if( SwitchExtension->iRoads == 4 ) { + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 2 ]->RaSegCount() ); + iPtr += 6 * SwitchExtension->Segments[ 2 ]->RaSegCount(); + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 3 ]->RaSegCount() ); + iPtr += 6 * SwitchExtension->Segments[ 3 ]->RaSegCount(); + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 4 ]->RaSegCount() ); + iPtr += 6 * SwitchExtension->Segments[ 4 ]->RaSegCount(); + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 5 ]->RaSegCount() ); + iPtr += 6 * SwitchExtension->Segments[ 5 ]->RaSegCount(); + } + else { + // presumed 3 roads otherwise, as we only support 3 & 4 road crossings + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 2 ]->RaSegCount() ); + iPtr += 6 * SwitchExtension->Segments[ 2 ]->RaSegCount(); + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 1 ]->RaSegCount() ); + iPtr += 6 * SwitchExtension->Segments[ 1 ]->RaSegCount(); + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * SwitchExtension->Segments[ 0 ]->RaSegCount() ); + iPtr += 6 * SwitchExtension->Segments[ 0 ]->RaSegCount(); + } + } + } + if( TextureID1 ) { + // roads + GfxRenderer.Bind( TextureID1 ); + ::glDrawArrays( GL_TRIANGLE_FAN, iPtr, SwitchExtension->iPoints ); + iPtr += SwitchExtension->iPoints; + } + } + break; + } + default: { break; } + } //switch etype break; - case 4: // rzeki - jeszcze do przemyślenia + } + case 4: { + // rzeki - jeszcze do przemyślenia if( ( seg = Segment->RaSegCount() ) > 0 ) { if( TextureID1 ) { GfxRenderer.Bind( TextureID1 ); // nawierzchnia @@ -2461,9 +2594,11 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); iPtr += 6 * seg; // pominięcie lewego pobocza glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 6 * seg ); + iPtr += 6 * seg; } } break; + } } EnvironmentReset(); }; @@ -2821,17 +2956,25 @@ TTrack * TTrack::RaAnimate() for (int i = 0; i < 12; ++i) { rpts3[i] = - vector6((fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, - -(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, iglica[i].z); + vector6( + (fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, + -(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, + iglica[i].z); rpts3[i + 12] = - vector6((fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, - -(fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); - rpts4[11 - i] = vector6((-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, - -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, - iglica[i].z); + vector6( + (fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, + -(fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, + szyna[i].z); + rpts4[11 - i] = + vector6( + (-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, + -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, + iglica[i].z); rpts4[23 - i] = - vector6((-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, - -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, szyna[i].z); + vector6( + (-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, + -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, + szyna[i].z); } CVertNormTex Vert[2 * 2 * 12]; // na razie 2 segmenty CVertNormTex *v = Vert; // bo RaAnimate() modyfikuje wskaźnik @@ -2840,42 +2983,41 @@ TTrack * TTrack::RaAnimate() 2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // pobranie fragmentu bufora VBO if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa - SwitchExtension->Segments[0]->RaAnimate(v, rpts3, -nnumPts, fTexLength, 0, - 2, SwitchExtension->fOffset2); - glBufferSubData(GL_ARRAY_BUFFER, - SwitchExtension->iLeftVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), - &Vert); // wysłanie fragmentu bufora VBO + SwitchExtension->Segments[ 0 ]->RenderLoft( v, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2, true ); + ::glBufferSubData( + GL_ARRAY_BUFFER, + SwitchExtension->iLeftVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), + &Vert); // wysłanie fragmentu bufora VBO v = Vert; - glGetBufferSubData(GL_ARRAY_BUFFER, - SwitchExtension->iRightVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), - &Vert); // pobranie fragmentu bufora VBO - SwitchExtension->Segments[1]->RaAnimate(v, rpts4, -nnumPts, fTexLength, 0, - 2, -fMaxOffset + - SwitchExtension->fOffset1); + ::glGetBufferSubData( + GL_ARRAY_BUFFER, + SwitchExtension->iRightVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), + &Vert); // pobranie fragmentu bufora VBO + SwitchExtension->Segments[ 1 ]->RenderLoft( v, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1, true ); } else { // oryginalnie lewa działała lepiej niż prawa - SwitchExtension->Segments[0]->RaAnimate( - v, rpts4, -nnumPts, fTexLength, 0, 2, - -SwitchExtension->fOffset2); // prawa iglica - glBufferSubData(GL_ARRAY_BUFFER, - SwitchExtension->iLeftVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), - &Vert); // wysłanie fragmentu bufora VBO + SwitchExtension->Segments[ 0 ]->RenderLoft( v, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2, true ); // prawa iglica + ::glBufferSubData( + GL_ARRAY_BUFFER, + SwitchExtension->iLeftVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), + &Vert); // wysłanie fragmentu bufora VBO v = Vert; - glGetBufferSubData(GL_ARRAY_BUFFER, - SwitchExtension->iRightVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), - &Vert); // pobranie fragmentu bufora VBO - SwitchExtension->Segments[1]->RaAnimate( - v, rpts3, -nnumPts, fTexLength, 0, 2, - fMaxOffset - SwitchExtension->fOffset1); // lewa iglica + ::glGetBufferSubData( + GL_ARRAY_BUFFER, + SwitchExtension->iRightVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), + &Vert); // pobranie fragmentu bufora VBO + SwitchExtension->Segments[ 1 ]->RenderLoft( v, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1, true ); // lewa iglica } - glBufferSubData( - GL_ARRAY_BUFFER, SwitchExtension->iRightVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // wysłanie fragmentu bufora VBO + ::glBufferSubData( + GL_ARRAY_BUFFER, + SwitchExtension->iRightVBO * sizeof(CVertNormTex), + 2 * 2 * 12 * sizeof(CVertNormTex), + &Vert); // wysłanie fragmentu bufora VBO } } else // gdy Display List @@ -2919,14 +3061,10 @@ TTrack * TTrack::RaAnimate() // aktualizacja pojazdów na torze if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie { - int size = - RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy + int size = RaArrayPrepare(); // wielkość tabeli potrzebna dla tej obrotnicy CVertNormTex *Vert = new CVertNormTex[size]; // bufor roboczy // CVertNormTex *v=Vert; //zmieniane przez - RaArrayFill(Vert, - Vert - - SwitchExtension - ->iLeftVBO); // iLeftVBO powinno zostać niezmienione + RaArrayFill(Vert, Vert - SwitchExtension->iLeftVBO); // iLeftVBO powinno zostać niezmienione glBufferSubData( GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex), size * sizeof(CVertNormTex), Vert); // wysłanie fragmentu bufora VBO diff --git a/dumb3d.h b/dumb3d.h index 57de1f1b..818306d9 100644 --- a/dumb3d.h +++ b/dumb3d.h @@ -104,14 +104,8 @@ class vector3 return &x; } - // union - // { - // struct - // { double x, y, z; - // }; - // scalar_t e[3]; - // }; + bool inline Equal(vector3 *v) { // sprawdzenie odległości punktów if (std::fabs(x - v->x) > 0.02) diff --git a/renderer.cpp b/renderer.cpp index c3c7e85f..23150308 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -11,8 +11,11 @@ http://mozilla.org/MPL/2.0/. #include "renderer.h" #include "globals.h" +#include "timer.h" #include "world.h" #include "dynobj.h" +#include "animmodel.h" +#include "traction.h" #include "uilayer.h" #include "logs.h" #include "usefull.h" @@ -31,11 +34,11 @@ bool opengl_camera::visible( TDynamicObject const *Dynamic ) const { // sphere test is faster than AABB, so we'll use it here - float3 diagonal( - Dynamic->MoverParameters->Dim.L, - Dynamic->MoverParameters->Dim.H, - Dynamic->MoverParameters->Dim.W ); - float const radius = diagonal.Length() * 0.5f; + glm::vec3 diagonal( + static_cast( Dynamic->MoverParameters->Dim.L ), + static_cast( Dynamic->MoverParameters->Dim.H ), + static_cast( Dynamic->MoverParameters->Dim.W ) ); + float const radius = glm::length( diagonal ) * 0.5f; return ( m_frustum.sphere_inside( Dynamic->GetPosition(), radius ) > 0.0f ); } @@ -183,7 +186,7 @@ opengl_renderer::Render( world_environment *Environment ) { if( Global::fFogEnd > 0 ) { // fog setup ::glFogfv( GL_FOG_COLOR, Global::FogColor ); - ::glFogf( GL_FOG_DENSITY, 1.0f / Global::fFogEnd ); + ::glFogf( GL_FOG_DENSITY, static_cast( 1.0 / Global::fFogEnd ) ); ::glEnable( GL_FOG ); } else { ::glDisable( GL_FOG ); } @@ -236,7 +239,7 @@ opengl_renderer::Render( world_environment *Environment ) { { Bind( m_moontextureid ); float3 mooncolor( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ); - ::glColor4f( mooncolor.x, mooncolor.y, mooncolor.z, 1.0f - Global::fLuminance * 0.5f ); + ::glColor4f( mooncolor.x, mooncolor.y, mooncolor.z, static_cast( 1.0 - Global::fLuminance * 0.5 ) ); auto const moonvector = Environment->m_moon.getDirection(); auto const moonposition = modelview * glm::vec4( moonvector.x, moonvector.y, moonvector.z, 1.0f ); @@ -296,9 +299,9 @@ opengl_renderer::Render( TGround *Ground ) { glEnable( GL_LIGHTING ); glColor3f( 1.0f, 1.0f, 1.0f ); - float3 const cameraposition = float3( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z ); - int const camerax = std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2; - int const cameraz = std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2; + glm::vec3 const cameraposition( Global::pCameraPosition.x, Global::pCameraPosition.y, Global::pCameraPosition.z ); + int const camerax = static_cast( std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2 ); + int const cameraz = static_cast( std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2 ); int const segmentcount = 2 * static_cast(std::ceil( m_drawrange * Global::fDistanceFactor / 1000.0f )); int const originx = std::max( 0, camerax - segmentcount / 2 ); int const originz = std::max( 0, cameraz - segmentcount / 2 ); @@ -317,15 +320,133 @@ opengl_renderer::Render( TGround *Ground ) { } bool -opengl_renderer::Render( TDynamicObject *Dynamic ) { +opengl_renderer::Render( TGroundNode *Node ) { - if( false == m_camera.visible( Dynamic ) ) { + Node->SetLastUsage( Timer::GetSimulationTime() ); - Dynamic->renderme = false; + switch (Node->iType) + { // obiekty renderowane niezależnie od odległości + case TP_SUBMODEL: + TSubModel::fSquareDist = 0; + Render( Node->smTerrain ); + return true; + } + + double const distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ); + if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) ) + || ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) { return false; } - Dynamic->renderme = true; + switch (Node->iType) + { + case TP_TRACK: { + // TODO: unify the render code after generic buffers are in place + if( Global::bUseVBO ) { + if( Node->iNumVerts ) { + Node->pTrack->RaRenderVBO( Node->iVboPtr ); + } + else { + return false; + } + } + else { + Node->pTrack->Render(); + } + return true; + } + case TP_MODEL: { + Node->Model->Render( &Node->pCenter ); + return true; + } + case TP_MEMCELL: { + GfxRenderer.Render( Node->MemCell ); + return true; + } + } + + // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 + if( ( Node->iFlags & 0x10 ) + || ( Node->fLineThickness < 0 ) ) { + // TODO: unify the render code after generic buffers are in place + if( false == Global::bUseVBO ) { + // additional setup for display lists + if( ( Node->DisplayListID == 0 ) + || ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji + Node->Compile(); + if( Global::bManageNodes ) + ResourceManager::Register( Node ); + }; + } + + if( ( Node->iType == GL_LINES ) + || ( Node->iType == GL_LINE_STRIP ) + || ( Node->iType == GL_LINE_LOOP ) ) { + // wszelkie linie są rysowane na samym końcu + if( Node->iNumPts ) { + // setup + // w zaleznosci od koloru swiatla + ::glColor4ub( + static_cast( std::floor( Node->Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ) ), + static_cast( std::floor( Node->Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ] ) ), + static_cast( std::floor( Node->Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ] ) ), + static_cast( std::min( 255.0, 255000 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ); + + GfxRenderer.Bind( 0 ); + + // render + // TODO: unify the render code after generic buffers are in place + if( Global::bUseVBO ) { + ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumPts ); + } + else { + ::glCallList( Node->DisplayListID ); + } + return true; + } + else { + return false; + } + } + else { + // GL_TRIANGLE etc + // setup + ::glColor3ub( + static_cast( Node->Diffuse[ 0 ] ), + static_cast( Node->Diffuse[ 1 ] ), + static_cast( Node->Diffuse[ 2 ] ) ); + + Bind( Node->TextureID ); + + // render + // TODO: unify the render code after generic buffers are in place + if( Global::bUseVBO ) { + // vbo render path + if( Node->iVboPtr >= 0 ) { + ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts ); + } + else { + return false; + } + } + else { + // display list render path + ::glCallList( Node->DisplayListID ); + } + return true; + } + } + // in theory we shouldn't ever get here but, eh + return false; +} + +bool +opengl_renderer::Render( TDynamicObject *Dynamic ) { + + Dynamic->renderme = m_camera.visible( Dynamic ); + if( false == Dynamic->renderme ) { + return false; + } // setup TSubModel::iInstance = ( size_t )this; //żeby nie robić cudzych animacji @@ -517,7 +638,7 @@ opengl_renderer::Render( TSubModel *Submodel ) { float const anglefactor = ( Submodel->fCosViewAngle - Submodel->fCosFalloffAngle ) / ( 1.0f - Submodel->fCosFalloffAngle ); // distance attenuation. NOTE: since it's fixed pipeline with built-in gamma correction we're using linear attenuation // we're capping how much effect the distance attenuation can have, otherwise the lights get too tiny at regular distances - float const distancefactor = std::max( 0.5, ( Submodel->fSquareMaxDist - TSubModel::fSquareDist ) / ( Submodel->fSquareMaxDist * Global::fDistanceFactor ) ); + float const distancefactor = static_cast( std::max( 0.5, ( Submodel->fSquareMaxDist - TSubModel::fSquareDist ) / ( Submodel->fSquareMaxDist * Global::fDistanceFactor ) ) ); if( lightlevel > 0.0f ) { // material configuration: @@ -609,6 +730,146 @@ opengl_renderer::Render( TMemCell *Memcell ) { ::glPopAttrib(); } +// NOTE: legacy render system switch +#define _PROBLEND + +bool +opengl_renderer::Render_Alpha( TGroundNode *Node ) { + + // SPOSOB NA POZBYCIE SIE RAMKI DOOKOLA TEXTURY ALPHA DLA OBIEKTOW ZAGNIEZDZONYCH W SCN JAKO + // NODE + + // W GROUND.H dajemy do klasy TGroundNode zmienna bool PROBLEND to samo robimy w klasie TGround + // nastepnie podczas wczytywania textury dla TRIANGLES w TGround::AddGroundNode + // sprawdzamy czy w nazwie jest @ i wg tego + // ustawiamy PROBLEND na true dla wlasnie wczytywanego trojkata (kazdy trojkat jest osobnym + // nodem) + // nastepnie podczas renderowania w bool TGroundNode::RenderAlpha() + // na poczatku ustawiamy standardowe GL_GREATER = 0.04 + // pozniej sprawdzamy czy jest wlaczony PROBLEND dla aktualnie renderowanego noda TRIANGLE, + // wlasciwie dla kazdego node'a + // i jezeli tak to odpowiedni GL_GREATER w przeciwnym wypadku standardowy 0.04 + + Node->SetLastUsage( Timer::GetSimulationTime() ); + + double const distancesquared = SquareMagnitude( ( Node->pCenter - Global::pCameraPosition ) / Global::ZoomFactor ); + if( ( distancesquared > ( Node->fSquareRadius * Global::fDistanceFactor ) ) + || ( distancesquared < ( Node->fSquareMinRadius / Global::fDistanceFactor ) ) ) { + return false; + } + + switch (Node->iType) + { + case TP_TRACTION: { + // TODO: unify the render code after generic buffers are in place + if( Node->bVisible ) { + if( Global::bUseVBO ) { + Node->hvTraction->RenderVBO( distancesquared, Node->iVboPtr ); + } + else { + Node->hvTraction->RenderDL( distancesquared ); + } + return true; + } + else { + return false; + } + } + case TP_MODEL: { + Node->Model->RenderAlpha( &Node->pCenter ); + return true; + } + } + + // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 + if( ( Node->iNumVerts && ( Node->iFlags & 0x20 ) ) + || ( Node->iNumPts && ( Node->fLineThickness > 0 ) ) ) { + +#ifdef _PROBLEND + if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 + { + ::glDisable( GL_BLEND ); + ::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + }; +#endif + // TODO: unify the render code after generic buffers are in place + if( false == Global::bUseVBO ) { + // additional setup for display lists + if( ( Node->DisplayListID == 0 ) + || ( Node->iVersion != Global::iReCompile ) ) { // Ra: wymuszenie rekompilacji + Node->Compile(); + if( Global::bManageNodes ) + ResourceManager::Register( Node ); + }; + } + + bool result( false ); + + if( ( Node->iType == GL_LINES ) + || ( Node->iType == GL_LINE_STRIP ) + || ( Node->iType == GL_LINE_LOOP ) ) { + // wszelkie linie są rysowane na samym końcu + if( Node->iNumPts ) { + // setup + // w zaleznosci od koloru swiatla + ::glColor4ub( + static_cast( std::floor( Node->Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ) ), + static_cast( std::floor( Node->Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ] ) ), + static_cast( std::floor( Node->Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ] ) ), + static_cast( std::min( 255.0, 255000 * Node->fLineThickness / ( distancesquared + 1.0 ) ) ) ); + + GfxRenderer.Bind( 0 ); + + // render + // TODO: unify the render code after generic buffers are in place + if( Global::bUseVBO ) { + ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumPts ); + } + else { + ::glCallList( Node->DisplayListID ); + } + result = true; + } + } + else { + // GL_TRIANGLE etc + // setup + ::glColor3ub( + static_cast( Node->Diffuse[ 0 ] ), + static_cast( Node->Diffuse[ 1 ] ), + static_cast( Node->Diffuse[ 2 ] ) ); + + Bind( Node->TextureID ); + + // render + // TODO: unify the render code after generic buffers are in place + if( Global::bUseVBO ) { + // vbo render path + if( Node->iVboPtr >= 0 ) { + ::glDrawArrays( Node->iType, Node->iVboPtr, Node->iNumVerts ); + result = true; + } + } + else { + // display list render path + ::glCallList( Node->DisplayListID ); + result = true; + } + } + // post-render cleanup +#ifdef _PROBLEND + if( ( Node->PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 + { + ::glEnable( GL_BLEND ); + ::glAlphaFunc( GL_GREATER, 0.04f ); + } +#endif + return result; + } + // in theory we shouldn't ever get here but, eh + return false; +} + bool opengl_renderer::Render_Alpha( TDynamicObject *Dynamic ) { @@ -978,12 +1239,12 @@ opengl_renderer::Update_Lights( light_array const &Lights ) { if( environment > 0.0f ) { luminance *= environment; } - renderlight->diffuse[ 0 ] = std::max( 0.0, scenelight.color.x - luminance ); - renderlight->diffuse[ 1 ] = std::max( 0.0, scenelight.color.y - luminance ); - renderlight->diffuse[ 2 ] = std::max( 0.0, scenelight.color.z - luminance ); - renderlight->ambient[ 0 ] = std::max( 0.0, scenelight.color.x * scenelight.intensity - luminance); - renderlight->ambient[ 1 ] = std::max( 0.0, scenelight.color.y * scenelight.intensity - luminance ); - renderlight->ambient[ 2 ] = std::max( 0.0, scenelight.color.z * scenelight.intensity - luminance ); + renderlight->diffuse[ 0 ] = static_cast( std::max( 0.0, scenelight.color.x - luminance ) ); + renderlight->diffuse[ 1 ] = static_cast( std::max( 0.0, scenelight.color.y - luminance ) ); + renderlight->diffuse[ 2 ] = static_cast( std::max( 0.0, scenelight.color.z - luminance ) ); + renderlight->ambient[ 0 ] = static_cast( std::max( 0.0, scenelight.color.x * scenelight.intensity - luminance) ); + renderlight->ambient[ 1 ] = static_cast( std::max( 0.0, scenelight.color.y * scenelight.intensity - luminance ) ); + renderlight->ambient[ 2 ] = static_cast( std::max( 0.0, scenelight.color.z * scenelight.intensity - luminance ) ); /* // NOTE: we have no simple way to determine whether the lights are falling on objects located in darker environment // until this issue is resolved we're disabling reduction of light strenght based on the global luminance @@ -994,7 +1255,7 @@ opengl_renderer::Update_Lights( light_array const &Lights ) { renderlight->ambient[ 1 ] = std::max( 0.0f, scenelight.color.y * scenelight.intensity ); renderlight->ambient[ 2 ] = std::max( 0.0f, scenelight.color.z * scenelight.intensity ); */ - ::glLightf( renderlight->id, GL_LINEAR_ATTENUATION, (0.25f * scenelight.count) / std::pow( scenelight.count, 2 ) * (scenelight.owner->DimHeadlights ? 1.25f : 1.0f) ); + ::glLightf( renderlight->id, GL_LINEAR_ATTENUATION, static_cast( (0.25 * scenelight.count) / std::pow( scenelight.count, 2 ) * (scenelight.owner->DimHeadlights ? 1.25 : 1.0) ) ); ::glEnable( renderlight->id ); renderlight->apply_intensity(); diff --git a/renderer.h b/renderer.h index 7f779308..d14f2995 100644 --- a/renderer.h +++ b/renderer.h @@ -124,6 +124,8 @@ public: Render( world_environment *Environment ); bool Render( TGround *Ground ); + bool + Render( TGroundNode *Node ); bool Render( TDynamicObject *Dynamic ); bool @@ -134,6 +136,8 @@ public: Render( TSubModel *Submodel ); void Render( TMemCell *Memcell ); + bool + Render_Alpha( TGroundNode *Node ); bool Render_Alpha( TDynamicObject *Dynamic ); bool From 98d99baa82c6caa77afe243cf3ab9c949451f60d Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 13 May 2017 17:11:35 +0200 Subject: [PATCH 2/5] build 170513. fix for switch animation for vbo render path. opengl requirement experimentally increased to 1.5+ --- Ground.cpp | 28 +++-- Track.cpp | 284 ++++++++++++++------------------------------------- Track.h | 2 +- renderer.cpp | 4 +- 4 files changed, 100 insertions(+), 218 deletions(-) diff --git a/Ground.cpp b/Ground.cpp index e8d6a2dc..a8b74537 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -1004,16 +1004,26 @@ bool TSubRect::RaTrackAnimAdd(TTrack *t) void TSubRect::RaAnimate() { // wykonanie animacji - if (!tTrackAnim) - return; // nie ma nic do animowania - if (Global::bUseVBO) - { // odświeżenie VBO sektora - if (GLEW_VERSION_1_5) // modyfikacje VBO są dostępne od OpenGL 1.5 - glBindBuffer(GL_ARRAY_BUFFER, m_nVBOVertices); - else // dla OpenGL 1.4 z GL_ARB_vertex_buffer_object odświeżenie całego sektora - Release(); // opróżnienie VBO sektora, aby się odświeżył z nowymi ustawieniami + if( !tTrackAnim ) { + // nie ma nic do animowania + return; } - tTrackAnim = tTrackAnim->RaAnimate(); // przeliczenie animacji kolejnego + // crude way to mark whether a vbo is bound, for the vbo render path + // TODO: sort this shit out and re-arrange into something more elegant... eventually + GLuint vertexbuffer{ static_cast(-1) }; + if (Global::bUseVBO) { + // odświeżenie VBO sektora + if( GLEW_VERSION_1_5 ) { + // modyfikacje VBO są dostępne od OpenGL 1.5 + vertexbuffer = m_nVBOVertices; + ::glBindBuffer( GL_ARRAY_BUFFER, vertexbuffer ); + } + else { + // dla OpenGL 1.4 z GL_ARB_vertex_buffer_object odświeżenie całego sektora + Release(); // opróżnienie VBO sektora, aby się odświeżył z nowymi ustawieniami + } + } + tTrackAnim = tTrackAnim->RaAnimate( vertexbuffer ); // przeliczenie animacji kolejnego }; TTraction * TSubRect::FindTraction(vector3 *Point, int &iConnection, TTraction *Exclude) diff --git a/Track.cpp b/Track.cpp index 2335248c..9769f613 100644 --- a/Track.cpp +++ b/Track.cpp @@ -454,16 +454,9 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) WriteLog(str); parser->getTokens(4); *parser >> fTrackLength >> fTrackWidth >> fFriction >> fSoundDistance; - // fTrackLength=Parser->GetNextSymbol().ToDouble(); //track length - // 100502 - // fTrackWidth=Parser->GetNextSymbol().ToDouble(); //track width - // fFriction=Parser->GetNextSymbol().ToDouble(); //friction coeff. - // fSoundDistance=Parser->GetNextSymbol().ToDouble(); //snd fTrackWidth2 = fTrackWidth; // rozstaw/szerokość w punkcie 2, na razie taka sama parser->getTokens(2); *parser >> iQualityFlag >> iDamageFlag; - // iQualityFlag=Parser->GetNextSymbol().ToInt(); //McZapkie: qualityflag - // iDamageFlag=Parser->GetNextSymbol().ToInt(); //damage if (iDamageFlag & 128) iAction |= 0x80; // flaga wykolejania z powodu uszkodzenia parser->getTokens(); @@ -511,9 +504,6 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) Global::iRailProFiltering)); parser->getTokens(3); *parser >> fTexHeight1 >> fTexWidth >> fTexSlope; - // fTexHeight=Parser->GetNextSymbol().ToDouble(); //tex sub height - // fTexWidth=Parser->GetNextSymbol().ToDouble(); //tex sub width - // fTexSlope=Parser->GetNextSymbol().ToDouble(); //tex sub slope width if (iCategoryFlag & 4) fTexHeight1 = -fTexHeight1; // rzeki mają wysokość odwrotnie niż drogi } @@ -767,8 +757,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) // nFouling[1]= } else if (str == "overhead") - { // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem - // prędkości + { // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem prędkości parser->getTokens(); *parser >> fOverhead; if (fOverhead > 0.0) @@ -776,8 +765,7 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) // ograniczenie dla pantografujących) } else if (str == "colides") - { // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem - // prędkości + { // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem prędkości parser->getTokens(); *parser >> token; // trColides=; //tor kolizyjny, na którym trzeba sprawdzać pojazdy pod kątem zderzenia @@ -821,8 +809,7 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent } else { - ErrorLog( - "Bad track: Event0 cannot be assigned to track, track already has one"); + ErrorLog( "Bad track: Event0 cannot be assigned to track, track already has one"); bError = true; } if (!evEvent1) @@ -835,15 +822,13 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent } else if (!asEvent1Name.empty()) { // Ra: tylko w logu informacja - ErrorLog("Bad track: Event1 \"" + asEvent1Name + - "\" does not exist"); + ErrorLog("Bad track: Event1 \"" + asEvent1Name + "\" does not exist"); bError = true; } } else { - ErrorLog( - "Bad track: Event1 cannot be assigned to track, track already has one"); + ErrorLog("Bad track: Event1 cannot be assigned to track, track already has one"); bError = true; } if (!evEvent2) @@ -856,15 +841,13 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent } else if (!asEvent2Name.empty()) { // Ra: tylko w logu informacja - ErrorLog("Bad track: Event2 \"" + asEvent2Name + - "\" does not exist"); + ErrorLog("Bad track: Event2 \"" + asEvent2Name + "\" does not exist"); bError = true; } } else { - ErrorLog( - "Bad track: Event2 cannot be assigned to track, track already has one"); + ErrorLog("Bad track: Event2 cannot be assigned to track, track already has one"); bError = true; } return !bError; @@ -908,8 +891,7 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv { if (!asEvent0Name.empty()) { // Ra: tylko w logu informacja - WriteLog("Eventall1 \"" + asEventall1Name + - "\" does not exist"); + WriteLog("Eventall1 \"" + asEventall1Name + "\" does not exist"); bError = true; } } @@ -1026,23 +1008,7 @@ void TTrack::MoveMe(vector3 pPosition) const int numPts = 4; const int nnumPts = 12; -/* -const vector6 szyna[nnumPts]= //szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn) -{pierwotna szyna, opracował youBy, zmiany w celu uzyskania symetrii - vector6( 0.111,-0.180,0.00, 1.000, 0.000,0.000), - vector6( 0.045,-0.155,0.15, 0.707, 0.707,0.000), - vector6( 0.045,-0.070,0.25, 0.707,-0.707,0.000), - vector6( 0.071,-0.040,0.35, 0.707,-0.707,0.000), //albo tu 0.073 - vector6( 0.072,-0.010,0.40, 0.707, 0.707,0.000), - vector6( 0.052,-0.000,0.45, 0.000, 1.000,0.000), - vector6( 0.020,-0.000,0.55, 0.000, 1.000,0.000), - vector6( 0.000,-0.010,0.60,-0.707, 0.707,0.000), - vector6( 0.001,-0.040,0.65,-0.707,-0.707,0.000), //albo tu -0.001 - vector6( 0.027,-0.070,0.75,-0.707,-0.707,0.000), //albo zostanie asymetryczna - vector6( 0.027,-0.155,0.85,-0.707, 0.707,0.000), - vector6(-0.039,-0.180,1.00,-1.000, 0.000,0.000) -}; -*/ + const vector6 szyna[nnumPts] = // szyna - vextor6(x,y,mapowanie tekstury,xn,yn,zn) { // tę wersję opracował Tolein (bez pochylenia) vector6(0.111, -0.180, 0.00, 1.000, 0.000, 0.000), @@ -1188,8 +1154,7 @@ void TTrack::Compile(GLuint tex) // profil if (iTrapezoid) // trapez albo przechyłki { // podsypka z podkladami trapezowata - // ewentualnie poprawić mapowanie, żeby środek mapował się na - // 1.435/4.671 ((0.3464,0.6536) + // ewentualnie poprawić mapowanie, żeby środek mapował się na 1.435/4.671 ((0.3464,0.6536) // bo się tekstury podsypki rozjeżdżają po zmianie proporcji profilu bpts1[0] = vector6(rozp, -fTexHeight1 - 0.18, 0.00, normal1.x, -normal1.y, 0.0); // lewy brzeg bpts1[1] = vector6((fHTW + side) * cos1, -(fHTW + side) * sin1 - 0.18, 0.33, 0.0, 1.0, 0.0); // krawędź załamania @@ -1575,8 +1540,7 @@ void TTrack::Compile(GLuint tex) tex ? TextureID2 == tex : true ) : - false ); // renderować nie trzeba, ale trzeba wyznaczyć - // punkty brzegowe nawierzchni + false ); // renderować nie trzeba, ale trzeba wyznaczyć punkty brzegowe nawierzchni // if (iTrapezoid) //trapez albo przechyłki if (SwitchExtension->iRoads == 4) { // pobocza do trapezowatej nawierzchni - dodatkowe punkty z drugiej strony odcinka @@ -1703,33 +1667,7 @@ void TTrack::Render() EnvironmentReset(); // ustawienie oświetlenia na zwykłe if (InMovement()) Release(); // zwrotnica w trakcie animacji do odrysowania - }; -//#ifdef _DEBUG -#if 0 - if (DebugModeFlag && ScannedFlag) //McZapkie-230702 - //if (iNumDynamics) //będzie kreska na zajętym torze - { - vector3 pos1,pos2,pos3; - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glColor3ub(255,0,0); - glBindTexture(GL_TEXTURE_2D,0); - glBegin(GL_LINE_STRIP); - pos1=Segment->FastGetPoint_0(); - pos2=Segment->FastGetPoint(0.5); - pos3=Segment->FastGetPoint_1(); - glVertex3f(pos1.x,pos1.y,pos1.z); - glVertex3f(pos2.x,pos2.y+10,pos2.z); - glVertex3f(pos3.x,pos3.y,pos3.z); - glEnd(); - glEnable(GL_LIGHTING); - glEnable(GL_DEPTH_TEST); - ScannedFlag=false; - } -#endif - // glLightfv(GL_LIGHT0,GL_AMBIENT,Global::ambientDayLight); - // glLightfv(GL_LIGHT0,GL_DIFFUSE,Global::diffuseDayLight); - // glLightfv(GL_LIGHT0,GL_SPECULAR,Global::specularDayLight); + } }; bool TTrack::CheckDynamicObject(TDynamicObject *Dynamic) @@ -1856,16 +1794,10 @@ int TTrack::RaArrayPrepare() } if (fTexHeight1 >= 0) { // normalne pobocze, na razie się składa z - // NOTE: for the road part 1x the point amount would be enough, but we provide extra padding - // on account of unexamined issues with geometry data bleeding between vbo chunks - // TODO: sort this out if/when the vbo system is revised return SwitchExtension->iPoints * ((TextureID1 ? 1 : 0) + (TextureID2 ? 12 : 0)); } else { // jeśli fTexHeight1<0, to są chodniki i może któregoś nie być - // NOTE: for the road part 1x the point amount would be enough, but we provide extra padding - // on account of unexamined issues with geometry data bleeding between vbo chunks - // TODO: sort this out if/when the vbo system is revised return SwitchExtension->iPoints * ((TextureID1 ? 1 : 0) + (TextureID2 ? 6 : 0 )); } } @@ -2048,23 +1980,23 @@ void TTrack::RaArrayFill(CVertNormTex *Vert, const CVertNormTex *Start) } if (SwitchExtension->RightSwitch) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa - SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy - SwitchExtension->Segments[0]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2); - SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2); SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength); + SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2 ); + SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy + SwitchExtension->Segments[0]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); - SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength); SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy - SwitchExtension->Segments[1]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1); - SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2); + SwitchExtension->Segments[1]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); + SwitchExtension->Segments[1]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); + SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength ); } else { // lewa działa lepiej niż prawa SwitchExtension->Segments[0]->RenderLoft( Vert, rpts1, nnumPts, fTexLength); // lewa szyna normalna cała + SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą SwitchExtension->iLeftVBO = Vert - Start; // indeks lewej iglicy SwitchExtension->Segments[0]->RenderLoft( Vert, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2); // prawa iglica - SwitchExtension->Segments[0]->RenderLoft( Vert, rpts2, nnumPts, fTexLength, 1.0, 2); // prawa szyna za iglicą - + SwitchExtension->iRightVBO = Vert - Start; // indeks prawej iglicy SwitchExtension->Segments[1]->RenderLoft( Vert, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1); // lewa iglica SwitchExtension->Segments[1]->RenderLoft( Vert, rpts1, nnumPts, fTexLength, 1.0, 2); // lewa szyna za iglicą @@ -2467,26 +2399,36 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO // dla kolejnych tekstur! EnvironmentSet(); int seg; - int i; switch( iCategoryFlag & 15 ) { case 1: { // tor if( eType == tt_Switch ) // dla zwrotnicy tylko szyny { + int const bladesegmentcount = 2; if( TextureID1 ) if( ( seg = SwitchExtension->Segments[ 0 ]->RaSegCount() ) > 0 ) { GfxRenderer.Bind( TextureID1 ); // szyny + - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); - iPtr += 24 * seg; // pominięcie lewej szyny - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); - iPtr += 24 * seg; // pominięcie prawej szyny + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); + iPtr += 24 * seg; + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * (seg - bladesegmentcount) ); + // NOTE: due to way blades bend need to render each segment separately, or some unwanted edges may show + iPtr += 24 * ( seg - bladesegmentcount ); + for( int i = 0; i < bladesegmentcount; ++i ) { + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 ); + iPtr += 24; + } } if( TextureID2 ) if( ( seg = SwitchExtension->Segments[ 1 ]->RaSegCount() ) > 0 ) { - GfxRenderer.Bind( TextureID2 ); // szyny - - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); - iPtr += 24 * seg; // pominięcie lewej szyny - glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); + GfxRenderer.Bind( TextureID2 ); + // NOTE: due to way blades bend need to render each segment separately, or some unwanted edges may show + for( int i = 0; i < bladesegmentcount; ++i ) { + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 ); + iPtr += 24; + } + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * ( seg - bladesegmentcount ) ); + iPtr += 24 * ( seg - bladesegmentcount ); + ::glDrawArrays( GL_TRIANGLE_STRIP, iPtr, 24 * seg ); iPtr += 24 * seg; } } @@ -2606,40 +2548,6 @@ void TTrack::RaRenderVBO( int iPtr ) { // renderowanie z użyciem VBO void TTrack::EnvironmentSet() { // ustawienie zmienionego światła glColor3f(1.0f, 1.0f, 1.0f); // Ra: potrzebne to? -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO: re-implement this - if (eEnvironment) - { // McZapkie-310702: zmiana oswietlenia w tunelu, wykopie - GLfloat ambientLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - GLfloat diffuseLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - GLfloat specularLight[4] = {0.5f, 0.5f, 0.5f, 1.0f}; - switch (eEnvironment) - { // modyfikacje oświetlenia zależnie od środowiska - case e_canyon: - for (int li = 0; li < 3; li++) - { - // ambientLight[li]= Global::ambientDayLight[li]*0.8; //0.7 - diffuseLight[li] = Global::diffuseDayLight[li] * 0.4; // 0.3 - specularLight[li] = Global::specularDayLight[li] * 0.5; // 0.4 - } - // glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); - break; - case e_tunnel: - for (int li = 0; li < 3; li++) - { - ambientLight[li] = Global::ambientDayLight[li] * 0.2; - diffuseLight[li] = Global::diffuseDayLight[li] * 0.1; - specularLight[li] = Global::specularDayLight[li] * 0.2; - } - glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); - break; - } - } -#else switch( eEnvironment ) { case e_canyon: { Global::DayLight.apply_intensity( 0.4f ); @@ -2653,22 +2561,10 @@ void TTrack::EnvironmentSet() break; } } -#endif }; void TTrack::EnvironmentReset() { // przywrócenie domyślnego światła -#ifdef EU07_USE_OLD_LIGHTING_MODEL - // TODO: re-implement this - switch (eEnvironment) - { // przywrócenie globalnych ustawień światła, o ile było zmienione - case e_canyon: // wykop - case e_tunnel: // tunel - glLightfv(GL_LIGHT0, GL_AMBIENT, Global::ambientDayLight); - glLightfv(GL_LIGHT0, GL_DIFFUSE, Global::diffuseDayLight); - glLightfv(GL_LIGHT0, GL_SPECULAR, Global::specularDayLight); - } -#else switch( eEnvironment ) { case e_canyon: case e_tunnel: { @@ -2679,7 +2575,6 @@ void TTrack::EnvironmentReset() break; } } -#endif }; void TTrack::RenderDyn() @@ -2911,7 +2806,7 @@ void TTrack::RaAnimListAdd(TTrack *t) } }; -TTrack * TTrack::RaAnimate() +TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) { // wykonanie rekurencyjne animacji, wywoływane przed wyświetleniem sektora // zwraca wskaźnik toru wymagającego dalszej animacji if (SwitchExtension->pNextAnim) @@ -2944,7 +2839,8 @@ TTrack * TTrack::RaAnimate() m = false; // koniec animacji } } - if (Global::bUseVBO) + if( ( Global::bUseVBO ) + && ( Vertexbuffer != -1 ) ) { // dla OpenGL 1.4 odświeży się cały sektor, w późniejszych poprawiamy fragment if (GLEW_VERSION_1_5) // dla OpenGL 1.4 to się nie wykona poprawnie if (TextureID1) // Ra: !!!! tu jest do poprawienia @@ -2953,71 +2849,47 @@ TTrack * TTrack::RaAnimate() double fHTW = 0.5 * fabs(fTrackWidth); double fHTW2 = fHTW; // Ra: na razie niech tak będzie double cos1 = 1.0, sin1 = 0.0, cos2 = 1.0, sin2 = 0.0; // Ra: ... - for (int i = 0; i < 12; ++i) - { - rpts3[i] = - vector6( - (fHTW + iglica[i].x) * cos1 + iglica[i].y * sin1, - -(fHTW + iglica[i].x) * sin1 + iglica[i].y * cos1, - iglica[i].z); - rpts3[i + 12] = - vector6( - (fHTW2 + szyna[i].x) * cos2 + szyna[i].y * sin2, - -(fHTW2 + szyna[i].x) * sin2 + iglica[i].y * cos2, - szyna[i].z); - rpts4[11 - i] = - vector6( - (-fHTW - iglica[i].x) * cos1 + iglica[i].y * sin1, - -(-fHTW - iglica[i].x) * sin1 + iglica[i].y * cos1, - iglica[i].z); - rpts4[23 - i] = - vector6( - (-fHTW2 - szyna[i].x) * cos2 + szyna[i].y * sin2, - -(-fHTW2 - szyna[i].x) * sin2 + iglica[i].y * cos2, - szyna[i].z); + for( int i = 0; i < 12; ++i ) { + + rpts3[ i ] = + vector6( +( fHTW + iglica[ i ].x ) * cos1 + iglica[ i ].y * sin1, + -( +fHTW + iglica[ i ].x ) * sin1 + iglica[ i ].y * cos1, iglica[ i ].z ); + rpts3[ i + 12 ] = + vector6( +( fHTW2 + szyna[ i ].x ) * cos2 + szyna[ i ].y * sin2, + -( +fHTW2 + szyna[ i ].x ) * sin2 + iglica[ i ].y * cos2, szyna[ i ].z ); + rpts4[ 11 - i ] = + vector6( ( -fHTW - iglica[ i ].x ) * cos1 + iglica[ i ].y * sin1, + -( -fHTW - iglica[ i ].x ) * sin1 + iglica[ i ].y * cos1, iglica[ i ].z ); + rpts4[ 23 - i ] = + vector6( ( -fHTW2 - szyna[ i ].x ) * cos2 + szyna[ i ].y * sin2, + -( -fHTW2 - szyna[ i ].x ) * sin2 + iglica[ i ].y * cos2, szyna[ i ].z ); } - CVertNormTex Vert[2 * 2 * 12]; // na razie 2 segmenty - CVertNormTex *v = Vert; // bo RaAnimate() modyfikuje wskaźnik - glGetBufferSubData( - GL_ARRAY_BUFFER, SwitchExtension->iLeftVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), &Vert); // pobranie fragmentu bufora VBO - if (SwitchExtension->RightSwitch) - { // nowa wersja z SPKS, ale odwrotnie lewa/prawa - SwitchExtension->Segments[ 0 ]->RenderLoft( v, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2, true ); - ::glBufferSubData( - GL_ARRAY_BUFFER, - SwitchExtension->iLeftVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), - &Vert); // wysłanie fragmentu bufora VBO - v = Vert; - ::glGetBufferSubData( - GL_ARRAY_BUFFER, - SwitchExtension->iRightVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), - &Vert); // pobranie fragmentu bufora VBO - SwitchExtension->Segments[ 1 ]->RenderLoft( v, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1, true ); + // NOTE: performance-wise it'd make much more sense to keep the most recent shape cached as part of switch extension, + // and only send updates when/if they take place, instead of the current back-and-forth + // TODO: implement optimized version + + // fetch current blade geometry + std::vector bladesbuffer; bladesbuffer.resize( 2 * 2 * 24 ); // 2 blades, 2 segments each + ::glGetBufferSubData( + GL_ARRAY_BUFFER, + SwitchExtension->iLeftVBO * sizeof( CVertNormTex ), + bladesbuffer.size() * sizeof( CVertNormTex ), + bladesbuffer.data() ); + auto bladevertices = bladesbuffer.data(); + if( SwitchExtension->RightSwitch ) { // nowa wersja z SPKS, ale odwrotnie lewa/prawa + SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2, true ); + SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1, true ); } - else - { // oryginalnie lewa działała lepiej niż prawa - SwitchExtension->Segments[ 0 ]->RenderLoft( v, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2, true ); // prawa iglica - ::glBufferSubData( - GL_ARRAY_BUFFER, - SwitchExtension->iLeftVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), - &Vert); // wysłanie fragmentu bufora VBO - v = Vert; - ::glGetBufferSubData( - GL_ARRAY_BUFFER, - SwitchExtension->iRightVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), - &Vert); // pobranie fragmentu bufora VBO - SwitchExtension->Segments[ 1 ]->RenderLoft( v, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1, true ); // lewa iglica + else { + SwitchExtension->Segments[ 0 ]->RenderLoft( bladevertices, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2, true ); // prawa iglica + SwitchExtension->Segments[ 1 ]->RenderLoft( bladevertices, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1, true ); // lewa iglica } + // push back updated geometry ::glBufferSubData( GL_ARRAY_BUFFER, - SwitchExtension->iRightVBO * sizeof(CVertNormTex), - 2 * 2 * 12 * sizeof(CVertNormTex), - &Vert); // wysłanie fragmentu bufora VBO + SwitchExtension->iLeftVBO * sizeof( CVertNormTex ), + bladesbuffer.size() * sizeof( CVertNormTex ), + bladesbuffer.data() ); } } else // gdy Display List diff --git a/Track.h b/Track.h index 07e971b5..6809afc6 100644 --- a/Track.h +++ b/Track.h @@ -256,7 +256,7 @@ class TTrack : public Resource void RaAssign(TGroundNode *gn, TAnimContainer *ac); void RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joined); void RaAnimListAdd(TTrack *t); - TTrack * RaAnimate(); + TTrack * RaAnimate(GLuint const Vertexbuffer = -1); void RadioStop(); void AxleCounter(int i, TDynamicObject *o) diff --git a/renderer.cpp b/renderer.cpp index 23150308..bf92c7b9 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1290,8 +1290,8 @@ opengl_renderer::Init_caps() { + " Vendor: " + std::string( (char *)glGetString( GL_VENDOR ) ) + " OpenGL Version: " + oglversion ); - if( !GLEW_VERSION_1_4 ) { - ErrorLog( "Requires openGL >= 1.4" ); + if( !GLEW_VERSION_1_5 ) { + ErrorLog( "Requires openGL >= 1.5" ); return false; } From 52a76f0ba199471a283acfd6e885578d7da2fcee Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 15 May 2017 17:23:25 +0200 Subject: [PATCH 3/5] build 170515. added converter start parameters, partial unification for traction render paths, minor fixes for multi-unit cab instruments --- DynObj.cpp | 14 +- Ground.cpp | 54 ++-- Ground.h | 3 - McZapkie/MOVER.h | 33 ++- McZapkie/Mover.cpp | 90 ++++--- Traction.cpp | 602 +++++++++++++++++++++++++-------------------- Traction.h | 5 +- Train.cpp | 18 +- 8 files changed, 451 insertions(+), 368 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 28336bae..05d458ca 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2458,14 +2458,14 @@ bool TDynamicObject::Update(double dt, double dt1) // opuszczenie pantografów przy niskim ciśnieniu /* // NOTE: disabled, the pantographs drop by themseleves when the pantograph tank pressure gets low enough - MoverParameters->PantFront( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); - MoverParameters->PantRear( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + MoverParameters->PantFront( false, ( MoverParameters->TrainType == dt_EZT ? range::unit : range::local ) ); + MoverParameters->PantRear( false, ( MoverParameters->TrainType == dt_EZT ? range::unit : range::local ) ); */ if( MoverParameters->TrainType != dt_EZT ) { // pressure switch safety measure -- open the line breaker, unless there's alternate source of traction voltage if( MoverParameters->GetTrainsetVoltage() < 0.5 * MoverParameters->EnginePowerSource.MaxVoltage ) { // TODO: check whether line breaker should be open EMU-wide - MoverParameters->MainSwitch( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + MoverParameters->MainSwitch( false, ( MoverParameters->TrainType == dt_EZT ? range::unit : range::local ) ); } } else { @@ -2473,7 +2473,7 @@ bool TDynamicObject::Update(double dt, double dt1) // and prevents their activation until pressure switch is set again MoverParameters->PantPressLockActive = true; // TODO: separate 'heating allowed' from actual heating flag, so we can disable it here without messing up heating toggle - MoverParameters->ConverterSwitch( false, command_range::unit ); + MoverParameters->ConverterSwitch( false, range::unit ); } // mark the pressure switch as spent MoverParameters->PantPressSwitchActive = false; @@ -2936,7 +2936,7 @@ bool TDynamicObject::Update(double dt, double dt1) && ( MoverParameters->EngineType != DieselEngine ) && ( MoverParameters->EngineType != WheelsDriven ) ) { // jeśli bateria wyłączona, a nie diesel ani drezyna reczna - if( MoverParameters->MainSwitch( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ) ) { + if( MoverParameters->MainSwitch( false, ( MoverParameters->TrainType == dt_EZT ? range::unit : range::local ) ) ) { // wyłączyć zasilanie // NOTE: we turn off entire EMU, but only the affected unit for other multi-unit consists MoverParameters->EventFlag = true; @@ -2945,8 +2945,8 @@ bool TDynamicObject::Update(double dt, double dt1) // TODO: have this dependant on .fiz-driven flag // NOTE: moved to pantspeed calculation part a little later in the function. all remarks and todo still apply /* - MoverParameters->PantFront( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); - MoverParameters->PantRear( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + MoverParameters->PantFront( false, ( MoverParameters->TrainType == dt_EZT ? range::unit : range::local ) ); + MoverParameters->PantRear( false, ( MoverParameters->TrainType == dt_EZT ? range::unit : range::local ) ); */ } } diff --git a/Ground.cpp b/Ground.cpp index a8b74537..7c6ab766 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -285,8 +285,7 @@ void TGroundNode::MoveMe(vector3 pPosition) void TGroundNode::RaRenderVBO() { // renderowanie z domyslnego bufora VBO glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]); - if (TextureID) - GfxRenderer.Bind(TextureID); // Ustaw aktywną teksturę + GfxRenderer.Bind( TextureID ); // Ustaw aktywną teksturę glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójkąty } @@ -2248,31 +2247,19 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) case GL_LINES: case GL_LINE_STRIP: case GL_LINE_LOOP: { - parser->getTokens( 3 ); - *parser >> tmp->Diffuse[ 0 ] >> tmp->Diffuse[ 1 ] >> tmp->Diffuse[ 2 ]; - // tmp->Diffuse[0]=Parser->GetNextSymbol().ToDouble()/255; - // tmp->Diffuse[1]=Parser->GetNextSymbol().ToDouble()/255; - // tmp->Diffuse[2]=Parser->GetNextSymbol().ToDouble()/255; - parser->getTokens(); - *parser >> tmp->fLineThickness; + parser->getTokens( 4 ); + *parser + >> tmp->Diffuse[ 0 ] + >> tmp->Diffuse[ 1 ] + >> tmp->Diffuse[ 2 ] + >> tmp->fLineThickness; TempVerts.clear(); TGroundVertex vertex; i = 0; parser->getTokens(); *parser >> token; do { - str = token; -/* - TempVerts[ i ].Point.x = atof( str.c_str() ); - parser->getTokens( 2 ); - *parser >> TempVerts[ i ].Point.y >> TempVerts[ i ].Point.z; - TempVerts[ i ].Point.RotateZ( aRotate.z / 180 * M_PI ); - TempVerts[ i ].Point.RotateX( aRotate.x / 180 * M_PI ); - TempVerts[ i ].Point.RotateY( aRotate.y / 180 * M_PI ); - TempVerts[ i ].Point += pOrigin; - tmp->pCenter += TempVerts[ i ].Point; -*/ - vertex.Point.x = std::atof( str.c_str() ); + vertex.Point.x = std::atof( token.c_str() ); parser->getTokens( 2 ); *parser >> vertex.Point.y @@ -2328,27 +2315,19 @@ TSubRect * TGround::GetSubRect(int iCol, int iRow) TEvent * TGround::FindEvent(const std::string &asEventName) { auto const lookup = m_eventmap.find( asEventName ); - return + return ( lookup != m_eventmap.end() ? - lookup->second : - nullptr; - /* //powolna wyszukiwarka - for (TEvent *Current=RootEvent;Current;Current=Current->Next2) - { - if (Current->asName==asEventName) - return Current; - } - return NULL; - */ + lookup->second : + nullptr ); } TEvent * TGround::FindEventScan( std::string const &asEventName ) { // wyszukanie eventu z opcją utworzenia niejawnego dla komórek skanowanych auto const lookup = m_eventmap.find( asEventName ); - auto e = + auto e = ( lookup != m_eventmap.end() ? - lookup->second : - nullptr; + lookup->second : + nullptr ); if (e) return e; // jak istnieje, to w porządku if (asEventName.rfind(":scan") != std::string::npos) // jeszcze może być event niejawny @@ -4290,11 +4269,6 @@ bool TGround::CheckQuery() return true; } -void TGround::OpenGLUpdate(HDC hDC) -{ - SwapBuffers(hDC); // swap buffers (double buffering) -}; - void TGround::UpdatePhys(double dt, int iter) { // aktualizacja fizyki stałym krokiem: dt=krok czasu [s], dt*iter=czas od ostatnich przeliczeń for (TGroundNode *Current = nRootOfType[TP_TRACTIONPOWERSOURCE]; Current; diff --git a/Ground.h b/Ground.h index 1a87a442..2fe2b4d6 100644 --- a/Ground.h +++ b/Ground.h @@ -293,8 +293,6 @@ class TGround TGroundNode *nRootOfType[TP_LAST]; // tablica grupująca obiekty, przyspiesza szukanie // TGroundNode *nLastOfType[TP_LAST]; //ostatnia TSubRect srGlobal; // zawiera obiekty globalne (na razie wyzwalacze czasowe) - int hh = 0, - mm = 0; // ustawienia czasu // int tracks,tracksfar; //liczniki torów typedef std::unordered_map event_map; event_map m_eventmap; @@ -374,7 +372,6 @@ class TGround void TrackJoin(TGroundNode *Current); private: - void OpenGLUpdate(HDC hDC); void RaTriangleDivider(TGroundNode *node); void Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam); bool PROBLEND; diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index a7cea124..95c0adad 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -139,6 +139,7 @@ static int const ctrain_passenger = 16; //mostek przejściowy static int const ctrain_scndpneumatic = 32; //przewody 8 atm (żółte; zasilanie powietrzem) static int const ctrain_heating = 64; //przewody ogrzewania WN static int const ctrain_depot = 128; //nie rozłączalny podczas zwykłych manewrów (międzyczłonowy), we wpisie wartość ujemna +// possible coupling types; can be combined enum coupling { faux = 0x0, coupler = 0x1, @@ -150,11 +151,16 @@ enum coupling { heating = 0x40, permanent = 0x80 }; -/*! przesylanie komend sterujacych*/ -enum command_range { +// possible effect ranges for control commands; exclusive +enum range { local, unit, consist +}; +// start method for devices; exclusive +enum start { + manual, + automatic }; /*typ hamulca elektrodynamicznego*/ static int const dbrake_none = 0; @@ -842,9 +848,14 @@ public: bool PantCompFlag = false; /*!o czy wlaczona sprezarka pantografow*/ bool CompressorAllow = false; /*! zezwolenie na uruchomienie sprezarki NBMX*/ bool CompressorGovernorLock{ false }; // indicates whether compressor pressure switch was activated due to reaching cut-out pressure - bool ConverterFlag = false ; /*! czy wlaczona przetwornica NBMX*/ + // TODO converter parameters, for when we start cleaning up mover parameters + start ConverterStart{ manual }; // whether converter is started manually, or by other means + float ConverterStartDelay{ 0.0f }; // delay (in seconds) before the converter is started, once its activation conditions are met + double ConverterStartDelayTimer{ 0.0 }; // helper, for tracking whether converter start delay passed bool ConverterAllow = false; /*zezwolenie na prace przetwornicy NBMX*/ - int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/ + bool ConverterFlag = false; /*! czy wlaczona przetwornica NBMX*/ + + int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/ double BrakeCtrlPosR = 0.0; /*nastawa hamulca zespolonego - plynna dla FV4a*/ double BrakeCtrlPos2 = 0.0; /*nastawa hamulca zespolonego - kapturek dla FV4a*/ int LocalBrakePos = 0; /*nastawa hamulca indywidualnego*/ @@ -1045,7 +1056,7 @@ public: bool AddPulseForce(int Multipler);/*dla drezyny*/ - bool Sandbox( bool const State, int const Notify = command_range::consist );/*wlacza/wylacza sypanie piasku*/ + bool Sandbox( bool const State, int const Notify = range::consist );/*wlacza/wylacza sypanie piasku*/ /*! zbijanie czuwaka/SHP*/ void SSReset(void); @@ -1101,12 +1112,12 @@ public: /*--funkcje dla lokomotyw*/ bool DirectionBackward(void);/*! kierunek ruchu*/ - bool MainSwitch( bool const State, int const Notify = command_range::consist );/*! wylacznik glowny*/ - bool ConverterSwitch( bool State, int const Notify = command_range::consist );/*! wl/wyl przetwornicy*/ - bool CompressorSwitch( bool State, int const Notify = command_range::consist );/*! wl/wyl sprezarki*/ + bool MainSwitch( bool const State, int const Notify = range::consist );/*! wylacznik glowny*/ + bool ConverterSwitch( bool State, int const Notify = range::consist );/*! wl/wyl przetwornicy*/ + bool CompressorSwitch( bool State, int const Notify = range::consist );/*! wl/wyl sprezarki*/ /*-funkcje typowe dla lokomotywy elektrycznej*/ - void ConverterCheck(); // przetwornica + void ConverterCheck( double const Timestep ); // przetwornica bool FuseOn(void); //bezpiecznik nadamiary bool FuseFlagCheck(void); // sprawdzanie flagi nadmiarowego void FuseOff(void); // wylaczenie nadmiarowego @@ -1129,8 +1140,8 @@ public: bool AutoRelayCheck(void);//symulacja automatycznego rozruchu bool ResistorsFlagCheck(void); //sprawdzenie kontrolki oporow rozruchowych NBMX - bool PantFront( bool const State, int const Notify = command_range::consist ); //obsluga pantografou przedniego - bool PantRear( bool const State, int const Notify = command_range::consist ); //obsluga pantografu tylnego + bool PantFront( bool const State, int const Notify = range::consist ); //obsluga pantografou przedniego + bool PantRear( bool const State, int const Notify = range::consist ); //obsluga pantografu tylnego /*-funkcje typowe dla lokomotywy spalinowej z przekladnia mechaniczna*/ bool dizel_EngageSwitch(double state); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index ff60e7cf..c171722b 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -773,7 +773,7 @@ void TMoverParameters::UpdatePantVolume(double dt) // wywalenie szybkiego z powodu niskiego ciśnienia if( GetTrainsetVoltage() < 0.5 * EnginePowerSource.MaxVoltage ) { // to jest trochę proteza; zasilanie członu może być przez sprzęg WN - if( MainSwitch( false, ( TrainType == dt_EZT ? command_range::unit : command_range::local ) ) ) { + if( MainSwitch( false, ( TrainType == dt_EZT ? range::unit : range::local ) ) ) { EventFlag = true; } } @@ -1366,7 +1366,7 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap Compressor = 0; CompressorFlag = false; }; - ConverterCheck(); + ConverterCheck(dt); if (CompressorSpeed > 0.0) // sprężarka musi mieć jakąś niezerową wydajność CompressorCheck(dt); //żeby rozważać jej załączenie i pracę UpdateBrakePressure(dt); @@ -1522,7 +1522,7 @@ double TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape Compressor = 0; CompressorFlag = false; }; - ConverterCheck(); + ConverterCheck(dt); if (CompressorSpeed > 0.0) // sprężarka musi mieć jakąś niezerową wydajność CompressorCheck(dt); //żeby rozważać jej załączenie i pracę UpdateBrakePressure(dt); @@ -1561,15 +1561,23 @@ double TMoverParameters::ShowEngineRotation(int VehN) return 0.0; }; -void TMoverParameters::ConverterCheck() -{ // sprawdzanie przetwornicy +// sprawdzanie przetwornicy +void TMoverParameters::ConverterCheck( double const Timestep ) { + // TODO: move other converter checks here, to have it all in one place for potential device object if( ( ConverterAllow ) && ( false == PantPressLockActive ) && ( Mains ) ) { - ConverterFlag = true; + // delay timer can be optionally configured, and is set anew whenever converter goes off + if( ConverterStartDelayTimer <= 0.0 ) { + ConverterFlag = true; + } + else { + ConverterStartDelayTimer -= Timestep; + } } else { ConverterFlag = false; + ConverterStartDelayTimer = static_cast( ConverterStartDelay ); } }; @@ -2087,10 +2095,10 @@ bool TMoverParameters::Sandbox( bool const State, int const Notify ) } } - if( Notify != command_range::local ) { + if( Notify != range::local ) { // if requested pass the command on auto const couplingtype = - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ); @@ -2348,11 +2356,11 @@ bool TMoverParameters::MainSwitch( bool const State, int const Notify ) { if( Mains ) { // jeśli był załączony - if( Notify != command_range::local ) { + if( Notify != range::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( "MainSwitch", int( State ), CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } @@ -2360,11 +2368,11 @@ bool TMoverParameters::MainSwitch( bool const State, int const Notify ) Mains = State; if( Mains ) { // jeśli został załączony - if( Notify != command_range::local ) { + if( Notify != range::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( "MainSwitch", int( State ), CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } @@ -2399,19 +2407,19 @@ bool TMoverParameters::ConverterSwitch( bool State, int const Notify ) CompressorAllow = ConverterAllow; } if( ConverterAllow == true ) { - if( Notify != command_range::local ) { + if( Notify != range::local ) { SendCtrlToNext( "ConverterSwitch", 1, CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } } else { - if( Notify != command_range::local ) { + if( Notify != range::local ) { SendCtrlToNext( "ConverterSwitch", 0, CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } @@ -2436,19 +2444,19 @@ bool TMoverParameters::CompressorSwitch( bool State, int const Notify ) CS = true; } if( CompressorAllow == true ) { - if( Notify != command_range::local ) { + if( Notify != range::local ) { SendCtrlToNext( "CompressorSwitch", 1, CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } } else { - if( Notify != command_range::local ) { + if( Notify != range::local ) { SendCtrlToNext( "CompressorSwitch", 0, CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } @@ -4165,7 +4173,7 @@ double TMoverParameters::TractionForce(double dt) if ( (std::max(GetTrainsetVoltage(), std::abs(Voltage)) < EnginePowerSource.CollectorParameters.MinV) || (std::max(GetTrainsetVoltage(), std::abs(Voltage)) * EnginePowerSource.CollectorParameters.OVP > EnginePowerSource.CollectorParameters.MaxV)) - if( MainSwitch( false, ( TrainType == dt_EZT ? command_range::unit : command_range::local ) ) ) // TODO: check whether we need to send this EMU-wide + if( MainSwitch( false, ( TrainType == dt_EZT ? range::unit : range::local ) ) ) // TODO: check whether we need to send this EMU-wide EventFlag = true; // wywalanie szybkiego z powodu niewłaściwego napięcia if (((DynamicBrakeType == dbrake_automatic) || (DynamicBrakeType == dbrake_switch)) && @@ -4464,7 +4472,7 @@ double TMoverParameters::TractionForce(double dt) // nie wchodzić w funkcję bez potrzeby if( ( std::max( std::abs( Voltage ), GetTrainsetVoltage() ) < EnginePowerSource.CollectorParameters.MinV ) || ( std::max( std::abs( Voltage ), GetTrainsetVoltage() ) > EnginePowerSource.CollectorParameters.MaxV + 200 ) ) { - MainSwitch( false, ( TrainType == dt_EZT ? command_range::unit : command_range::local ) ); // TODO: check whether we need to send this EMU-wide + MainSwitch( false, ( TrainType == dt_EZT ? range::unit : range::local ) ); // TODO: check whether we need to send this EMU-wide } } tmpV = abs(nrot) * (PI * WheelDiameter) * 3.6; //*DirAbsolute*eimc[eimc_s_p]; - do przemyslenia dzialanie pp @@ -4538,21 +4546,21 @@ double TMoverParameters::TractionForce(double dt) { PosRatio = 0; tmp = 4; - Sandbox( true, command_range::local ); + Sandbox( true, range::local ); } // przeciwposlizg if ((abs((PosRatio + 9.80 * dizel_fill) * dmoment * 100) > 0.95 * Adhesive(RunningTrack.friction) * TotalMassxg)) { PosRatio = 0; tmp = 9; - Sandbox( true, command_range::local ); + Sandbox( true, range::local ); } // przeciwposlizg if ((SlippingWheels)) { // PosRatio = -PosRatio * 0; // serio -0 ??? PosRatio = 0; tmp = 9; - Sandbox( true, command_range::local ); + Sandbox( true, range::local ); } // przeciwposlizg dizel_fill += Max0R(Min0R(PosRatio - dizel_fill, 0.1), -0.1) * 2 * @@ -5190,22 +5198,22 @@ bool TMoverParameters::PantFront( bool const State, int const Notify ) PantFrontUp = State; if( State == true ) { PantFrontStart = 0; - if( Notify != command_range::local ) { + if( Notify != range::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( "PantFront", 1, CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } } else { PantFrontStart = 1; - if( Notify != command_range::local ) { + if( Notify != range::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( "PantFront", 0, CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } @@ -5243,22 +5251,22 @@ bool TMoverParameters::PantRear( bool const State, int const Notify ) PantRearUp = State; if( State == true ) { PantRearStart = 0; - if( Notify != command_range::local ) { + if( Notify != range::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( "PantRear", 1, CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } } else { PantRearStart = 1; - if( Notify != command_range::local ) { + if( Notify != range::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( "PantRear", 0, CabNo, - ( Notify == command_range::unit ? + ( Notify == range::unit ? ctrain_controll | ctrain_depot : ctrain_controll ) ); } @@ -7048,6 +7056,20 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { 0; extract_value( StopBrakeDecc, "SBD", line, "" ); + + // converter + { + std::map starts{ + { "Manual", start::manual }, + { "Automatic", start::automatic } + }; + auto lookup = starts.find( extract_value( "ConverterStart", line ) ); + ConverterStart = + lookup != starts.end() ? + lookup->second : + start::manual; + } + extract_value( ConverterStartDelay, "ConverterStartDelay", line, "" ); } void TMoverParameters::LoadFIZ_Light( std::string const &line ) { @@ -8148,7 +8170,7 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C } else if (Command == "Sandbox") { - OK = Sandbox( CValue1 == 1, command_range::local ); + OK = Sandbox( CValue1 == 1, range::local ); } else if (Command == "CabSignal") /*SHP,Indusi*/ { // Ra: to powinno działać tylko w członie obsadzonym diff --git a/Traction.cpp b/Traction.cpp index c0b5f181..6aa04184 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -116,25 +116,22 @@ void TTraction::Optimize() uiDisplayList = glGenLists(1); glNewList(uiDisplayList, GL_COMPILE); - GfxRenderer.Bind(0); - // glColor3ub(0,0,0); McZapkie: to do render - - // glPushMatrix(); - // glTranslatef(pPosition.x,pPosition.y,pPosition.z); - if (Wires != 0) { // Dlugosc odcinka trakcji 'Winger - double ddp = hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z); - + double ddp = std::hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z); if (Wires == 2) WireOffset = 0; // Przewoz jezdny 1 'Marcin glBegin(GL_LINE_STRIP); - glVertex3f(pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint1.y, - pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); - glVertex3f(pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint2.y, - pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + glVertex3f( + pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, + pPoint1.y, + pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + glVertex3f( + pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, + pPoint2.y, + pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); glEnd(); // Nie wiem co 'Marcin Math3D::vector3 pt1, pt2, pt3, pt4, v1, v2; @@ -146,24 +143,25 @@ void TTraction::Optimize() float f = step; float mid = 0.5; float t; - // Przewod nosny 'Marcin - if (Wires != 1) + if (Wires > 1) { glBegin(GL_LINE_STRIP); glVertex3f(pPoint3.x, pPoint3.y, pPoint3.z); - for (int i = 0; i < iNumSections - 1; i++) + for (int i = 0; i < iNumSections - 1; ++i) { pt3 = pPoint3 + v1 * f; - t = (1 - fabs(f - mid) * 2); + t = (1 - std::fabs(f - mid) * 2); if ((Wires < 4) || ((i != 0) && (i != iNumSections - 2))) - glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference, pt3.z); + glVertex3f( + pt3.x, + pt3.y - std::sqrt(t) * fHeightDifference, + pt3.z); f += step; } glVertex3f(pPoint4.x, pPoint4.y, pPoint4.z); glEnd(); } - // Drugi przewod jezdny 'Winger if (Wires > 2) { @@ -181,14 +179,17 @@ void TTraction::Optimize() { glBegin(GL_LINE_STRIP); glVertex3f(pPoint3.x, pPoint3.y - 0.65f * fHeightDifference, pPoint3.z); - for (int i = 0; i < iNumSections - 1; i++) + for (int i = 0; i < iNumSections - 1; ++i) { pt3 = pPoint3 + v1 * f; - t = (1 - fabs(f - mid) * 2); + t = (1 - std::fabs(f - mid) * 2); glVertex3f( pt3.x, - pt3.y - sqrt(t) * fHeightDifference - - ((i == 0) || (i == iNumSections - 2) ? 0.25f * fHeightDifference : +0.05), + pt3.y - std::sqrt( t ) * fHeightDifference - ( + ( ( i == 0 ) + || ( i == iNumSections - 2 ) ) ? + 0.25f * fHeightDifference : + 0.05 ), pt3.z); f += step; } @@ -202,36 +203,47 @@ void TTraction::Optimize() if (Wires != 1) { glBegin(GL_LINES); - for (int i = 0; i < iNumSections - 1; i++) + for (int i = 0; i < iNumSections - 1; ++i) { float flo, flo1; flo = (Wires == 4 ? 0.25f * fHeightDifference : 0); flo1 = (Wires == 4 ? +0.05 : 0); pt3 = pPoint3 + v1 * f; pt4 = pPoint1 + v2 * f; - t = (1 - fabs(f - mid) * 2); + t = (1 - std::fabs(f - mid) * 2); if ((i % 2) == 0) { - glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference - - ((i == 0) || (i == iNumSections - 2) ? flo : flo1), - pt3.z); - glVertex3f(pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pt4.y, - pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + glVertex3f( + pt3.x, + pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1), + pt3.z); + glVertex3f( + pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, + pt4.y, + pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); } else { - glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference - - ((i == 0) || (i == iNumSections - 2) ? flo : flo1), - pt3.z); - glVertex3f(pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pt4.y, - pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); + glVertex3f( + pt3.x, + pt3.y - std::sqrt(t) * fHeightDifference - ((i == 0) || (i == iNumSections - 2) ? flo : flo1), + pt3.z); + glVertex3f( + pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, + pt4.y, + pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset); } if ((Wires == 4) && ((i == 1) || (i == iNumSections - 3))) { - glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference - 0.05, pt3.z); - glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference, pt3.z); + glVertex3f( + pt3.x, + pt3.y - std::sqrt(t) * fHeightDifference - 0.05, + pt3.z); + glVertex3f( + pt3.x, + pt3.y - std::sqrt(t) * fHeightDifference, + pt3.z); } - // endif; f += step; } glEnd(); @@ -249,146 +261,89 @@ void TTraction::InitCenter(vector3 Angles, vector3 pOrigin) void TTraction::RenderDL(float mgn) // McZapkie: mgn to odleglosc od obserwatora { // McZapkie: ustalanie przezroczystosci i koloru linii: - if (Wires != 0 && !TestFlag(DamageFlag, 128)) // rysuj jesli sa druty i nie zerwana + if( Wires != 0 && !TestFlag( DamageFlag, 128 ) ) // rysuj jesli sa druty i nie zerwana { - // glDisable(GL_LIGHTING); //aby nie używało wektorów normalnych do kolorowania - glColor4f(0, 0, 0, 1); // jak nieznany kolor to czarne nieprzezroczyste - if (!Global::bSmoothTraction) - glDisable(GL_LINE_SMOOTH); // na liniach kiepsko wygląda - robi gradient - float linealpha = 5000 * WireThickness / (mgn + 1.0); //*WireThickness - if (linealpha > 1.2f) - linealpha = 1.2f; // zbyt grube nie są dobre - glLineWidth(linealpha); - if (linealpha > 1.0f) - linealpha = 1.0f; - // McZapkie-261102: kolor zalezy od materialu i zasniedzenia - float r, g, b; - switch (Material) - { // Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były - // trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor - case 1: - if (TestFlag(DamageFlag, 1)) - { - r = 0.00000f; - g = 0.32549f; - b = 0.2882353f; // zielona miedź - } - else - { - r = 0.35098f; - g = 0.22549f; - b = 0.1f; // czerwona miedź - } - break; - case 2: - if (TestFlag(DamageFlag, 1)) - { - r = 0.10f; - g = 0.10f; - b = 0.10f; // czarne Al - } - else - { - r = 0.25f; - g = 0.25f; - b = 0.25f; // srebrne Al - } - break; - // tymczasowo pokazanie zasilanych odcinków - case 4: - r = 0.5f; - g = 0.5f; - b = 1.0f; - break; // niebieskie z podłączonym zasilaniem - case 5: - r = 1.0f; - g = 0.0f; - b = 0.0f; - break; // czerwone z podłączonym zasilaniem 1 - case 6: - r = 0.0f; - g = 1.0f; - b = 0.0f; - break; // zielone z podłączonym zasilaniem 2 - case 7: - r = 1.0f; - g = 1.0f; - b = 0.0f; - break; //żółte z podłączonym zasilaniem z obu stron + // setup + GfxRenderer.Bind( 0 ); + if( !Global::bSmoothTraction ) { + // na liniach kiepsko wygląda - robi gradient + ::glDisable( GL_LINE_SMOOTH ); } - if (DebugModeFlag) - if (hvParallel) - { // jeśli z bieżnią wspólną, to dodatkowo przyciemniamy - r *= 0.6f; - g *= 0.6f; - b *= 0.6f; - } -#ifdef EU07_USE_OLD_LIGHTING_MODEL - r *= Global::ambientDayLight[ 0 ]; // w zaleźności od koloru swiatła - g *= Global::ambientDayLight[ 1 ]; - b *= Global::ambientDayLight[ 2 ]; -#else - r *= Global::DayLight.ambient[ 0 ]; // w zaleźności od koloru swiatła - g *= Global::DayLight.ambient[ 1 ]; - b *= Global::DayLight.ambient[2]; -#endif - if (linealpha > 1.0f) - linealpha = 1.0f; // trzeba ograniczyć do <=1 - glColor4f(r, g, b, linealpha); + float linealpha = 5000 * WireThickness / ( mgn + 1.0 ); //*WireThickness + linealpha = std::min( 1.2f, linealpha ); // zbyt grube nie są dobre + ::glLineWidth( linealpha ); + // McZapkie-261102: kolor zalezy od materialu i zasniedzenia + float + red{ 0.0f }, + green{ 0.0f }, + blue{ 0.0f }; + wire_color( red, green, blue ); + ::glColor4f( red, green, blue, linealpha ); + // draw code if (!uiDisplayList) Optimize(); // generowanie DL w miarę potrzeby - glCallList(uiDisplayList); - glLineWidth(1.0); - glEnable(GL_LINE_SMOOTH); - // glEnable(GL_LIGHTING); //bez tego się modele nie oświetlają + ::glCallList(uiDisplayList); + // cleanup + ::glLineWidth(1.0); + ::glEnable(GL_LINE_SMOOTH); } } +// przygotowanie tablic do skopiowania do VBO (zliczanie wierzchołków) int TTraction::RaArrayPrepare() -{ // przygotowanie tablic do skopiowania do VBO (zliczanie wierzchołków) - // if (bVisible) //o ile w ogóle widać - switch (Wires) - { - case 1: - iLines = 2; - break; - case 2: - iLines = iNumSections ? 4 * (iNumSections)-2 + 2 : 4; - break; - case 3: - iLines = iNumSections ? 4 * (iNumSections)-2 + 4 : 6; - break; - case 4: - iLines = iNumSections ? 4 * (iNumSections)-2 + 6 : 8; - break; - default: - iLines = 0; +{ + // jezdny + iLines = 2; + // przewod nosny + if( Wires > 1 ) { + iLines += 2 + ( + Wires < 4 ? + std::max( 0, iNumSections - 1 ) : + ( iNumSections > 2 ? + std::max( 0, iNumSections - 1 - 2 ) : + std::max( 0, iNumSections - 1 - 1 ) ) ); + } + // drugi przewod jezdny + if( Wires > 2 ) { + iLines += 2; + } + if( Wires == 4 ) { + iLines += 2 + std::max( 0, iNumSections - 1 ); + } + // przewody pionowe (wieszaki) + if( Wires > 1 ) { + iLines += 2 * ( std::max( 0, iNumSections - 1 ) ); + if( ( Wires == 4 ) + &&( iNumSections > 0 ) ) { + iLines += ( + iNumSections > 4 ? + 4 : + 2 ); + } } - // else iLines=0; return iLines; }; void TTraction::RaArrayFill(CVertNormTex *Vert) { // wypełnianie tablic VBO - CVertNormTex *old = Vert; - double ddp = hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z); + double ddp = std::hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z); if (Wires == 2) WireOffset = 0; // jezdny - Vert->x = pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; + Vert->x = pPoint1.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; Vert->y = pPoint1.y; - Vert->z = pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + Vert->z = pPoint1.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; ++Vert; - Vert->x = pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; + Vert->x = pPoint2.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; Vert->y = pPoint2.y; - Vert->z = pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; + Vert->z = pPoint2.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; ++Vert; // Nie wiem co 'Marcin Math3D::vector3 pt1, pt2, pt3, pt4, v1, v2; v1 = pPoint4 - pPoint3; v2 = pPoint2 - pPoint1; float step = 0; - if (iNumSections > 0) + if( iNumSections > 0 ) step = 1.0f / (float)iNumSections; float f = step; float mid = 0.5; @@ -400,18 +355,18 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->y = pPoint3.y; Vert->z = pPoint3.z; ++Vert; - for (int i = 0; i < iNumSections - 1; i++) + for (int i = 0; i < iNumSections - 1; ++i) { pt3 = pPoint3 + v1 * f; - t = (1 - fabs(f - mid) * 2); - Vert->x = pt3.x; - Vert->y = pt3.y - sqrt(t) * fHeightDifference; - Vert->z = pt3.z; - ++Vert; - Vert->x = pt3.x; // drugi raz, bo nie jest line_strip - Vert->y = pt3.y - sqrt(t) * fHeightDifference; - Vert->z = pt3.z; - ++Vert; + t = (1 - std::fabs(f - mid) * 2); + if( ( Wires < 4 ) + || ( ( i != 0 ) + && ( i != iNumSections - 2 ) ) ) { + Vert->x = pt3.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference; + Vert->z = pt3.z; + ++Vert; + } f += step; } Vert->x = pPoint4.x; @@ -420,7 +375,7 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) ++Vert; } // Drugi przewod jezdny 'Winger - if (Wires == 3) + if (Wires > 2) { Vert->x = pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; Vert->y = pPoint1.y; @@ -431,124 +386,145 @@ void TTraction::RaArrayFill(CVertNormTex *Vert) Vert->z = pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; ++Vert; } + f = step; - // Przewody pionowe (wieszaki) 'Marcin, poprawki na 2 przewody jezdne 'Winger - if (Wires > 1) - { - for (int i = 0; i < iNumSections - 1; i++) - { + + if( Wires == 4 ) { + Vert->x = pPoint3.x; + Vert->y = pPoint3.y - 0.65f * fHeightDifference; + Vert->z = pPoint3.z; + ++Vert; + for( int i = 0; i < iNumSections - 1; ++i ) { pt3 = pPoint3 + v1 * f; - pt4 = pPoint1 + v2 * f; - t = (1 - fabs(f - mid) * 2); + t = ( 1 - std::fabs( f - mid ) * 2 ); Vert->x = pt3.x; - Vert->y = pt3.y - sqrt(t) * fHeightDifference; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( + ( ( i == 0 ) + || ( i == iNumSections - 2 ) ) ? + 0.25f * fHeightDifference : + 0.05 ); Vert->z = pt3.z; ++Vert; - if ((i % 2) == 0) - { - Vert->x = pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; - Vert->y = pt4.y; - Vert->z = pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; - } - else - { - Vert->x = pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset; - Vert->y = pt4.y; - Vert->z = pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset; - } - ++Vert; + f += step; + } + Vert->x = pPoint4.x; + Vert->y = pPoint4.y - 0.65f * fHeightDifference; + Vert->z = pPoint4.z; + } + f = step; + + // Przewody pionowe (wieszaki) 'Marcin, poprawki na 2 przewody jezdne 'Winger + if (Wires > 1) + { + for (int i = 0; i < iNumSections - 1; ++i) + { + float flo, flo1; + flo = ( Wires == 4 ? 0.25f * fHeightDifference : 0 ); + flo1 = ( Wires == 4 ? +0.05 : 0 ); + pt3 = pPoint3 + v1 * f; + pt4 = pPoint1 + v2 * f; + t = (1 - std::fabs(f - mid) * 2); + + if( ( i % 2 ) == 0 ) { + Vert->x = pt3.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ); + Vert->z = pt3.z; + ++Vert; + Vert->x = pt4.x - ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; + Vert->y = pt4.y; + Vert->z = pt4.z - ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; + ++Vert; + } + else { + Vert->x = pt3.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - ( ( i == 0 ) || ( i == iNumSections - 2 ) ? flo : flo1 ); + Vert->z = pt3.z; + ++Vert; + Vert->x = pt4.x + ( pPoint2.z / ddp - pPoint1.z / ddp ) * WireOffset; + Vert->y = pt4.y; + Vert->z = pt4.z + ( -pPoint2.x / ddp + pPoint1.x / ddp ) * WireOffset; + ++Vert; + } + if( ( ( Wires == 4 ) + && ( ( i == 1 ) + || ( i == iNumSections - 3 ) ) ) ) { + Vert->x = pt3.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference - 0.05; + Vert->z = pt3.z; + ++Vert; + Vert->x = pt3.x; + Vert->y = pt3.y - std::sqrt( t ) * fHeightDifference; + Vert->z = pt3.z; + ++Vert; + } f += step; } } - if ((Vert - old) != iLines) - WriteLog("!!! Wygenerowano punktów " + std::to_string(Vert - old) + ", powinno być " + - std::to_string(iLines)); }; void TTraction::RenderVBO(float mgn, int iPtr) { // renderowanie z użyciem VBO if (Wires != 0 && !TestFlag(DamageFlag, 128)) // rysuj jesli sa druty i nie zerwana { + // setup GfxRenderer.Bind(0); - glDisable(GL_LIGHTING); // aby nie używało wektorów normalnych do kolorowania - glColor4f(0, 0, 0, 1); // jak nieznany kolor to czarne nieprzezroczyste - if (!Global::bSmoothTraction) - glDisable(GL_LINE_SMOOTH); // na liniach kiepsko wygląda - robi gradient - float linealpha = 5000 * WireThickness / (mgn + 1.0); //*WireThickness - if (linealpha > 1.2f) - linealpha = 1.2f; // zbyt grube nie są dobre - glLineWidth(linealpha); - // McZapkie-261102: kolor zalezy od materialu i zasniedzenia - float r, g, b; - switch (Material) - { // Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były - // trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor - case 1: - if (TestFlag(DamageFlag, 1)) - { - r = 0.00000f; - g = 0.32549f; - b = 0.2882353f; // zielona miedź - } - else - { - r = 0.35098f; - g = 0.22549f; - b = 0.1f; // czerwona miedź - } - break; - case 2: - if (TestFlag(DamageFlag, 1)) - { - r = 0.10f; - g = 0.10f; - b = 0.10f; // czarne Al - } - else - { - r = 0.25f; - g = 0.25f; - b = 0.25f; // srebrne Al - } - break; - // tymczasowo pokazanie zasilanych odcinków - case 4: - r = 0.5f; - g = 0.5f; - b = 1.0f; - break; // niebieskie z podłączonym zasilaniem - case 5: - r = 1.0f; - g = 0.0f; - b = 0.0f; - break; // czerwone z podłączonym zasilaniem 1 - case 6: - r = 0.0f; - g = 1.0f; - b = 0.0f; - break; // zielone z podłączonym zasilaniem 2 - case 7: - r = 1.0f; - g = 1.0f; - b = 0.0f; - break; //żółte z podłączonym zasilaniem z obu stron + if( !Global::bSmoothTraction ) { + // na liniach kiepsko wygląda - robi gradient + ::glDisable( GL_LINE_SMOOTH ); } -#ifdef EU07_USE_OLD_LIGHTING_MODEL - r *= Global::ambientDayLight[ 0 ]; // w zaleźności od koloru swiatła - g *= Global::ambientDayLight[ 1 ]; - b *= Global::ambientDayLight[ 2 ]; -#else - r *= Global::DayLight.ambient[ 0 ]; // w zaleźności od koloru swiatła - g *= Global::DayLight.ambient[ 1 ]; - b *= Global::DayLight.ambient[ 2 ]; -#endif - if (linealpha > 1.0f) - linealpha = 1.0f; // trzeba ograniczyć do <=1 - glColor4f(r, g, b, linealpha); - glDrawArrays(GL_LINES, iPtr, iLines); - glLineWidth(1.0); - glEnable(GL_LINE_SMOOTH); - glEnable(GL_LIGHTING); // bez tego się modele nie oświetlają + float linealpha = 5000 * WireThickness / (mgn + 1.0); //*WireThickness + linealpha = std::min( 1.2f, linealpha ); // zbyt grube nie są dobre + ::glLineWidth(linealpha); + // McZapkie-261102: kolor zalezy od materialu i zasniedzenia + float + red{ 0.0f }, + green{ 0.0f }, + blue{ 0.0f }; + wire_color( red, green, blue ); + ::glColor4f(red, green, blue, linealpha); + // draw code + // jezdny + ::glDrawArrays( GL_LINE_STRIP, iPtr, 2 ); + iPtr += 2; + // przewod nosny + if( Wires > 1 ) { + auto const piececount = 2 + ( + Wires < 4 ? + std::max( 0 , iNumSections - 1 ) : + ( iNumSections > 2 ? + std::max( 0, iNumSections - 1 - 2 ) : + std::max( 0, iNumSections - 1 - 1 ) ) ); + ::glDrawArrays( GL_LINE_STRIP, iPtr, piececount ); + iPtr += piececount; + } + // drugi przewod jezdny + if( Wires > 2 ) { + ::glDrawArrays( GL_LINE_STRIP, iPtr, 2 ); + iPtr += 2; + } + if( Wires == 4 ) { + auto const piececount = 2 + std::max( 0, iNumSections - 1 ); + ::glDrawArrays( GL_LINE_STRIP, iPtr, piececount ); + iPtr += piececount; + } + // przewody pionowe (wieszaki) + if( Wires != 1 ) { + auto piececount = 2 * std::max( 0, iNumSections - 1 ); + if( ( Wires == 4 ) + && ( iNumSections > 0 ) ) { + piececount += ( + iNumSections > 4 ? + 4 : + 2 ); + } + if( piececount > 0 ) { + ::glDrawArrays( GL_LINES, iPtr, piececount ); + iPtr += piececount; + } + } + // cleanup + ::glLineWidth(1.0); + ::glEnable(GL_LINE_SMOOTH); } }; @@ -619,11 +595,16 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) else ps = psPower[d ^ 1]; // zasilacz od przeciwnej strony niż idzie analiza d = iNext[d]; // kierunek - // double r; //sumaryczna rezystancja +#ifdef EU07_USE_OLD_TRACTIONPOWER_CODE if (DebugModeFlag) // tylko podczas testów Material = 4; // pokazanie, że to przęsło ma podłączone zasilanie +#else + // TBD, TODO: we don't need to maintain 4-7 value range as it's part of legacy system + PowerState = 4; +#endif while (t ? !t->psPower[d] : false) // jeśli jest jakiś kolejny i nie ma ustalonego zasilacza { // ustawienie zasilacza i policzenie rezystancji zastępczej +#ifdef EU07_USE_OLD_TRACTIONPOWER_CODE if (DebugModeFlag) // tylko podczas testów if (t->Material != 4) // przęsła zasilającego nie modyfikować { @@ -631,6 +612,16 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) t->Material = 4; // tymczasowo, aby zmieniła kolor t->Material |= d ? 2 : 1; // kolor zależny od strony, z której jest zasilanie } +#else + if( t->PowerState != 4 ) { + // przęsła zasilającego nie modyfikować + if( t->PowerState < 4 ) { + // tymczasowo, aby zmieniła kolor + t->PowerState = 4; + } + t->PowerState |= d ? 2 : 1; // kolor zależny od strony, z której jest zasilanie + } +#endif t->psPower[d] = ps; // skopiowanie wskaźnika zasilacza od danej strony t->fResistance[d] = r; // wpisanie rezystancji w kierunku tego zasilacza r += t->fResistivity * Length3(t->vParametric); // doliczenie oporu kolejnego odcinka @@ -716,3 +707,84 @@ double TTraction::VoltageGet(double u, double i) return psPower[1]->CurrentGet(res + r1t) * res; return 0.0; // gdy nie podłączony wcale? }; + +void +TTraction::wire_color( float &Red, float &Green, float &Blue ) const { + + if( false == DebugModeFlag ) { + switch( Material ) { // Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były + // trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor + case 1: { + if( TestFlag( DamageFlag, 1 ) ) { + Red = 0.00000f; + Green = 0.32549f; + Blue = 0.2882353f; // zielona miedź + } + else { + Red = 0.35098f; + Green = 0.22549f; + Blue = 0.1f; // czerwona miedź + } + break; + } + case 2: { + if( TestFlag( DamageFlag, 1 ) ) { + Red = 0.10f; + Green = 0.10f; + Blue = 0.10f; // czarne Al + } + else { + Red = 0.25f; + Green = 0.25f; + Blue = 0.25f; // srebrne Al + } + break; + } + default: {break; } + } + // w zaleźności od koloru swiatła + Red *= Global::DayLight.ambient[ 0 ]; + Green *= Global::DayLight.ambient[ 1 ]; + Blue *= Global::DayLight.ambient[ 2 ]; + } + else { + // tymczasowo pokazanie zasilanych odcinków + switch( PowerState ) { + + case 4: { + // niebieskie z podłączonym zasilaniem + Red = 0.5f; + Green = 0.5f; + Blue = 1.0f; + break; + } + case 5: { + // czerwone z podłączonym zasilaniem 1 + Red = 1.0f; + Green = 0.0f; + Blue = 0.0f; + break; + } + case 6: { + // zielone z podłączonym zasilaniem 2 + Red = 0.0f; + Green = 1.0f; + Blue = 0.0f; + break; + } + case 7: { + //żółte z podłączonym zasilaniem z obu stron + Red = 1.0f; + Green = 1.0f; + Blue = 0.0f; + break; + } + default: { break; } + } + if( hvParallel ) { // jeśli z bieżnią wspólną, to dodatkowo przyciemniamy + Red *= 0.6f; + Green *= 0.6f; + Blue *= 0.6f; + } + } +} \ No newline at end of file diff --git a/Traction.h b/Traction.h index 7dcbd496..e1484819 100644 --- a/Traction.h +++ b/Traction.h @@ -54,8 +54,7 @@ class TTraction TTraction *hvParallel = nullptr; // jednokierunkowa i zapętlona lista przęseł ewentualnej bieżni wspólnej float fResistance[2]; // rezystancja zastępcza do punktu zasilania (0: przęsło zasilane, <0: do policzenia) int iTries = 0; - // bool bVisible; - // DWORD dwFlags; + int PowerState{ 0 }; // type of incoming power, if any void Optimize(); @@ -78,5 +77,7 @@ class TTraction void ResistanceCalc(int d = -1, double r = 0, TTractionPowerSource *ps = NULL); void PowerSet(TTractionPowerSource *ps); double VoltageGet(double u, double i); +private: + void wire_color( float &Red, float &Green, float &Blue ) const; }; //--------------------------------------------------------------------------- diff --git a/Train.cpp b/Train.cpp index d7444fe8..b5525474 100644 --- a/Train.cpp +++ b/Train.cpp @@ -1600,7 +1600,7 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com if( Train->mvControlled->EngineType != DieselEngine ) { if( Train->mvControlled->MainSwitch( true ) ) { // side-effects - Train->mvControlled->ConverterSwitch( Train->ggConverterButton.GetValue() > 0.5 ); + Train->mvControlled->ConverterSwitch( ( Train->ggConverterButton.GetValue() > 0.5 ) || ( Train->mvControlled->ConverterStart == start::automatic ) ); Train->mvControlled->CompressorSwitch( Train->ggCompressorButton.GetValue() > 0.5 ); } } @@ -1636,6 +1636,11 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Command ) { + if( Train->mvControlled->ConverterStart == start::automatic ) { + // let the automatic thing do its automatic thing... + return; + } + if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down if( ( false == Train->mvControlled->ConverterAllow ) @@ -3680,7 +3685,7 @@ bool TTrain::Update( double const Deltatime ) // TODO: check whether it should affect entire consist for EMU // TODO: check whether it should happen if there's power supplied alternatively through hvcouplers // TODO: potentially move this to the mover module, as there isn't much reason to have this dependent on the operator presence - mvControlled->MainSwitch( false, ( mvControlled->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + mvControlled->MainSwitch( false, ( mvControlled->TrainType == dt_EZT ? range::unit : range::local ) ); } } @@ -3711,7 +3716,7 @@ bool TTrain::Update( double const Deltatime ) { mvControlled->ConvOvldFlag = true; if (mvControlled->TrainType != dt_EZT) - mvControlled->MainSwitch( false, ( mvControlled->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + mvControlled->MainSwitch( false, ( mvControlled->TrainType == dt_EZT ? range::unit : range::local ) ); } else if( fConverterTimer >= fConverterPrzekaznik ) { // changed switch from always true to take into account state of the compressor switch @@ -4440,9 +4445,10 @@ bool TTrain::Update( double const Deltatime ) tmp = DynamicObject->PrevConnected; if (tmp) - if (tmp->MoverParameters->Mains) + if ( mvControlled->Battery || mvControlled->ConverterFlag ) { - btLampkaWylSzybkiB.TurnOn(); + btLampkaWylSzybkiB.Turn( tmp->MoverParameters->Mains ); + btLampkaOporyB.Turn(tmp->MoverParameters->ResistorsFlagCheck()); btLampkaBezoporowaB.Turn( tmp->MoverParameters->ResistorsFlagCheck() || @@ -5312,7 +5318,7 @@ bool TTrain::Update( double const Deltatime ) switch (LampkaUniversal3_typ) { case 0: - btLampkaUniversal3.Turn(mvControlled->Battery); + btLampkaUniversal3.Turn( mvControlled->Battery || mvControlled->ConverterFlag ); break; case 1: btLampkaUniversal3.Turn(mvControlled->Mains); From 23f4892bcc2f74b490a62b25fd29d1ba73896117 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 16 May 2017 14:13:28 +0200 Subject: [PATCH 4/5] basic executable versioning --- EU07.cpp | 40 +++++++++++++++++++++++++++++++++++++++- Globals.cpp | 7 ++----- Globals.h | 2 -- Logs.cpp | 2 +- Traction.cpp | 33 ++++++++++++++++++--------------- World.cpp | 11 +++++------ maszyna.rc | Bin 5814 -> 6376 bytes maszyna.vcxproj.filters | 3 +++ stdafx.h | 1 + version.h | 5 +++++ 10 files changed, 74 insertions(+), 30 deletions(-) create mode 100644 version.h diff --git a/EU07.cpp b/EU07.cpp index 57162e81..291933d4 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -52,6 +52,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #pragma comment( lib, "setupapi.lib" ) #pragma comment( lib, "python27.lib" ) #pragma comment (lib, "dbghelp.lib") +#pragma comment (lib, "version.lib") #ifdef CAN_I_HAS_LIBPNG #pragma comment (lib, "libpng16.lib") #endif @@ -224,12 +225,49 @@ int main(int argc, char *argv[]) AllocConsole(); SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), FOREGROUND_GREEN ); } - +/* std::string executable( argv[ 0 ] ); auto const pathend = executable.rfind( '\\' ); Global::ExecutableName = ( pathend != std::string::npos ? executable.substr( executable.rfind( '\\' ) + 1 ) : executable ); +*/ + // retrieve product version from the file's version data table + { + auto const fileversionsize = ::GetFileVersionInfoSize( argv[ 0 ], NULL ); + std::vectorfileversiondata; fileversiondata.resize( fileversionsize ); + if( ::GetFileVersionInfo( argv[ 0 ], NULL, fileversionsize, fileversiondata.data() ) ) { + + struct lang_codepage { + WORD language; + WORD codepage; + } *langcodepage; + UINT datasize; + + ::VerQueryValue( + fileversiondata.data(), + TEXT( "\\VarFileInfo\\Translation" ), + (LPVOID*)&langcodepage, + &datasize ); + + std::string subblock; subblock.resize( 50 ); + ::StringCchPrintf( + &subblock[0], subblock.size(), + TEXT( "\\StringFileInfo\\%04x%04x\\ProductVersion" ), + langcodepage->language, + langcodepage->codepage ); + + VOID *stringdata; + if( ::VerQueryValue( + fileversiondata.data(), + subblock.data(), + &stringdata, + &datasize ) ) { + + Global::asVersion = std::string( reinterpret_cast(stringdata) ); + } + } + } for (int i = 1; i < argc; ++i) { diff --git a/Globals.cpp b/Globals.cpp index afd6a465..d34088fe 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -32,8 +32,7 @@ std::string Global::AppName{ "EU07" }; std::string Global::asCurrentSceneryPath = "scenery/"; std::string Global::asCurrentTexturePath = std::string(szTexturePath); std::string Global::asCurrentDynamicPath = ""; -int Global::iSlowMotion = - 0; // info o malym FPS: 0-OK, 1-wyłączyć multisampling, 3-promień 1.5km, 7-1km +int Global::iSlowMotion = 0; // info o malym FPS: 0-OK, 1-wyłączyć multisampling, 3-promień 1.5km, 7-1km TDynamicObject *Global::changeDynObj = NULL; // info o zmianie pojazdu double Global::ABuDebug = 0; std::string Global::asSky = "1"; @@ -48,9 +47,7 @@ GLFWwindow *Global::window; bool Global::shiftState; bool Global::ctrlState; int Global::iCameraLast = -1; -std::string Global::asRelease = "16.0.1172.482"; -std::string Global::asVersion = "Compilation 2017-03-19, release " + Global::asRelease; // tutaj, bo wysyłany -std::string Global::ExecutableName; +std::string Global::asVersion = "couldn't retrieve version string"; 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 double Global::fSunDeclination = 0.0; // deklinacja Słońca diff --git a/Globals.h b/Globals.h index ca665df5..c44fef01 100644 --- a/Globals.h +++ b/Globals.h @@ -266,9 +266,7 @@ class Global static float ZoomFactor; // determines current camera zoom level. TODO: move it to the renderer static float FieldOfView; // vertical field of view for the camera. TODO: move it to the renderer static int iCameraLast; - static std::string asRelease; // numer static std::string asVersion; // z opisem - static std::string ExecutableName; static GLint iMaxTextureSize; // maksymalny rozmiar tekstury static int iTextMode; // tryb pracy wyświetlacza tekstowego static int iScreenMode[12]; // numer ekranu wyświetlacza tekstowego diff --git a/Logs.cpp b/Logs.cpp index 6b1bd677..3770f7d9 100644 --- a/Logs.cpp +++ b/Logs.cpp @@ -112,7 +112,7 @@ void ErrorLog(const char *str) "logs/errors (" + filename_scenery() + ") " + filename_date() + ".txt" : "errors.txt" ); errors.open( filename, std::ios::trunc ); - errors << "EU07.EXE " + Global::asRelease << "\n"; + errors << "EU07.EXE " + Global::asVersion << "\n"; } if (str) errors << str; diff --git a/Traction.cpp b/Traction.cpp index 6aa04184..4aa4d8d3 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -599,10 +599,10 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) if (DebugModeFlag) // tylko podczas testów Material = 4; // pokazanie, że to przęsło ma podłączone zasilanie #else - // TBD, TODO: we don't need to maintain 4-7 value range as it's part of legacy system PowerState = 4; #endif - while (t ? !t->psPower[d] : false) // jeśli jest jakiś kolejny i nie ma ustalonego zasilacza + while( ( t != nullptr ) + && ( t->psPower[d] == nullptr ) ) // jeśli jest jakiś kolejny i nie ma ustalonego zasilacza { // ustawienie zasilacza i policzenie rezystancji zastępczej #ifdef EU07_USE_OLD_TRACTIONPOWER_CODE if (DebugModeFlag) // tylko podczas testów @@ -615,11 +615,14 @@ void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps) #else if( t->PowerState != 4 ) { // przęsła zasilającego nie modyfikować - if( t->PowerState < 4 ) { - // tymczasowo, aby zmieniła kolor + if( t->psPowered != nullptr ) { + t->PowerState = 4; } - t->PowerState |= d ? 2 : 1; // kolor zależny od strony, z której jest zasilanie + else { + // kolor zależny od strony, z której jest zasilanie + t->PowerState |= d ? 2 : 1; + } } #endif t->psPower[d] = ps; // skopiowanie wskaźnika zasilacza od danej strony @@ -751,34 +754,34 @@ TTraction::wire_color( float &Red, float &Green, float &Blue ) const { // tymczasowo pokazanie zasilanych odcinków switch( PowerState ) { - case 4: { - // niebieskie z podłączonym zasilaniem - Red = 0.5f; - Green = 0.5f; - Blue = 1.0f; - break; - } - case 5: { + case 1: { // czerwone z podłączonym zasilaniem 1 Red = 1.0f; Green = 0.0f; Blue = 0.0f; break; } - case 6: { + case 2: { // zielone z podłączonym zasilaniem 2 Red = 0.0f; Green = 1.0f; Blue = 0.0f; break; } - case 7: { + case 3: { //żółte z podłączonym zasilaniem z obu stron Red = 1.0f; Green = 1.0f; Blue = 0.0f; break; } + case 4: { + // niebieskie z podłączonym zasilaniem + Red = 0.5f; + Green = 0.5f; + Blue = 1.0f; + break; + } default: { break; } } if( hvParallel ) { // jeśli z bieżnią wspólną, to dodatkowo przyciemniamy diff --git a/World.cpp b/World.cpp index cb003bfe..b7a11860 100644 --- a/World.cpp +++ b/World.cpp @@ -281,11 +281,10 @@ bool TWorld::Init( GLFWwindow *Window ) { Global::window = Window; // do WM_COPYDATA Global::pCamera = &Camera; // Ra: wskaźnik potrzebny do likwidacji drgań - WriteLog("\nStarting MaSzyna rail vehicle simulator."); - WriteLog( "Release " + Global::asRelease + " (executable: " + Global::ExecutableName + ")" ); - WriteLog("Online documentation and additional files on http://eu07.pl"); - WriteLog("Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " - "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n"); + WriteLog( "\nStarting MaSzyna rail vehicle simulator (release: " + Global::asVersion + ")" ); + WriteLog( "For online documentation and additional files refer to: http://eu07.pl"); + WriteLog( "Authors: Marcin_EU, McZapkie, ABu, Winger, Tolaris, nbmx, OLO_EU, Bart, Quark-t, " + "ShaXbee, Oli_EU, youBy, KURS90, Ra, hunter, szociu, Stele, Q, firleju and others\n" ); UILayer.set_background( "logo" ); @@ -1982,7 +1981,7 @@ TWorld::Update_UI() { case( GLFW_KEY_F9 ) : { // informacja o wersji, sposobie wyświetlania i błędach OpenGL - uitextline1 = Global::asVersion; // informacja o wersji + uitextline1 = "MaSzyna " + Global::asVersion; // informacja o wersji if( Global::iMultiplayer ) { uitextline1 += " (multiplayer mode is active)"; } diff --git a/maszyna.rc b/maszyna.rc index ac76d2e13680f203d41ccdf7ae22f32e5ea40aa4..4736fb51865821fb456bc3acf5b565882f5eb1ab 100644 GIT binary patch delta 920 zcmdm{`@(R80@LJgj3UBi45z zH!HE-Ls5XLfAU0b(a8l|Vw*iUcQ7LB!=lWETWGTjcLeL?C;>67`HWFedh!+ltI6{O L#5T(arZEEmg|?y@iWmKH(CAe&I Vlc*GH9z#Au$;6GKlh=ug0RUdyG7ta& diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 618b4702..0dcd5af5 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -431,6 +431,9 @@ Header Files\input + + Header Files + diff --git a/stdafx.h b/stdafx.h index 4cd20a12..c331c425 100644 --- a/stdafx.h +++ b/stdafx.h @@ -26,6 +26,7 @@ #undef NOMINMAX #include #include +#include #endif // stl #include diff --git a/version.h b/version.h new file mode 100644 index 00000000..866a8597 --- /dev/null +++ b/version.h @@ -0,0 +1,5 @@ +#pragma once + +#define VERSION_MAJOR 17 +#define VERSION_MINOR 516 +#define VERSION_REVISION 0 From c6fbfbbb29f043e61f6b9bc16d543f131c9ac7dc Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 18 May 2017 01:52:04 +0200 Subject: [PATCH 5/5] build 170517. minor ai tweaks, scan direction update fix --- Driver.cpp | 103 ++++---- Driver.h | 12 +- Ground.cpp | 653 ++++++--------------------------------------------- Ground.h | 10 +- Track.cpp | 8 +- Train.cpp | 10 +- World.cpp | 19 +- renderer.cpp | 177 +++++++++++++- renderer.h | 2 + version.h | 2 +- 10 files changed, 332 insertions(+), 664 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index cf192ad7..5dc88575 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -82,8 +82,8 @@ Tutaj łączymy teorię z praktyką - tu nic nie działa i nikt nie wie dlaczego // stałe const double EasyReactionTime = 0.5; //[s] przebłyski świadomości dla zwykłej jazdy const double HardReactionTime = 0.2; -const double EasyAcceleration = 0.5; //[m/ss] -const double HardAcceleration = 0.9; +const double EasyAcceleration = 0.85; //[m/ss] +const double HardAcceleration = 9.81; const double PrepareTime = 2.0; //[s] przebłyski świadomości przy odpalaniu bool WriteLogFlag = false; @@ -450,7 +450,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) TEvent *pEvent{ nullptr }; double fLastDir{ 0.0 }; - if (iTableDirection != iDirection) { + if (iTableDirection != iDirection ) { // jeśli zmiana kierunku, zaczynamy od toru ze wskazanym pojazdem iTableDirection = iDirection; // ustalenie w jakim kierunku jest wypełniana tabelka względem pojazdu pTrack = pVehicle->RaTrackGet(); // odcinek, na którym stoi @@ -468,6 +468,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) SemNextStopIndex = -1; } else { + if( iTableDirection == 0 ) { return; } // kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor) if( ( SemNextStopIndex != -1 ) && ( sSpeedTable[SemNextStopIndex].fVelNext < 1.0 ) ) { @@ -501,6 +502,11 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) pTrack->Length() ); } + if( iTableDirection == 0 ) { + // don't bother + return; + } + if( fCurrentDistance >= fDistance ) { // all done return; @@ -1664,14 +1670,20 @@ void TController::AutoRewident() } }; +int TController::CheckDirection() { + + int d = mvOccupied->DirAbsolute; // który sprzęg jest z przodu + if( !d ) // jeśli nie ma ustalonego kierunku + d = mvOccupied->CabNo; // to jedziemy wg aktualnej kabiny + iDirection = d; // ustalenie kierunku jazdy (powinno zrobić PrepareEngine?) + return d; +} + bool TController::CheckVehicles(TOrders user) { // sprawdzenie stanu posiadanych pojazdów w składzie i zapalenie świateł TDynamicObject *p; // roboczy wskaźnik na pojazd iVehicles = 0; // ilość pojazdów w składzie - int d = mvOccupied->DirAbsolute; // który sprzęg jest z przodu - if (!d) // jeśli nie ma ustalonego kierunku - d = mvOccupied->CabNo; // to jedziemy wg aktualnej kabiny - iDirection = d; // ustalenie kierunku jazdy (powinno zrobić PrepareEngine?) + int d = CheckDirection(); d = d >= 0 ? 0 : 1; // kierunek szukania czoła (numer sprzęgu) pVehicles[0] = p = pVehicle->FirstFind(d); // pojazd na czele składu // liczenie pojazdów w składzie i ustalenie parametrów @@ -2058,20 +2070,22 @@ bool TController::PrepareEngine() mvOccupied->BatterySwitch(true); if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) { // jeśli silnikowy jest pantografującym - if (mvControlling->PantPress > 4.3) - { // jeżeli jest wystarczające ciśnienie w pantografach + mvControlling->PantFront( true ); + mvControlling->PantRear( true ); + if (mvControlling->PantPress < 4.2) { + // załączenie małej sprężarki + if( mvControlling->TrainType != dt_EZT ) { + // odłączenie zbiornika głównego, bo z nim nie da rady napompować + mvControlling->bPantKurek3 = false; + } + mvControlling->PantCompFlag = true; // załączenie sprężarki pantografów + } + else { + // jeżeli jest wystarczające ciśnienie w pantografach if ((!mvControlling->bPantKurek3) || (mvControlling->PantPress <= mvControlling->ScndPipePress)) // kurek przełączony albo główna już pompuje mvControlling->PantCompFlag = false; // sprężarkę pantografów można już wyłączyć - mvControlling->PantFront(true); - mvControlling->PantRear(true); - } - else if (mvControlling->PantPress < 4.2) //żeby nie załączał zaraz po przekroczeniu 4.0 - { // załączenie małej sprężarki - mvControlling->bPantKurek3 = - false; // odłączenie zbiornika głównego, bo z nim nie da rady napompować - mvControlling->PantCompFlag = true; // załączenie sprężarki pantografów } } // if (mvOccupied->TrainType==dt_EZT) @@ -2352,11 +2366,19 @@ bool TController::IncSpeed() if (tsGuardSignal->GetStatus() & DSBSTATUS_PLAYING) // jeśli gada, to nie jedziemy return false; bool OK = true; - if ( ( iDrivigFlags & moveDoorOpened ) - && ( VelDesired > 0.0 ) ) // to prevent door shuffle on stop - Doors(false); // zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime) - if (fActionTime < 0.0) // gdy jest nakaz poczekać z jazdą, to nie ruszać + if( ( iDrivigFlags & moveDoorOpened ) + && ( VelDesired > 0.0 ) ) { // to prevent door shuffle on stop + // zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime) + Doors( false ); + } + if( fActionTime < 0.0 ) { + // gdy jest nakaz poczekać z jazdą, to nie ruszać return false; + } + if( true == mvOccupied->DepartureSignal ) { + // shut off departure warning + mvOccupied->DepartureSignal = false; + } if (mvControlling->SlippingWheels) return false; // jak poślizg, to nie przyspieszamy switch (mvOccupied->EngineType) @@ -2528,8 +2550,6 @@ void TController::SpeedSet() switch (mvOccupied->EngineType) { case None: // McZapkie-041003: wagon sterowniczy - if (fActionTime >= -1.0) - mvOccupied->DepartureSignal = false; // trochę niech pobuczy, zanim pojedzie if (mvControlling->MainCtrlPosNo > 0) { // jeśli ma czym kręcić // TODO: sprawdzanie innego czlonu //if (!FuseFlagCheck()) @@ -2714,17 +2734,24 @@ void TController::Doors(bool what) { // zamykanie if (mvOccupied->DoorOpenCtrl == 1) { // jeśli drzwi sterowane z kabiny - if (AIControllFlag) - if (mvOccupied->DoorLeftOpened || mvOccupied->DoorRightOpened) - { // AI zamyka drzwi przed odjazdem - if (mvOccupied->DoorClosureWarning) + if( AIControllFlag ) { + if( mvOccupied->DoorLeftOpened || mvOccupied->DoorRightOpened ) { // AI zamyka drzwi przed odjazdem + if( ( true == mvOccupied->DoorClosureWarning ) + && ( false == mvOccupied->DepartureSignal ) + && ( true == TestFlag( iDrivigFlags, moveDoorOpened ) ) ) { mvOccupied->DepartureSignal = true; // załącenie bzyczka - mvOccupied->DoorLeft(false); // zamykanie drzwi - mvOccupied->DoorRight(false); + fActionTime = -3.0 - 0.1 * Random( 10 ); // 3-4 second wait + } + if( fActionTime > -0.5 ) { // Ra: trzeba by ustawić jakiś czas oczekiwania na zamknięcie się drzwi - fActionTime = -1.5 - 0.1 * Random(10); // czekanie sekundę, może trochę dłużej - iDrivigFlags &= ~moveDoorOpened; // nie wykonywać drugi raz + mvOccupied->DoorLeft( false ); // zamykanie drzwi + mvOccupied->DoorRight( false ); + iDrivigFlags &= ~moveDoorOpened; + // 1.5-2.5 sec wait, +potentially 0.5 remaining + fActionTime = -1.5 - 0.1 * Random( 10 ); + } } + } } else { // jeśli nie, to zamykanie w składzie wagonowym @@ -2736,7 +2763,7 @@ void TController::Doors(bool what) p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła) } // WaitingSet(5); //10 sekund tu to za długo, opóźnia odjazd o pół minuty - fActionTime = -1.5 - 0.1 * Random(10); // czekanie sekundę, może trochę dłużej + fActionTime = -3.0 - 0.1 * Random(10); // czekanie sekundę, może trochę dłużej iDrivigFlags &= ~moveDoorOpened; // zostały zamknięte - nie wykonywać drugi raz } } @@ -3261,18 +3288,12 @@ bool TController::UpdateSituation(double dt) { if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) { - if (mvOccupied->ScndPipePress > 4.3) // gdy główna sprężarka bezpiecznie nabije - // ciśnienie - mvControlling->bPantKurek3 = - true; // to można przestawić kurek na zasilanie pantografów z głównej pneumatyki + if (mvOccupied->ScndPipePress > 4.3) // gdy główna sprężarka bezpiecznie nabije ciśnienie + mvControlling->bPantKurek3 = true; // to można przestawić kurek na zasilanie pantografów z głównej pneumatyki fVoltage = 0.5 * (fVoltage + fabs(mvControlling->RunningTraction.TractionVoltage)); // uśrednione napięcie - // sieci: przy spadku - // poniżej wartości - // minimalnej opóźnić - // rozruch o losowy - // czas + // sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas if (fVoltage < mvControlling->EnginePowerSource.CollectorParameters .MinV) // gdy rozłączenie WS z powodu niskiego napięcia if (fActionTime >= 0) // jeśli czas oczekiwania nie został ustawiony diff --git a/Driver.h b/Driver.h index d33a2510..ea961098 100644 --- a/Driver.h +++ b/Driver.h @@ -320,9 +320,11 @@ class TController // procedury dotyczace rozkazow dla maszynisty void SetVelocity(double NewVel, double NewVelNext, TStopReason r = stopNone); // uaktualnia informacje o prędkości +/* bool SetProximityVelocity( double NewDist, double NewVelNext); // uaktualnia informacje o prędkości przy nastepnym semaforze +*/ public: void JumpToNextOrder(); void JumpToFirstOrder(); @@ -331,6 +333,7 @@ class TController inline TOrders OrderCurrentGet(); inline TOrders OrderNextGet(); bool CheckVehicles(TOrders user = Wait_for_orders); + int CheckDirection(); private: void CloseLog(); @@ -351,21 +354,22 @@ class TController void DirectionForward(bool forward); int OrderDirectionChange(int newdir, TMoverParameters *Vehicle); void Lights(int head, int rear); - double Distance(vector3 &p1, vector3 &n, vector3 &p2); +// double Distance(vector3 &p1, vector3 &n, vector3 &p2); private: // Ra: metody obsługujące skanowanie toru TEvent *CheckTrackEvent(double fDirection, TTrack *Track); - bool TableCheckEvent(TEvent *e); +// bool TableCheckEvent(TEvent *e); bool TableAddNew(); bool TableNotFound(TEvent const *Event) const; - void TableClear(); - TEvent *TableCheckTrackEvent(double fDirection, TTrack *Track); +// TEvent *TableCheckTrackEvent(double fDirection, TTrack *Track); void TableTraceRoute(double fDistance, TDynamicObject *pVehicle = NULL); void TableCheck(double fDistance); TCommandType TableUpdate(double &fVelDes, double &fDist, double &fNext, double &fAcc); void TablePurger(); public: std::size_t TableSize() const { return sSpeedTable.size(); } + void TableClear(); + int TableDirection() { return iTableDirection; } private: // Ra: stare funkcje skanujące, używane do szukania sygnalizatora z tyłu bool BackwardTrackBusy(TTrack *Track); diff --git a/Ground.cpp b/Ground.cpp index 7c6ab766..2ba293fa 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -50,6 +50,9 @@ extern "C" bool bCondition; // McZapkie: do testowania warunku na event multiple std::string LogComment; +// TODO: switch to the new unified code after we have in place merging of individual triangle nodes into material-based soups +#define EU07_USE_OLD_RENDERCODE + //--------------------------------------------------------------------------- // Obiekt renderujący siatkę jest sztucznie tworzonym obiektem pomocniczym, // grupującym siatki obiektów dla danej tekstury. Obiektami składowymi mogą @@ -289,145 +292,6 @@ void TGroundNode::RaRenderVBO() glDrawArrays(iType, iVboPtr, iNumVerts); // Narysuj naraz wszystkie trójkąty } -#ifdef EU07_USE_OLD_RENDERCODE -void TGroundNode::RenderVBO() { // renderowanie obiektu z VBO - faza nieprzezroczystych - - switch( iType ) { // obiekty renderowane niezależnie od odległości - case TP_SUBMODEL: - TSubModel::fSquareDist = 0; - GfxRenderer.Render( smTerrain ); - } - - double distancesquared = SquareMagnitude( pCenter - Global::pCameraPosition ) / Global::ZoomFactor; - if( ( distancesquared > ( fSquareRadius * Global::fDistanceFactor ) ) - || ( distancesquared < ( fSquareMinRadius / Global::fDistanceFactor ) ) ) { - return; - } - - switch( iType ) { - case TP_TRACK: { - if( iNumVerts ) - pTrack->RaRenderVBO( iVboPtr ); - return; - } - case TP_MODEL: { - Model->Render( &pCenter ); - return; - } - case TP_MEMCELL: { - GfxRenderer.Render( MemCell ); - return; - } - } - - if( ( iFlags & 0x10 ) || ( fLineThickness < 0 ) ) { - - if( ( iType == GL_LINES ) || ( iType == GL_LINE_STRIP ) || ( iType == GL_LINE_LOOP ) ) { - - if( iNumPts ) { - - float linealpha = 255000 * fLineThickness / ( distancesquared + 1.0 ); - if( linealpha > 255 ) - linealpha = 255; - float r, g, b; - r = floor( Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ); // w zaleznosci od koloru swiatla - g = floor( Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ] ); - b = floor( Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ] ); - glColor4ub( r, g, b, linealpha ); // przezroczystosc dalekiej linii - GfxRenderer.Bind( 0 ); - - glDrawArrays( iType, iVboPtr, iNumPts ); // rysowanie linii - } - } - // GL_TRIANGLE etc - else { - if( iVboPtr >= 0 ) { - RaRenderVBO(); - } - } - - SetLastUsage( Timer::GetSimulationTime() ); - } -}; - -void TGroundNode::RenderAlphaVBO() -{ // renderowanie obiektu z VBO - faza przezroczystych - - double distancesquared = SquareMagnitude( pCenter - Global::pCameraPosition ) / Global::ZoomFactor; - if( ( distancesquared > ( fSquareRadius * Global::fDistanceFactor ) ) - || ( distancesquared < ( fSquareMinRadius / Global::fDistanceFactor ) ) ) { - return; - } - - switch( iType ) { - case TP_TRACTION: { - if( bVisible ) { - hvTraction->RenderVBO( distancesquared, iVboPtr ); - } - return; - } - case TP_MODEL: { - Model->RenderAlpha( &pCenter ); - return; - } - } - - // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 - if( ( iNumVerts && ( iFlags & 0x20 ) ) - || ( iNumPts && ( fLineThickness > 0 ) ) ) { - -#ifdef _PROBLEND - if( ( PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - glDisable( GL_BLEND ); - glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - }; -#endif - - if( ( iType == GL_LINES ) - || ( iType == GL_LINE_STRIP ) - || ( iType == GL_LINE_LOOP ) ) { - - if( iNumPts ) { - - float linealpha = 255000 * fLineThickness / (distancesquared + 1.0); - if (linealpha > 255) - linealpha = 255; -#ifdef EU07_USE_OLD_LIGHTING_MODEL - r = Diffuse[ 0 ] * Global::ambientDayLight[ 0 ]; // w zaleznosci od koloru swiatla - g = Diffuse[ 1 ] * Global::ambientDayLight[ 1 ]; - b = Diffuse[ 2 ] * Global::ambientDayLight[ 2 ]; -#else - float r = Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ]; // w zaleznosci od koloru swiatla - float g = Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ]; - float b = Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ]; -#endif - glColor4ub( r, g, b, linealpha ); // przezroczystosc dalekiej linii - GfxRenderer.Bind( 0 ); - - glDrawArrays( iType, iVboPtr, iNumPts ); // rysowanie linii - } - } - else { - if( iVboPtr >= 0 ) { - RaRenderVBO(); - } - } - - SetLastUsage( Timer::GetSimulationTime() ); - } - -#ifdef _PROBLEND - if( ( PROBLEND ) ) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - glEnable( GL_BLEND ); - glAlphaFunc( GL_GREATER, 0.04f ); - } -#endif -} - -#endif - void TGroundNode::Compile(bool many) { // tworzenie skompilowanej listy w wyświetlaniu DL if (!many) @@ -444,34 +308,32 @@ void TGroundNode::Compile(bool many) if ((iType == GL_LINES) || (iType == GL_LINE_STRIP) || (iType == GL_LINE_LOOP)) { glBegin(iType); - for (int i = 0; i < iNumPts; i++) + for (int i = 0; i < iNumPts; ++i) glVertex3dv(&Points[i].x); glEnd(); } else if (iType == GL_TRIANGLE_STRIP || iType == GL_TRIANGLE_FAN || iType == GL_TRIANGLES) { // jak nie linie, to trójkąty - TGroundNode *tri = this; - do - { // pętla po obiektach w grupie w celu połączenia siatek - // TODO: eliminate these calls, they're duplicated by setup part in the unified render function - glColor3ub(tri->Diffuse[0], tri->Diffuse[1], tri->Diffuse[2]); - GfxRenderer.Bind(Global::bWireFrame ? 0 : tri->TextureID); - - glBegin(Global::bWireFrame ? GL_LINE_LOOP : tri->iType); - for (int i = 0; i < tri->iNumVerts; i++) - { - glNormal3dv(&tri->Vertices[i].Normal.x); - glTexCoord2f(tri->Vertices[i].tu, tri->Vertices[i].tv); - glVertex3dv(&tri->Vertices[i].Point.x); - }; - glEnd(); - tri = NULL; // a jak nie, to koniec - } while (tri); + // TODO: eliminate these calls, they're duplicated by setup part in the unified render function +#ifdef EU07_USE_OLD_RENDERCODE + glColor3ub(Diffuse[0], Diffuse[1], Diffuse[2]); + GfxRenderer.Bind(TextureID); +#endif + glBegin(iType); + for (int i = 0; i < iNumVerts; ++i) + { + glNormal3dv(&Vertices[i].Normal.x); + glTexCoord2f(Vertices[i].tu, Vertices[i].tv); + glVertex3dv(&Vertices[i].Point.x); + }; + glEnd(); } else if (iType == TP_MESH) { // grupa ze wspólną teksturą - wrzucanie do wspólnego Display List +#ifdef EU07_USE_OLD_RENDERCODE if (TextureID) GfxRenderer.Bind(TextureID); // Ustaw aktywną teksturę +#endif TGroundNode *n = nNode; while (n ? n->TextureID == TextureID : false) { // wszystkie obiekty o tej samej testurze @@ -523,161 +385,6 @@ void TGroundNode::RenderHidden() } }; -#ifdef EU07_USE_OLD_RENDERCODE -void TGroundNode::RenderDL() -{ // wyświetlanie obiektu przez Display List - switch (iType) - { // obiekty renderowane niezależnie od odległości - case TP_SUBMODEL: - TSubModel::fSquareDist = 0; - GfxRenderer.Render( smTerrain ); - } - - double distancesquared = SquareMagnitude(pCenter - Global::pCameraPosition) / Global::ZoomFactor; - if( ( distancesquared > ( fSquareRadius * Global::fDistanceFactor ) ) - || ( distancesquared < ( fSquareMinRadius / Global::fDistanceFactor ) ) ) { - return; - } - - switch (iType) - { - case TP_TRACK: { - pTrack->Render(); - return; - } - case TP_MODEL: { - Model->Render( &pCenter ); - return; - } - case TP_MEMCELL: { - GfxRenderer.Render( MemCell ); - return; - } - } - - // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 - if ((iFlags & 0x10) || (fLineThickness < 0)) - { - if (!DisplayListID || (iVersion != Global::iReCompile)) // Ra: wymuszenie rekompilacji - { - Compile(); - if (Global::bManageNodes) - ResourceManager::Register(this); - }; - - if ((iType == GL_LINES) || (iType == GL_LINE_STRIP) || (iType == GL_LINE_LOOP)) - { // wszelkie linie są rysowane na samym końcu - if( iNumPts ) { - - float linealpha = 255000 * fLineThickness / ( distancesquared + 1.0 ); - if( linealpha > 255 ) - linealpha = 255; - float r, g, b; - r = floor( Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ] ); // w zaleznosci od koloru swiatla - g = floor( Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ] ); - b = floor( Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ] ); - glColor4ub( r, g, b, linealpha ); // przezroczystosc dalekiej linii - GfxRenderer.Bind( 0 ); - - glCallList( DisplayListID ); - } - } - // GL_TRIANGLE etc - else - glCallList(DisplayListID); - - SetLastUsage(Timer::GetSimulationTime()); - }; -}; - -void TGroundNode::RenderAlphaDL() -{ - // SPOSOB NA POZBYCIE SIE RAMKI DOOKOLA TEXTURY ALPHA DLA OBIEKTOW ZAGNIEZDZONYCH W SCN JAKO - // NODE - - // W GROUND.H dajemy do klasy TGroundNode zmienna bool PROBLEND to samo robimy w klasie TGround - // nastepnie podczas wczytywania textury dla TRIANGLES w TGround::AddGroundNode - // sprawdzamy czy w nazwie jest @ i wg tego - // ustawiamy PROBLEND na true dla wlasnie wczytywanego trojkata (kazdy trojkat jest osobnym - // nodem) - // nastepnie podczas renderowania w bool TGroundNode::RenderAlpha() - // na poczatku ustawiamy standardowe GL_GREATER = 0.04 - // pozniej sprawdzamy czy jest wlaczony PROBLEND dla aktualnie renderowanego noda TRIANGLE, - // wlasciwie dla kazdego node'a - // i jezeli tak to odpowiedni GL_GREATER w przeciwnym wypadku standardowy 0.04 - - double distancesquared = SquareMagnitude( pCenter - Global::pCameraPosition ) / Global::ZoomFactor; - if( ( distancesquared > ( fSquareRadius * Global::fDistanceFactor ) ) - || ( distancesquared < ( fSquareMinRadius / Global::fDistanceFactor ) ) ) { - return; - } - - switch( iType ) { - case TP_TRACTION: { - if( bVisible ) - hvTraction->RenderDL( distancesquared ); - return; - } - case TP_MODEL: { - Model->RenderAlpha( &pCenter ); - return; - } - }; - - // TODO: sprawdzic czy jest potrzebny warunek fLineThickness < 0 - if( ( iNumVerts && ( iFlags & 0x20 ) ) - || ( iNumPts && ( fLineThickness > 0 ) ) ) { - -#ifdef _PROBLEND - if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - glDisable(GL_BLEND); - glAlphaFunc(GL_GREATER, 0.50f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - }; -#endif - if (!DisplayListID) //||Global::bReCompile) //Ra: wymuszenie rekompilacji - { - Compile(); - if (Global::bManageNodes) - ResourceManager::Register(this); - }; - - if( ( iType == GL_LINES ) - || ( iType == GL_LINE_STRIP ) - || ( iType == GL_LINE_LOOP ) ) { - - if( iNumPts ) { - - float linealpha = 255000 * fLineThickness / ( distancesquared + 1.0 ); - if (linealpha > 255) - linealpha = 255; - float r = Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ]; // w zaleznosci od koloru swiatla - float g = Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ]; - float b = Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ]; - glColor4ub( r, g, b, linealpha ); // przezroczystosc dalekiej linii - GfxRenderer.Bind( 0 ); - - glCallList( DisplayListID ); - } - } - // GL_TRIANGLE etc - else { - glCallList( DisplayListID ); - } - - SetLastUsage(Timer::GetSimulationTime()); - } - -#ifdef _PROBLEND - if ((PROBLEND)) // sprawdza, czy w nazwie nie ma @ //Q: 13122011 - Szociu: 27012012 - { - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER, 0.04f); - } -#endif -} -#endif - //------------------------------------------------------------------------------ //------------------ Podstawowy pojemnik terenu - sektor ----------------------- //------------------------------------------------------------------------------ @@ -701,7 +408,6 @@ void TSubRect::NodeAdd(TGroundNode *Node) // nRenderAlpha - lista grup renderowanych z własnych VBO albo DL z przezroczystością // nRenderWires - lista grup renderowanych z własnych VBO albo DL - druty i linie // nMeshed - obiekty do pogrupowania wg tekstur - GLuint t; // pomocniczy kod tekstury switch (Node->iType) { case TP_SOUND: // te obiekty są sprawdzanie niezależnie od kierunku patrzenia @@ -720,7 +426,7 @@ void TSubRect::NodeAdd(TGroundNode *Node) else { // tory nieruchome mogą być pogrupowane wg tekstury, przy VBO wszystkie Node->TextureID = Node->pTrack->TextureGet(0); // pobranie tekstury do sortowania - t = Node->pTrack->TextureGet(1); + GLuint t = Node->pTrack->TextureGet(1); if (Node->TextureID) // jeżeli jest pierwsza { if (t && (Node->TextureID != t)) @@ -757,6 +463,7 @@ void TSubRect::NodeAdd(TGroundNode *Node) Node->nNext3 = nRenderRectAlpha; nRenderRectAlpha = Node; } // DL: do przezroczystych z sektora +#ifdef EU07_USE_OLD_RENDERCODE else if (Global::bUseVBO) { Node->nNext3 = nRenderRect; @@ -767,23 +474,12 @@ void TSubRect::NodeAdd(TGroundNode *Node) Node->nNext3 = nRender; nRender = Node; } // DL: do nieprzezroczystych wszelakich - /* - //Ra: na razie wyłączone do testów VBO - //if - ((Node->iType==GL_TRIANGLE_STRIP)||(Node->iType==GL_TRIANGLE_FAN)||(Node->iType==GL_TRIANGLES)) - if (Node->fSquareMinRadius==0.0) //znikające z bliska nie mogą być optymalizowane - if (Node->fSquareRadius>=160000.0) //tak od 400m to już normalne trójkąty muszą być - //if (Node->iFlags&0x10) //i nieprzezroczysty - {if (pTriGroup) //jeżeli był już jakiś grupujący - {if (pTriGroup->fSquareRadius>Node->fSquareRadius) //i miał większy zasięg - Node->fSquareRadius=pTriGroup->fSquareRadius; //zwiększenie zakresu widoczności - grupującego - pTriGroup->pTriGroup=Node; //poprzedniemu doczepiamy nowy - } - Node->pTriGroup=Node; //nowy lider ma się sam wyświetlać - wskaźnik na siebie - pTriGroup=Node; //zapamiętanie lidera - } - */ +#else + else { + Node->nNext3 = nRenderRect; + nRenderRect = Node; + } // do nieprzezroczystych z sektora +#endif break; case TP_TRACTION: case GL_LINES: @@ -834,6 +530,7 @@ void TSubRect::RaNodeAdd(TGroundNode *Node) switch (Node->iType) { case TP_TRACK: +#ifdef EU07_USE_OLD_RENDERCODE if (Global::bUseVBO) { Node->nNext3 = nRenderRect; @@ -844,6 +541,10 @@ void TSubRect::RaNodeAdd(TGroundNode *Node) Node->nNext3 = nRender; nRender = Node; } // DL: do nieprzezroczystych +#else + Node->nNext3 = nRenderRect; + nRenderRect = Node; +#endif break; case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: @@ -853,6 +554,7 @@ void TSubRect::RaNodeAdd(TGroundNode *Node) Node->nNext3 = nRenderRectAlpha; nRenderRectAlpha = Node; } // DL: do przezroczystych z sektora +#ifdef EU07_USE_OLD_RENDERCODE else if (Global::bUseVBO) { Node->nNext3 = nRenderRect; @@ -863,6 +565,12 @@ void TSubRect::RaNodeAdd(TGroundNode *Node) Node->nNext3 = nRender; nRender = Node; } // DL: do nieprzezroczystych wszelakich +#else + else { + Node->nNext3 = nRenderRect; + nRenderRect = Node; + } // do nieprzezroczystych z sektora +#endif break; case TP_MODEL: // modele zawsze wyświetlane z własnego VBO if ((Node->iFlags & 0x20200020) == 0) // czy brak przezroczystości? @@ -1003,7 +711,7 @@ bool TSubRect::RaTrackAnimAdd(TTrack *t) void TSubRect::RaAnimate() { // wykonanie animacji - if( !tTrackAnim ) { + if( tTrackAnim == nullptr ) { // nie ma nic do animowania return; } @@ -1075,7 +783,7 @@ void TSubRect::LoadNodes() } n = n->nNext2; // następny z sektora } - if (!m_nVertexCount) + if (m_nVertexCount <= 0) return; // jeśli nie ma obiektów do wyświetlenia z VBO, to koniec if (Global::bUseVBO) { // tylko liczenie wierzchołów, gdy nie ma VBO @@ -1146,6 +854,12 @@ void TSubRect::RenderDL() { // renderowanie nieprzezroczystych (DL) TGroundNode *node; RaAnimate(); // przeliczenia animacji torów w sektorze +/* + LoadNodes(); // czemu tutaj? +*/ + for( node = nRenderRect; node; node = node->nNext3 ) { + GfxRenderer.Render( node ); // nieprzezroczyste obiekty terenu + } for( node = nRender; node; node = node->nNext3 ) GfxRenderer.Render( node ); // nieprzezroczyste obiekty (oprócz pojazdów) for (node = nRenderMixed; node; node = node->nNext3) @@ -1160,44 +874,6 @@ void TSubRect::RenderDL() } } #endif -/* - float width = 100.0f; - float height = 25.0f; - float3 vTopLeftFront( m_area.center.x - width, m_area.center.y + height, m_area.center.z + width ); - float3 vTopLeftBack( m_area.center.x - width, m_area.center.y + height, m_area.center.z - width ); - float3 vTopRightBack( m_area.center.x + width, m_area.center.y + height, m_area.center.z - width ); - float3 vTopRightFront( m_area.center.x + width, m_area.center.y + height, m_area.center.z + width ); - - float3 vBottom_LeftFront( m_area.center.x - width, m_area.center.y - height, m_area.center.z + width ); - float3 vBottom_LeftBack( m_area.center.x - width, m_area.center.y - height, m_area.center.z - width ); - float3 vBottomRightBack( m_area.center.x + width, m_area.center.y - height, m_area.center.z - width ); - float3 vBottomRightFront( m_area.center.x + width, m_area.center.y - height, m_area.center.z + width ); - - glDisable( GL_LIGHTING ); - glDisable( GL_TEXTURE_2D ); - glColor3ub( 255, 255, (iTracks ? 0 : 255) ); - glBegin( GL_LINE_LOOP ); - glVertex3fv( &vTopLeftFront.x ); - glVertex3fv( &vTopLeftBack.x ); - glVertex3fv( &vTopRightBack.x ); - glVertex3fv( &vTopRightFront.x ); - glEnd(); - glBegin( GL_LINE_LOOP ); - glVertex3fv( &vBottom_LeftFront.x ); - glVertex3fv( &vBottom_LeftBack.x ); - glVertex3fv( &vBottomRightBack.x ); - glVertex3fv( &vBottomRightFront.x ); - glEnd(); - glBegin( GL_LINES ); - glVertex3fv( &vTopLeftFront.x ); glVertex3fv( &vBottom_LeftFront.x ); - glVertex3fv( &vTopLeftBack.x ); glVertex3fv( &vBottom_LeftBack.x ); - glVertex3fv( &vTopRightBack.x ); glVertex3fv( &vBottomRightBack.x ); - glVertex3fv( &vTopRightFront.x ); glVertex3fv( &vBottomRightFront.x ); - glEnd(); - glColor3ub( 255, 255, 255 ); - glEnable( GL_TEXTURE_2D ); - glEnable( GL_LIGHTING ); -*/ }; void TSubRect::RenderAlphaDL() @@ -1215,7 +891,9 @@ void TSubRect::RenderVBO() { // renderowanie nieprzezroczystych (VBO) TGroundNode *node; RaAnimate(); // przeliczenia animacji torów w sektorze +/* LoadNodes(); // czemu tutaj? +*/ if (StartVBO()) { for( node = nRenderRect; node; node = node->nNext3 ) @@ -1285,6 +963,7 @@ TGroundRect::Init() { void TGroundRect::RenderDL() { // renderowanie kwadratu kilometrowego (DL), jeśli jeszcze nie zrobione +#ifdef EU07_USE_OLD_RENDERCODE if (iLastDisplay != iFrameNumber) { // tylko jezeli dany kwadrat nie był jeszcze renderowany // for (TGroundNode* node=pRender;node;node=node->pNext3) @@ -1307,6 +986,18 @@ void TGroundRect::RenderDL() GfxRenderer.Render( nRootMesh ); iLastDisplay = iFrameNumber; // drugi raz nie potrzeba } +#else + if( iLastDisplay != iFrameNumber ) { // tylko jezeli dany kwadrat nie był jeszcze renderowany + LoadNodes(); // ewentualne tworzenie siatek + if( nRenderRect ) { + for( TGroundNode *node = nRenderRect; node; node = node->nNext3 ) // następny tej grupy + GfxRenderer.Render( node ); // nieprzezroczyste trójkąty kwadratu kilometrowego + } + if( nRootMesh ) + GfxRenderer.Render( nRootMesh ); + iLastDisplay = iFrameNumber; + } +#endif }; void TGroundRect::RenderVBO() @@ -1314,10 +1005,14 @@ void TGroundRect::RenderVBO() if (iLastDisplay != iFrameNumber) { // tylko jezeli dany kwadrat nie był jeszcze renderowany LoadNodes(); // ewentualne tworzenie siatek - if (StartVBO()) + if ( nRenderRect && StartVBO()) { for (TGroundNode *node = nRenderRect; node; node = node->nNext3) // następny tej grupy +#ifdef EU07_USE_OLD_RENDERCODE node->RaRenderVBO(); // nieprzezroczyste trójkąty kwadratu kilometrowego +#else + GfxRenderer.Render( node ); // nieprzezroczyste trójkąty kwadratu kilometrowego +#endif EndVBO(); iLastDisplay = iFrameNumber; } @@ -4619,220 +4314,6 @@ bool TGround::GetTraction(TDynamicObject *model) return true; }; -bool -TGround::Render( Math3D::vector3 const &Camera ) { - - GfxRenderer.Update_Lights( m_lights ); - - if( Global::bUseVBO ) { // renderowanie przez VBO - if( !RenderVBO( Camera ) ) - return false; - if( !RenderAlphaVBO( Camera ) ) - return false; - } - else { - // renderowanie przez Display List - if( !RenderDL( Camera ) ) - return false; - if( !RenderAlphaDL( Camera ) ) - return false; - } - return true; -} - -bool TGround::RenderDL(vector3 pPosition) -{ // renderowanie scenerii z Display List - faza nieprzezroczystych - glDisable(GL_BLEND); - glAlphaFunc(GL_GREATER, 0.50f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) - CameraDirection.x = sin(Global::pCameraRotation); // wektor kierunkowy - CameraDirection.z = cos(Global::pCameraRotation); - TGroundNode *node; - glColor3f(1.0f, 1.0f, 1.0f); - glEnable(GL_LIGHTING); - int n = 2 * iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach - int c = GetColFromX(pPosition.x); - int r = GetRowFromZ(pPosition.z); - TSubRect *tmp; - for (node = srGlobal.nRenderHidden; node; node = node->nNext3) - node->RenderHidden(); // rednerowanie globalnych (nie za często?) - int i, j, k; - // renderowanie czołgowe dla obiektów aktywnych a niewidocznych - for (j = r - n; j <= r + n; j++) - for (i = c - n; i <= c + n; i++) - if ((tmp = FastGetSubRect(i, j)) != NULL) - { - tmp->LoadNodes(); // oznaczanie aktywnych sektorów - for (node = tmp->nRenderHidden; node; node = node->nNext3) - node->RenderHidden(); - tmp->RenderSounds(); // jeszcze dźwięki pojazdów by się przydały, również - // niewidocznych - } - // renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - iRendered = 0; // ilość renderowanych sektorów - vector3 direction; - for (k = 0; k < Global::iSegmentsRendered; ++k) // sektory w kolejności odległości - { // przerobione na użycie SectorOrder - i = SectorOrder[k].x; // na starcie oba >=0 - j = SectorOrder[k].y; - do - { - if (j <= 0) - i = -i; // pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0 - // czwarty: j>=0, i>=0; - j = -j; // i oraz j musi być zmienione wcześniej, żeby continue działało - direction = vector3(i, 0, j); // wektor od kamery do danego sektora - if (LengthSquared3(direction) > 5) // te blisko są zawsze wyświetlane - { - direction = SafeNormalize(direction); // normalizacja - if (CameraDirection.x * direction.x + CameraDirection.z * direction.z < 0.55) - continue; // pomijanie sektorów poza kątem patrzenia - } - // NOTE: terrain data is disabled, as it's moved to the renderer - Rects[(i + c) / iNumSubRects][(j + r) / iNumSubRects] - .RenderDL(); // kwadrat kilometrowy nie zawsze, bo szkoda FPS - if ((tmp = FastGetSubRect(i + c, j + r)) != NULL) - if (tmp->iNodeCount) // o ile są jakieś obiekty, bo po co puste sektory przelatywać - pRendered[iRendered++] = tmp; // tworzenie listy sektorów do renderowania - } while ((i < 0) || (j < 0)); // są 4 przypadki, oprócz i=j=0 - } - for (i = 0; i < iRendered; i++) - pRendered[i]->RenderDL(); // renderowanie nieprzezroczystych - return true; -} - -bool TGround::RenderAlphaDL(vector3 pPosition) -{ // renderowanie scenerii z Display List - faza przezroczystych - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER, 0.04f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - TGroundNode *node; - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - TSubRect *tmp; - // Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - int i; - for (i = iRendered - 1; i >= 0; --i) // od najdalszych - { // przezroczyste trójkąty w oddzielnym cyklu przed modelami - tmp = pRendered[i]; - for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) - GfxRenderer.Render_Alpha( node ); // przezroczyste modele - } - for (i = iRendered - 1; i >= 0; --i) // od najdalszych - { // renderowanie przezroczystych modeli oraz pojazdów - pRendered[i]->RenderAlphaDL(); - } - glDisable(GL_LIGHTING); // linie nie powinny świecić - for (i = iRendered - 1; i >= 0; --i) // od najdalszych - { // druty na końcu, żeby się nie robiły białe plamy na tle lasu - tmp = pRendered[i]; - for( node = tmp->nRenderWires; node; node = node->nNext3 ) - GfxRenderer.Render_Alpha( node ); // druty - } - return true; -} - -bool TGround::RenderVBO(vector3 pPosition) -{ // renderowanie scenerii z VBO - faza nieprzezroczystych - glDisable(GL_BLEND); - glAlphaFunc(GL_GREATER, 0.50f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek - CameraDirection.x = sin(Global::pCameraRotation); // wektor kierunkowy - CameraDirection.z = cos(Global::pCameraRotation); - TGroundNode *node; - glColor3f(1.0f, 1.0f, 1.0f); - glEnable(GL_LIGHTING); - int n = 2 * iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach - int c = GetColFromX(pPosition.x); - int r = GetRowFromZ(pPosition.z); - TSubRect *tmp; - for (node = srGlobal.nRenderHidden; node; node = node->nNext3) - node->RenderHidden(); // rednerowanie globalnych (nie za często?) - int i, j, k; - // renderowanie czołgowe dla obiektów aktywnych a niewidocznych - for (j = r - n; j <= r + n; j++) - for (i = c - n; i <= c + n; i++) - { - if ((tmp = FastGetSubRect(i, j)) != NULL) - { - for (node = tmp->nRenderHidden; node; node = node->nNext3) - node->RenderHidden(); - tmp->RenderSounds(); // jeszcze dźwięki pojazdów by się przydały, również - // niewidocznych - } - } - // renderowanie progresywne - zależne od FPS oraz kierunku patrzenia - iRendered = 0; // ilość renderowanych sektorów - vector3 direction; - for (k = 0; k < Global::iSegmentsRendered; ++k) // sektory w kolejności odległości - { // przerobione na użycie SectorOrder - i = SectorOrder[k].x; // na starcie oba >=0 - j = SectorOrder[k].y; - do - { - if (j <= 0) - i = -i; // pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0 - // czwarty: j>=0, i>=0; - j = -j; // i oraz j musi być zmienione wcześniej, żeby continue działało - direction = vector3(i, 0, j); // wektor od kamery do danego sektora - if (LengthSquared3(direction) > 5) // te blisko są zawsze wyświetlane - { - direction = SafeNormalize(direction); // normalizacja - if (CameraDirection.x * direction.x + CameraDirection.z * direction.z < 0.55) - continue; // pomijanie sektorów poza kątem patrzenia - } - Rects[(i + c) / iNumSubRects][(j + r) / iNumSubRects] - .RenderVBO(); // kwadrat kilometrowy nie zawsze, bo szkoda FPS - if ((tmp = FastGetSubRect(i + c, j + r)) != NULL) - if (tmp->iNodeCount) // jeżeli są jakieś obiekty, bo po co puste sektory przelatywać - pRendered[iRendered++] = tmp; // tworzenie listy sektorów do renderowania - } while ((i < 0) || (j < 0)); // są 4 przypadki, oprócz i=j=0 - } - // dodać rednerowanie terenu z E3D - jedno VBO jest używane dla całego modelu, chyba że jest ich - // więcej - if (Global::pTerrainCompact) - Global::pTerrainCompact->TerrainRenderVBO(TGroundRect::iFrameNumber); - for (i = 0; i < iRendered; i++) - { // renderowanie nieprzezroczystych - pRendered[i]->RenderVBO(); - } - return true; -} - -bool TGround::RenderAlphaVBO(vector3 pPosition) -{ // renderowanie scenerii z VBO - faza przezroczystych - glEnable(GL_BLEND); - glAlphaFunc(GL_GREATER, 0.04f); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f - TGroundNode *node; - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - TSubRect *tmp; - int i; - for (i = iRendered - 1; i >= 0; --i) // od najdalszych - { // renderowanie przezroczystych trójkątów sektora - tmp = pRendered[i]; - tmp->LoadNodes(); // ewentualne tworzenie siatek - if (tmp->StartVBO()) - { - for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) - if( node->iVboPtr >= 0 ) - GfxRenderer.Render_Alpha( node ); // nieprzezroczyste obiekty terenu - tmp->EndVBO(); - } - } - for (i = iRendered - 1; i >= 0; --i) // od najdalszych - pRendered[i]->RenderAlphaVBO(); // przezroczyste modeli oraz pojazdy - glDisable(GL_LIGHTING); // linie nie powinny świecić - for (i = iRendered - 1; i >= 0; --i) // od najdalszych - { // druty na końcu, żeby się nie robiły białe plamy na tle lasu - tmp = pRendered[i]; - if (tmp->StartVBO()) - { - for( node = tmp->nRenderWires; node; node = node->nNext3 ) - GfxRenderer.Render_Alpha( node ); // przezroczyste modele - tmp->EndVBO(); - } - } - return true; -}; - #ifdef _WINDOWS //--------------------------------------------------------------------------- void TGround::Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) diff --git a/Ground.h b/Ground.h index 2fe2b4d6..ee20b738 100644 --- a/Ground.h +++ b/Ground.h @@ -97,8 +97,6 @@ struct TGroundVertex } }; -class TSubRect; // sektor (aktualnie 200m×200m, ale może być zmieniony) - class TGroundNode : public Resource { // obiekt scenerii @@ -216,8 +214,7 @@ class TSubRect : public Resource, public CMesh void Sort(); // optymalizacja obiektów w sektorze (sortowanie wg tekstur) TTrack * FindTrack(vector3 *Point, int &iConnection, TTrack *Exclude); TTraction * FindTraction(vector3 *Point, int &iConnection, TTraction *Exclude); - bool StartVBO(); // ustwienie VBO sektora dla (nRenderRect), (nRenderRectAlpha) i - // (nRenderWires) + bool StartVBO(); // ustwienie VBO sektora dla (nRenderRect), (nRenderRectAlpha) i (nRenderWires) bool RaTrackAnimAdd(TTrack *t); // zgłoszenie toru do animacji void RaAnimate(); // przeliczenie animacji torów void RenderDL(); // renderowanie nieprzezroczystych w Display Lists @@ -335,11 +332,6 @@ class TGround void Update_Lights(); // updates scene lights array bool AddToQuery(TEvent *Event, TDynamicObject *Node); bool GetTraction(TDynamicObject *model); - bool Render( Math3D::vector3 const &Camera ); - bool RenderDL(vector3 pPosition); - bool RenderAlphaDL(vector3 pPosition); - bool RenderVBO(vector3 pPosition); - bool RenderAlphaVBO(vector3 pPosition); bool CheckQuery(); TGroundNode * DynamicFindAny(std::string asNameToFind); TGroundNode * DynamicFind(std::string asNameToFind); diff --git a/Track.cpp b/Track.cpp index 9769f613..17cbef7f 100644 --- a/Track.cpp +++ b/Track.cpp @@ -2659,8 +2659,8 @@ bool TTrack::Switch(int i, double t, double d) true) // jeśli nie dodane do animacji { // nie ma się co bawić SwitchExtension->fOffset = SwitchExtension->fDesiredOffset; - RaAnimate(); // przeliczenie położenia iglic; czy zadziała na niewyświetlanym - // sektorze w VBO? + // przeliczenie położenia iglic; czy zadziała na niewyświetlanym sektorze w VBO? + RaAnimate(); } return true; } @@ -2809,8 +2809,8 @@ void TTrack::RaAnimListAdd(TTrack *t) TTrack * TTrack::RaAnimate(GLuint const Vertexbuffer) { // wykonanie rekurencyjne animacji, wywoływane przed wyświetleniem sektora // zwraca wskaźnik toru wymagającego dalszej animacji - if (SwitchExtension->pNextAnim) - SwitchExtension->pNextAnim = SwitchExtension->pNextAnim->RaAnimate(); + if( SwitchExtension->pNextAnim ) + SwitchExtension->pNextAnim = SwitchExtension->pNextAnim->RaAnimate( Vertexbuffer ); bool m = true; // animacja trwa if (eType == tt_Switch) // dla zwrotnicy tylko szyny { diff --git a/Train.cpp b/Train.cpp index b5525474..262f1c0c 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5802,14 +5802,12 @@ bool TTrain::CabChange(int iDirection) DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName + ".mmd")) { // zmiana kabiny w ramach tego samego pojazdu - DynamicObject->MoverParameters - ->CabActivisation(); // załączenie rozrządu (wirtualne kabiny) + DynamicObject->MoverParameters->CabActivisation(); // załączenie rozrządu (wirtualne kabiny) + DynamicObject->Mechanik->CheckVehicles( Change_direction ); return true; // udało się zmienić kabinę } - DynamicObject->MoverParameters->CabActivisation(); // aktywizacja - // poprzedniej, bo - // jeszcze nie wiadomo, - // czy jakiś pojazd jest + // aktywizacja poprzedniej, bo jeszcze nie wiadomo, czy jakiś pojazd jest + DynamicObject->MoverParameters->CabActivisation(); } return false; // ewentualna zmiana pojazdu } diff --git a/World.cpp b/World.cpp index b7a11860..5ca62383 100644 --- a/World.cpp +++ b/World.cpp @@ -620,10 +620,6 @@ void TWorld::OnKeyDown(int cKey) else { glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); } -/* - ++Global::iReCompile; // odświeżyć siatki - // Ra: jeszcze usunąć siatki ze skompilowanych obiektów! -*/ } } break; @@ -1750,9 +1746,12 @@ TWorld::Update_UI() { UITable->text_lines.emplace_back( Global::Bezogonkow( "| " + station + " | " + arrival + " | " + departure + " | " + vmax + " | " + tableline->StationWare, true ), - ( ( owner->iStationStart < table->StationIndex ) && ( i < table->StationIndex ) ? - float4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minął i odjazd był, to nazwa stacji będzie na zielono - Global::UITextColor ) + ( ( owner->iStationStart < table->StationIndex ) + && ( i < table->StationIndex ) + && ( time.wHour >= tableline->Dh ) + && ( time.wMinute >= tableline->Dm ) ? + float4( 0.0f, 1.0f, 0.0f, 1.0f ) :// czas minął i odjazd był, to nazwa stacji będzie na zielono + Global::UITextColor ) ); // divider/footer UITable->text_lines.emplace_back( "+----------------------------+-------+-------+-----+", Global::UITextColor ); @@ -1995,9 +1994,11 @@ TWorld::Update_UI() { + GfxRenderer.Info(); // dump last opengl error, if any - GLenum glerror = glGetError(); + GLenum glerror = ::glGetError(); if( glerror != GL_NO_ERROR ) { - Global::LastGLError = to_string( glerror ) + " (" + Global::Bezogonkow( (char *)gluErrorString( glerror ) ) + ")"; + std::string glerrorstring( (char *)::gluErrorString( glerror ) ); + win1250_to_ascii( glerrorstring ); + Global::LastGLError = std::to_string( glerror ) + " (" + glerrorstring + ")"; } if( false == Global::LastGLError.empty() ) { uitextline3 = diff --git a/renderer.cpp b/renderer.cpp index bf92c7b9..2fe2ede1 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "globals.h" #include "timer.h" #include "world.h" +#include "data.h" #include "dynobj.h" #include "animmodel.h" #include "traction.h" @@ -146,7 +147,7 @@ opengl_renderer::Render() { m_camera.update_frustum(); Render( &World.Environment ); - World.Ground.Render( World.Camera.Pos ); + Render( &World.Ground ); World.Render_Cab(); @@ -293,7 +294,7 @@ opengl_renderer::Render( world_environment *Environment ) { bool opengl_renderer::Render( TGround *Ground ) { - +/* glDisable( GL_BLEND ); glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f glEnable( GL_LIGHTING ); @@ -315,8 +316,102 @@ opengl_renderer::Render( TGround *Ground ) { } } } +*/ + ::glEnable( GL_LIGHTING ); + ::glDisable( GL_BLEND ); + ::glAlphaFunc( GL_GREATER, 0.50f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + ::glColor3f( 1.0f, 1.0f, 1.0f ); + + ++TGroundRect::iFrameNumber; // zwięszenie licznika ramek (do usuwniania nadanimacji) + + Update_Lights( Ground->m_lights ); + + Ground->CameraDirection.x = std::sin( Global::pCameraRotation ); // wektor kierunkowy + Ground->CameraDirection.z = std::cos( Global::pCameraRotation ); + TGroundNode *node; + // rednerowanie globalnych (nie za często?) + for( node = Ground->srGlobal.nRenderHidden; node; node = node->nNext3 ) { + node->RenderHidden(); + } + // renderowanie czołgowe dla obiektów aktywnych a niewidocznych + int n = 2 * iNumSubRects; //(2*==2km) promień wyświetlanej mapy w sektorach + int c = Ground->GetColFromX( Global::pCameraPosition.x ); + int r = Ground->GetRowFromZ( Global::pCameraPosition.z ); + TSubRect *tmp; + int i, j, k; + for( j = r - n; j <= r + n; j++ ) { + for( i = c - n; i <= c + n; i++ ) { + if( ( tmp = Ground->FastGetSubRect( i, j ) ) != nullptr ) { + // oznaczanie aktywnych sektorów + tmp->LoadNodes(); + + for( node = tmp->nRenderHidden; node; node = node->nNext3 ) { + node->RenderHidden(); + } + // jeszcze dźwięki pojazdów by się przydały, również niewidocznych + tmp->RenderSounds(); + } + } + } + // renderowanie progresywne - zależne od FPS oraz kierunku patrzenia + Ground->iRendered = 0; // ilość renderowanych sektorów + Math3D::vector3 direction; + for( k = 0; k < Global::iSegmentsRendered; ++k ) // sektory w kolejności odległości + { // przerobione na użycie SectorOrder + i = SectorOrder[ k ].x; // na starcie oba >=0 + j = SectorOrder[ k ].y; + do { + // pierwszy przebieg: j<=0, i>=0; drugi: j>=0, i<=0; trzeci: j<=0, i<=0 czwarty: j>=0, i>=0; + if( j <= 0 ) + i = -i; + j = -j; // i oraz j musi być zmienione wcześniej, żeby continue działało + direction = Math3D::vector3( i, 0, j ); // wektor od kamery do danego sektora + if( Math3D::LengthSquared3( direction ) > 5 ) // te blisko są zawsze wyświetlane + { + direction = Math3D::SafeNormalize( direction ); // normalizacja + if( Ground->CameraDirection.x * direction.x + Ground->CameraDirection.z * direction.z < 0.55 ) + continue; // pomijanie sektorów poza kątem patrzenia + } + // kwadrat kilometrowy nie zawsze, bo szkoda FPS + if( Global::bUseVBO ) { + // vbo render path + Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderVBO(); + } + else { + // display list render path + Ground->Rects[ ( i + c ) / iNumSubRects ][ ( j + r ) / iNumSubRects ].RenderDL(); + } + if( ( tmp = Ground->FastGetSubRect( i + c, j + r ) ) != nullptr ) { + if( tmp->iNodeCount ) { + // o ile są jakieś obiekty, bo po co puste sektory przelatywać + Ground->pRendered[ Ground->iRendered++ ] = tmp; // tworzenie listy sektorów do renderowania + } + } + } while( ( i < 0 ) || ( j < 0 ) ); // są 4 przypadki, oprócz i=j=0 + } + + // dodać renderowanie terenu z E3D - jedno VBO jest używane dla całego modelu, chyba że jest ich więcej + if( Global::bUseVBO ) { + if( Global::pTerrainCompact ) { + Global::pTerrainCompact->TerrainRenderVBO( TGroundRect::iFrameNumber ); + } + } + + // renderowanie nieprzezroczystych + for( i = 0; i < Ground->iRendered; ++i ) { + if( Global::bUseVBO ) { + // vbo render path + Ground->pRendered[ i ]->RenderVBO(); + } + else { + // display list render path + Ground->pRendered[ i ]->RenderDL(); + } + } + + // regular render takes care of all solid geometry present in the scene, thus we can launch alpha parts render here + return Render_Alpha( Ground ); - return true; } bool @@ -431,7 +526,12 @@ opengl_renderer::Render( TGroundNode *Node ) { } else { // display list render path - ::glCallList( Node->DisplayListID ); + if( Node->DisplayListID != 0 ) { + ::glCallList( Node->DisplayListID ); + } + else { + return false; + } } return true; } @@ -730,6 +830,75 @@ opengl_renderer::Render( TMemCell *Memcell ) { ::glPopAttrib(); } +bool +opengl_renderer::Render_Alpha( TGround *Ground ) { + + // legacy version of the code: + ::glEnable( GL_BLEND ); + ::glAlphaFunc( GL_GREATER, 0.04f ); // im mniejsza wartość, tym większa ramka, domyślnie 0.1f + ::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + + TGroundNode *node; + TSubRect *tmp; + // Ra: renderowanie progresywne - zależne od FPS oraz kierunku patrzenia + for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych + { // przezroczyste trójkąty w oddzielnym cyklu przed modelami + tmp = Ground->pRendered[ i ]; + if( Global::bUseVBO ) { + // vbo render path + if( tmp->StartVBO() ) { + for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) { + if( node->iVboPtr >= 0 ) { + Render_Alpha( node ); + } + } + tmp->EndVBO(); + } + } + else { + // display list render path + for( node = tmp->nRenderRectAlpha; node; node = node->nNext3 ) { + Render_Alpha( node ); + } + } + } + for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych + { // renderowanie przezroczystych modeli oraz pojazdów + if( Global::bUseVBO ) { + // vbo render path + Ground->pRendered[ i ]->RenderAlphaVBO(); + } + else { + // display list render path + Ground->pRendered[ i ]->RenderAlphaDL(); + } + } + + ::glDisable( GL_LIGHTING ); // linie nie powinny świecić + + for( int i = Ground->iRendered - 1; i >= 0; --i ) // od najdalszych + { // druty na końcu, żeby się nie robiły białe plamy na tle lasu + tmp = Ground->pRendered[ i ]; + if( Global::bUseVBO ) { + // vbo render path + if( tmp->StartVBO() ) { + for( node = tmp->nRenderWires; node; node = node->nNext3 ) { + Render_Alpha( node ); + } + tmp->EndVBO(); + } + } + else { + // display list render path + for( node = tmp->nRenderWires; node; node = node->nNext3 ) { + Render_Alpha( node ); // druty + } + } + } + + return true; +} + // NOTE: legacy render system switch #define _PROBLEND diff --git a/renderer.h b/renderer.h index d14f2995..65531612 100644 --- a/renderer.h +++ b/renderer.h @@ -136,6 +136,8 @@ public: Render( TSubModel *Submodel ); void Render( TMemCell *Memcell ); + bool + Render_Alpha( TGround *Ground ); bool Render_Alpha( TGroundNode *Node ); bool diff --git a/version.h b/version.h index 866a8597..5ecf5416 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 516 +#define VERSION_MINOR 517 #define VERSION_REVISION 0