From c3eea71370eb94cff1fd96185458643fab6eb2c5 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Thu, 3 Nov 2022 19:47:46 +0000
Subject: Restructure how shaders are worked with

Needs a tidy-up
---
 game/network/network.impl.h        |   2 +-
 game/terrain.cpp                   |   5 +-
 game/vehicles/railVehicleClass.cpp |   6 +-
 gfx/gl/glSource.cpp                |  40 -----------
 gfx/gl/glSource.h                  |  16 -----
 gfx/gl/program.cpp                 |  35 ++++++++++
 gfx/gl/program.h                   |  46 +++++++++++++
 gfx/gl/programHandle.cpp           |  14 ----
 gfx/gl/programHandle.h             |  13 ----
 gfx/gl/sceneShader.cpp             | 135 ++++++++++++++++---------------------
 gfx/gl/sceneShader.h               |  81 ++++++++++++++--------
 gfx/gl/shader.cpp                  |  41 +++++++++++
 gfx/gl/shader.h                    |  21 ++++++
 gfx/gl/uiShader.cpp                |  31 +++------
 gfx/gl/uiShader.h                  |  37 ++++++++--
 lib/embed-glsl.cpp.m4              |   4 +-
 lib/embed-glsl.h.m4                |   4 +-
 ui/editNetwork.cpp                 |   2 +-
 ui/gameMainSelector.h              |   2 +
 ui/gameMainWindow.cpp              |  10 ---
 ui/gameMainWindow.h                |   1 -
 ui/sceneRenderer.cpp               |   4 +-
 ui/sceneRenderer.h                 |  12 +++-
 ui/text.cpp                        |   2 +-
 ui/toolbar.cpp                     |   2 +-
 ui/window.h                        |   3 -
 26 files changed, 323 insertions(+), 246 deletions(-)
 delete mode 100644 gfx/gl/glSource.cpp
 delete mode 100644 gfx/gl/glSource.h
 create mode 100644 gfx/gl/program.cpp
 create mode 100644 gfx/gl/program.h
 delete mode 100644 gfx/gl/programHandle.cpp
 delete mode 100644 gfx/gl/programHandle.h
 create mode 100644 gfx/gl/shader.cpp
 create mode 100644 gfx/gl/shader.h

