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();