diff --git a/CMakeLists.txt b/CMakeLists.txt index 1891f6c7..9f39b19a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,4 +105,7 @@ target_link_libraries(${PROJECT_NAME} ${PYTHON_LIBRARIES}) find_package(PNG REQUIRED) include_directories(${PNG_INCLUDE_DIRS}) -target_link_libraries(${PROJECT_NAME} ${PNG_LIBRARIES}) \ No newline at end of file +target_link_libraries(${PROJECT_NAME} ${PNG_LIBRARIES}) + +find_package(GLM REQUIRED) +include_directories(${GLM_INCLUDE_DIRS}) \ No newline at end of file diff --git a/CMake_modules/FindGLM.cmake b/CMake_modules/FindGLM.cmake new file mode 100644 index 00000000..5bfa9649 --- /dev/null +++ b/CMake_modules/FindGLM.cmake @@ -0,0 +1,52 @@ +# +# Find GLM +# +# Try to find GLM : OpenGL Mathematics. +# This module defines +# - GLM_INCLUDE_DIRS +# - GLM_FOUND +# +# The following variables can be set as arguments for the module. +# - GLM_ROOT_DIR : Root library directory of GLM +# +# References: +# - https://github.com/Groovounet/glm/blob/master/util/FindGLM.cmake +# - https://bitbucket.org/alfonse/gltut/src/28636298c1c0/glm-0.9.0.7/FindGLM.cmake +# + +# Additional modules +include(FindPackageHandleStandardArgs) + +if (WIN32) + # Find include files + find_path( + GLM_INCLUDE_DIR + NAMES glm/glm.hpp + PATHS + $ENV{PROGRAMFILES}/include + ${GLM_ROOT_DIR}/include + DOC "The directory where glm/glm.hpp resides") +else() + # Find include files + find_path( + GLM_INCLUDE_DIR + NAMES glm/glm.hpp + PATHS + /usr/include + /usr/local/include + /sw/include + /opt/local/include + ${GLM_ROOT_DIR}/include + DOC "The directory where glm/glm.hpp resides") +endif() + +# Handle REQUIRD argument, define *_FOUND variable +find_package_handle_standard_args(GLM DEFAULT_MSG GLM_INCLUDE_DIR) + +# Define GLM_INCLUDE_DIRS +if (GLM_FOUND) + set(GLM_INCLUDE_DIRS ${GLM_INCLUDE_DIR}) +endif() + +# Hide some variables +mark_as_advanced(GLM_INCLUDE_DIR) diff --git a/EU07.cpp b/EU07.cpp index 023bcb11..3d1cc35b 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -231,6 +231,8 @@ int main(int argc, char *argv[]) glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE); glfwWindowHint(GLFW_SAMPLES, 1 << Global::iMultisampling); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); if (Global::bFullScreen) { @@ -279,11 +281,19 @@ int main(int argc, char *argv[]) GfxRenderer.Init(); Global::pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów - if (!World.Init(window)) + try { - std::cout << "failed to init TWorld" << std::endl; - return -1; - } + if (!World.Init(window)) + { + std::cout << "failed to init TWorld" << std::endl; + return -1; + } + } + catch (std::runtime_error e) + { + WriteLog(e.what()); + return -1; + } Console *pConsole = new Console(); // Ra: nie wiem, czy ma to sens, ale jakoś zainicjowac trzeba diff --git a/Globals.cpp b/Globals.cpp index c7f6e1f8..7d8080fa 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -103,8 +103,7 @@ GLfloat Global::ambientLight[] = {0.80f, 0.80f, 0.85f, 1.0f}; // stałe GLfloat Global::diffuseLight[] = {0.85f, 0.85f, 0.80f, 1.0f}; GLfloat Global::specularLight[] = {0.95f, 0.94f, 0.90f, 1.0f}; #else -opengl_light Global::DayLight; -int Global::DynamicLightCount{ 3 }; +int Global::DynamicLightCount = 7; #endif GLfloat Global::whiteLight[] = {1.00f, 1.00f, 1.00f, 1.0f}; GLfloat Global::noLight[] = {0.00f, 0.00f, 0.00f, 1.0f}; @@ -220,6 +219,8 @@ double Global::fMWDamp[2] = { 800, 1023 }; double Global::fMWDlowVolt[2] = { 150, 1023 }; int Global::iMWDdivider = 5; +Global::daylight_s Global::daylight; + //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- diff --git a/Globals.h b/Globals.h index 8db176d2..2599c83b 100644 --- a/Globals.h +++ b/Globals.h @@ -234,7 +234,6 @@ class Global static GLfloat specularLight[]; #else // TODO: put these things in the renderer - static opengl_light DayLight; static int DynamicLightCount; #endif static GLfloat whiteLight[]; @@ -366,5 +365,15 @@ class Global static double fMWDamp[2]; static double fMWDlowVolt[2]; static int iMWDdivider; + + struct daylight_s + { + float3 position; + float3 direction; + float3 color; + float3 ambient; + }; + + static daylight_s daylight; }; //--------------------------------------------------------------------------- diff --git a/Ground.cpp b/Ground.cpp index 36c85663..9c0e48f5 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -339,9 +339,9 @@ void TGroundNode::RenderVBO() 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 ] ); + r = floor( Diffuse[ 0 ] * Global::daylight.ambient.x ); // w zaleznosci od koloru swiatla + g = floor( Diffuse[ 1 ] * Global::daylight.ambient.y ); + b = floor( Diffuse[ 2 ] * Global::daylight.ambient.z ); #endif glColor4ub(r, g, b, linealpha); // przezroczystosc dalekiej linii // glDisable(GL_LIGHTING); //nie powinny świecić @@ -405,9 +405,9 @@ void TGroundNode::RenderAlphaVBO() g = Diffuse[ 1 ] * Global::ambientDayLight[ 1 ]; b = Diffuse[ 2 ] * Global::ambientDayLight[ 2 ]; #else - r = Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ]; // w zaleznosci od koloru swiatla - g = Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ]; - b = Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ]; + r = Diffuse[ 0 ] * Global::daylight.ambient.x; // w zaleznosci od koloru swiatla + g = Diffuse[ 1 ] * Global::daylight.ambient.y; + b = Diffuse[ 2 ] * Global::daylight.ambient.z; #endif glColor4ub(r, g, b, linealpha); // przezroczystosc dalekiej linii // glDisable(GL_LIGHTING); //nie powinny świecić @@ -605,9 +605,9 @@ void TGroundNode::RenderDL() g = Diffuse[ 1 ] * Global::ambientDayLight[ 1 ]; b = Diffuse[ 2 ] * Global::ambientDayLight[ 2 ]; #else - r = Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ]; // w zaleznosci od koloru swiatla - g = Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ]; - b = Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ]; + r = Diffuse[ 0 ] * Global::daylight.ambient.x; // w zaleznosci od koloru swiatla + g = Diffuse[ 1 ] * Global::daylight.ambient.y; + b = Diffuse[ 2 ] * Global::daylight.ambient.z; #endif glColor4ub(r, g, b, 1.0); glCallList(DisplayListID); @@ -686,9 +686,9 @@ void TGroundNode::RenderAlphaDL() g = Diffuse[ 1 ] * Global::ambientDayLight[ 1 ]; b = Diffuse[ 2 ] * Global::ambientDayLight[ 2 ]; #else - r = Diffuse[ 0 ] * Global::DayLight.ambient[ 0 ]; // w zaleznosci od koloru swiatla - g = Diffuse[ 1 ] * Global::DayLight.ambient[ 1 ]; - b = Diffuse[ 2 ] * Global::DayLight.ambient[ 2 ]; + r = Diffuse[ 0 ] * Global::daylight.ambient.x; // w zaleznosci od koloru swiatla + g = Diffuse[ 1 ] * Global::daylight.ambient.y; + b = Diffuse[ 2 ] * Global::daylight.ambient.z; #endif glColor4ub(r, g, b, linealpha); // przezroczystosc dalekiej linii glCallList(DisplayListID); @@ -2877,10 +2877,9 @@ bool TGround::Init(std::string File) #else parser.getTokens(3, false); parser - >> Global::DayLight.direction.x - >> Global::DayLight.direction.y - >> Global::DayLight.direction.z;; - Global::DayLight.direction.Normalize(); + >> Global::daylight.direction.x + >> Global::daylight.direction.y + >> Global::daylight.direction.z; #endif parser.getTokens(9, false); @@ -2901,7 +2900,7 @@ bool TGround::Init(std::string File) // kolor wszechobceny >> Global::DayLight.ambient[0] >> Global::DayLight.ambient[1] - >> Global::DayLight.ambient[2] + >> Global::daylight.ambient.z // kolor padający >> Global::DayLight.diffuse[0] >> Global::DayLight.diffuse[1] diff --git a/Ground.h b/Ground.h index 57fa0d82..63bb3ae9 100644 --- a/Ground.h +++ b/Ground.h @@ -308,7 +308,8 @@ class TGround event_map m_eventmap; TNames m_trackmap; #endif - light_array m_lights; // collection of dynamic light sources present in the scene + + light_array m_lights; private: // metody prywatne bool EventConditon(TEvent *e); diff --git a/Model3d.cpp b/Model3d.cpp index 1441037b..cc51713c 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -23,6 +23,10 @@ Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others #include "Timer.h" #include "mtable.h" #include "sn_utils.h" +#include "World.h" + +extern TWorld World; + //--------------------------------------------------------------------------- using namespace Mtable; @@ -1243,6 +1247,7 @@ void TSubModel::RenderVBO() if (b_Anim) RaAnimation(b_Anim); } + World.shader.copy_gl_mvp(); if (eType < TP_ROTATOR) { // renderowanie obiektów OpenGL if (iAlpha & iFlags & 0x1F) // rysuj gdy element nieprzezroczysty @@ -1418,6 +1423,7 @@ void TSubModel::RenderAlphaVBO() if (b_aAnim) RaAnimation(b_aAnim); } + World.shader.copy_gl_mvp(); glColor3fv(f4Diffuse); if (eType < TP_ROTATOR) { // renderowanie obiektów OpenGL diff --git a/Track.cpp b/Track.cpp index 9cd56f24..0c563e58 100644 --- a/Track.cpp +++ b/Track.cpp @@ -2463,7 +2463,6 @@ void TTrack::RaRenderVBO(int iPtr) // dla kolejnych tekstur! EnvironmentSet(); int seg; - int i; switch (iCategoryFlag & 15) { case 1: // tor diff --git a/Traction.cpp b/Traction.cpp index c0b5f181..ad579b53 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -328,9 +328,9 @@ void TTraction::RenderDL(float mgn) // McZapkie: mgn to odleglosc od obserwatora 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]; + r *= Global::daylight.ambient.x; // w zaleźności od koloru swiatła + g *= Global::daylight.ambient.y; + b *= Global::daylight.ambient.z; #endif if (linealpha > 1.0f) linealpha = 1.0f; // trzeba ograniczyć do <=1 @@ -538,9 +538,9 @@ void TTraction::RenderVBO(float mgn, int iPtr) 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 ]; + r *= Global::daylight.ambient.x; // w zaleźności od koloru swiatła + g *= Global::daylight.ambient.y; + b *= Global::daylight.ambient.z; #endif if (linealpha > 1.0f) linealpha = 1.0f; // trzeba ograniczyć do <=1 diff --git a/VBO.cpp b/VBO.cpp index cd9483d3..b8da80c3 100644 --- a/VBO.cpp +++ b/VBO.cpp @@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/. #include "GL/glew.h" #include "usefull.h" #include "sn_utils.h" +#include "World.h" //--------------------------------------------------------------------------- void CVertNormTex::deserialize(std::istream &s) @@ -64,10 +65,18 @@ void CMesh::BuildVBOs(bool del) { // tworzenie VBO i kasowanie już niepotrzebnych tablic // pobierz numer VBO oraz ustaw go jako aktywny glGenBuffers(1, &m_nVBOVertices); // pobierz numer - glBindBuffer(GL_ARRAY_BUFFER, m_nVBOVertices); // ustaw bufor jako aktualny + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, m_nVBOVertices); glBufferData(GL_ARRAY_BUFFER, m_nVertexCount * sizeof(CVertNormTex), m_pVNT, GL_STATIC_DRAW); - // WriteLog("Assigned VBO number "+AnsiString(m_nVBOVertices)+", vertices: - // "+AnsiString(m_nVertexCount)); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (GLvoid*)0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (GLvoid*)(sizeof(float) * 3)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (GLvoid*)(sizeof(float) * 6)); + glEnableVertexAttribArray(2); + glBindVertexArray(0); + if (del) SafeDeleteArray(m_pVNT); // wierzchołki już się nie przydadzą }; @@ -77,33 +86,32 @@ void CMesh::Clear() // inna nazwa, żeby nie mieszało się z funkcją wirtualną sprzątacza if (m_nVBOVertices) // jeśli było coś rezerwowane { - glDeleteBuffers(1, &m_nVBOVertices); // Free The Memory - // WriteLog("Released VBO number "+AnsiString(m_nVBOVertices)); + glDeleteBuffers(1, &m_nVBOVertices); + glDeleteVertexArrays(1, &vao); } m_nVBOVertices = 0; m_nVertexCount = -1; // do ponownego zliczenia SafeDeleteArray(m_pVNT); // usuwanie tablic, gdy były użyte do Vertex Array }; +extern TWorld World; + bool CMesh::StartVBO() { // początek rysowania elementów z VBO if (m_nVertexCount <= 0) return false; // nie ma nic do rysowania w ten sposób - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (m_nVBOVertices) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, m_nVBOVertices); - glVertexPointer( 3, GL_FLOAT, sizeof(CVertNormTex), static_cast(nullptr) ); // pozycje - glNormalPointer( GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 12 ); // normalne - glTexCoordPointer( 2, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 24 ); // wierzchołki - } + glBindVertexArray(vao); + + glUseProgram(World.shader); + World.shader.copy_gl_mvp(); return true; // można rysować z VBO }; bool CMesh::StartColorVBO() { // początek rysowania punktów świecących z VBO + return false; //m7todo + /* if (m_nVertexCount <= 0) return false; // nie ma nic do rysowania w ten sposób glEnableClientState(GL_VERTEX_ARRAY); @@ -116,15 +124,11 @@ bool CMesh::StartColorVBO() glColorPointer( 3, GL_FLOAT, sizeof( CVertNormTex ), static_cast( nullptr ) + 12 ); // kolory } return true; // można rysować z VBO + */ }; void CMesh::EndVBO() { // koniec użycia VBO - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - // glBindBuffer(GL_ARRAY_BUFFER,0); //takie coś psuje, mimo iż polecali użyć - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Ra: to na przyszłość + glBindVertexArray(0); + glUseProgram(0); }; diff --git a/VBO.h b/VBO.h index 3c0ec334..59728a63 100644 --- a/VBO.h +++ b/VBO.h @@ -7,6 +7,8 @@ obtain one at http://mozilla.org/MPL/2.0/. */ +#include "shader.h" + #ifndef VBOH #define VBOH //--------------------------------------------------------------------------- @@ -28,6 +30,8 @@ class CVertNormTex class CMesh { // wsparcie dla VBO + GLuint vao; + gl_program shader; public: int m_nVertexCount; // liczba wierzchołków CVertNormTex *m_pVNT; diff --git a/World.cpp b/World.cpp index 9578428e..32ad1d17 100644 --- a/World.cpp +++ b/World.cpp @@ -186,7 +186,7 @@ bool TWorld::Init(GLFWwindow *w) WriteLog(glver); if (!GLEW_VERSION_1_4) { - std::cout << "required opengl >=1.4" << std::endl; + std::cout << "required opengl >=3.2" << std::endl; return false; } @@ -249,6 +249,9 @@ bool TWorld::Init(GLFWwindow *w) WriteLog("Max texture size: " + std::to_string(Global::iMaxTextureSize)); } /*-----------------------Render Initialization----------------------*/ + + shader = gl_program_light({gl_shader("lighting.vert"), gl_shader("blinnphong.frag")}); + glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glMatrixMode( GL_MODELVIEW ); @@ -453,15 +456,13 @@ bool TWorld::Init(GLFWwindow *w) GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; ::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient ); - Global::DayLight.id = opengl_renderer::sunlight; // directional light // TODO, TBD: test omni-directional variant - Global::DayLight.position[ 3 ] = 1.0f; - ::glLightf( opengl_renderer::sunlight, GL_SPOT_CUTOFF, 90.0 ); + // rgb value for 5780 kelvin - Global::DayLight.diffuse[ 0 ] = 255.0f / 255.0f; - Global::DayLight.diffuse[ 1 ] = 242.0f / 255.0f; - Global::DayLight.diffuse[ 2 ] = 231.0f / 255.0f; + Global::daylight.color.x = 255.0f / 255.0f; + Global::daylight.color.y = 242.0f / 255.0f; + Global::daylight.color.z = 231.0f / 255.0f; #endif Ground.Init(Global::SceneryFile); @@ -2925,6 +2926,7 @@ void TWorld::CabChange(TDynamicObject *old, TDynamicObject *now) void world_environment::init() { + m_skydome.init(); m_sun.init(); m_stars.init(); m_clouds.Init(); @@ -2938,8 +2940,6 @@ world_environment::update() { auto const position = m_sun.getPosition(); // ...update the global data to match new sun state... Global::SunAngle = m_sun.getAngle(); - Global::DayLight.set_position( position ); - Global::DayLight.direction = -1.0 * m_sun.getDirection(); // ...update skydome to match the current sun position as well... m_skydome.Update( position ); // ...retrieve current sky colour and brightness... @@ -2950,15 +2950,14 @@ world_environment::update() { // NOTE: intensity combines intensity of the sun and the light reflected by the sky dome // it'd be more technically correct to have just the intensity of the sun here, // but whether it'd _look_ better is something to be tested - Global::DayLight.diffuse[ 0 ] = intensity * 255.0f / 255.0f; - Global::DayLight.diffuse[ 1 ] = intensity * 242.0f / 255.0f; - Global::DayLight.diffuse[ 2 ] = intensity * 231.0f / 255.0f; - Global::DayLight.ambient[ 0 ] = skydomecolour.x; - Global::DayLight.ambient[ 1 ] = skydomecolour.y; - Global::DayLight.ambient[ 2 ] = skydomecolour.z; - - Global::fLuminance = intensity; + Global::daylight.position = float3(position.x, position.y, position.z); + vector3 sun = -1.0 * m_sun.getDirection(); + Global::daylight.direction = float3(sun.x, sun.y, sun.z); + Global::daylight.color = float3(intensity * 255.0f / 255.0f, + intensity * 242.0f / 255.0f, + intensity * 231.0f / 255.0f); + Global::daylight.ambient = float3(skydomecolour.x, skydomecolour.y, skydomecolour.z); // update the fog. setting it to match the average colour of the sky dome is cheap // but quite effective way to make the distant items blend with background better @@ -2970,6 +2969,8 @@ world_environment::update() { ::glClearColor( skydomecolour.x, skydomecolour.y, skydomecolour.z, 1.0f ); // kolor nieba } +extern TWorld World; + void world_environment::render() { @@ -2990,8 +2991,9 @@ world_environment::render() { // mark sun position for easier debugging m_sun.render(); } - Global::DayLight.apply_angle(); - Global::DayLight.apply_intensity(); + + World.shader.set_ambient(Global::daylight.ambient); + World.shader.set_light(0, gl_program_light::DIR, Global::daylight.position, Global::daylight.direction, 0.0f, 0.0f, Global::daylight.color, 0.0f, 0.0f); ::glPopMatrix(); ::glDepthMask( GL_TRUE ); diff --git a/World.h b/World.h index 67b0ece1..09f85a78 100644 --- a/World.h +++ b/World.h @@ -89,10 +89,13 @@ class TWorld int tprev; // poprzedni czas double Acc; // przyspieszenie styczne bool m_init{ false }; // indicates whether initial update of the world was performed + public: void ModifyTGA(std::string const &dir = ""); void CreateE3D(std::string const &dir = "", bool dyn = false); void CabChange(TDynamicObject *old, TDynamicObject *now); + + gl_program_light shader; //m7todo: tmp }; //--------------------------------------------------------------------------- diff --git a/renderer.cpp b/renderer.cpp index 3f539555..1348a987 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -10,39 +10,27 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "renderer.h" #include "globals.h" +#include "World.h" opengl_renderer GfxRenderer; +extern TWorld World; void opengl_renderer::Init() { - // create dynamic light pool - for( int idx = 0; idx < Global::DynamicLightCount; ++idx ) { - - opengl_light light; - light.id = GL_LIGHT1 + idx; - - light.position[ 3 ] = 1.0f; - ::glLightf( light.id, GL_SPOT_CUTOFF, 7.5f ); - ::glLightf( light.id, GL_SPOT_EXPONENT, 7.5f ); - ::glLightf( light.id, GL_CONSTANT_ATTENUATION, 0.0f ); - ::glLightf( light.id, GL_LINEAR_ATTENUATION, 0.035f ); - - m_lights.emplace_back( light ); - } } void opengl_renderer::Update_Lights( light_array const &Lights ) { - size_t const count = std::min( m_lights.size(), Lights.data.size() ); + size_t const count = std::min( (size_t)Global::DynamicLightCount, Lights.data.size() ); if( count == 0 ) { return; } - auto renderlight = m_lights.begin(); + size_t renderlight = 0; for( auto const &scenelight : Lights.data ) { - if( renderlight == m_lights.end() ) { + if( renderlight == Global::DynamicLightCount ) { // we ran out of lights to assign break; } @@ -55,40 +43,27 @@ opengl_renderer::Update_Lights( light_array const &Lights ) { // but there could still be weaker lights which are closer, so keep looking continue; } - // if the light passed tests so far, it's good enough - renderlight->set_position( scenelight.position ); - renderlight->direction = scenelight.direction; - auto const luminance = Global::fLuminance; // TODO: adjust this based on location, e.g. for tunnels - 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 ); + // if the light passed tests so far, it's good enough - ::glLightf( renderlight->id, GL_LINEAR_ATTENUATION, (0.25f * scenelight.count) / std::pow( scenelight.count, 2 ) ); - ::glEnable( renderlight->id ); + auto const luminance = Global::fLuminance; // TODO: adjust this based on location, e.g. for tunnels + float3 position(scenelight.position.x, scenelight.position.y, scenelight.position.z); + float3 direction(scenelight.direction.x, scenelight.direction.y, scenelight.direction.z); + float3 color(scenelight.color.x, + scenelight.color.y, + scenelight.color.z); - renderlight->apply_intensity(); - renderlight->apply_angle(); + World.shader.set_light((GLuint)renderlight + 1, gl_program_light::SPOT, position, direction, 0.906f, 0.866f, color, 0.007f, 0.0002f); ++renderlight; } - while( renderlight != m_lights.end() ) { - // if we went through all scene lights and there's still opengl lights remaining, kill these - ::glDisable( renderlight->id ); - ++renderlight; - } + World.shader.set_light_count((GLuint)renderlight + 1); } void opengl_renderer::Disable_Lights() { - for( size_t idx = 0; idx < m_lights.size() + 1; ++idx ) { - - ::glDisable( GL_LIGHT0 + (int)idx ); - } + World.shader.set_light_count(0); } //--------------------------------------------------------------------------- diff --git a/renderer.h b/renderer.h index 719d78ae..d5cc2750 100644 --- a/renderer.h +++ b/renderer.h @@ -14,47 +14,6 @@ http://mozilla.org/MPL/2.0/. #include "lightarray.h" #include "dumb3d.h" -struct opengl_light { - - GLuint id{ (GLuint)-1 }; - Math3D::vector3 direction; - GLfloat position[ 4 ]; // 4th parameter specifies directional(0) or omni-directional(1) light source - GLfloat ambient[ 4 ]; - GLfloat diffuse[ 4 ]; - GLfloat specular[ 4 ]; - - opengl_light() { - position[ 0 ] = position[ 1 ] = position[ 2 ] = 0.0f; position[ 3 ] = 1.0f; // 0,0,0,1 - ambient[ 0 ] = ambient[ 1 ] = ambient[ 2 ] = 0.0f; ambient[ 3 ] = 1.0f; // 0,0,0,1 - diffuse[ 0 ] = diffuse[ 1 ] = diffuse[ 2 ] = diffuse[ 3 ] = 1.0f; // 1,1,1,1 - specular[ 0 ] = specular[ 1 ] = specular[ 2 ] = specular[ 3 ] = 1.0f; // 1,1,1,1 - } - - inline - void apply_intensity() { - - glLightfv( id, GL_AMBIENT, ambient ); - glLightfv( id, GL_DIFFUSE, diffuse ); - glLightfv( id, GL_SPECULAR, specular ); - } - inline - void apply_angle() { - - glLightfv( id, GL_POSITION, position ); - if( position[ 3 ] == 1.0f ) { - GLfloat directionarray[] = { (GLfloat)direction.x, (GLfloat)direction.y, (GLfloat)direction.z }; - glLightfv( id, GL_SPOT_DIRECTION, directionarray ); - } - } - inline - void set_position( Math3D::vector3 const &Position ) { - - position[ 0 ] = Position.x; - position[ 1 ] = Position.y; - position[ 2 ] = Position.z; - } -}; - // encapsulates basic rendering setup. // for modern opengl this translates to a specific collection of glsl shaders, // for legacy opengl this is combination of blending modes, active texture units etc @@ -104,19 +63,16 @@ public: } // members - GLenum static const sunlight{ GL_LIGHT0 }; + GLenum static const sunlight{ 0 }; private: // types enum class rendermode { color }; - - typedef std::vector opengllight_array; // members rendermode renderpass{ rendermode::color }; - opengllight_array m_lights; texture_manager m_textures; }; diff --git a/shader.cpp b/shader.cpp index 68b76112..7396aef6 100644 --- a/shader.cpp +++ b/shader.cpp @@ -4,6 +4,12 @@ #include "stdafx.h" #include "shader.h" +#include "Float3d.h" +#include "Logs.h" + +#include +#include +#include inline bool strcend(std::string const &value, std::string const &ending) { @@ -14,6 +20,8 @@ inline bool strcend(std::string const &value, std::string const &ending) gl_shader::gl_shader(std::string filename) { + WriteLog("loading shader " + filename + " ..", false); + std::stringstream stream; std::ifstream f; f.exceptions(std::ifstream::badbit); @@ -48,13 +56,20 @@ gl_shader::gl_shader(std::string filename) glGetShaderInfoLog(id, 512, 0, info); throw std::runtime_error("failed to compile " + filename + ": " + std::string(info)); } + + WriteLog("done."); +} + +gl_shader::operator GLuint() +{ + return id; } gl_program::gl_program(std::vector shaders) { id = glCreateProgram(); for (auto s : shaders) - glAttachShader(id, s.id); + glAttachShader(id, s); glLinkProgram(id); GLint status; @@ -67,7 +82,79 @@ gl_program::gl_program(std::vector shaders) } } -void gl_program::use() +gl_program::operator GLuint() +{ + return id; +} + +gl_program_mvp::gl_program_mvp(std::vector v) : gl_program(v) +{ + mv_uniform = glGetUniformLocation(id, "modelview"); + p_uniform = glGetUniformLocation(id, "projection"); +} + +void gl_program_mvp::copy_gl_mvp() +{ + float4x4 mv, p; + glGetFloatv(GL_MODELVIEW_MATRIX, mv.e); + glGetFloatv(GL_PROJECTION_MATRIX, p.e); + + glUniformMatrix4fv(mv_uniform, 1, GL_FALSE, mv.e); + glUniformMatrix4fv(p_uniform, 1, GL_FALSE, p.e); +} + +gl_program_light::gl_program_light(std::vector v) : gl_program_mvp(v) +{ + ambient_uniform = glGetUniformLocation(id, "ambient"); + lcount_uniform = glGetUniformLocation(id, "lights_count"); + + for (size_t i = 0; i < MAX_LIGHTS; i++) + { + lights_uniform[i].type = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].type").c_str()); + lights_uniform[i].pos = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].pos").c_str()); + lights_uniform[i].dir = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].dir").c_str()); + lights_uniform[i].in_cutoff = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].in_cutoff").c_str()); + lights_uniform[i].out_cutoff = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].out_cutoff").c_str()); + lights_uniform[i].color = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].color").c_str()); + lights_uniform[i].linear = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].linear").c_str()); + lights_uniform[i].quadratic = glGetUniformLocation(id, std::string("lights[" + std::to_string(i) + "].quadratic").c_str()); + } + + glUseProgram(id); + glUniform3f(ambient_uniform, 1.0f, 1.0f, 1.0f); + glUniform1i(lcount_uniform, 0); +} + +void gl_program_light::set_ambient(float3 &ambient) { glUseProgram(id); + glUniform3fv(ambient_uniform, 1, &ambient.x); +} + +void gl_program_light::set_light_count(GLuint count) +{ + glUseProgram(id); + glUniform1ui(lcount_uniform, count); +} + +void gl_program_light::set_light(GLuint i, type t, float3 &pos, float3 &dir, + float in_cutoff, float out_cutoff, + float3 &color, float linear, float quadratic) +{ + float arr[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, arr); + glm::mat4 mv = glm::make_mat4(arr); + + glm::vec3 trans_pos = mv * glm::vec4(pos.x, pos.y, pos.z, 1.0f); + glm::vec3 trans_dir = mv * glm::vec4(dir.x, dir.y, dir.z, 0.0f); + + glUseProgram(id); + glUniform1ui(lights_uniform[i].type, (GLuint)t); + glUniform3fv(lights_uniform[i].pos, 1, glm::value_ptr(trans_pos)); + glUniform3fv(lights_uniform[i].dir, 1, glm::value_ptr(trans_dir)); + glUniform1f(lights_uniform[i].in_cutoff, in_cutoff); + glUniform1f(lights_uniform[i].out_cutoff, out_cutoff); + glUniform3fv(lights_uniform[i].color, 1, &color.x); + glUniform1f(lights_uniform[i].linear, linear); + glUniform1f(lights_uniform[i].quadratic, quadratic); } \ No newline at end of file diff --git a/shader.h b/shader.h index 48aacfaf..7656baec 100644 --- a/shader.h +++ b/shader.h @@ -2,21 +2,74 @@ * 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" + class gl_shader { -public: GLuint id; - +public: gl_shader(); gl_shader(std::string); + + operator GLuint(); }; class gl_program { +protected: GLuint id; public: gl_program() = default; gl_program(std::vector); - void use(); + operator GLuint(); +}; + +class gl_program_mvp : public gl_program +{ + GLuint mv_uniform; + GLuint p_uniform; + +public: + gl_program_mvp() = default; + gl_program_mvp(std::vector); + + void copy_gl_mvp(); +}; + +class gl_program_light : public gl_program_mvp +{ +public: + static const size_t MAX_LIGHTS = 8; + + enum type + { + SPOT = 0, + POINT, + DIR + }; + + gl_program_light() = default; + gl_program_light(std::vector); + + void set_ambient(float3 &ambient); + void set_light_count(GLuint count); + void set_light(GLuint id, type t, float3 &pos, float3 &dir, float in_cutoff, float out_cutoff, + float3 &color, float linear, float quadratic); + +private: + GLuint lcount_uniform; + GLuint ambient_uniform; + struct light_s + { + GLuint type; + GLuint pos; + GLuint dir; + GLuint in_cutoff; + GLuint out_cutoff; + GLuint color; + GLuint linear; + GLuint quadratic; + } lights_uniform[MAX_LIGHTS]; }; \ No newline at end of file diff --git a/skydome.cpp b/skydome.cpp index 2afb16c3..b3746dc2 100644 --- a/skydome.cpp +++ b/skydome.cpp @@ -1,9 +1,10 @@ - #include "stdafx.h" #include "skydome.h" #include "color.h" #include "usefull.h" +#include "Globals.h" + // sky gradient based on "A practical analytic model for daylight" // by A. J. Preetham Peter Shirley Brian Smits (University of Utah) @@ -42,18 +43,32 @@ float CSkyDome::m_zenithymatrix[ 3 ][ 4 ] = { //******************************************************************************// -CSkyDome::CSkyDome (int const Tesselation) : - m_tesselation( Tesselation ) { +float clamp( float const Value, float const Min, float const Max ) { -// SetSunPosition( Math3D::vector3(75.0f, 0.0f, 0.0f) ); - SetTurbidity( 3.0f ); - SetExposure( true, 20.0f ); - SetOvercastFactor( 0.05f ); - SetGammaCorrection( 2.2f ); - Generate(); + float value = Value; + if( value < Min ) { value = Min; } + if( value > Max ) { value = Max; } + return value; } -CSkyDome::~CSkyDome() { +float interpolate( float const First, float const Second, float const Factor ) { + + return ( First * ( 1.0f - Factor ) ) + ( Second * Factor ); +} + +//******************************************************************************// + +void CSkyDome::init(int const Tesselation) +{ + m_tesselation = Tesselation; + // SetSunPosition( Math3D::vector3(75.0f, 0.0f, 0.0f) ); + SetTurbidity(3.0f); + SetExposure(true, 20.0f); + SetOvercastFactor(0.05f); + SetGammaCorrection(2.2f); + m_shader = gl_program_mvp({ gl_shader("color.frag"), + gl_shader("vbocolor.vert") }); + Generate(); } //******************************************************************************// @@ -118,7 +133,7 @@ void CSkyDome::Update( Math3D::vector3 const &Sun ) { // render skydome to screen void CSkyDome::Render() { - if( m_vertexbuffer == -1 ) { + if( m_vao == -1 ) { // build the buffers ::glGenBuffers( 1, &m_vertexbuffer ); ::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer ); @@ -131,23 +146,30 @@ void CSkyDome::Render() { ::glGenBuffers( 1, &m_indexbuffer ); ::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer ); ::glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof( unsigned short ), m_indices.data(), GL_STATIC_DRAW ); + + glGenVertexArrays(1, &m_vao); + glBindVertexArray(m_vao); + glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float3), 0); + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, m_coloursbuffer); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float3), 0); + glEnableVertexAttribArray(1); + glBindVertexArray(0); + // NOTE: vertex and index source data is superfluous past this point, but, eh } // begin - ::glEnableClientState( GL_VERTEX_ARRAY ); - ::glEnableClientState( GL_COLOR_ARRAY ); - // positions - ::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer ); - ::glVertexPointer( 3, GL_FLOAT, sizeof( float3 ), reinterpret_cast( 0 ) ); - // colours - ::glBindBuffer( GL_ARRAY_BUFFER, m_coloursbuffer ); - ::glColorPointer( 3, GL_FLOAT, sizeof( float3 ), reinterpret_cast( 0 ) ); - // indices - ::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer ); - ::glDrawElements( GL_TRIANGLES, static_cast( m_indices.size() ), GL_UNSIGNED_SHORT, reinterpret_cast( 0 ) ); - // cleanup - ::glDisableClientState( GL_COLOR_ARRAY ); - ::glDisableClientState( GL_VERTEX_ARRAY ); + + glUseProgram(m_shader); + glBindVertexArray(m_vao); + + m_shader.copy_gl_mvp(); + + glDrawElements(GL_TRIANGLES, (GLsizei)m_indices.size(), GL_UNSIGNED_SHORT, 0); + glBindVertexArray(0); + glUseProgram(0); } bool CSkyDome::SetSunPosition( Math3D::vector3 const &Direction ) { diff --git a/skydome.h b/skydome.h index ba625975..ff6ca0ca 100644 --- a/skydome.h +++ b/skydome.h @@ -2,14 +2,15 @@ #include "dumb3d.h" #include "float3d.h" +#include "shader.h" // sky gradient based on "A practical analytic model for daylight" // by A. J. Preetham Peter Shirley Brian Smits (University of Utah) class CSkyDome { public: - CSkyDome( int const Tesselation = 54 ); - ~CSkyDome(); + void init(int const Tesselation = 54); + void Generate(); void RebuildColors(); @@ -39,8 +40,10 @@ private: float m_gammacorrection; float3 m_averagecolour; + gl_program_mvp m_shader; + // data - int const m_tesselation; + int m_tesselation; std::vector m_vertices; std::vector m_indices; // std::vector m_normals; @@ -48,6 +51,7 @@ private: GLuint m_vertexbuffer{ (GLuint)-1 }; GLuint m_indexbuffer{ (GLuint)-1 }; GLuint m_coloursbuffer{ (GLuint)-1 }; + GLuint m_vao = (GLuint)-1; static float m_distributionluminance[ 5 ][ 2 ]; static float m_distributionxcomp[ 5 ][ 2 ];