diff --git a/game/network/network.impl.h b/game/network/network.impl.h
index 5f60c80..045335f 100644
--- a/game/network/network.impl.h
+++ b/game/network/network.impl.h
@@ -7,7 +7,7 @@ void
 NetworkOf<T>::render(const SceneShader & shader) const
 {
 	if constexpr (std::is_base_of_v<Renderable, T>) {
-		shader.setModel(Location {}, SceneShader::Program::StaticPos);
+		shader.absolute.use();
 		texture->bind();
 		links.apply(&Renderable::render, shader);
 	}
diff --git a/game/terrain.cpp b/game/terrain.cpp
index 911a541..31f7fb1 100644
--- a/game/terrain.cpp
+++ b/game/terrain.cpp
@@ -85,12 +85,11 @@ Terrain::tick(TickDuration dur)
 void
 Terrain::render(const SceneShader & shader) const
 {
-	shader.setModel(Location {}, SceneShader::Program::LandMass);
+	shader.landmass.use();
 	grass->bind();
 	meshes.apply(&Mesh::Draw);
 
-	shader.setModel(Location {}, SceneShader::Program::Water);
-	shader.setUniform("waves", {waveCycle, 0, 0});
+	shader.water.use(waveCycle);
 	water->bind();
 	meshes.apply(&Mesh::Draw);
 }
diff --git a/game/vehicles/railVehicleClass.cpp b/game/vehicles/railVehicleClass.cpp
index 7d69338..5bcdc6e 100644
--- a/game/vehicles/railVehicleClass.cpp
+++ b/game/vehicles/railVehicleClass.cpp
@@ -42,13 +42,13 @@ void
 RailVehicleClass::render(
 		const SceneShader & shader, const Location & location, const std::array<Location, 2> & bl) const
 {
+	shader.basic.use(location);
 	texture->bind();
+	bodyMesh->Draw();
 	for (auto b = 0U; b < bogies.size(); ++b) {
-		shader.setModel(bl[b]);
+		shader.basic.setModel(bl[b]);
 		bogies[b]->Draw();
 	}
-	shader.setModel(location);
-	bodyMesh->Draw();
 }
 
 float
diff --git a/gfx/gl/glSource.cpp b/gfx/gl/glSource.cpp
deleted file mode 100644
index 962d096..0000000
--- a/gfx/gl/glSource.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "glSource.h"
-#include <array>
-#include <stdexcept>
-#include <string>
-
-GLsource::ShaderRef
-GLsource::compile() const
-{
-	ShaderRef id {type};
-	glShaderSource(id, 1, &text, &len);
-	glCompileShader(id);
-
-	CheckShaderError(id, GL_COMPILE_STATUS, false, "Error compiling shader!");
-	return id;
-}
-
-void
-GLsource::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage)
-{
-	GLint success = 0;
-
-	if (isProgram) {
-		glGetProgramiv(shader, flag, &success);
-	}
-	else {
-		glGetShaderiv(shader, flag, &success);
-	}
-
-	if (success == GL_FALSE) {
-		std::array<GLchar, 1024> error {};
-		if (isProgram) {
-			glGetProgramInfoLog(shader, error.size(), nullptr, error.data());
-		}
-		else {
-			glGetShaderInfoLog(shader, error.size(), nullptr, error.data());
-		}
-
-		throw std::runtime_error {std::string {errorMessage} + ": '" + std::string {error.data(), error.size()} + "'"};
-	}
-}
diff --git a/gfx/gl/glSource.h b/gfx/gl/glSource.h
deleted file mode 100644
index c6b1f41..0000000
--- a/gfx/gl/glSource.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-#include <GL/glew.h>
-#include <glRef.hpp>
-#include <string_view>
-
-struct GLsource {
-	using ShaderRef = glRef<GLuint, &__glewCreateShader, &__glewDeleteShader>;
-
-	const GLchar * text;
-	GLint len;
-	GLuint type;
-
-	[[nodiscard]] ShaderRef compile() const;
-	static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage);
-};
diff --git a/gfx/gl/program.cpp b/gfx/gl/program.cpp
new file mode 100644
index 0000000..c36cc80
--- /dev/null
+++ b/gfx/gl/program.cpp
@@ -0,0 +1,35 @@
+#include "program.h"
+#include "shader.h"
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/transform.hpp>
+#include <location.hpp>
+#include <maths.h>
+
+void
+Program::linkAndValidate() const
+{
+	glLinkProgram(m_program);
+	Shader::CheckShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program");
+
+	glValidateProgram(m_program);
+	Shader::CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program");
+}
+
+void
+Program::use() const
+{
+	glUseProgram(m_program);
+}
+
+Program::UniformLocation::UniformLocation(GLuint program, const char * name) :
+	location {glGetUniformLocation(program, name)}
+{
+}
+
+Program::RequiredUniformLocation::RequiredUniformLocation(GLuint program, const char * name) :
+	UniformLocation {program, name}
+{
+	if (location < 0) {
+		throw std::logic_error("Required uniform does not exist");
+	}
+}
diff --git a/gfx/gl/program.h b/gfx/gl/program.h
new file mode 100644
index 0000000..711a26d
--- /dev/null
+++ b/gfx/gl/program.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "shader.h"
+#include <GL/glew.h>
+#include <glRef.hpp>
+#include <glm/mat4x4.hpp>
+
+class Location;
+
+class Program {
+public:
+	template<typename... S> Program(const S &... srcs)
+	{
+		(glAttachShader(m_program, srcs), ...);
+		linkAndValidate();
+	}
+	virtual ~Program() = default;
+
+	class UniformLocation {
+	public:
+		UniformLocation(GLuint prog, const char * name);
+		operator auto() const
+		{
+			return location;
+		}
+
+	protected:
+		GLint location;
+	};
+
+	class RequiredUniformLocation : public UniformLocation {
+	public:
+		RequiredUniformLocation(GLuint prog, const char * name);
+	};
+
+	operator GLuint() const
+	{
+		return m_program;
+	}
+
+protected:
+	void use() const;
+	using ProgramRef = glRef<GLuint, &__glewCreateProgram, &__glewDeleteProgram>;
+	void linkAndValidate() const;
+	ProgramRef m_program;
+};
diff --git a/gfx/gl/programHandle.cpp b/gfx/gl/programHandle.cpp
deleted file mode 100644
index bfe06f2..0000000
--- a/gfx/gl/programHandle.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "programHandle.h"
-#include "glSource.h"
-
-ProgramHandleBase::ProgramHandleBase(GLuint vs, GLuint fs) : viewProjection_uniform {}, model_uniform {}
-{
-	glAttachShader(m_program, vs);
-	glAttachShader(m_program, fs);
-
-	glLinkProgram(m_program);
-	GLsource::CheckShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program");
-
-	glValidateProgram(m_program);
-	GLsource::CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program");
-}
diff --git a/gfx/gl/programHandle.h b/gfx/gl/programHandle.h
deleted file mode 100644
index a2a7a2d..0000000
--- a/gfx/gl/programHandle.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-#include <GL/glew.h>
-#include <glRef.hpp>
-
-class ProgramHandleBase {
-public:
-	ProgramHandleBase(GLuint, GLuint);
-	using ProgramRef = glRef<GLuint, &__glewCreateProgram, &__glewDeleteProgram>;
-
-	ProgramRef m_program;
-	GLint viewProjection_uniform, model_uniform;
-};
diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp
index 48c0f42..bec6553 100644
--- a/gfx/gl/sceneShader.cpp
+++ b/gfx/gl/sceneShader.cpp
@@ -1,77 +1,58 @@
-#include "sceneShader.h"
-#include "gfx/gl/glSource.h"
-#include <array>
-#include <cstddef>
-#include <gfx/gl/programHandle.h>
-#include <gfx/gl/shaders/fs-basicShader.h>
-#include <gfx/gl/shaders/fs-landmassShader.h>
-#include <gfx/gl/shaders/fs-waterShader.h>
-#include <gfx/gl/shaders/vs-basicShader.h>
-#include <gfx/gl/shaders/vs-landmassShader.h>
-#include <gfx/gl/shaders/vs-waterShader.h>
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-#include <glm/gtx/transform.hpp>
-#include <location.hpp>
-#include <maths.h>
-
-SceneShader::ProgramHandle::ProgramHandle(GLuint vs, GLuint fs) : ProgramHandleBase {vs, fs}
-{
-	glBindAttribLocation(m_program, 0, "position");
-	glBindAttribLocation(m_program, 1, "texCoord");
-	glBindAttribLocation(m_program, 2, "normal");
-
-	viewProjection_uniform = glGetUniformLocation(m_program, "viewProjection");
-	model_uniform = glGetUniformLocation(m_program, "model");
-}
-
-SceneShader::SceneShader() :
-	programs {{{
-					   basicShader_vs.compile(),
-					   basicShader_fs.compile(),
-			   },
-			{
-					waterShader_vs.compile(),
-					waterShader_fs.compile(),
-			},
-			{
-					landmassShader_vs.compile(),
-					landmassShader_fs.compile(),
-			},
-			{
-					landmassShader_vs.compile(),
-					basicShader_fs.compile(),
-			}}}
-{
-}
-
-void
-SceneShader::setView(glm::mat4 proj) const
-{
-	for (const auto & prog : programs) {
-		glUseProgram(prog.m_program);
-		glUniformMatrix4fv(prog.viewProjection_uniform, 1, GL_FALSE, glm::value_ptr(proj));
-	}
-}
-
-void
-SceneShader::setUniform(const GLchar * uniform, glm::vec3 v) const
-{
-	for (const auto & prog : programs) {
-		if (auto loc = glGetUniformLocation(prog.m_program, uniform); loc >= 0) {
-			glUseProgram(prog.m_program);
-			glUniform3fv(loc, 1, glm::value_ptr(v));
-		}
-	}
-}
-
-void
-SceneShader::setModel(const Location & loc, Program pid) const
-{
-	auto & prog = programs[static_cast<std::size_t>(pid)];
-	glUseProgram(prog.m_program);
-	if (prog.model_uniform >= 0) {
-		const auto model {glm::translate(loc.pos) * rotate_ypr(loc.rot)};
-		glUniformMatrix4fv(prog.model_uniform, 1, GL_FALSE, glm::value_ptr(model));
-	}
-}
+#include "sceneShader.h"
+#include <array>
+#include <gfx/gl/shaders/fs-basicShader.h>
+#include <gfx/gl/shaders/fs-landmassShader.h>
+#include <gfx/gl/shaders/fs-waterShader.h>
+#include <gfx/gl/shaders/vs-basicShader.h>
+#include <gfx/gl/shaders/vs-landmassShader.h>
+#include <gfx/gl/shaders/vs-waterShader.h>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/transform.hpp>
+#include <location.hpp>
+#include <maths.h>
+
+SceneShader::SceneShader() :
+	landmass {landmassShader_vs, landmassShader_fs}, absolute {landmassShader_vs, basicShader_fs}
+{
+}
+
+void
+SceneShader::setView(glm::mat4 proj) const
+{
+	for (const auto & prog : std::array<const SceneProgram *, 4> {&basic, &water, &landmass, &absolute}) {
+		prog->setView(proj);
+	}
+}
+
+void
+SceneShader::SceneProgram::setView(const glm::mat4 & viewProjection) const
+{
+	glUseProgram(*this);
+	glUniformMatrix4fv(viewProjectionLoc, 1, GL_FALSE, glm::value_ptr(viewProjection));
+}
+
+SceneShader::BasicProgram::BasicProgram() : SceneProgram {basicShader_vs, basicShader_fs}, modelLoc {*this, "model"} { }
+
+void
+SceneShader::BasicProgram::setModel(Location const & location) const
+{
+	const auto model {glm::translate(location.pos) * rotate_ypr(location.rot)};
+	glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
+}
+
+void
+SceneShader::BasicProgram::use(Location const & location) const
+{
+	Program::use();
+	setModel(location);
+}
+
+SceneShader::WaterProgram::WaterProgram() : SceneProgram {waterShader_vs, waterShader_fs}, waveLoc {*this, "waves"} { }
+
+void
+SceneShader::WaterProgram::use(float waveCycle) const
+{
+	Program::use();
+	glm::vec3 waves {waveCycle, 0.F, 0.F};
+	glUniform3fv(waveLoc, 1, glm::value_ptr(waves));
+}
diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h
index 61c159b..a85e55b 100644
--- a/gfx/gl/sceneShader.h
+++ b/gfx/gl/sceneShader.h
@@ -1,27 +1,54 @@
-#pragma once
-
-#include "programHandle.h"
-#include <GL/glew.h>
-#include <array>
-#include <glm/glm.hpp>
-
-class Location;
-
-class SceneShader {
-public:
-	enum class Program { Basic = 0, Water = 1, LandMass = 2, StaticPos = 3 };
-
-	SceneShader();
-
-	void setView(glm::mat4 view) const;
-	void setModel(const Location &, Program = Program::Basic) const;
-	void setUniform(const GLchar *, glm::vec3 dir) const;
-
-private:
-	class ProgramHandle : public ProgramHandleBase {
-	public:
-		ProgramHandle(GLuint, GLuint);
-	};
-
-	std::array<ProgramHandle, 4> programs;
-};
+#pragma once
+
+#include "program.h"
+
+class Location;
+
+struct SceneShader {
+	class SceneProgram : public Program {
+	public:
+		template<typename... S>
+		inline SceneProgram(const S &... srcs) : Program {srcs...}, viewProjectionLoc {*this, "viewProjection"}
+		{
+		}
+
+		void setView(const glm::mat4 &) const;
+
+	private:
+		RequiredUniformLocation viewProjectionLoc;
+	};
+
+	class BasicProgram : public SceneProgram {
+	public:
+		BasicProgram();
+		void setModel(const Location &) const;
+		void use(const Location &) const;
+
+	private:
+		RequiredUniformLocation modelLoc;
+	};
+
+	class AbsolutePosProgram : public SceneProgram {
+	public:
+		using Program::use;
+		using SceneProgram::SceneProgram;
+	};
+
+	class WaterProgram : public SceneProgram {
+	public:
+	public:
+		WaterProgram();
+		void use(float waveCycle) const;
+
+	private:
+		RequiredUniformLocation waveLoc;
+	};
+
+	SceneShader();
+
+	BasicProgram basic;
+	WaterProgram water;
+	AbsolutePosProgram landmass, absolute;
+
+	void setView(glm::mat4 proj) const;
+};
diff --git a/gfx/gl/shader.cpp b/gfx/gl/shader.cpp
new file mode 100644
index 0000000..8b0f614
--- /dev/null
+++ b/gfx/gl/shader.cpp
@@ -0,0 +1,41 @@
+#include "shader.h"
+#include <array>
+#include <stdexcept>
+#include <string>
+
+Shader::operator GLuint() const
+{
+	if (!shader) {
+		shader.emplace(type);
+		glShaderSource(*shader, 1, &text, &len);
+		glCompileShader(*shader);
+
+		CheckShaderError(*shader, GL_COMPILE_STATUS, false, "Error compiling shader!");
+	}
+	return *shader;
+}
+
+void
+Shader::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage)
+{
+	GLint success = 0;
+
+	if (isProgram) {
+		glGetProgramiv(shader, flag, &success);
+	}
+	else {
+		glGetShaderiv(shader, flag, &success);
+	}
+
+	if (success == GL_FALSE) {
+		std::array<GLchar, 1024> error {};
+		if (isProgram) {
+			glGetProgramInfoLog(shader, error.size(), nullptr, error.data());
+		}
+		else {
+			glGetShaderInfoLog(shader, error.size(), nullptr, error.data());
+		}
+
+		throw std::runtime_error {std::string {errorMessage} + ": '" + std::string {error.data(), error.size()} + "'"};
+	}
+}
diff --git a/gfx/gl/shader.h b/gfx/gl/shader.h
new file mode 100644
index 0000000..1a8ddef
--- /dev/null
+++ b/gfx/gl/shader.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <GL/glew.h>
+#include <glRef.hpp>
+#include <optional>
+#include <string_view>
+
+class Shader {
+public:
+	constexpr Shader(const GLchar * text, GLint len, GLuint type) : text {text}, len {len}, type {type} { }
+
+	operator GLuint() const;
+	static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage);
+
+private:
+	using ShaderRef = glRef<GLuint, &__glewCreateShader, &__glewDeleteShader>;
+	const GLchar * text;
+	GLint len;
+	GLuint type;
+	mutable std::optional<ShaderRef> shader {};
+};
diff --git a/gfx/gl/uiShader.cpp b/gfx/gl/uiShader.cpp
index fbcdd15..78e0064 100644
--- a/gfx/gl/uiShader.cpp
+++ b/gfx/gl/uiShader.cpp
@@ -1,6 +1,6 @@
 #include "uiShader.h"
