From 0a8cb83ec628f8cf05eb32eef574c27f42afcdd2 Mon Sep 17 00:00:00 2001 From: Ryan Herriman Date: Tue, 17 Jun 2025 18:40:05 -0600 Subject: [PATCH 1/5] Preliminary attempt at coronas, ground curve --- rsrc/shaders/sky_frag.glsl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/rsrc/shaders/sky_frag.glsl b/rsrc/shaders/sky_frag.glsl index 2c57d454d..3e1336451 100644 --- a/rsrc/shaders/sky_frag.glsl +++ b/rsrc/shaders/sky_frag.glsl @@ -1,3 +1,4 @@ +#define GROUND_PHI -0.0075 #define MAX_LIGHTS 4 in vec3 tex_coord; @@ -45,8 +46,10 @@ vec3 apply_fog(vec3 color, vec3 viewDir, float dist) { } vec3 draw_celestial(vec3 inColor, float phi, float gradientHeight, vec3 offsetFragPos, int i) { - if (lightCelestialRadius[i] == 0.0 || phi <= 0.0) return inColor; + if (lightCelestialRadius[i] == 0.0 || phi <= GROUND_PHI) return inColor; float dist = distance(offsetFragPos, lightPos[i]); + float coronaRadius = lightCelestialRadius[i] * (1 + length(lightDir[i])); + //float horizonRadius = coronaRadius * (1 - clamp(phi, 0.0, 1.0)); return mix( inColor, mix( @@ -54,7 +57,9 @@ vec3 draw_celestial(vec3 inColor, float phi, float gradientHeight, vec3 offsetFr lightColor[i] * gradientHeight + horizonColor * (1.0 - gradientHeight), float(phi < highAlt) ), - float(dist <= lightCelestialRadius[i]) + pow(clamp(1 - ((dist - lightCelestialRadius[i]) / (coronaRadius - lightCelestialRadius[i])), 0.0, 1.0), 4) + //clamp(1 - (lightCelestialRadius[i] / coronaRadius), 0.0, 1.0) + //float(dist <= lightCelestialRadius[i]) ); } @@ -105,7 +110,7 @@ void main() float(phi > highAlt) ), groundColor + spec(viewDir), - float(phi <= 0.0) + float(phi <= GROUND_PHI) ), 1.0 ); @@ -119,7 +124,7 @@ void main() mix( -dot(camPos, vec3(0, 1, 0)) / dot(-viewDir, vec3(0, 1, 0)), maxHazeDist, - float(phi >= 0.0) + float(phi >= GROUND_PHI) ), maxHazeDist ); From 19cfed0f0e93fecc83f9ac28e039fc9c4cbc09a8 Mon Sep 17 00:00:00 2001 From: Ryan Herriman Date: Wed, 1 Oct 2025 22:03:50 -0600 Subject: [PATCH 2/5] Add glow to materials --- .../avaraline-strict-mode/alf/layout/io.alf | 375 ++++++++-------- .../alf/layout/not-nul.alf | 416 +++++++++--------- rsrc/aftershock/default.avarascript | 6 +- rsrc/default.avarascript | 2 + rsrc/shaders/hud_vert.glsl | 5 +- rsrc/shaders/world_frag.glsl | 11 +- rsrc/shaders/world_vert.glsl | 6 +- src/bsp/CBSPPart.cpp | 20 + src/bsp/CBSPPart.h | 1 + src/game/CSmart.cpp | 1 + src/level/LevelLoader.cpp | 32 ++ src/level/LevelLoader.h | 2 + src/render/LegacyOpenGLRenderer.cpp | 11 +- src/render/Material.h | 54 ++- src/render/ModernOpenGLRenderer.cpp | 11 +- src/render/OpenGLVertices.cpp | 2 + src/render/OpenGLVertices.h | 1 + 17 files changed, 535 insertions(+), 421 deletions(-) diff --git a/levels/avaraline-strict-mode/alf/layout/io.alf b/levels/avaraline-strict-mode/alf/layout/io.alf index a1f98a5f6..5e469f746 100644 --- a/levels/avaraline-strict-mode/alf/layout/io.alf +++ b/levels/avaraline-strict-mode/alf/layout/io.alf @@ -1,5 +1,5 @@ - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - - - - + + + + + + + diff --git a/levels/avaraline-strict-mode/alf/layout/not-nul.alf b/levels/avaraline-strict-mode/alf/layout/not-nul.alf index a5bc65862..06d7af17f 100644 --- a/levels/avaraline-strict-mode/alf/layout/not-nul.alf +++ b/levels/avaraline-strict-mode/alf/layout/not-nul.alf @@ -1,5 +1,5 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - + + + diff --git a/rsrc/aftershock/default.avarascript b/rsrc/aftershock/default.avarascript index 6c4e92ed6..a85d6c0c9 100644 --- a/rsrc/aftershock/default.avarascript +++ b/rsrc/aftershock/default.avarascript @@ -265,8 +265,10 @@ // Material properties: defaultMaterial.specular = 0 defaultMaterial.shininess = 0 - baseMaterial.specular = defaultMaterial.specular - baseMaterial.shininess = defaultMaterial.shininess + defaultMaterial.glow = 0 + baseMaterial.specular = 0 + baseMaterial.shininess = 0 + baseMaterial.glow = 0 // Advanced weapon powers: grenadePower = 2.05 diff --git a/rsrc/default.avarascript b/rsrc/default.avarascript index 2e56b83ee..c079938f1 100644 --- a/rsrc/default.avarascript +++ b/rsrc/default.avarascript @@ -265,8 +265,10 @@ // Material properties: defaultMaterial.specular = 0 defaultMaterial.shininess = 0 + defaultMaterial.glow = 0 baseMaterial.specular = 0 baseMaterial.shininess = 0 + baseMaterial.glow = 0 // Advanced weapon powers: grenadePower = 2.25 diff --git a/rsrc/shaders/hud_vert.glsl b/rsrc/shaders/hud_vert.glsl index 2b903d6d5..e436b7132 100644 --- a/rsrc/shaders/hud_vert.glsl +++ b/rsrc/shaders/hud_vert.glsl @@ -1,7 +1,8 @@ layout(location = 0) in vec3 vertexPosition_modelspace; layout(location = 1) in vec4 vertexColor; layout(location = 2) in vec4 vertexSpecular; -layout(location = 3) in vec3 vertexNormal; +layout(location = 3) in float vertexGlow; +layout(location = 4) in vec3 vertexNormal; uniform mat4 view; uniform mat4 proj; @@ -9,6 +10,7 @@ uniform mat4 model; out vec4 fragmentColor; out vec4 fragmentSpecular; +out float fragmentGlow; out vec3 fragmentNormal; void main() { @@ -16,5 +18,6 @@ void main() { gl_Position = proj * (pos * model * view); fragmentColor = vertexColor; fragmentSpecular = vertexSpecular; + fragmentGlow = vertexGlow; fragmentNormal = vertexNormal; } diff --git a/rsrc/shaders/world_frag.glsl b/rsrc/shaders/world_frag.glsl index d07f3bf7d..2b5c83827 100644 --- a/rsrc/shaders/world_frag.glsl +++ b/rsrc/shaders/world_frag.glsl @@ -4,6 +4,7 @@ in vec4 fragmentColor; in vec3 fragmentSpecular; in float fragmentShininess; +in float fragmentGlow; in vec3 fragmentNormal; in vec3 fragPos; @@ -81,9 +82,13 @@ float noise() { vec4 light_color(vec3 viewDir) { return mix( - ambient * vec4(ambientColor, 1.0) * fragmentColor, - vec4((ambient * ambientColor) + diffuse() + spec(viewDir), 1.0) * fragmentColor, - float(lightsActive) + mix( + ambient * vec4(ambientColor, 1.0) * fragmentColor, + vec4((ambient * ambientColor) + diffuse() + spec(viewDir), 1.0) * fragmentColor, + float(lightsActive) + ), + fragmentColor, + float(fragmentGlow > 0.0) ); } diff --git a/rsrc/shaders/world_vert.glsl b/rsrc/shaders/world_vert.glsl index 78d1575f5..405bd5872 100644 --- a/rsrc/shaders/world_vert.glsl +++ b/rsrc/shaders/world_vert.glsl @@ -1,9 +1,11 @@ layout(location = 0) in vec3 vertexPosition_modelspace; layout(location = 1) in vec4 vertexColor; layout(location = 2) in vec4 vertexSpecular; -layout(location = 3) in vec3 vertexNormal; +layout(location = 3) in float vertexGlow; +layout(location = 4) in vec3 vertexNormal; uniform float maxShininess; +uniform float maxGlow; uniform mat4 model; uniform mat4 view; uniform mat4 proj; @@ -12,6 +14,7 @@ uniform mat3 normalTransform; out vec4 fragmentColor; out vec3 fragmentSpecular; out float fragmentShininess; +out float fragmentGlow; out vec3 fragmentNormal; out vec3 fragPos; @@ -21,6 +24,7 @@ void main() { fragmentColor = vertexColor; fragmentSpecular = vertexSpecular.rgb; fragmentShininess = vertexSpecular.a * maxShininess; + fragmentGlow = vertexGlow * maxGlow; fragmentNormal = vertexNormal * normalTransform; fragPos = (pos * model).xyz; } diff --git a/src/bsp/CBSPPart.cpp b/src/bsp/CBSPPart.cpp index 5f754976f..405d51d45 100644 --- a/src/bsp/CBSPPart.cpp +++ b/src/bsp/CBSPPart.cpp @@ -110,6 +110,7 @@ void CBSPPart::IBSPPart(short resId) { nlohmann::json const &mat = doc["materials"][i]; ARGBColor color = ARGBColor(0x00ffffff); // Default to invisible "white." ARGBColor spec = defaultMaterial.GetSpecular().WithA(defaultMaterial.GetShininess()); + uint8_t glow = defaultMaterial.GetGlow(); if (mat.find("base") != mat.end()) { color = ARGBColor::Parse(mat["base"]) @@ -137,6 +138,13 @@ void CBSPPart::IBSPPart(short resId) { spec = baseMaterial.GetSpecular().WithA(baseMaterial.GetShininess()); } current = current.WithSpecular(spec).WithShininess(spec.GetA()); + + spec = mat.value("glow", 0); + original = original.WithGlow(glow); + if (glow == defaultMaterial.GetGlow()) { + glow = baseMaterial.GetGlow(); + } + current = current.WithGlow(glow); materialTable.push_back(MaterialRecord(original, current)); } @@ -476,6 +484,18 @@ void CBSPPart::ReplaceShininessForColor(ARGBColor origColor, uint8_t newShinines if (shininessReplaced && vData) vData->Replace(*this); } +void CBSPPart::ReplaceGlowForColor(ARGBColor origColor, uint8_t newGlow) { + bool glowReplaced = false; + for (auto &material : materialTable) { + if (material.original.GetColor() == origColor) { + material.current = material.current.WithGlow(newGlow); + glowReplaced = true; + } + } + // (No need to check for alpha here.) + if (glowReplaced && vData) vData->Replace(*this); +} + void CBSPPart::ReplaceMaterial(Material origMaterial, Material newMaterial) { bool materialReplaced = false; for (auto &material : materialTable) { diff --git a/src/bsp/CBSPPart.h b/src/bsp/CBSPPart.h index c563a9863..b702d419f 100644 --- a/src/bsp/CBSPPart.h +++ b/src/bsp/CBSPPart.h @@ -214,6 +214,7 @@ class CBSPPart { virtual void ReplaceMaterialForColor(ARGBColor origColor, Material newMaterial); virtual void ReplaceSpecularForColor(ARGBColor origColor, ARGBColor newSpecular); virtual void ReplaceShininessForColor(ARGBColor origColor, uint8_t newShininess); + virtual void ReplaceGlowForColor(ARGBColor origColor, uint8_t newGlow); virtual void ReplaceMaterial(Material origMaterial, Material newMaterial); virtual void ReplaceAllMaterials(Material newMaterial); diff --git a/src/game/CSmart.cpp b/src/game/CSmart.cpp index 358eb0de3..6e5bdebde 100644 --- a/src/game/CSmart.cpp +++ b/src/game/CSmart.cpp @@ -60,6 +60,7 @@ long CSmart::Arm(CSmartPart *aPart) { shields = FIX3(100); partList[0]->ReplaceColor(*ColorManager::getMarkerColor(1), ColorManager::getMissileArmedColor()); + partList[0]->ReplaceGlowForColor(*ColorManager::getMarkerColor(1), 16); targetIdent = 0; targetPart = NULL; diff --git a/src/level/LevelLoader.cpp b/src/level/LevelLoader.cpp index 792d0e15b..ac025a686 100644 --- a/src/level/LevelLoader.cpp +++ b/src/level/LevelLoader.cpp @@ -77,6 +77,7 @@ Material GetDefaultMaterial() { defaultMaterial = defaultMaterial.WithSpecular(*specular); } defaultMaterial = defaultMaterial.WithShininessVar(iDefaultMaterialShininess); + defaultMaterial = defaultMaterial.WithGlowVar(iDefaultMaterialGlow); return defaultMaterial; } @@ -87,6 +88,7 @@ Material GetBaseMaterial() { baseMaterial = baseMaterial.WithSpecular(*specular); } baseMaterial = baseMaterial.WithShininessVar(iBaseMaterialShininess); + baseMaterial = baseMaterial.WithGlowVar(iBaseMaterialGlow); return baseMaterial; } @@ -153,6 +155,8 @@ struct ALFWalker: pugi::xml_tree_walker { attr = "material.0.specular"; } else if (attr.compare("material.shininess") == 0) { attr = "material.0.shininess"; + } else if (attr.compare("material.glow") == 0) { + attr = "material.0.glow"; } // XML attributes can't have brackets, so we turn light.0.i into light[0].i std::regex subscript("\\.(\\d+)"); @@ -274,6 +278,14 @@ struct ALFWalker: pugi::xml_tree_walker { palette[3] = palette[3].WithShininessVar(iBaseMaterialShininess); } + if (!node.attribute("baseMaterial.glow").empty()) { + // When baseMaterial properties are set, apply it to all mats. + palette[0] = palette[0].WithGlowVar(iBaseMaterialGlow); + palette[1] = palette[1].WithGlowVar(iBaseMaterialGlow); + palette[2] = palette[2].WithGlowVar(iBaseMaterialGlow); + palette[3] = palette[3].WithGlowVar(iBaseMaterialGlow); + } + if (!node.attribute("material.specular").empty()) { const std::optional color = ReadColorVar("material[0].specular"); if (color) { @@ -328,6 +340,26 @@ struct ALFWalker: pugi::xml_tree_walker { if (!node.attribute("material.3.shininess").empty()) { palette[3] = palette[3].WithShininessVar("material[3].shininess"); } + + if (!node.attribute("material.glow").empty()) { + palette[0] = palette[0].WithGlowVar("material[0].glow"); + } + + if (!node.attribute("material.0.glow").empty()) { + palette[0] = palette[0].WithGlowVar("material[0].glow"); + } + + if (!node.attribute("material.1.glow").empty()) { + palette[1] = palette[1].WithGlowVar("material[1].glow"); + } + + if (!node.attribute("material.2.glow").empty()) { + palette[2] = palette[2].WithGlowVar("material[2].glow"); + } + + if (!node.attribute("material.3.glow").empty()) { + palette[3] = palette[3].WithGlowVar("material[3].glow"); + } if (!node.attribute("x").empty() && !node.attribute("z").empty() && !node.attribute("w").empty() && !node.attribute("d").empty()) { diff --git a/src/level/LevelLoader.h b/src/level/LevelLoader.h index 7e8f74490..fdd084b12 100644 --- a/src/level/LevelLoader.h +++ b/src/level/LevelLoader.h @@ -274,8 +274,10 @@ enum { // Materials iDefaultMaterialSpecular, iDefaultMaterialShininess, + iDefaultMaterialGlow, iBaseMaterialSpecular, iBaseMaterialShininess, + iBaseMaterialGlow, // Advanced weapons iGrenadePower, diff --git a/src/render/LegacyOpenGLRenderer.cpp b/src/render/LegacyOpenGLRenderer.cpp index 6ffad6df9..32041783b 100644 --- a/src/render/LegacyOpenGLRenderer.cpp +++ b/src/render/LegacyOpenGLRenderer.cpp @@ -187,6 +187,7 @@ void LegacyOpenGLRenderer::ApplyLights() AdjustAmbient(*worldShader, ambientIntensity); worldShader->SetFloat3("ambientColor", ambientRGB); worldShader->SetFloat("maxShininess", MAX_SHININESS_EXP); + worldShader->SetFloat("maxGlow", MAX_GLOW); worldShader->SetBool("lightsActive", true); skyShader->Use(); @@ -507,10 +508,14 @@ void LegacyOpenGLRenderer::Draw(OpenGLShader &shader, const CBSPPart &part, floa // Specular! glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (4 * sizeof(uint8_t)))); glEnableVertexAttribArray(2); + + // Glow! + glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((3 * sizeof(float)) + (8 * sizeof(uint8_t)))); + glEnableVertexAttribArray(3); // Normal! - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((3 * sizeof(float)) + (8 * sizeof(uint8_t)))); - glEnableVertexAttribArray(3); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((4 * sizeof(float)) + (8 * sizeof(uint8_t)))); + glEnableVertexAttribArray(4); // Custom, per-object lighting and depth testing! float extraAmbient = ToFloat(part.extraAmbient); @@ -545,6 +550,8 @@ void LegacyOpenGLRenderer::Draw(OpenGLShader &shader, const CBSPPart &part, floa glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(4); __glCheckErrors(); // Restore previous lighting and depth testing state. diff --git a/src/render/Material.h b/src/render/Material.h index 07c5394dd..be106e81a 100644 --- a/src/render/Material.h +++ b/src/render/Material.h @@ -8,22 +8,27 @@ #include #include +#define MAX_GLOW 256.0f #define MAX_SHININESS_EXP 1024.0f class Material { public: void* operator new(std::size_t) = delete; - bool operator==(const Material& other) { return color == other.color && specular == other.specular; } - bool operator!=(const Material& other) { return color != other.color && specular != other.specular; } - constexpr Material(ARGBColor color = 0xFF000000, ARGBColor specular = 0x00000000): color(color), specular(specular) {} + bool operator==(const Material& other) { return color == other.color && specular == other.specular && glow == other.glow; } + bool operator!=(const Material& other) { return color != other.color && specular != other.specular && glow != other.glow; } + constexpr Material(ARGBColor color = 0xFF000000, ARGBColor specular = 0x00000000, uint8_t glow = 0): color(color), specular(specular), glow(glow) {} inline ARGBColor GetColor() const { return color; } inline ARGBColor GetSpecular() const { return specular.WithA(0x00); } + inline uint8_t GetGlow() const { return glow; } inline bool HasAlpha() const { return color.HasAlpha(); } inline Material WithColor(ARGBColor c) const { - return Material(c, specular); + return Material(c, specular, glow); } inline Material WithSpecular(ARGBColor s) const { - return Material(color, s.WithA(specular.GetA())); + return Material(color, s.WithA(specular.GetA()), glow); + } + inline Material WithGlow(uint8_t g) const { + return Material(color, specular, g); } // Convenience getters. @@ -38,40 +43,59 @@ class Material { // Convenience setters. inline Material WithA(uint8_t a) const { - return Material(color.WithA(a), specular); + return Material(color.WithA(a), specular, glow); } inline Material WithR(uint8_t r) const { - return Material(color.WithR(r), specular); + return Material(color.WithR(r), specular, glow); } inline Material WithG(uint8_t g) const { - return Material(color.WithG(g), specular); + return Material(color.WithG(g), specular, glow); } inline Material WithB(uint8_t b) const { - return Material(color.WithB(b), specular); + return Material(color.WithB(b), specular, glow); } inline Material WithSpecR(uint8_t r) const { - return Material(color, specular.WithR(r)); + return Material(color, specular.WithR(r), glow); } inline Material WithSpecG(uint8_t g) const { - return Material(color, specular.WithG(g)); + return Material(color, specular.WithG(g), glow); } inline Material WithSpecB(uint8_t b) const { - return Material(color, specular.WithB(b)); + return Material(color, specular.WithB(b), glow); } inline Material WithShininess(uint8_t s) const { - return Material(color, specular.WithA(s)); + return Material(color, specular.WithA(s), glow); + } + inline Material WithGlowVar(short index) { + Fixed glow = ReadFixedMaterialVar(index); + return Material(color, specular, ConstrainGlow(glow)); + } + inline Material WithGlowVar(const char *s) { + Fixed glow = ReadFixedMaterialVar(s); + return Material(color, specular, ConstrainGlow(glow)); } inline Material WithShininessVar(short index) { Fixed shininess = ReadFixedMaterialVar(index); - return Material(color, specular.WithA(ConstrainShininess(shininess))); + return Material(color, specular.WithA(ConstrainShininess(shininess)), glow); } inline Material WithShininessVar(const char *s) { Fixed shininess = ReadFixedMaterialVar(s); - return Material(color, specular.WithA(ConstrainShininess(shininess))); + return Material(color, specular.WithA(ConstrainShininess(shininess)), glow); } private: ARGBColor color = 0xFF000000; ARGBColor specular = 0x00000000; // Alpha channel = shininess value + uint8_t glow = 0; + + /** + * Constrain input values for glow. + * + * @param glow The fixed-point glow value. Valid range is 0 to MAX_GLOW. + * @return the nearest approximate value that we can cram into 8 bits, i.e. scaled to a range of 0 - 255 + */ + inline uint8_t ConstrainGlow(Fixed glow) { + return std::round(std::clamp(ToFloat(glow), 0.0f, MAX_GLOW) * 255 / MAX_GLOW); + } /** * Constrain input values for shininess. diff --git a/src/render/ModernOpenGLRenderer.cpp b/src/render/ModernOpenGLRenderer.cpp index 4c234d5bd..9eb9ce2b3 100644 --- a/src/render/ModernOpenGLRenderer.cpp +++ b/src/render/ModernOpenGLRenderer.cpp @@ -230,6 +230,7 @@ void ModernOpenGLRenderer::ApplyLights() AdjustAmbient(*worldShader, ambientIntensity); worldShader->SetFloat3("ambientColor", ambientRGB); worldShader->SetFloat("maxShininess", MAX_SHININESS_EXP); + worldShader->SetFloat("maxGlow", MAX_GLOW); worldShader->SetBool("lightsActive", true); skyShader->Use(); @@ -618,10 +619,14 @@ void ModernOpenGLRenderer::Draw(OpenGLShader &shader, const CBSPPart &part, floa // Specular! glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (4 * sizeof(uint8_t)))); glEnableVertexAttribArray(2); + + // Glow! + glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((3 * sizeof(float)) + (8 * sizeof(uint8_t)))); + glEnableVertexAttribArray(3); // Normal! - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((3 * sizeof(float)) + (8 * sizeof(uint8_t)))); - glEnableVertexAttribArray(3); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((4 * sizeof(float)) + (8 * sizeof(uint8_t)))); + glEnableVertexAttribArray(4); // Custom, per-object lighting and depth testing! float extraAmbient = ToFloat(part.extraAmbient); @@ -656,6 +661,8 @@ void ModernOpenGLRenderer::Draw(OpenGLShader &shader, const CBSPPart &part, floa glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(4); // Restore previous lighting and depth testing state. if (part.privateAmbient != -1 || extraAmbient > 0) { diff --git a/src/render/OpenGLVertices.cpp b/src/render/OpenGLVertices.cpp index 9636a311e..77e9ea291 100644 --- a/src/render/OpenGLVertices.cpp +++ b/src/render/OpenGLVertices.cpp @@ -170,6 +170,7 @@ void OpenGLVertices::Append(const CBSPPart &part) vertex.specG = material.GetSpecG(); vertex.specB = material.GetSpecB(); vertex.specS = material.GetShininess(); + vertex.glow = (static_cast(material.GetGlow()) / 255.0f) * MAX_GLOW; vertex.nx = poly.normal.x; vertex.ny = poly.normal.y; vertex.nz = poly.normal.z; @@ -199,6 +200,7 @@ void OpenGLVertices::Append(const CBSPPart &part) vertex.specG = material.GetSpecG(); vertex.specB = material.GetSpecB(); vertex.specS = material.GetShininess(); + vertex.glow = (static_cast(material.GetGlow()) / 255.0f) * MAX_GLOW; vertex.nx = -poly.normal.x; vertex.ny = -poly.normal.y; vertex.nz = -poly.normal.z; diff --git a/src/render/OpenGLVertices.h b/src/render/OpenGLVertices.h index 84003e78c..31f1e8767 100644 --- a/src/render/OpenGLVertices.h +++ b/src/render/OpenGLVertices.h @@ -19,6 +19,7 @@ struct GLData { uint8_t specG = 0; uint8_t specB = 0; uint8_t specS = 0; + float glow = 0; float nx = 0.0f; float ny = 0.0f; float nz = 0.0f; From 7f2a6b8b0e5d39cef93d9b71ad6e28f3cc9bbcb7 Mon Sep 17 00:00:00 2001 From: Ryan Herriman Date: Thu, 2 Oct 2025 13:32:54 -0600 Subject: [PATCH 3/5] Glow back to uint8 in vertex array, reserve slots --- rsrc/shaders/hud_vert.glsl | 5 ++++- rsrc/shaders/world_vert.glsl | 5 ++++- src/render/LegacyOpenGLRenderer.cpp | 17 ++++++++++++++--- src/render/ModernOpenGLRenderer.cpp | 17 ++++++++++++++--- src/render/OpenGLVertices.cpp | 4 ++-- src/render/OpenGLVertices.h | 5 ++++- 6 files changed, 42 insertions(+), 11 deletions(-) diff --git a/rsrc/shaders/hud_vert.glsl b/rsrc/shaders/hud_vert.glsl index e436b7132..3b9e9c57b 100644 --- a/rsrc/shaders/hud_vert.glsl +++ b/rsrc/shaders/hud_vert.glsl @@ -2,7 +2,10 @@ layout(location = 0) in vec3 vertexPosition_modelspace; layout(location = 1) in vec4 vertexColor; layout(location = 2) in vec4 vertexSpecular; layout(location = 3) in float vertexGlow; -layout(location = 4) in vec3 vertexNormal; +layout(location = 4) in float vertexReserved1; +layout(location = 5) in float vertexReserved2; +layout(location = 6) in float vertexReserved3; +layout(location = 7) in vec3 vertexNormal; uniform mat4 view; uniform mat4 proj; diff --git a/rsrc/shaders/world_vert.glsl b/rsrc/shaders/world_vert.glsl index 405bd5872..8bbd88aea 100644 --- a/rsrc/shaders/world_vert.glsl +++ b/rsrc/shaders/world_vert.glsl @@ -2,7 +2,10 @@ layout(location = 0) in vec3 vertexPosition_modelspace; layout(location = 1) in vec4 vertexColor; layout(location = 2) in vec4 vertexSpecular; layout(location = 3) in float vertexGlow; -layout(location = 4) in vec3 vertexNormal; +layout(location = 4) in float vertexReserved1; +layout(location = 5) in float vertexReserved2; +layout(location = 6) in float vertexReserved3; +layout(location = 7) in vec3 vertexNormal; uniform float maxShininess; uniform float maxGlow; diff --git a/src/render/LegacyOpenGLRenderer.cpp b/src/render/LegacyOpenGLRenderer.cpp index 32041783b..d7ab75533 100644 --- a/src/render/LegacyOpenGLRenderer.cpp +++ b/src/render/LegacyOpenGLRenderer.cpp @@ -510,12 +510,20 @@ void LegacyOpenGLRenderer::Draw(OpenGLShader &shader, const CBSPPart &part, floa glEnableVertexAttribArray(2); // Glow! - glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((3 * sizeof(float)) + (8 * sizeof(uint8_t)))); + glVertexAttribPointer(3, 1, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (8 * sizeof(uint8_t)))); glEnableVertexAttribArray(3); + + // Reserved + glVertexAttribPointer(4, 1, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (9 * sizeof(uint8_t)))); + glEnableVertexAttribArray(4); + glVertexAttribPointer(5, 1, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (10 * sizeof(uint8_t)))); + glEnableVertexAttribArray(5); + glVertexAttribPointer(6, 1, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (11 * sizeof(uint8_t)))); + glEnableVertexAttribArray(6); // Normal! - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((4 * sizeof(float)) + (8 * sizeof(uint8_t)))); - glEnableVertexAttribArray(4); + glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((3 * sizeof(float)) + (12 * sizeof(uint8_t)))); + glEnableVertexAttribArray(7); // Custom, per-object lighting and depth testing! float extraAmbient = ToFloat(part.extraAmbient); @@ -552,6 +560,9 @@ void LegacyOpenGLRenderer::Draw(OpenGLShader &shader, const CBSPPart &part, floa glDisableVertexAttribArray(2); glDisableVertexAttribArray(3); glDisableVertexAttribArray(4); + glDisableVertexAttribArray(5); + glDisableVertexAttribArray(6); + glDisableVertexAttribArray(7); __glCheckErrors(); // Restore previous lighting and depth testing state. diff --git a/src/render/ModernOpenGLRenderer.cpp b/src/render/ModernOpenGLRenderer.cpp index 9eb9ce2b3..8d910ac78 100644 --- a/src/render/ModernOpenGLRenderer.cpp +++ b/src/render/ModernOpenGLRenderer.cpp @@ -621,12 +621,20 @@ void ModernOpenGLRenderer::Draw(OpenGLShader &shader, const CBSPPart &part, floa glEnableVertexAttribArray(2); // Glow! - glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((3 * sizeof(float)) + (8 * sizeof(uint8_t)))); + glVertexAttribPointer(3, 1, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (8 * sizeof(uint8_t)))); glEnableVertexAttribArray(3); + + // Reserved + glVertexAttribPointer(4, 1, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (9 * sizeof(uint8_t)))); + glEnableVertexAttribArray(4); + glVertexAttribPointer(5, 1, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (10 * sizeof(uint8_t)))); + glEnableVertexAttribArray(5); + glVertexAttribPointer(6, 1, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GLData), (void *)((3 * sizeof(float)) + (11 * sizeof(uint8_t)))); + glEnableVertexAttribArray(6); // Normal! - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((4 * sizeof(float)) + (8 * sizeof(uint8_t)))); - glEnableVertexAttribArray(4); + glVertexAttribPointer(7, 3, GL_FLOAT, GL_FALSE, sizeof(GLData), (void *)((3 * sizeof(float)) + (12 * sizeof(uint8_t)))); + glEnableVertexAttribArray(7); // Custom, per-object lighting and depth testing! float extraAmbient = ToFloat(part.extraAmbient); @@ -663,6 +671,9 @@ void ModernOpenGLRenderer::Draw(OpenGLShader &shader, const CBSPPart &part, floa glDisableVertexAttribArray(2); glDisableVertexAttribArray(3); glDisableVertexAttribArray(4); + glDisableVertexAttribArray(5); + glDisableVertexAttribArray(6); + glDisableVertexAttribArray(7); // Restore previous lighting and depth testing state. if (part.privateAmbient != -1 || extraAmbient > 0) { diff --git a/src/render/OpenGLVertices.cpp b/src/render/OpenGLVertices.cpp index 77e9ea291..607d9ee8d 100644 --- a/src/render/OpenGLVertices.cpp +++ b/src/render/OpenGLVertices.cpp @@ -170,7 +170,7 @@ void OpenGLVertices::Append(const CBSPPart &part) vertex.specG = material.GetSpecG(); vertex.specB = material.GetSpecB(); vertex.specS = material.GetShininess(); - vertex.glow = (static_cast(material.GetGlow()) / 255.0f) * MAX_GLOW; + vertex.glow = material.GetGlow(); vertex.nx = poly.normal.x; vertex.ny = poly.normal.y; vertex.nz = poly.normal.z; @@ -200,7 +200,7 @@ void OpenGLVertices::Append(const CBSPPart &part) vertex.specG = material.GetSpecG(); vertex.specB = material.GetSpecB(); vertex.specS = material.GetShininess(); - vertex.glow = (static_cast(material.GetGlow()) / 255.0f) * MAX_GLOW; + vertex.glow = material.GetGlow(); vertex.nx = -poly.normal.x; vertex.ny = -poly.normal.y; vertex.nz = -poly.normal.z; diff --git a/src/render/OpenGLVertices.h b/src/render/OpenGLVertices.h index 31f1e8767..949065ef8 100644 --- a/src/render/OpenGLVertices.h +++ b/src/render/OpenGLVertices.h @@ -19,7 +19,10 @@ struct GLData { uint8_t specG = 0; uint8_t specB = 0; uint8_t specS = 0; - float glow = 0; + uint8_t glow = 0; + uint8_t reserved1 = 0; + uint8_t reserved2 = 0; + uint8_t reserved3 = 0; float nx = 0.0f; float ny = 0.0f; float nz = 0.0f; From ee573c818134dfc3112644a34757e0f67ed5bcd8 Mon Sep 17 00:00:00 2001 From: Ryan Herriman Date: Tue, 18 Nov 2025 21:08:40 -0700 Subject: [PATCH 4/5] Fix bug with baked glow in BSPs, kill ground curve --- .../avaraline-strict-mode/alf/layout/io.alf | 10 +- .../alf/layout/not-nul.alf | 346 +++++++++--------- platform/macos/Info.plist | 27 ++ rsrc/shaders/sky_frag.glsl | 2 +- src/bsp/CBSPPart.cpp | 2 +- 5 files changed, 209 insertions(+), 178 deletions(-) diff --git a/levels/avaraline-strict-mode/alf/layout/io.alf b/levels/avaraline-strict-mode/alf/layout/io.alf index 5e469f746..1f6d77b72 100644 --- a/levels/avaraline-strict-mode/alf/layout/io.alf +++ b/levels/avaraline-strict-mode/alf/layout/io.alf @@ -198,7 +198,7 @@ - + @@ -210,11 +210,11 @@ - + - + @@ -226,11 +226,11 @@ - + - + diff --git a/levels/avaraline-strict-mode/alf/layout/not-nul.alf b/levels/avaraline-strict-mode/alf/layout/not-nul.alf index 06d7af17f..21b4f4576 100644 --- a/levels/avaraline-strict-mode/alf/layout/not-nul.alf +++ b/levels/avaraline-strict-mode/alf/layout/not-nul.alf @@ -1,246 +1,250 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - + - + - - + + - + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -265,11 +269,11 @@ - + - - - + + + diff --git a/platform/macos/Info.plist b/platform/macos/Info.plist index 3e2cf897a..443267707 100644 --- a/platform/macos/Info.plist +++ b/platform/macos/Info.plist @@ -2,7 +2,34 @@ + CFBundleDocumentTypes + + + NSHighResolutionCapable + UTExportedTypeDeclarations + + + UTTypeConformsTo + + public.xml + + UTTypeIcons + + UTTypeIconBadgeName + + + UTTypeIdentifier + net.avaraline.alf + UTTypeTagSpecification + + public.filename-extension + + alf + + + + diff --git a/rsrc/shaders/sky_frag.glsl b/rsrc/shaders/sky_frag.glsl index 3e1336451..3daba2ce7 100644 --- a/rsrc/shaders/sky_frag.glsl +++ b/rsrc/shaders/sky_frag.glsl @@ -1,4 +1,4 @@ -#define GROUND_PHI -0.0075 +#define GROUND_PHI 0.0 #define MAX_LIGHTS 4 in vec3 tex_coord; diff --git a/src/bsp/CBSPPart.cpp b/src/bsp/CBSPPart.cpp index 405d51d45..f98c75ed4 100644 --- a/src/bsp/CBSPPart.cpp +++ b/src/bsp/CBSPPart.cpp @@ -139,7 +139,7 @@ void CBSPPart::IBSPPart(short resId) { } current = current.WithSpecular(spec).WithShininess(spec.GetA()); - spec = mat.value("glow", 0); + glow = mat.value("glow", 0); original = original.WithGlow(glow); if (glow == defaultMaterial.GetGlow()) { glow = baseMaterial.GetGlow(); From 4c025296e9e498aab9c6413306aff5464a7208b7 Mon Sep 17 00:00:00 2001 From: Ryan Herriman Date: Thu, 18 Dec 2025 17:46:56 -0700 Subject: [PATCH 5/5] Slight cleanups --- src/bsp/CBSPPart.cpp | 14 +++++++++++++- src/bsp/CBSPPart.h | 1 + src/game/CScout.cpp | 10 ++++++++++ src/game/CWorldShader.h | 2 +- src/render/Material.h | 4 ++-- 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/bsp/CBSPPart.cpp b/src/bsp/CBSPPart.cpp index f98c75ed4..839ed294e 100644 --- a/src/bsp/CBSPPart.cpp +++ b/src/bsp/CBSPPart.cpp @@ -108,7 +108,7 @@ void CBSPPart::IBSPPart(short resId) { original = baseMaterial; current = baseMaterial; nlohmann::json const &mat = doc["materials"][i]; - ARGBColor color = ARGBColor(0x00ffffff); // Default to invisible "white." + ARGBColor color = defaultMaterial.GetColor(); ARGBColor spec = defaultMaterial.GetSpecular().WithA(defaultMaterial.GetShininess()); uint8_t glow = defaultMaterial.GetGlow(); @@ -496,6 +496,18 @@ void CBSPPart::ReplaceGlowForColor(ARGBColor origColor, uint8_t newGlow) { if (glowReplaced && vData) vData->Replace(*this); } +void CBSPPart::ReplaceAllGlow(uint8_t newGlow) { + bool glowReplaced = false; + for (auto &material : materialTable) { + if (material.current.GetGlow() != newGlow) { + glowReplaced = true; + } + material.current = material.current.WithGlow(newGlow); + } + // (No need to check for alpha here.) + if (glowReplaced && vData) vData->Replace(*this); +} + void CBSPPart::ReplaceMaterial(Material origMaterial, Material newMaterial) { bool materialReplaced = false; for (auto &material : materialTable) { diff --git a/src/bsp/CBSPPart.h b/src/bsp/CBSPPart.h index b702d419f..337671995 100644 --- a/src/bsp/CBSPPart.h +++ b/src/bsp/CBSPPart.h @@ -215,6 +215,7 @@ class CBSPPart { virtual void ReplaceSpecularForColor(ARGBColor origColor, ARGBColor newSpecular); virtual void ReplaceShininessForColor(ARGBColor origColor, uint8_t newShininess); virtual void ReplaceGlowForColor(ARGBColor origColor, uint8_t newGlow); + virtual void ReplaceAllGlow(uint8_t newGlow); virtual void ReplaceMaterial(Material origMaterial, Material newMaterial); virtual void ReplaceAllMaterials(Material newMaterial); diff --git a/src/game/CScout.cpp b/src/game/CScout.cpp index da6ed5bc4..e3c04e313 100644 --- a/src/game/CScout.cpp +++ b/src/game/CScout.cpp @@ -45,6 +45,16 @@ CScout::CScout(CAbstractPlayer *thePlayer, short theTeam, ARGBColor longTeamColo partCount = 1; LoadPart(0, kScoutBSP); partList[0]->ReplaceColor(*ColorManager::getMarkerColor(0), longTeamColor); + for (CSmartPart **thePart = partList; *thePart; thePart++) { + (*thePart)->ReplaceSpecularForColor(*ColorManager::getMarkerColor(0), ARGBColor(0x333333)); + (*thePart)->ReplaceShininessForColor(*ColorManager::getMarkerColor(0), 4); + (*thePart)->ReplaceSpecularForColor(*ColorManager::getMarkerColor(1), ARGBColor(0x454545)); + (*thePart)->ReplaceShininessForColor(*ColorManager::getMarkerColor(1), 8); + (*thePart)->ReplaceSpecularForColor(*ColorManager::getMarkerColor(2), ARGBColor(0xa6a6a6)); + (*thePart)->ReplaceShininessForColor(*ColorManager::getMarkerColor(2), 48); + (*thePart)->ReplaceSpecularForColor(*ColorManager::getMarkerColor(3), ARGBColor(0x808080)); + (*thePart)->ReplaceShininessForColor(*ColorManager::getMarkerColor(3), 24); + } hitSoundId = 220; diff --git a/src/game/CWorldShader.h b/src/game/CWorldShader.h index 0358cde3d..003ddbfa7 100644 --- a/src/game/CWorldShader.h +++ b/src/game/CWorldShader.h @@ -45,5 +45,5 @@ class CWorldShader { CWorldShader(); - virtual void Reset(); + void Reset(); }; diff --git a/src/render/Material.h b/src/render/Material.h index be106e81a..7ed1b91c5 100644 --- a/src/render/Material.h +++ b/src/render/Material.h @@ -16,7 +16,7 @@ class Material { void* operator new(std::size_t) = delete; bool operator==(const Material& other) { return color == other.color && specular == other.specular && glow == other.glow; } bool operator!=(const Material& other) { return color != other.color && specular != other.specular && glow != other.glow; } - constexpr Material(ARGBColor color = 0xFF000000, ARGBColor specular = 0x00000000, uint8_t glow = 0): color(color), specular(specular), glow(glow) {} + constexpr Material(ARGBColor color = 0xFFFFFFFF, ARGBColor specular = 0x00000000, uint8_t glow = 0): color(color), specular(specular), glow(glow) {} inline ARGBColor GetColor() const { return color; } inline ARGBColor GetSpecular() const { return specular.WithA(0x00); } inline uint8_t GetGlow() const { return glow; } @@ -83,7 +83,7 @@ class Material { return Material(color, specular.WithA(ConstrainShininess(shininess)), glow); } private: - ARGBColor color = 0xFF000000; + ARGBColor color = 0xFFFFFFFF; ARGBColor specular = 0x00000000; // Alpha channel = shininess value uint8_t glow = 0;