From 741bb027df58fd9f30f4d94cdaf2d6416e11e3ee Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Tue, 16 Apr 2024 00:23:43 +0100
Subject: Custom vertex, vertex shader and fragment shader for landmass

Handles global position type, colourBias for surface types
---
 game/terrain.cpp                   | 22 ++++++++++++++++------
 game/terrain.h                     |  9 ++++++++-
 gfx/gl/sceneShader.cpp             |  3 ++-
 gfx/gl/shaders/landmass.fs         | 23 +++++++++++++++--------
 gfx/gl/shaders/landmass.vs         | 23 +++++++++++++++++++++++
 gfx/gl/shaders/shadowFixedPoint.vs |  9 ---------
 gfx/gl/shaders/shadowLandmass.vs   | 13 +++++++++++++
 gfx/gl/shadowMapper.cpp            |  6 +++---
 gfx/gl/shadowMapper.h              |  2 +-
 9 files changed, 81 insertions(+), 29 deletions(-)
 create mode 100644 gfx/gl/shaders/landmass.vs
 delete mode 100644 gfx/gl/shaders/shadowFixedPoint.vs
 create mode 100644 gfx/gl/shaders/shadowLandmass.vs

diff --git a/game/terrain.cpp b/game/terrain.cpp
index c19bd0a..3b16e79 100644
--- a/game/terrain.cpp
+++ b/game/terrain.cpp
@@ -15,11 +15,21 @@
 #include <utility>
 #include <vector>
 
+static constexpr RGB openSurface {-1};
+
 Terrain::Terrain(std::shared_ptr<GeoData> tm) : geoData {std::move(tm)}, grass {std::make_shared<Texture>("grass.png")}
 {
 	generateMeshes();
 }
 
+template<>
+VertexArrayObject &
+VertexArrayObject::addAttribsFor<Terrain::Vertex>(const GLuint arrayBuffer, const GLuint divisor)
+{
+	return addAttribs<Terrain::Vertex, &Terrain::Vertex::pos, &Terrain::Vertex::normal, &Terrain::Vertex::colourBias>(
+			arrayBuffer, divisor);
+}
+
 void
 Terrain::generateMeshes()
 {
@@ -32,13 +42,13 @@ Terrain::generateMeshes()
 			[this, &vertexIndex, &vertices](const GeoData::VertexHandle v) {
 				std::for_each(geoData->vf_begin(v), geoData->vf_end(v),
 						[&vertexIndex, v, this, &vertices](const GeoData::FaceHandle f) {
-							if (const auto vertexIndexRef
-									= vertexIndex.emplace(std::make_pair(v, geoData->get_surface(f)), 0);
+							const auto surface = geoData->get_surface(f);
+							if (const auto vertexIndexRef = vertexIndex.emplace(std::make_pair(v, surface), 0);
 									vertexIndexRef.second) {
 								vertexIndexRef.first->second = vertices.size();
 
-								const auto p = geoData->point(v);
-								vertices.emplace_back(p, RelativePosition2D(p) / 10000.F, geoData->normal(v));
+								vertices.emplace_back(geoData->point(v), geoData->normal(v),
+										surface ? surface->colorBias : openSurface);
 							}
 						});
 			});
@@ -49,7 +59,7 @@ Terrain::generateMeshes()
 							return vertexIndex[std::make_pair(v, geoData->get_surface(f))];
 						});
 			});
-	meshes.create<Mesh>(vertices, indices);
+	meshes.create<MeshT<Vertex>>(vertices, indices);
 }
 
 void
@@ -68,6 +78,6 @@ Terrain::render(const SceneShader & shader) const
 void
 Terrain::shadows(const ShadowMapper & shadowMapper) const
 {
-	shadowMapper.fixedPoint.use();
+	shadowMapper.landmess.use();
 	meshes.apply(&Mesh::Draw);
 }
diff --git a/game/terrain.h b/game/terrain.h
index 54593fc..d088f89 100644
--- a/game/terrain.h
+++ b/game/terrain.h
@@ -2,6 +2,7 @@
 
 #include "chronology.h"
 #include "collection.h"
+#include "config/types.h"
 #include "game/worldobject.h"
 #include <gfx/models/mesh.h>
 #include <gfx/renderable.h>
