From 6526620364e370928653ebe7c605d36842535260 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 8 Mar 2017 01:25:09 +0100 Subject: [PATCH 1/2] view range factor implementation --- Camera.cpp | 2 +- EU07.cpp | 1 + Globals.cpp | 10 ++++++++-- Model3d.cpp | 43 +++++++++++++++++++------------------------ RealSound.cpp | 7 +++---- Texture.cpp | 6 ++++++ skydome.cpp | 27 ++------------------------- usefull.h | 41 ++++++++++++++++------------------------- 8 files changed, 56 insertions(+), 81 deletions(-) diff --git a/Camera.cpp b/Camera.cpp index c714fb88..ffd58d66 100644 --- a/Camera.cpp +++ b/Camera.cpp @@ -53,7 +53,7 @@ void TCamera::OnCursorMove(double x, double y) Yaw += 2 * M_PI; if (Type == tp_Follow) // jeżeli jazda z pojazdem { - Fix(Pitch, -M_PI_4, M_PI_4); // ograniczenie kąta spoglądania w dół i w górę + clamp(Pitch, -M_PI_4, M_PI_4); // ograniczenie kąta spoglądania w dół i w górę // Fix(Yaw,-M_PI,M_PI); } } diff --git a/EU07.cpp b/EU07.cpp index 3fd1ca49..aeae755f 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -93,6 +93,7 @@ void window_resize_callback(GLFWwindow *window, int w, int h) { Global::ScreenWidth = w; Global::ScreenHeight = h; + Global::fDistanceFactor = h / 768.0f; // not sure if this is really something we want to use glViewport(0, 0, w, h); } diff --git a/Globals.cpp b/Globals.cpp index a8e3af98..b0e54344 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -120,7 +120,7 @@ int Global::iHiddenEvents = 1; // czy łączyć eventy z torami poprzez nazwę t int Global::Keys[MaxKeys]; int Global::iWindowWidth = 800; int Global::iWindowHeight = 600; -float Global::fDistanceFactor = 768.0; // baza do przeliczania odległości dla LoD +float Global::fDistanceFactor = Global::ScreenHeight / 768.0; // baza do przeliczania odległości dla LoD int Global::iFeedbackMode = 1; // tryb pracy informacji zwrotnej int Global::iFeedbackPort = 0; // dodatkowy adres dla informacji zwrotnych bool Global::bFreeFly = false; @@ -154,7 +154,8 @@ bool Global::bSmoothTraction = false; // wygładzanie drutów starym sposobem std::string Global::szDefaultExt = Global::szTexturesDDS; // domyślnie od DDS int Global::iMultisampling = 2; // tryb antyaliasingu: 0=brak,1=2px,2=4px,3=8px,4=16px bool Global::bGlutFont = false; // czy tekst generowany przez GLUT32.DLL -int Global::iConvertModels = 7; // tworzenie plików binarnych, +2-optymalizacja transformów +//int Global::iConvertModels = 7; // tworzenie plików binarnych, +2-optymalizacja transformów +int Global::iConvertModels{ 0 }; // temporary override, to prevent generation of .e3d not compatible with old exe int Global::iSlowMotionMask = -1; // maska wyłączanych właściwości dla zwiększenia FPS int Global::iModifyTGA = 7; // czy korygować pliki TGA dla szybszego wczytywania // bool Global::bTerrainCompact=true; //czy zapisać teren w pliku @@ -620,6 +621,11 @@ void Global::ConfigParse(cParser &Parser) // tworzenie plików binarnych Parser.getTokens(1, false); Parser >> Global::iConvertModels; + // temporary override, to prevent generation of .e3d not compatible with old exe + Global::iConvertModels = + ( Global::iConvertModels > 128 ? + Global::iConvertModels - 128 : + 0 ); } else if (token == "inactivepause") { diff --git a/Model3d.cpp b/Model3d.cpp index 1f7151ff..d3378b69 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -74,7 +74,7 @@ void TSubModel::FirstInit() // Hits=NULL; // CollisionPts=NULL; // CollisionPtsCount=0; - Opacity = 1.0; // przy wczytywaniu modeli było dzielone przez 100... + Opacity = 0.0f; // przy wczytywaniu modeli było dzielone przez 100... bWire = false; fWireSize = 0; fNearAttenStart = 40; @@ -376,13 +376,10 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) TextureID = GfxRenderer.GetTextureId( texture, szTexturePath ); // TexAlpha=TTexturesManager::GetAlpha(TextureID); // iFlags|=TexAlpha?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta - if (Opacity < 1.0) // przezroczystość z tekstury brana tylko dla Opacity - // 0! - iFlags |= GfxRenderer.Texture(TextureID).has_alpha ? - 0x20 : - 0x10; // 0x10-nieprzezroczysta, 0x20-przezroczysta - else - iFlags |= 0x10; // normalnie nieprzezroczyste + iFlags |= + ( GfxRenderer.Texture(TextureID).has_alpha ? + 0x20 : + 0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta // renderowanie w cyklu przezroczystych tylko jeśli: // 1. Opacity=0 (przejściowo <1, czy tam <100) oraz // 2. tekstura ma przezroczystość @@ -391,19 +388,19 @@ int TSubModel::Load(cParser &parser, TModel3d *Model, int Pos, bool dynamic) else iFlags |= 0x10; + // visibility range std::string discard; parser.getTokens(5, false); parser >> discard >> fSquareMaxDist >> discard >> fSquareMinDist >> discard; - if (fSquareMaxDist >= 0.0) - { - fSquareMaxDist *= fSquareMaxDist; - } - else - { - fSquareMaxDist = 15000 * 15000; - } // 15km to więcej, niż się obecnie wyświetla + if( fSquareMaxDist <= 0.0 ) { + // 15km to więcej, niż się obecnie wyświetla + fSquareMaxDist = 15000.0; + } + fSquareMaxDist *= fSquareMaxDist; fSquareMinDist *= fSquareMinDist; + + // transformation matrix fMatrix = new float4x4(); readMatrix(parser, *fMatrix); // wczytanie transform if (!fMatrix->IdentityIs()) @@ -688,7 +685,7 @@ void TSubModel::DisplayLists() glColorMaterial(GL_FRONT, GL_EMISSION); glDisable(GL_LIGHTING); // Tolaris-030603: bo mu punkty swiecace sie blendowaly glBegin(GL_POINTS); - glVertex3f( 0.0f, 0.0f, -0.025f ); // shift point towards the viewer, to avoid z-fighting with the light polygons + glVertex3f( 0.0f, 0.0f, -0.05f ); // shift point towards the viewer, to avoid z-fighting with the light polygons glEnd(); glEnable(GL_LIGHTING); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); @@ -1484,7 +1481,7 @@ void TSubModel::AdjustDist() if (fSquareMaxDist > 0.0) fSquareMaxDist *= Global::fDistanceFactor; if (fSquareMinDist > 0.0) - fSquareMinDist *= Global::fDistanceFactor; + fSquareMinDist /= Global::fDistanceFactor; // if (fNearAttenStart>0.0) fNearAttenStart*=Global::fDistanceFactor; // if (fNearAttenEnd>0.0) fNearAttenEnd*=Global::fDistanceFactor; if (Child) @@ -2015,12 +2012,10 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v, if (pTexture.find_last_of("/\\") == std::string::npos) pTexture.insert(0, Global::asCurrentTexturePath); TextureID = GfxRenderer.GetTextureId(pTexture, szTexturePath); - if( Opacity < 1.0 ) // przezroczystość z tekstury brana tylko dla Opacity 0! - iFlags |= GfxRenderer.Texture( TextureID ).has_alpha ? - 0x20 : - 0x10; // 0x10-nieprzezroczysta, 0x20-przezroczysta - else - iFlags |= 0x10; // normalnie nieprzezroczyste + iFlags |= + ( GfxRenderer.Texture( TextureID ).has_alpha ? + 0x20 : + 0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta } else TextureID = iTexture; diff --git a/RealSound.cpp b/RealSound.cpp index 6f667148..19b814e6 100644 --- a/RealSound.cpp +++ b/RealSound.cpp @@ -19,6 +19,7 @@ http://mozilla.org/MPL/2.0/. //#include "math.h" #include "Timer.h" #include "mczapkie/mctools.h" +#include "usefull.h" TRealSound::TRealSound(std::string const &SoundName, double SoundAttenuation, double X, double Y, double Z, bool Dynamic, bool freqmod, double rmin) @@ -177,7 +178,7 @@ void TRealSound::AdjFreq(double Freq, double dt) // McZapkie TODO: dorobic tu ef // Freq moze byc liczba dodatnia mniejsza od 1 lub wieksza od 1 { float df, Vlist; - if ((Global::bSoundEnabled) && (AM != 0)) + if ((Global::bSoundEnabled) && (AM != 0) && (pSound != nullptr)) { if (dt > 0) // efekt Dopplera @@ -190,9 +191,7 @@ void TRealSound::AdjFreq(double Freq, double dt) // McZapkie TODO: dorobic tu ef if (Timer::GetSoundTimer()) { df = fFrequency * df; // TODO - brac czestotliwosc probkowania z wav - pSound->SetFrequency((df < DSBFREQUENCY_MIN ? - DSBFREQUENCY_MIN : - (df > DSBFREQUENCY_MAX ? DSBFREQUENCY_MAX : df))); + pSound->SetFrequency( clamp( df, static_cast(DSBFREQUENCY_MIN), static_cast(DSBFREQUENCY_MAX) ) ); } } } diff --git a/Texture.cpp b/Texture.cpp index 878c4f3d..b3b6732c 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -275,6 +275,12 @@ opengl_texture::load_DDS() { --mapcount; } */ + if( datasize == 0 ) { + // catch malformed .dds files + WriteLog( "File \"" + name + "\" is malformed and holds no texture data." ); + data_state = resource_state::failed; + return; + } // reserve space and load texture data data.resize( datasize ); if( offset != 0 ) { diff --git a/skydome.cpp b/skydome.cpp index 68a1f316..2afb16c3 100644 --- a/skydome.cpp +++ b/skydome.cpp @@ -2,6 +2,7 @@ #include "stdafx.h" #include "skydome.h" #include "color.h" +#include "usefull.h" // sky gradient based on "A practical analytic model for daylight" // by A. J. Preetham Peter Shirley Brian Smits (University of Utah) @@ -41,21 +42,6 @@ float CSkyDome::m_zenithymatrix[ 3 ][ 4 ] = { //******************************************************************************// -float clamp( float const Value, float const Min, float const Max ) { - - float value = Value; - if( value < Min ) { value = Min; } - if( value > Max ) { value = Max; } - return value; -} - -float interpolate( float const First, float const Second, float const Factor ) { - - return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); -} - -//******************************************************************************// - CSkyDome::CSkyDome (int const Tesselation) : m_tesselation( Tesselation ) { @@ -121,8 +107,6 @@ void CSkyDome::Generate() { } } -//******************************************************************************// - void CSkyDome::Update( Math3D::vector3 const &Sun ) { if( true == SetSunPosition( Sun ) ) { @@ -166,8 +150,6 @@ void CSkyDome::Render() { ::glDisableClientState( GL_VERTEX_ARRAY ); } -//******************************************************************************// - bool CSkyDome::SetSunPosition( Math3D::vector3 const &Direction ) { auto sundirection = SafeNormalize( float3( Direction.x, Direction.y, Direction.z) ); @@ -205,8 +187,6 @@ void CSkyDome::SetOvercastFactor( float const Overcast ) { m_overcast = clamp( Overcast, 0.0f, 1.0f ); } -//******************************************************************************// - void CSkyDome::GetPerez( float *Perez, float Distribution[ 5 ][ 2 ], const float Turbidity ) { Perez[ 0 ] = Distribution[ 0 ][ 0 ] * Turbidity + Distribution[ 0 ][ 1 ]; @@ -227,8 +207,6 @@ float CSkyDome::GetZenith( float Zenithmatrix[ 3 ][ 4 ], const float Theta, cons } -//******************************************************************************// - float CSkyDome::PerezFunctionO1( float Perezcoeffs[ 5 ], const float Thetasun, const float Zenithval ) { const float val = ( 1.0f + Perezcoeffs[ 0 ] * std::exp( Perezcoeffs[ 1 ] ) ) * @@ -244,7 +222,6 @@ float CSkyDome::PerezFunctionO2( float Perezcoeffs[ 5 ], const float Icostheta, ( 1.0f + Perezcoeffs[ 2 ] * std::exp( Perezcoeffs[ 3 ] * Gamma ) + Perezcoeffs[ 4 ] * Cosgamma2 ); } -//******************************************************************************// void CSkyDome::RebuildColors() { // get zenith luminance @@ -320,7 +297,7 @@ void CSkyDome::RebuildColors() { // override the hue, based on sun height above the horizon. crude way to deal with model shortcomings // correction begins when the sun is higher than 10 degrees above the horizon, and fully in effect at 10+15 degrees - auto const degreesabovehorizon = 90.0f - m_thetasun * ( 180.0f / M_PI ); + float const degreesabovehorizon = 90.0f - m_thetasun * ( 180.0f / M_PI ); auto const sunbasedphase = clamp( (1.0f / 15.0f) * ( degreesabovehorizon - 10.0f ), 0.0f, 1.0f ); // correction is applied in linear manner from the bottom, becomes fully in effect for vertices with y = 0.50 auto const heightbasedphase = clamp( vertex.y * 2.0f, 0.0f, 1.0f ); diff --git a/usefull.h b/usefull.h index aabeba22..7c7cb2b6 100644 --- a/usefull.h +++ b/usefull.h @@ -9,17 +9,7 @@ http://mozilla.org/MPL/2.0/. #pragma once -//#define B1(t) (t*t*t) -//#define B2(t) (3*t*t*(1-t)) -//#define B3(t) (3*t*(1-t)*(1-t)) -//#define B4(t) ((1-t)*(1-t)*(1-t)) -// Ra: to jest mocno nieoptymalne: 10+3*4=22 mnożenia, 6 odejmowań, 3*3=9 dodawań -// Ra: po przeliczeniu współczynników mamy: 3*3=9 mnożeń i 3*3=9 dodawań -//#define Interpolate(t,p1,cp1,cp2,p2) (B4(t)*p1+B3(t)*cp1+B2(t)*cp2+B1(t)*p2) - -// Ra: "delete NULL" nic nie zrobi, więc "if (a!=NULL)" jest zbędne -//#define SafeFree(a) if (a!=NULL) free(a) -//#define M_PI = 3.141592653589793 +#include "stdafx.h" #define SafeDelete(a) \ { \ @@ -37,25 +27,26 @@ http://mozilla.org/MPL/2.0/. #define DegToRad(a) ((M_PI / 180.0) * (a)) //(a) w nawiasie, bo może być dodawaniem #define RadToDeg(r) ((180.0 / M_PI) * (r)) -#define Fix(a, b, c) \ - { \ - if (a < b) \ - a = b; \ - if (a > c) \ - a = c; \ - } - #define asModelsPath std::string("models\\") #define asSceneryPath std::string("scenery\\") -//#define asTexturePath AnsiString("textures\\") -//#define asTextureExt AnsiString(".bmp") #define szSceneryPath "scenery\\" #define szTexturePath "textures\\" -//#define szDefaultTextureExt ".dds" - -//#define DevelopTime //FIXME -//#define EditorMode #define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a)) +template +_Type clamp( _Type const Value, _Type const Min, _Type const Max ) { + + _Type value = Value; + if( value < Min ) { value = Min; } + if( value > Max ) { value = Max; } + return value; +} + +template +_Type interpolate( _Type const First, _Type const Second, float const Factor ) { + + return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); +} + //--------------------------------------------------------------------------- From b5ae395c426fbd1c6e94dcce4f48734685557ea3 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 8 Mar 2017 23:54:20 +0100 Subject: [PATCH 2/2] camera frustum --- Camera.cpp | 14 ++++ Camera.h | 10 +++ DynObj.cpp | 8 +- EU07.cpp | 2 +- Globals.cpp | 6 +- Model3d.cpp | 21 ++++- World.cpp | 15 +++- frustum.cpp | 178 ++++++++++++++++++++++++++++++++++++++++ frustum.h | 67 +++++++++++++++ maszyna.vcxproj | 2 + maszyna.vcxproj.filters | 6 ++ 11 files changed, 314 insertions(+), 15 deletions(-) create mode 100644 frustum.cpp create mode 100644 frustum.h diff --git a/Camera.cpp b/Camera.cpp index ffd58d66..e92180ee 100644 --- a/Camera.cpp +++ b/Camera.cpp @@ -169,3 +169,17 @@ void TCamera::Stop() Type = tp_Follow; Velocity = vector3(0, 0, 0); }; + +// returns true if specified object is within camera frustum, false otherwise +bool +TCamera::IsVisible( 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 = static_cast(diagonal.Length()) * 0.5f; + + return ( m_frustum.sphere_inside( Dynamic->GetPosition(), radius ) > 0.0f ); +} diff --git a/Camera.h b/Camera.h index 0d1ab315..2ec975da 100644 --- a/Camera.h +++ b/Camera.h @@ -11,6 +11,9 @@ http://mozilla.org/MPL/2.0/. #define CameraH #include "dumb3d.h" +#include "frustum.h" +#include "dynobj.h" + using namespace Math3D; //--------------------------------------------------------------------------- @@ -25,6 +28,8 @@ class TCamera { private: vector3 pOffset; // nie używane (zerowe) + cFrustum m_frustum; + public: // McZapkie: potrzebuje do kiwania na boki double Pitch; double Yaw; // w środku: 0=do przodu; na zewnątrz: 0=na południe @@ -51,6 +56,11 @@ class TCamera void SetCabMatrix(vector3 &p); void RaLook(); void Stop(); + inline + void + SetFrustum() { m_frustum.calculate(); } + bool + IsVisible( TDynamicObject const *Dynamic ) const; // bool GetMatrix(matrix4x4 &Matrix); vector3 PtNext, PtPrev; }; diff --git a/DynObj.cpp b/DynObj.cpp index cf31b015..1a3a2dc3 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -3703,6 +3703,7 @@ void TDynamicObject::TurnOff() void TDynamicObject::Render() { // rysowanie elementów nieprzezroczystych // youBy - sprawdzamy, czy jest sens renderowac +/* double modelrotate; vector3 tempangle; // zmienne @@ -3713,8 +3714,7 @@ void TDynamicObject::Render() if (ObjSqrDist < 500) // jak jest blisko - do 70m modelrotate = 0.01; // mały kąt, żeby nie znikało else - { // Global::pCameraRotation to kąt bewzględny w świecie (zero - na - // północ) + { // Global::pCameraRotation to kąt bewzględny w świecie (zero - na północ) tempangle = (vPosition - Global::pCameraPosition); // wektor od kamery modelrotate = ABuAcos(tempangle); // określenie kąta // if (modelrotate>M_PI) modelrotate-=(2*M_PI); @@ -3730,8 +3730,8 @@ void TDynamicObject::Render() if (modelrotate < maxrot) renderme = true; - - if (renderme) +*/ + if (Global::pCamera->IsVisible(this)) { TSubModel::iInstance = (size_t)this; //żeby nie robić cudzych animacji // AnsiString asLoadName=""; diff --git a/EU07.cpp b/EU07.cpp index aeae755f..3e3eedcf 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -93,7 +93,7 @@ void window_resize_callback(GLFWwindow *window, int w, int h) { Global::ScreenWidth = w; Global::ScreenHeight = h; - Global::fDistanceFactor = h / 768.0f; // not sure if this is really something we want to use + Global::fDistanceFactor = std::max( 0.5f, h / 768.0f ); // not sure if this is really something we want to use glViewport(0, 0, w, h); } diff --git a/Globals.cpp b/Globals.cpp index b0e54344..9693076d 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -495,9 +495,9 @@ void Global::ConfigParse(cParser &Parser) { Parser.getTokens(); - Parser >> token; - - Global::bUseVBO = (token == "yes"); + Parser >> Global::bUseVBO; + // NOTE: temporary override until render paths are sorted out + Global::bUseVBO = false; } else if (token == "feedbackmode") { diff --git a/Model3d.cpp b/Model3d.cpp index d3378b69..040a0eec 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1050,7 +1050,9 @@ void TSubModel::RaAnimation(TAnimType a) void TSubModel::RenderDL() { // główna procedura renderowania przez DL - if (iVisible && (fSquareDist >= fSquareMinDist) && (fSquareDist < fSquareMaxDist)) + if( ( iVisible ) + && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) + && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) { if (iFlags & 0xC000) { @@ -1147,7 +1149,9 @@ void TSubModel::RenderDL() void TSubModel::RenderAlphaDL() { // renderowanie przezroczystych przez DL - if (iVisible && (fSquareDist >= fSquareMinDist) && (fSquareDist < fSquareMaxDist)) + if( ( iVisible ) + && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) + && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) { if (iFlags & 0xC000) { @@ -1227,7 +1231,9 @@ void TSubModel::RenderAlphaDL() void TSubModel::RenderVBO() { // główna procedura renderowania przez VBO - if (iVisible && (fSquareDist >= fSquareMinDist) && (fSquareDist < fSquareMaxDist)) + if( ( iVisible ) + && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) + && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) { if (iFlags & 0xC000) { @@ -1400,7 +1406,9 @@ void TSubModel::RenderVBO() void TSubModel::RenderAlphaVBO() { // renderowanie przezroczystych przez VBO - if (iVisible && (fSquareDist >= fSquareMinDist) && (fSquareDist < fSquareMaxDist)) + if( ( iVisible ) + && ( fSquareDist >= (fSquareMinDist / Global::fDistanceFactor) ) + && ( fSquareDist <= (fSquareMaxDist * Global::fDistanceFactor) ) ) { if (iFlags & 0xC000) { @@ -1475,6 +1483,8 @@ void TSubModel::RaArrayFill(CVertNormTex *Vert) Next->RaArrayFill(Vert); }; +// NOTE: leftover from static distance factor adjustment. +// TODO: get rid of it, once we have the dynamic adjustment code in place void TSubModel::AdjustDist() { // aktualizacja odległości faz LoD, zależna od // rozdzielczości pionowej oraz multisamplingu @@ -2120,10 +2130,13 @@ void TModel3d::Init() } if (iNumVerts) { +/* // NOTE: we will be applying distance factor dynamically during render, + // so we're leaving the defined ranges intact if (Global::fDistanceFactor != 1.0) // trochę zaoszczędzi czasu na modelach z wieloma submocelami Root->AdjustDist(); // aktualizacja odległości faz LoD, zależnie od // rozdzielczości pionowej oraz multisamplingu +*/ if (Global::bUseVBO) { if (!m_pVNT) // jeśli nie ma jeszcze tablicy (wczytano z pliku diff --git a/World.cpp b/World.cpp index 3cf31fe2..94d7ab85 100644 --- a/World.cpp +++ b/World.cpp @@ -30,8 +30,6 @@ http://mozilla.org/MPL/2.0/. #include "Console.h" #include "color.h" -#define TEXTURE_FILTER_CONTROL_EXT 0x8500 -#define TEXTURE_LOD_BIAS_EXT 0x8501 //--------------------------------------------------------------------------- // GLUTAPI void APIENTRY glutBitmapCharacterDLL(void *font, int character); @@ -283,6 +281,7 @@ bool TWorld::Init( GLFWwindow *w ) { glEnable(GL_CULL_FACE); // Cull back-facing triangles glLineWidth(1.0f); glPointSize(3.0f); + glEnable( GL_POINT_SMOOTH ); #ifdef EU07_USE_OLD_LIGHTING_MODEL // ----------- LIGHTING SETUP ----------- // Light values and coordinates @@ -1110,13 +1109,22 @@ bool TWorld::Update() int updatecount = 1; if( dt > m_primaryupdaterate ) // normalnie 0.01s { +/* + // NOTE: experimentally disabled physics update cap auto const iterations = std::ceil(dt / m_primaryupdaterate); updatecount = std::min( 20, static_cast( iterations ) ); +*/ + updatecount = std::ceil( dt / m_primaryupdaterate ); +/* + // NOTE: changing dt wrecks things further down the code. re-acquire proper value later or cleanup here dt = dt / iterations; // Ra: fizykę lepiej by było przeliczać ze stałym krokiem +*/ } // NOTE: updates are limited to 20, but dt is distributed over potentially many more iterations // this means at count > 20 simulation and render are going to desync. is that right? - Ground.Update(dt, updatecount); // tu zrobić tylko coklatkową aktualizację przesunięć + // NOTE: experimentally changing this to prevent the desync. + // TODO: test what happens if we hit more than 20 * 0.01 sec slices, i.e. less than 5 fps + Ground.Update(dt / updatecount, updatecount); // tu zrobić tylko coklatkową aktualizację przesunięć /* if (DebugModeFlag) if (Global::bActive) // nie przyspieszać, gdy jedzie w tle :) @@ -1437,6 +1445,7 @@ bool TWorld::Render() glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity(); Camera.SetMatrix(); // ustawienie macierzy kamery względem początku scenerii + Camera.SetFrustum(); // update camera frustum to match current data if( !Global::bWireFrame ) { // bez nieba w trybie rysowania linii diff --git a/frustum.cpp b/frustum.cpp new file mode 100644 index 00000000..f0244f5a --- /dev/null +++ b/frustum.cpp @@ -0,0 +1,178 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#include "stdafx.h" +#include "frustum.h" + +void +cFrustum::calculate() { + + float proj[ 16 ]; + float modl[ 16 ]; + float clip[ 16 ]; + + glGetFloatv( GL_PROJECTION_MATRIX, proj ); + glGetFloatv( GL_MODELVIEW_MATRIX, modl ); + + // multiply the matrices to retrieve clipping planes + clip[ 0 ] = modl[ 0 ] * proj[ 0 ] + modl[ 1 ] * proj[ 4 ] + modl[ 2 ] * proj[ 8 ] + modl[ 3 ] * proj[ 12 ]; + clip[ 1 ] = modl[ 0 ] * proj[ 1 ] + modl[ 1 ] * proj[ 5 ] + modl[ 2 ] * proj[ 9 ] + modl[ 3 ] * proj[ 13 ]; + clip[ 2 ] = modl[ 0 ] * proj[ 2 ] + modl[ 1 ] * proj[ 6 ] + modl[ 2 ] * proj[ 10 ] + modl[ 3 ] * proj[ 14 ]; + clip[ 3 ] = modl[ 0 ] * proj[ 3 ] + modl[ 1 ] * proj[ 7 ] + modl[ 2 ] * proj[ 11 ] + modl[ 3 ] * proj[ 15 ]; + + clip[ 4 ] = modl[ 4 ] * proj[ 0 ] + modl[ 5 ] * proj[ 4 ] + modl[ 6 ] * proj[ 8 ] + modl[ 7 ] * proj[ 12 ]; + clip[ 5 ] = modl[ 4 ] * proj[ 1 ] + modl[ 5 ] * proj[ 5 ] + modl[ 6 ] * proj[ 9 ] + modl[ 7 ] * proj[ 13 ]; + clip[ 6 ] = modl[ 4 ] * proj[ 2 ] + modl[ 5 ] * proj[ 6 ] + modl[ 6 ] * proj[ 10 ] + modl[ 7 ] * proj[ 14 ]; + clip[ 7 ] = modl[ 4 ] * proj[ 3 ] + modl[ 5 ] * proj[ 7 ] + modl[ 6 ] * proj[ 11 ] + modl[ 7 ] * proj[ 15 ]; + + clip[ 8 ] = modl[ 8 ] * proj[ 0 ] + modl[ 9 ] * proj[ 4 ] + modl[ 10 ] * proj[ 8 ] + modl[ 11 ] * proj[ 12 ]; + clip[ 9 ] = modl[ 8 ] * proj[ 1 ] + modl[ 9 ] * proj[ 5 ] + modl[ 10 ] * proj[ 9 ] + modl[ 11 ] * proj[ 13 ]; + clip[ 10 ] = modl[ 8 ] * proj[ 2 ] + modl[ 9 ] * proj[ 6 ] + modl[ 10 ] * proj[ 10 ] + modl[ 11 ] * proj[ 14 ]; + clip[ 11 ] = modl[ 8 ] * proj[ 3 ] + modl[ 9 ] * proj[ 7 ] + modl[ 10 ] * proj[ 11 ] + modl[ 11 ] * proj[ 15 ]; + + clip[ 12 ] = modl[ 12 ] * proj[ 0 ] + modl[ 13 ] * proj[ 4 ] + modl[ 14 ] * proj[ 8 ] + modl[ 15 ] * proj[ 12 ]; + clip[ 13 ] = modl[ 12 ] * proj[ 1 ] + modl[ 13 ] * proj[ 5 ] + modl[ 14 ] * proj[ 9 ] + modl[ 15 ] * proj[ 13 ]; + clip[ 14 ] = modl[ 12 ] * proj[ 2 ] + modl[ 13 ] * proj[ 6 ] + modl[ 14 ] * proj[ 10 ] + modl[ 15 ] * proj[ 14 ]; + clip[ 15 ] = modl[ 12 ] * proj[ 3 ] + modl[ 13 ] * proj[ 7 ] + modl[ 14 ] * proj[ 11 ] + modl[ 15 ] * proj[ 15 ]; + + // get the sides of the frustum. + m_frustum[ side_RIGHT ][ plane_A ] = clip[ 3 ] - clip[ 0 ]; + m_frustum[ side_RIGHT ][ plane_B ] = clip[ 7 ] - clip[ 4 ]; + m_frustum[ side_RIGHT ][ plane_C ] = clip[ 11 ] - clip[ 8 ]; + m_frustum[ side_RIGHT ][ plane_D ] = clip[ 15 ] - clip[ 12 ]; + normalize_plane( side_RIGHT ); + + m_frustum[ side_LEFT ][ plane_A ] = clip[ 3 ] + clip[ 0 ]; + m_frustum[ side_LEFT ][ plane_B ] = clip[ 7 ] + clip[ 4 ]; + m_frustum[ side_LEFT ][ plane_C ] = clip[ 11 ] + clip[ 8 ]; + m_frustum[ side_LEFT ][ plane_D ] = clip[ 15 ] + clip[ 12 ]; + normalize_plane( side_LEFT ); + + m_frustum[ side_BOTTOM ][ plane_A ] = clip[ 3 ] + clip[ 1 ]; + m_frustum[ side_BOTTOM ][ plane_B ] = clip[ 7 ] + clip[ 5 ]; + m_frustum[ side_BOTTOM ][ plane_C ] = clip[ 11 ] + clip[ 9 ]; + m_frustum[ side_BOTTOM ][ plane_D ] = clip[ 15 ] + clip[ 13 ]; + normalize_plane( side_BOTTOM ); + + m_frustum[ side_TOP ][ plane_A ] = clip[ 3 ] - clip[ 1 ]; + m_frustum[ side_TOP ][ plane_B ] = clip[ 7 ] - clip[ 5 ]; + m_frustum[ side_TOP ][ plane_C ] = clip[ 11 ] - clip[ 9 ]; + m_frustum[ side_TOP ][ plane_D ] = clip[ 15 ] - clip[ 13 ]; + normalize_plane( side_TOP ); + + m_frustum[ side_BACK ][ plane_A ] = clip[ 3 ] - clip[ 2 ]; + m_frustum[ side_BACK ][ plane_B ] = clip[ 7 ] - clip[ 6 ]; + m_frustum[ side_BACK ][ plane_C ] = clip[ 11 ] - clip[ 10 ]; + m_frustum[ side_BACK ][ plane_D ] = clip[ 15 ] - clip[ 14 ]; + normalize_plane( side_BACK ); + + m_frustum[ side_FRONT ][ plane_A ] = clip[ 3 ] + clip[ 2 ]; + m_frustum[ side_FRONT ][ plane_B ] = clip[ 7 ] + clip[ 6 ]; + m_frustum[ side_FRONT ][ plane_C ] = clip[ 11 ] + clip[ 10 ]; + m_frustum[ side_FRONT ][ plane_D ] = clip[ 15 ] + clip[ 14 ]; + normalize_plane( side_FRONT ); +} + +bool +cFrustum::point_inside( float const X, float const Y, float const Z ) const { + + // cycle through the sides of the frustum, checking if the point is behind them + for( int idx = 0; idx < 6; ++idx ) { + if( m_frustum[ idx ][ plane_A ] * X + + m_frustum[ idx ][ plane_B ] * Y + + m_frustum[ idx ][ plane_C ] * Z + + m_frustum[ idx ][ plane_D ] <= 0 ) + return false; + } + + // the point is in front of each frustum plane, i.e. inside of the frustum + return true; +} + +float +cFrustum::sphere_inside( float const X, float const Y, float const Z, float const Radius ) const { + + float distance; + // go through all the sides of the frustum. bail out as soon as possible + for( int idx = 0; idx < 6; ++idx ) { + distance = + m_frustum[ idx ][ plane_A ] * X + + m_frustum[ idx ][ plane_B ] * Y + + m_frustum[ idx ][ plane_C ] * Z + + m_frustum[ idx ][ plane_D ]; + if( distance <= -Radius ) + return 0.0f; + } + return distance + Radius; +} + +bool +cFrustum::cube_inside( float const X, float const Y, float const Z, float const Size ) const { + + for( int idx = 0; idx < 6; ++idx ) { + if( m_frustum[ idx ][ plane_A ] * ( X - Size ) + + m_frustum[ idx ][ plane_B ] * ( Y - Size ) + + m_frustum[ idx ][ plane_C ] * ( Z - Size ) + + m_frustum[ idx ][ plane_D ] > 0 ) + continue; + if( m_frustum[ idx ][ plane_A ] * ( X + Size ) + + m_frustum[ idx ][ plane_B ] * ( Y - Size ) + + m_frustum[ idx ][ plane_C ] * ( Z - Size ) + + m_frustum[ idx ][ plane_D ] > 0 ) + continue; + if( m_frustum[ idx ][ plane_A ] * ( X - Size ) + + m_frustum[ idx ][ plane_B ] * ( Y + Size ) + + m_frustum[ idx ][ plane_C ] * ( Z - Size ) + + m_frustum[ idx ][ plane_D ] > 0 ) + continue; + if( m_frustum[ idx ][ plane_A ] * ( X + Size ) + + m_frustum[ idx ][ plane_B ] * ( Y + Size ) + + m_frustum[ idx ][ plane_C ] * ( Z - Size ) + + m_frustum[ idx ][ plane_D ] > 0 ) + continue; + if( m_frustum[ idx ][ plane_A ] * ( X - Size ) + + m_frustum[ idx ][ plane_B ] * ( Y - Size ) + + m_frustum[ idx ][ plane_C ] * ( Z + Size ) + + m_frustum[ idx ][ plane_D ] > 0 ) + continue; + if( m_frustum[ idx ][ plane_A ] * ( X + Size ) + + m_frustum[ idx ][ plane_B ] * ( Y - Size ) + + m_frustum[ idx ][ plane_C ] * ( Z + Size ) + + m_frustum[ idx ][ plane_D ] > 0 ) + continue; + if( m_frustum[ idx ][ plane_A ] * ( X - Size ) + + m_frustum[ idx ][ plane_B ] * ( Y + Size ) + + m_frustum[ idx ][ plane_C ] * ( Z + Size ) + + m_frustum[ idx ][ plane_D ] > 0 ) + continue; + if( m_frustum[ idx ][ plane_A ] * ( X + Size ) + + m_frustum[ idx ][ plane_B ] * ( Y + Size ) + + m_frustum[ idx ][ plane_C ] * ( Z + Size ) + + m_frustum[ idx ][ plane_D ] > 0 ) + continue; + + return false; + } + + return true; +} + +void cFrustum::normalize_plane( cFrustum::side const Side ) { + + float magnitude = + std::sqrt( + m_frustum[ Side ][ plane_A ] * m_frustum[ Side ][ plane_A ] + + m_frustum[ Side ][ plane_B ] * m_frustum[ Side ][ plane_B ] + + m_frustum[ Side ][ plane_C ] * m_frustum[ Side ][ plane_C ] ); + + m_frustum[ Side ][ plane_A ] /= magnitude; + m_frustum[ Side ][ plane_B ] /= magnitude; + m_frustum[ Side ][ plane_C ] /= magnitude; + m_frustum[ Side ][ plane_D ] /= magnitude; +} diff --git a/frustum.h b/frustum.h new file mode 100644 index 00000000..be8b9265 --- /dev/null +++ b/frustum.h @@ -0,0 +1,67 @@ +/* +This Source Code Form is subject to the +terms of the Mozilla Public License, v. +2.0. If a copy of the MPL was not +distributed with this file, You can +obtain one at +http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include "float3d.h" +#include "dumb3d.h" + +// generic frustum class. used to determine if objects are inside current view area + +class cFrustum { + +public: +// constructors: + +// methods: + // update the frustum to match current view orientation + void + calculate(); + // returns true if specified point is inside of the frustum + inline + bool + point_inside( float3 const &Point ) const { return point_inside( Point.x, Point.y, Point.z ); } + inline + bool + point_inside( Math3D::vector3 const &Point ) const { return point_inside( static_cast( Point.x ), static_cast( Point.y ), static_cast( Point.z ) ); } + bool + point_inside( float const X, float const Y, float const Z ) const; + // tests if the sphere is in frustum, returns the distance between origin and sphere centre + inline + float + sphere_inside( float3 const &Center, float const Radius ) const { return sphere_inside( Center.x, Center.y, Center.z, Radius ); } + inline + float + sphere_inside( Math3D::vector3 const &Center, float const Radius ) const { return sphere_inside( static_cast( Center.x ), static_cast( Center.y ), static_cast( Center.z ), Radius ); } + float + sphere_inside( float const X, float const Y, float const Z, float const Radius ) const; + // returns true if specified cube is inside of the frustum. Size = half of the length + inline + bool + cube_inside( float3 const &Center, float const Size ) const { return cube_inside( Center.x, Center.y, Center.z, Size ); } + inline + bool + cube_inside( Math3D::vector3 const &Center, float const Size ) const { return cube_inside( static_cast( Center.x ), static_cast( Center.y ), static_cast( Center.z ), Size ); } + bool + cube_inside( float const X, float const Y, float const Z, float const Size ) const; + +protected: +// types: + // planes of the frustum + enum side { side_RIGHT = 0, side_LEFT = 1, side_BOTTOM = 2, side_TOP = 3, side_BACK = 4, side_FRONT = 5 }; + // parameters of the frustum plane: A, B, C define plane normal, D defines distance from origin + enum plane { plane_A = 0, plane_B = 1, plane_C = 2, plane_D = 3 }; + +// methods: + void + normalize_plane( cFrustum::side const Side ); // normalizes a plane (A side) from the frustum + +// members: + float m_frustum[6][4]; // holds the A B C and D values (normal & distance) for each side of the frustum. +}; diff --git a/maszyna.vcxproj b/maszyna.vcxproj index 19e4a244..ad2f4f28 100644 --- a/maszyna.vcxproj +++ b/maszyna.vcxproj @@ -101,6 +101,7 @@ + @@ -166,6 +167,7 @@ + diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index 39c0f4ba..525c37ab 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -201,6 +201,9 @@ Source Files + + Source Files + @@ -389,6 +392,9 @@ Header Files + + Header Files +