-#include <gfx/gl/glSource.h>
-#include <gfx/gl/programHandle.h>
+#include <gfx/gl/program.h>
+#include <gfx/gl/shader.h>
 #include <gfx/gl/shaders/fs-uiShader.h>
 #include <gfx/gl/shaders/fs-uiShaderFont.h>
 #include <gfx/gl/shaders/vs-uiShader.h>
@@ -8,30 +8,21 @@
 #include <glm/gtc/type_ptr.hpp>
 #include <initializer_list>
 
-UIShader::UIShader(size_t width, size_t height) :
-	progDefault {uiShader_vs.compile(), uiShader_fs.compile()}, progText {uiShader_vs.compile(),
-																		uiShaderFont_fs.compile()}
+UIShader::IconProgram::IconProgram(const glm::mat4 & vp) : UIProgram {vp, uiShader_vs, uiShader_fs} { }
+UIShader::TextProgram::TextProgram(const glm::mat4 & vp) :
+	UIProgram {vp, uiShader_vs, uiShaderFont_fs}, colorLoc {*this, "colour"}
 {
-	for (const auto prog : {&progDefault, &progText}) {
-		if (auto loc = glGetUniformLocation(prog->m_program, "uiProjection"); loc >= 0) {
-			glUseProgram(prog->m_program);
-			const auto uiProjection = glm::ortho<float>(0, static_cast<float>(width), 0, static_cast<float>(height));
-			glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(uiProjection));
-		}
-	}
 }
 
