diff --git a/Avara.msvc/AvaraCore.vcxproj b/Avara.msvc/AvaraCore.vcxproj index 9eb2f754..0885b47e 100644 --- a/Avara.msvc/AvaraCore.vcxproj +++ b/Avara.msvc/AvaraCore.vcxproj @@ -285,6 +285,7 @@ + @@ -476,6 +477,7 @@ + diff --git a/Avara.msvc/AvaraCore.vcxproj.filters b/Avara.msvc/AvaraCore.vcxproj.filters index 4da9feb9..404fa6e1 100644 --- a/Avara.msvc/AvaraCore.vcxproj.filters +++ b/Avara.msvc/AvaraCore.vcxproj.filters @@ -636,6 +636,9 @@ Header Files + + Header Files + @@ -1118,5 +1121,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Avara.xcodeproj/project.pbxproj b/Avara.xcodeproj/project.pbxproj index 31f6ce98..28012eca 100644 --- a/Avara.xcodeproj/project.pbxproj +++ b/Avara.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6025AE4E2C255E6A00A57EFB /* LegacyOpenGLRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 60C274E22C23EBE9005B67A9 /* LegacyOpenGLRenderer.cpp */; }; 940541ED2B5875B200E32241 /* OpenGLShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 940541EC2B5875B200E32241 /* OpenGLShader.cpp */; }; 940541EE2B5875B200E32241 /* OpenGLShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 940541EC2B5875B200E32241 /* OpenGLShader.cpp */; }; 9419E8472B49ECB1007C50D0 /* CTeamColorAdjuster.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9419E8462B49ECB1007C50D0 /* CTeamColorAdjuster.cpp */; }; @@ -387,6 +388,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 60C274E22C23EBE9005B67A9 /* LegacyOpenGLRenderer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LegacyOpenGLRenderer.cpp; sourceTree = ""; }; + 60C274E32C23EBE9005B67A9 /* LegacyOpenGLRenderer.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; path = LegacyOpenGLRenderer.h; sourceTree = ""; }; 940541EB2B58744500E32241 /* OpenGLShader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OpenGLShader.h; sourceTree = ""; }; 940541EC2B5875B200E32241 /* OpenGLShader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = OpenGLShader.cpp; sourceTree = ""; }; 9419E8452B49EC89007C50D0 /* CTeamColorAdjuster.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTeamColorAdjuster.h; sourceTree = ""; }; @@ -1083,6 +1086,8 @@ children = ( 947F5C642B576B9F00F41689 /* ModernOpenGLRenderer.cpp */, 947F5C632B576ACD00F41689 /* ModernOpenGLRenderer.h */, + 60C274E22C23EBE9005B67A9 /* LegacyOpenGLRenderer.cpp */, + 60C274E32C23EBE9005B67A9 /* LegacyOpenGLRenderer.h */, 947F5C672B57A30100F41689 /* NullRenderer.h */, 940541EC2B5875B200E32241 /* OpenGLShader.cpp */, 940541EB2B58744500E32241 /* OpenGLShader.h */, @@ -2390,6 +2395,7 @@ E5890CBF29895118007A875D /* CAbstractActor.cpp in Sources */, E5890CAA29895118007A875D /* CAbstractPipe.cpp in Sources */, E5890F0929895124007A875D /* stb_vorbis.c in Sources */, + 6025AE4E2C255E6A00A57EFB /* LegacyOpenGLRenderer.cpp in Sources */, E5890D0529895118007A875D /* CSoundMixer.cpp in Sources */, E5890CF529895118007A875D /* CRamp.cpp in Sources */, E5890C9F29895118007A875D /* Resource.cpp in Sources */, @@ -2597,6 +2603,7 @@ COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=macosx*]" = ""; ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2621,6 +2628,7 @@ PRODUCT_BUNDLE_IDENTIFIER = net.avaraline.Avara; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SWIFT_EMIT_LOC_STRINGS = YES; }; name = Debug; @@ -2661,6 +2669,7 @@ PRODUCT_BUNDLE_IDENTIFIER = net.avaraline.Avara; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SWIFT_EMIT_LOC_STRINGS = YES; }; name = Release; diff --git a/src/game/CAvaraApp.cpp b/src/game/CAvaraApp.cpp index d2965776..ac534be1 100755 --- a/src/game/CAvaraApp.cpp +++ b/src/game/CAvaraApp.cpp @@ -37,6 +37,7 @@ #include "Tags.h" #include "Debug.h" #include "ModernOpenGLRenderer.h" +#include "LegacyOpenGLRenderer.h" // included while we fake things out #include "CPlayerManager.h" @@ -79,7 +80,13 @@ CAvaraAppImpl::CAvaraAppImpl() : CApplication("Avara") { ui->LoadImages(mNVGContext); } - gRenderer = new ModernOpenGLRenderer(mSDLWindow); + if (Get(kUseLegacyRenderer)) { + gRenderer = new LegacyOpenGLRenderer(mSDLWindow); + } + else { + gRenderer = new ModernOpenGLRenderer(mSDLWindow); + } + gRenderer->UpdateViewRect(mSize.x, mSize.y, mPixelRatio); gRenderer->SetFOV(Number(kFOV)); gRenderer->ResetLights(); diff --git a/src/gui/Preferences.h b/src/gui/Preferences.h index 1a39b15d..4e5ed77e 100755 --- a/src/gui/Preferences.h +++ b/src/gui/Preferences.h @@ -42,6 +42,7 @@ using json = nlohmann::json; #define kFullScreenTag "fullscreen" #define kFOV "fov" #define kFXAA "fxaa" +#define kUseLegacyRenderer "useLegacyRenderer" // Other graphics settings #define kColorBlindMode "colorBlindMode" @@ -196,6 +197,7 @@ static json defaultPrefs = { {kThrottle, 0}, {kGoodGamePhrases, {}}, {kShowElo, false}, + {kUseLegacyRenderer, false} }; diff --git a/src/render/LegacyOpenGLRenderer.cpp b/src/render/LegacyOpenGLRenderer.cpp new file mode 100644 index 00000000..2876285e --- /dev/null +++ b/src/render/LegacyOpenGLRenderer.cpp @@ -0,0 +1,475 @@ +#include "LegacyOpenGLRenderer.h" + +#include "AssetManager.h" +#include "ColorManager.h" +#include "FastMat.h" +#include "OpenGLVertices.h" + +#include + +#include + +#define SKY_VERT "sky_vert.glsl" +#define SKY_FRAG "sky_frag.glsl" + +#define OBJ_VERT "world_vert.glsl" +#define OBJ_FRAG "world_frag.glsl" + +const float legacySkyboxVertices[] = { + -5.0f, 5.0f, -5.0f, + -5.0f, -5.0f, -5.0f, + 5.0f, -5.0f, -5.0f, + 5.0f, -5.0f, -5.0f, + 5.0f, 5.0f, -5.0f, + -5.0f, 5.0f, -5.0f, + + -5.0f, -5.0f, 5.0f, + -5.0f, -5.0f, -5.0f, + -5.0f, 5.0f, -5.0f, + -5.0f, 5.0f, -5.0f, + -5.0f, 5.0f, 5.0f, + -5.0f, -5.0f, 5.0f, + + 5.0f, -5.0f, -5.0f, + 5.0f, -5.0f, 5.0f, + 5.0f, 5.0f, 5.0f, + 5.0f, 5.0f, 5.0f, + 5.0f, 5.0f, -5.0f, + 5.0f, -5.0f, -5.0f, + + -5.0f, -5.0f, 5.0f, + -5.0f, 5.0f, 5.0f, + 5.0f, 5.0f, 5.0f, + 5.0f, 5.0f, 5.0f, + 5.0f, -5.0f, 5.0f, + -5.0f, -5.0f, 5.0f, + + -5.0f, 5.0f, -5.0f, + 5.0f, 5.0f, -5.0f, + 5.0f, 5.0f, 5.0f, + 5.0f, 5.0f, 5.0f, + -5.0f, 5.0f, 5.0f, + -5.0f, 5.0f, -5.0f, + + -5.0f, -5.0f, -5.0f, + -5.0f, -5.0f, 5.0f, + 5.0f, -5.0f, -5.0f, + 5.0f, -5.0f, -5.0f, + -5.0f, -5.0f, 5.0f, + 5.0f, -5.0f, 5.0f +}; + +const char *__glGetErrorString(GLenum error) +{ + switch (error) { + case GL_NO_ERROR: + return "No Error"; + case GL_INVALID_ENUM: + return "Invalid Enum"; + case GL_INVALID_VALUE: + return "Invalid Value"; + case GL_INVALID_OPERATION: + return "Invalid Operation"; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "Invalid Framebuffer Operation"; + case GL_OUT_OF_MEMORY: + return "Out of Memory"; + case GL_STACK_UNDERFLOW: + return "Stack Underflow"; + case GL_STACK_OVERFLOW: + return "Stack Overflow"; + // case GL_CONTEXT_LOST: + // return "Context Lost"; + default: + return "Unknown Error"; + } +} + +void ___glCheckErrors(const char *filename, int line) +{ + GLenum err; + while ((err = glGetError()) != GL_NO_ERROR) + SDL_Log("OpenGL Error: %s (%d) [%u] %s\n", filename, line, err, __glGetErrorString(err)); +} +#define __glCheckErrors() ___glCheckErrors(__FILE__, __LINE__) + +inline glm::mat4 ToFloatMat(const Matrix &m) +{ + glm::mat4 mat(1.0); + for (int i = 0; i < 3; i ++) { + mat[0][i] = ToFloat(m[0][i]); + mat[1][i] = ToFloat(m[1][i]); + mat[2][i] = ToFloat(m[2][i]); + mat[3][i] = ToFloat(m[3][i]); + } + return mat; +} + +LegacyOpenGLRenderer::LegacyOpenGLRenderer(SDL_Window *window) : AbstractRenderer() +{ + this->window = window; + + GLsizei w, h; + SDL_GL_GetDrawableSize(window, &w, &h); + viewParams->viewPixelDimensions.h = w; + viewParams->viewPixelDimensions.v = h; + + dynamicWorld = new CBSPWorldImpl(100); + + // Initialize shaders. + skyShader = LoadShader(SKY_VERT, SKY_FRAG); + worldShader = LoadShader(OBJ_VERT, OBJ_FRAG); + ApplyLights(); + ApplyProjection(); + + // Create a separate VBO and VAO for the skybox, and upload its geometry to the GPU. + glGenVertexArrays(1, &skyVertArray); + glGenBuffers(1, &skyBuffer); + __glCheckErrors(); + glBindVertexArray(skyVertArray); + __glCheckErrors(); + glBindBuffer(GL_ARRAY_BUFFER, skyBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(legacySkyboxVertices), legacySkyboxVertices, GL_STATIC_DRAW); + + __glCheckErrors(); + // Rebind to default VBO/VAO. + glBindVertexArray(0); + __glCheckErrors(); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE); + __glCheckErrors(); + +} + +LegacyOpenGLRenderer::~LegacyOpenGLRenderer() { + delete dynamicWorld; + AbstractRenderer::~AbstractRenderer(); +} + +void LegacyOpenGLRenderer::AddPart(CBSPPart *part) +{ + dynamicWorld->AddPart(part); +} + +void LegacyOpenGLRenderer::ApplyLights() +{ + float ambientIntensity = ToFloat(viewParams->ambientLight); + float ambientRGB[3]; + viewParams->ambientLightColor.ExportGLFloats(ambientRGB, 3); + + //hudShader->Use(); + //AdjustAmbient(*hudShader, HUD_AMBIENT); + + worldShader->Use(); + AdjustAmbient(*worldShader, ambientIntensity); + worldShader->SetFloat3("ambientColor", ambientRGB); + + for (int i = 0; i < 4; i++) { + float intensity = ToFloat(viewParams->dirLightSettings[i].intensity); + float elevation = ToFloat(viewParams->dirLightSettings[i].angle1); + float azimuth = ToFloat(viewParams->dirLightSettings[i].angle2); + float rgb[3]; + viewParams->dirLightSettings[i].color.ExportGLFloats(rgb, 3); + + float xyz[3] = { + sin(Deg2Rad(-azimuth)) * intensity, + sin(Deg2Rad(-elevation)) * intensity, + cos(Deg2Rad(azimuth)) * intensity + }; + + switch (i) { + case 0: + worldShader->SetFloat3("light0", xyz); + worldShader->SetFloat3("light0Color", rgb); + break; + case 1: + worldShader->SetFloat3("light1", xyz); + worldShader->SetFloat3("light1Color", rgb); + break; + case 2: + worldShader->SetFloat3("light2", xyz); + worldShader->SetFloat3("light2Color", rgb); + break; + case 3: + worldShader->SetFloat3("light3", xyz); + worldShader->SetFloat3("light3Color", rgb); + break; + } + } +} + +void LegacyOpenGLRenderer::ApplyProjection() +{ + SDL_GL_GetDrawableSize(this->window, &resolution[0], &resolution[1]); + + glm::mat4 proj = glm::scale( + glm::perspective( + glm::radians(fov), + (float)viewParams->viewPixelDimensions.h / (float)viewParams->viewPixelDimensions.v, + 0.099f, + 1000.0f + ), + glm::vec3(-1, 1, -1) + ); + + skyShader->Use(); + skyShader->SetMat4("proj", proj); + __glCheckErrors(); + + worldShader->Use(); + worldShader->SetMat4("proj", proj); + __glCheckErrors(); + + //hudShader->Use(); + //hudShader->SetMat4("proj", proj); + //glCheckErrors(); +} + +void LegacyOpenGLRenderer::UpdateViewRect(int width, int height, float pixelRatio) +{ + AbstractRenderer::UpdateViewRect(width, height, pixelRatio); + ApplyProjection(); +} + +void LegacyOpenGLRenderer::LevelReset() +{ + dynamicWorld->DisposeParts(); + AbstractRenderer::LevelReset(); +} + +std::unique_ptr LegacyOpenGLRenderer::NewVertexDataInstance() +{ + return std::make_unique(); +} + +void LegacyOpenGLRenderer::OverheadPoint(Fixed *pt, Fixed *extent) +{ + dynamicWorld->OverheadPoint(pt, extent); +} + +void LegacyOpenGLRenderer::RefreshWindow() +{ + SDL_GL_SwapWindow(window); +} + +void LegacyOpenGLRenderer::RemovePart(CBSPPart *part) +{ + dynamicWorld->RemovePart(part); +} + +void LegacyOpenGLRenderer::RenderFrame() +{ + Clear(); + ApplyView(); + + // RENDER SKYBOX /////////////////////////////////////////////////////////////////////////////// + + Matrix *trans = &(viewParams->viewMatrix); + + // Get rid of the view translation. + glm::mat4 glMatrix = ToFloatMat(*trans); + glMatrix[3][0] = glMatrix[3][1] = glMatrix[3][2] = 0; + + float groundColorRGB[3]; + float lowSkyColorRGB[3]; + float highSkyColorRGB[3]; + skyParams->groundColor.ExportGLFloats(groundColorRGB, 3); + skyParams->lowSkyColor.ExportGLFloats(lowSkyColorRGB, 3); + skyParams->highSkyColor.ExportGLFloats(highSkyColorRGB, 3); + + // Switch to first offscreen FBO. + //glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + glBindVertexArray(skyVertArray); + glBindBuffer(GL_ARRAY_BUFFER, skyBuffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, NULL); + glEnableVertexAttribArray(0); + + skyShader->Use(); + skyShader->SetMat4("view", glMatrix); + skyShader->SetFloat3("groundColor", groundColorRGB); + skyShader->SetFloat3("horizonColor", lowSkyColorRGB); + skyShader->SetFloat3("skyColor", highSkyColorRGB); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(legacySkyboxVertices)); + glDisableVertexAttribArray(0); + + __glCheckErrors(); + // RENDER WORLD //////////////////////////////////////////////////////////////////////// + + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CCW); + glEnable(GL_DEPTH_TEST); + + worldShader->Use(); + + dynamicWorld->PrepareForRender(); + + __glCheckErrors(); + float defaultAmbient = ToFloat(viewParams->ambientLight); + + auto partList = dynamicWorld->GetVisiblePartListPointer(); + auto partCount = dynamicWorld->GetVisiblePartCount(); + for (uint16_t i = 0; i < partCount; i++) { + Draw(*worldShader, **partList, defaultAmbient); + partList++; + } +} + +void LegacyOpenGLRenderer::AdjustAmbient(OpenGLShader &shader, float intensity) +{ + shader.SetFloat("ambient", intensity); +} + +void LegacyOpenGLRenderer::ApplyView() +{ + glm::mat4 glMatrix = ToFloatMat(viewParams->viewMatrix); + + worldShader->Use(); + worldShader->SetMat4("view", glMatrix); + __glCheckErrors(); +} + +void LegacyOpenGLRenderer::Clear() +{ + glClearColor(0.3f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +} + +void LegacyOpenGLRenderer::Draw(OpenGLShader &shader, const CBSPPart &part, float defaultAmbient) +{ + OpenGLVertices *glData = dynamic_cast(part.vData.get()); + + if (glData == nullptr) return; + + glBindVertexArray(glData->opaque.vertexArray); + glBindBuffer(GL_ARRAY_BUFFER, glData->opaque.vertexBuffer); + glBufferData(GL_ARRAY_BUFFER, glData->opaque.glDataSize, glData->opaque.glData.data(), GL_STREAM_DRAW); + + // Position! + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), 0); + glEnableVertexAttribArray(0); + + // RGBAColor! + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + // Normal! + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)(7 * sizeof(float))); + glEnableVertexAttribArray(2); + + // Custom, per-object lighting and depth testing! + float extraAmbient = ToFloat(part.extraAmbient); + if (part.privateAmbient != -1) { + AdjustAmbient(shader, ToFloat(part.privateAmbient)); + } + if (extraAmbient > 0) { + AdjustAmbient(shader, defaultAmbient + extraAmbient); + } + if (part.ignoreDepthTesting) { + glDisable(GL_DEPTH_TEST); + } + if (part.ignoreDirectionalLights) { + IgnoreDirectionalLights(shader, true); + __glCheckErrors(); + } + + SetTransforms(part); + shader.Use(); + __glCheckErrors(); + + glDrawArrays(GL_TRIANGLES, 0, glData->opaque.pointCount); + + glBindVertexArray(glData->alpha.vertexArray); + glBindBuffer(GL_ARRAY_BUFFER, glData->alpha.vertexBuffer); + glBufferData(GL_ARRAY_BUFFER, glData->alpha.glDataSize, glData->alpha.glData.data(), GL_STREAM_DRAW); + + // Position! + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), 0); + glEnableVertexAttribArray(0); + + // RGBAColor! + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + // Normal! + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)(7 * sizeof(float))); + glEnableVertexAttribArray(2); + glDrawArrays(GL_TRIANGLES, 0, glData->alpha.pointCount); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + __glCheckErrors(); + + // Restore previous lighting and depth testing state. + if (part.privateAmbient != -1 || extraAmbient > 0) { + AdjustAmbient(shader, defaultAmbient); + __glCheckErrors(); + } + if (part.ignoreDepthTesting) { + glEnable(GL_DEPTH_TEST); + } + if (part.ignoreDirectionalLights) { + IgnoreDirectionalLights(shader, false); + __glCheckErrors(); + } + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + __glCheckErrors(); +} + +void LegacyOpenGLRenderer::IgnoreDirectionalLights(OpenGLShader &shader, bool yn) +{ + shader.SetFloat("lightsActive", (yn) ? 0.0f : 1.0f); +} + +std::unique_ptr LegacyOpenGLRenderer::LoadShader(const std::string &vertFile, + const std::string &fragFile) +{ + std::optional vertPath, fragPath; + + vertPath = AssetManager::GetShaderPath(vertFile); + fragPath = AssetManager::GetShaderPath(fragFile); + + if (!vertPath || !fragPath) { + SDL_Log("Failed to find shader (%s, %s)", vertFile.c_str(), fragFile.c_str()); + exit(1); + } + + return std::make_unique(*vertPath, *fragPath); +} + +void LegacyOpenGLRenderer::SetTransforms(const CBSPPart &part) { + glm::mat4 mv = ToFloatMat(part.fullTransform); + if (part.hasScale) { + glm::vec3 sc = glm::vec3( + ToFloat(part.scale[0]), + ToFloat(part.scale[1]), + ToFloat(part.scale[2]) + ); + mv = glm::scale(mv, sc); + } + + glm::mat3 normalMat = glm::mat3(1.0f); + for (int i = 0; i < 3; i ++) { + normalMat[0][i] = ToFloat((part.itsTransform)[0][i]); + normalMat[1][i] = ToFloat((part.itsTransform)[1][i]); + normalMat[2][i] = ToFloat((part.itsTransform)[2][i]); + } + + worldShader->Use(); + worldShader->SetMat4("modelview", mv); + worldShader->SetMat3("normalTransform", normalMat, true); +} diff --git a/src/render/LegacyOpenGLRenderer.h b/src/render/LegacyOpenGLRenderer.h new file mode 100644 index 00000000..cc83b19b --- /dev/null +++ b/src/render/LegacyOpenGLRenderer.h @@ -0,0 +1,53 @@ +#pragma once + +#include "AbstractRenderer.h" +#include "CBSPPart.h" +#include "CBSPWorld.h" +#include "OpenGLShader.h" +#include "VertexData.h" + +#include + +#include + +class LegacyOpenGLRenderer final: public AbstractRenderer { +public: + LegacyOpenGLRenderer(SDL_Window *window); + virtual ~LegacyOpenGLRenderer() override; + + virtual void AddHUDPart(CBSPPart *part) override { + part->ignoreDirectionalLights = true; + part->ignoreDepthTesting = true; + AddPart(part); + }; + + virtual void AddPart(CBSPPart *part) override; + virtual void ApplyLights() override; + virtual void ApplyProjection() override; + virtual void LevelReset() override; + virtual std::unique_ptr NewVertexDataInstance() override; + virtual void OverheadPoint(Fixed *pt, Fixed *extent) override; + virtual void RefreshWindow() override; + virtual void RemoveHUDPart(CBSPPart *part) override { RemovePart(part); }; + virtual void RemovePart(CBSPPart *part) override; + virtual void RenderFrame() override; + void UpdateViewRect(int width, int height, float pixelRatio) override; +private: + SDL_Window *window; + + CBSPWorldImpl *dynamicWorld; + std::unique_ptr skyShader; + std::unique_ptr worldShader; + + GLsizei resolution[2]; + GLuint skyBuffer; + GLuint skyVertArray; + + void AdjustAmbient(OpenGLShader &shader, float intensity); + void ApplyView(); + void Clear(); + void Draw(OpenGLShader &shader, const CBSPPart &part, float defaultAmbient); + void IgnoreDirectionalLights(OpenGLShader &shader, bool yn); + std::unique_ptr LoadShader(const std::string &vertFile, const std::string &fragFile); + void SetTransforms(const CBSPPart &part); +}; diff --git a/src/render/OpenGLVertices.h b/src/render/OpenGLVertices.h index 2c82de0a..33e0367a 100644 --- a/src/render/OpenGLVertices.h +++ b/src/render/OpenGLVertices.h @@ -36,6 +36,7 @@ struct GLVertexCollection { class OpenGLVertices: public VertexData { public: friend class ModernOpenGLRenderer; + friend class LegacyOpenGLRenderer; OpenGLVertices(); virtual ~OpenGLVertices();