@@ -20,10 +21,16 @@ public:
 
 	void tick(TickDuration) override;
 
+	struct Vertex {
+		GlobalPosition3D pos;
+		Normal3D normal;
+		RGB colourBias;
+	};
+
 private:
 	void generateMeshes();
 
 	std::shared_ptr<GeoData> geoData;
-	Collection<Mesh, false> meshes;
+	Collection<MeshT<Vertex>, false> meshes;
 	std::shared_ptr<Texture> grass;
 };
diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp
index 2dd9612..985faa0 100644
--- a/gfx/gl/sceneShader.cpp
+++ b/gfx/gl/sceneShader.cpp
@@ -12,6 +12,7 @@
 #include <gfx/gl/shaders/vs-dynamicPoint.h>
 #include <gfx/gl/shaders/vs-dynamicPointInst.h>
 #include <gfx/gl/shaders/vs-fixedPoint.h>
+#include <gfx/gl/shaders/vs-landmass.h>
 #include <gfx/gl/shaders/vs-networkCurve.h>
 #include <gfx/gl/shaders/vs-networkStraight.h>
 #include <gfx/gl/shaders/vs-pointLight.h>
@@ -33,7 +34,7 @@ SceneShader::allPrograms(auto member, auto &&... ps) const
 }
 
 SceneShader::SceneShader() :
-	basicInst {dynamicPointInst_vs, material_fs}, landmass {fixedPoint_vs, landmass_fs},
+	basicInst {dynamicPointInst_vs, material_fs}, landmass {landmass_vs, landmass_fs},
 	absolute {fixedPoint_vs, material_fs}, spotLightInst {spotLight_vs, spotLight_gs, spotLight_fs},
 	pointLightInst {pointLight_vs, pointLight_gs, pointLight_fs},
 	networkStraight {networkStraight_vs, networkStraight_gs, network_fs},
diff --git a/gfx/gl/shaders/landmass.fs b/gfx/gl/shaders/landmass.fs
index fc43bf2..55e3c24 100644
--- a/gfx/gl/shaders/landmass.fs
+++ b/gfx/gl/shaders/landmass.fs
@@ -1,9 +1,12 @@
 #version 330 core
 