-void
-UIShader::useDefault() const
+UIShader::UIShader(size_t width, size_t height) :
+	UIShader {glm::ortho<float>(0, static_cast<float>(width), 0, static_cast<float>(height))}
 {
-	glUseProgram(progDefault.m_program);
 }
+UIShader::UIShader(const glm::mat4 & viewProjection) : icon {viewProjection}, text {viewProjection} { }
 
 void
-UIShader::useText(glm::vec3 colour) const
+UIShader::TextProgram::use(const glm::vec3 & colour) const
 {
-	glUseProgram(progText.m_program);
-	if (auto loc = glGetUniformLocation(progText.m_program, "colour"); loc >= 0) {
-		glUniform3fv(loc, 1, glm::value_ptr(colour));
-	}
+	Program::use();
+	glUniform3fv(colorLoc, 1, glm::value_ptr(colour));
 }
diff --git a/gfx/gl/uiShader.h b/gfx/gl/uiShader.h
index ea5bf25..ee44af7 100644
--- a/gfx/gl/uiShader.h
+++ b/gfx/gl/uiShader.h
@@ -1,19 +1,44 @@
 #pragma once
 
-#include "programHandle.h"
+#include "program.h"
 #include <GL/glew.h>
 #include <cstddef>
 #include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
 
 class UIShader {
 public:
 	UIShader(std::size_t width, std::size_t height);
-	void useDefault() const;
-	void useText(glm::vec3) const;
 
 private:
-	class UIProgramHandle : public ProgramHandleBase {
-		using ProgramHandleBase::ProgramHandleBase;
+	explicit UIShader(const glm::mat4 & viewProjection);
+
+	class UIProgram : public Program {
+	public:
+		template<typename... S> UIProgram(const glm::mat4 & vp, S &&... srcs) : Program {std::forward<S>(srcs)...}
+		{
+			RequiredUniformLocation uiProjectionLoc {*this, "uiProjection"};
+			glUseProgram(*this);
+			glUniformMatrix4fv(uiProjectionLoc, 1, GL_FALSE, glm::value_ptr(vp));
+		}
+	};
+
+	class IconProgram : public UIProgram {
+	public:
+		explicit IconProgram(const glm::mat4 & vp);
+		using Program::use;
+	};
+
+	class TextProgram : public UIProgram {
+	public:
+		explicit TextProgram(const glm::mat4 & vp);
+		void use(const glm::vec3 & colour) const;
+
+	private:
+		RequiredUniformLocation colorLoc;
 	};
-	UIProgramHandle progDefault, progText;
+
+public:
+	IconProgram icon;
+	TextProgram text;
 };
diff --git a/lib/embed-glsl.cpp.m4 b/lib/embed-glsl.cpp.m4
index 003db65..5b25e0a 100644
--- a/lib/embed-glsl.cpp.m4
+++ b/lib/embed-glsl.cpp.m4
@@ -2,11 +2,11 @@ changecom()dnl
 // NAME
 #include "substr(TYPE,1)-NAME.h"
 #include <GL/glew.h>
-#include "gfx/gl/glSource.h"
+#include "gfx/gl/shader.h"
 #include "lib/strings.hpp"
 
 constexpr const GLchar * src { R"GLSL-EMBED(dnl
 include(SOURCE))GLSL-EMBED" };
 constexpr auto len { constexpr_strlen (src) };
 
-const GLsource NAME`_'substr(TYPE,1) { src, len, GLTYPE };
+const Shader NAME`_'substr(TYPE,1) { src, len, GLTYPE };
diff --git a/lib/embed-glsl.h.m4 b/lib/embed-glsl.h.m4
index 57ba0cf..a2b4770 100644
--- a/lib/embed-glsl.h.m4
+++ b/lib/embed-glsl.h.m4
@@ -1,6 +1,6 @@
 #pragma once
 
 // NAME
-#include <gfx/gl/glSource.h>
+#include <gfx/gl/shader.h>
 
-extern const GLsource NAME`_'substr(TYPE,1);
+extern const Shader NAME`_'substr(TYPE,1);
diff --git a/ui/editNetwork.cpp b/ui/editNetwork.cpp
index 991cbc3..754053b 100644
--- a/ui/editNetwork.cpp
+++ b/ui/editNetwork.cpp
@@ -51,7 +51,7 @@ EditNetwork::render(const SceneShader & shader) const
 {
 	if (builder) {
 		blue.bind();
-		shader.setModel(Location {}, SceneShader::Program::StaticPos);
+		shader.absolute.use();
 		builder->render(shader);
 	}
 }
diff --git a/ui/gameMainSelector.h b/ui/gameMainSelector.h
index 9c05127..aacd67a 100644
--- a/ui/gameMainSelector.h
+++ b/ui/gameMainSelector.h
@@ -7,6 +7,8 @@
 #include <glm/glm.hpp>
 #include <memory>
 #include <string>
+
+class SceneShader;
 class Ray;
 class UIShader;
 class Camera;
diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp
index 792ffab..1d90417 100644
--- a/ui/gameMainWindow.cpp
+++ b/ui/gameMainWindow.cpp
@@ -36,10 +36,6 @@ GameMainWindow::GameMainWindow(size_t w, size_t h) :
 	uiComponents.create<ManualCameraController>(glm::vec2 {-1150, -1150});
 	auto gms = uiComponents.create<GameMainSelector>(&camera, glm::vec2 {w, h});
 	uiComponents.create<GameMainToolbar>(gms.get());
-
-	shader.setUniform("lightDirection", glm::normalize(glm::vec3 {1, 0, -1}));
-	shader.setUniform("lightColor", {.6, .6, .6});
-	shader.setUniform("ambientColor", {0.5, 0.5, 0.5});
 }
 
 void