-include(`materialInterface.glsl')
 include(`materialOut.glsl')
+in vec3 FragPos;
+in vec3 Normal;
+flat in vec3 ColourBias;
 
 uniform sampler2D texture0;
+uniform ivec3 viewPoint;
 
 const vec3 grass = vec3(.1, .4, .05);
 const vec3 slope = vec3(.6, .6, .4);
@@ -11,9 +14,9 @@ const vec3 rock = vec3(.2, .2, .1);
 const vec3 sand = vec3(.76, .7, .5);
 const vec3 snow = vec3(.97, .97, .99);
 
-const float beachline = 500;
-const float snowline_low = 28000;
-const float snowline_high = 30000;
+const int beachline = 500;
+const int snowline_low = 28000;
+const int snowline_high = 30000;
 
 const float slope_min = .99;
 const float slope_mid = .95;
@@ -28,10 +31,14 @@ mixBetween(vec3 colA, vec3 colB, float blend, float low, float high)
 void
 main()
 {
-	vec3 color = texture(texture0, TexCoords).rgb;
+	ivec3 position = ivec3(FragPos) + viewPoint;
+	vec3 color = texture(texture0, vec2(position.xy % 10000) / 10000.0).rgb;
 
-	float height = FragPos.z;
-	if (height < beachline) { // Sandy beach
+	int height = position.z;
+	if (ColourBias.r >= 0) {
+		color *= ColourBias;
+	}
+	else if (height < beachline) { // Sandy beach
 		color *= sand;
 	}
 	else if (Normal.z < slope_max) { // Dark rocky face
@@ -60,7 +67,7 @@ main()
 		}
 	}
 
-	gPosition = ivec4(FragPos, 1);
+	gPosition = ivec4(position, 1);
 	gNormal = vec4(Normal, 1);
 	gAlbedoSpec = vec4(color, 1);
 }
diff --git a/gfx/gl/shaders/landmass.vs b/gfx/gl/shaders/landmass.vs
new file mode 100644
index 0000000..9617cb9
--- /dev/null
+++ b/gfx/gl/shaders/landmass.vs
@@ -0,0 +1,23 @@
+#version 330 core
+#extension GL_ARB_shading_language_420pack : enable
+
+layout(location = 0) in ivec3 position;
+layout(location = 1) in vec3 normal;
+layout(location = 2) in vec3 colourBias;
+
+out vec3 FragPos;
+out vec3 Normal;
+flat out vec3 ColourBias;
+
+uniform mat4 viewProjection;
+uniform ivec3 viewPoint;
+
+void
+main()
+{
+	FragPos = position - viewPoint;
+	Normal = normal;
+	ColourBias = colourBias;
+
+	gl_Position = viewProjection * vec4(FragPos, 1);
+}
diff --git a/gfx/gl/shaders/shadowFixedPoint.vs b/gfx/gl/shaders/shadowFixedPoint.vs
deleted file mode 100644
index 1376388..0000000
--- a/gfx/gl/shaders/shadowFixedPoint.vs
+++ /dev/null
@@ -1,9 +0,0 @@
-#version 330 core
-
-include(`meshIn.glsl')
-
-uniform ivec3 viewPoint;
-const mat3 model = mat3(1);
-const ivec3 modelPos = ivec3(0);
-
-include(`commonShadowPoint.glsl')
diff --git a/gfx/gl/shaders/shadowLandmass.vs b/gfx/gl/shaders/shadowLandmass.vs
new file mode 100644
index 0000000..becf142
--- /dev/null
+++ b/gfx/gl/shaders/shadowLandmass.vs
@@ -0,0 +1,13 @@
+#version 330 core
+
+layout(location = 0) in ivec3 position;
+
+uniform ivec3 viewPoint;
+
+out vec4 vworldPos;
+
+void
+main()
+{
+	vworldPos = vec4(position - viewPoint, 1);
+}
diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp
index 4dbee8d..206e4a7 100644
--- a/gfx/gl/shadowMapper.cpp
+++ b/gfx/gl/shadowMapper.cpp
@@ -4,7 +4,7 @@
 #include "gfx/gl/shaders/gs-commonShadowPoint.h"
 #include "gfx/gl/shaders/vs-shadowDynamicPoint.h"
 #include "gfx/gl/shaders/vs-shadowDynamicPointInst.h"
-#include "gfx/gl/shaders/vs-shadowFixedPoint.h"
+#include "gfx/gl/shaders/vs-shadowLandmass.h"
 #include "gl_traits.h"
 #include "location.h"
 #include "maths.h"
@@ -18,7 +18,7 @@
 #include <vector>
 
 ShadowMapper::ShadowMapper(const TextureAbsCoord & s) :
-	fixedPoint {shadowFixedPoint_vs}, dynamicPointInst {shadowDynamicPointInst_vs}, size {s}
+	landmess {shadowLandmass_vs}, dynamicPointInst {shadowDynamicPointInst_vs}, size {s}
 {
 	glBindTexture(GL_TEXTURE_2D_ARRAY, depthMap);
 	glTexImage3D(
@@ -92,7 +92,7 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const
 
 				return lightProjection * lightViewDir;
 			});
-	for (const auto p : std::initializer_list<const ShadowProgram *> {&fixedPoint, &dynamicPoint, &dynamicPointInst}) {
+	for (const auto p : std::initializer_list<const ShadowProgram *> {&landmess, &dynamicPoint, &dynamicPointInst}) {
 		p->setView(out, lightViewPoint);
 	}
 	scene.shadows(*this);
diff --git a/gfx/gl/shadowMapper.h b/gfx/gl/shadowMapper.h
index a95d4c1..dcf7e3f 100644
--- a/gfx/gl/shadowMapper.h
+++ b/gfx/gl/shadowMapper.h
@@ -50,7 +50,7 @@ public:
 		RequiredUniformLocation modelPosLoc;
 	};
 
-	FixedPoint fixedPoint, dynamicPointInst;
+	FixedPoint landmess, dynamicPointInst;
 	DynamicPoint dynamicPoint;
 
 	// NOLINTNEXTLINE(hicpp-explicit-conversions)
-- 
cgit v1.2.3