@@ -58,9 +54,3 @@ GameMainWindow::render() const
 	});
 	Window::render();
 }
-
-const SceneShader &
-GameMainWindow::getShader() const
-{
-	return shader;
-}
diff --git a/ui/gameMainWindow.h b/ui/gameMainWindow.h
index 09d17d1..c01888f 100644
--- a/ui/gameMainWindow.h
+++ b/ui/gameMainWindow.h
@@ -16,7 +16,6 @@ public:
 	void render() const override;
 
 private:
-	const SceneShader & getShader() const override;
 	SceneShader shader;
 	Camera camera;
 };
diff --git a/ui/sceneRenderer.cpp b/ui/sceneRenderer.cpp
index 5e03704..6e75dec 100644
--- a/ui/sceneRenderer.cpp
+++ b/ui/sceneRenderer.cpp
@@ -10,7 +10,7 @@ static constexpr std::array<glm::vec4, 4> displayVAOdata {{
 		{1.0f, 1.0f, 1.0f, 1.0f},
 		{1.0f, -1.0f, 1.0f, 0.0f},
 }};
-SceneRenderer::SceneRenderer(glm::ivec2 size) : lighting {lightingShader_vs.compile(), lightingShader_fs.compile()}
+SceneRenderer::SceneRenderer(glm::ivec2 size) : lighting {lightingShader_vs, lightingShader_fs}
 {
 	glBindVertexArray(displayVAO);
 	glBindBuffer(GL_ARRAY_BUFFER, displayVBO);
@@ -60,7 +60,6 @@ SceneRenderer::render(std::function<void()> content) const
 	// Lighting pass
 	glDisable(GL_BLEND);
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-	glUseProgram(lighting.m_program);
 	glActiveTexture(GL_TEXTURE0);
 	glBindTexture(GL_TEXTURE_2D, gPosition);
 	glActiveTexture(GL_TEXTURE1);
@@ -68,6 +67,7 @@ SceneRenderer::render(std::function<void()> content) const
 	glActiveTexture(GL_TEXTURE2);
 	glBindTexture(GL_TEXTURE_2D, gAlbedoSpec);
 	// TODO Configure lights
+	lighting.use();
 	glBindVertexArray(displayVAO);
 	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 	glBindVertexArray(0);
diff --git a/ui/sceneRenderer.h b/ui/sceneRenderer.h
index 6176f1b..6c96418 100644
--- a/ui/sceneRenderer.h
+++ b/ui/sceneRenderer.h
@@ -1,12 +1,13 @@
 #pragma once
 
-#include "gfx/gl/sceneShader.h"
+#include "gfx/gl/program.h"
 #include "lib/glArrays.h"
 #include <functional>
+#include <glm/fwd.hpp>
 
 class SceneRenderer {
 public:
-	SceneRenderer(glm::ivec2 size);
+	explicit SceneRenderer(glm::ivec2 size);
 
 	void render(std::function<void()> content) const;
 
@@ -14,7 +15,12 @@ private:
 	glFrameBuffer gBuffer;
 	glTexture gPosition, gNormal, gAlbedoSpec;
 	glRenderBuffer depth;
-	ProgramHandleBase lighting;
+	class DeferredLightProgram : public Program {
+	public:
+		using Program::Program;
+		using Program::use;
+	};
+	DeferredLightProgram lighting;
 	glVertexArray displayVAO;
 	glBuffer displayVBO;
 };
diff --git a/ui/text.cpp b/ui/text.cpp
index 872e3f3..d24c268 100644
--- a/ui/text.cpp
+++ b/ui/text.cpp
@@ -43,7 +43,7 @@ Text::Text(std::string_view s, Position pos, glm::vec3 c) : UIComponent {pos}, c
 void
 Text::render(const UIShader & shader, const Position &) const
 {
-	shader.useText(colour);
+	shader.text.use(colour);
 	glActiveTexture(GL_TEXTURE0);
 	for (const auto & m : models) {
 		glBindTexture(GL_TEXTURE_2D, m.texture);
diff --git a/ui/toolbar.cpp b/ui/toolbar.cpp
index ada97b0..31d87dc 100644
--- a/ui/toolbar.cpp
+++ b/ui/toolbar.cpp
@@ -18,7 +18,7 @@ Toolbar::Toolbar(const std::initializer_list<InitInfo> & initInfo) : UIComponent
 void
 Toolbar::render(const UIShader & uiShader, const Position & parentPos) const
 {
-	uiShader.useDefault();
+	uiShader.icon.use();
 	const auto absPos = this->position + parentPos;
 	icons.apply(&UIComponent::render, uiShader, absPos);
 }
diff --git a/ui/window.h b/ui/window.h
index b3d3f68..0661915 100644
--- a/ui/window.h
+++ b/ui/window.h
@@ -10,8 +10,6 @@
 #include <special_members.hpp>
 #include <string>
 
-class SceneShader;
-
 class Window {
 public:
 	Window(size_t width, size_t height, const std::string & title);
@@ -30,7 +28,6 @@ public:
 protected:
 	[[nodiscard]] SDL_GLContext glContext() const;
 	virtual void render() const;
-	virtual const SceneShader & getShader() const = 0;
 
 	using SDL_WindowPtr = wrapped_ptrt<SDL_Window, SDL_CreateWindow, SDL_DestroyWindow>;
 	const glm::ivec2 size;
-- 
cgit v1.2.3