From d2d9c33c7911f14395ea3b60d3c0ea9f9dcb1d01 Mon Sep 17 00:00:00 2001
From: heinezen <heinezen@hotmail.de>
Date: Sat, 20 Apr 2024 21:08:25 +0200
Subject: [PATCH 1/9] renderer: Compute camera scaling variables for uniform
 buffer,

---
 assets/shaders/terrain.vert.glsl              | 12 ++++++++--
 assets/shaders/world2d.vert.glsl              | 19 ++++++++++-----
 libopenage/renderer/camera/camera.cpp         | 23 +++++++++++--------
 libopenage/renderer/camera/camera.h           |  9 ++++++++
 libopenage/renderer/stages/camera/manager.cpp | 20 +++++++++++++---
 5 files changed, 63 insertions(+), 20 deletions(-)

diff --git a/assets/shaders/terrain.vert.glsl b/assets/shaders/terrain.vert.glsl
index aef9b45867..614f6f382b 100644
--- a/assets/shaders/terrain.vert.glsl
+++ b/assets/shaders/terrain.vert.glsl
@@ -7,9 +7,17 @@ out vec2 tex_pos;
 
 uniform mat4 model;
 
+// camera parameters for transforming the object position
+// and scaling the subtex to the correct size
 layout (std140) uniform camera {
-    mat4 view;
-    mat4 proj;
+    // view matrix (world to view space)
+    mat4  view;
+    // projection matrix (view to clip space)
+    mat4  proj;
+    // inverse zoom factor (1.0 / zoom)
+    float inv_zoom;
+    // inverse viewport size (1.0 / viewport size)
+    vec2  inv_viewport_size;
 };
 
 void main() {
diff --git a/assets/shaders/world2d.vert.glsl b/assets/shaders/world2d.vert.glsl
index 76cd6db34d..edb557e4a9 100644
--- a/assets/shaders/world2d.vert.glsl
+++ b/assets/shaders/world2d.vert.glsl
@@ -5,10 +5,17 @@ layout(location=1) in vec2 uv;
 
 out vec2 vert_uv;
 
-// transformation for object (not vertex!) position to clip space
+// camera parameters for transforming the object position
+// and scaling the subtex to the correct size
 layout (std140) uniform camera {
-    mat4 view;
-    mat4 proj;
+    // view matrix (world to view space)
+    mat4  view;
+    // projection matrix (view to clip space)
+    mat4  proj;
+    // inverse zoom factor (1.0 / zoom)
+    float inv_zoom;
+    // inverse viewport size (1.0 / viewport size)
+    vec2  inv_viewport_size;
 };
 
 // can be used to move the object position in world space _before_
@@ -51,9 +58,9 @@ void main() {
 
     // create a move matrix for positioning the vertices
     // uses the scale and the transformed object position in clip space
-    mat4 move = mat4(scale.x, 0.0, 0.0, 0.0,
-                     0.0, scale.y, 0.0, 0.0,
-                     0.0, 0.0, 1.0, 0.0,
+    mat4 move = mat4(scale.x,        0.0,            0.0,            0.0,
+                     0.0,            scale.y,        0.0,            0.0,
+                     0.0,            0.0,            1.0,            0.0,
                      obj_clip_pos.x, obj_clip_pos.y, obj_clip_pos.z, 1.0);
 
     // calculate the final vertex position
diff --git a/libopenage/renderer/camera/camera.cpp b/libopenage/renderer/camera/camera.cpp
index 604ddf440f..884aceca1b 100644
--- a/libopenage/renderer/camera/camera.cpp
+++ b/libopenage/renderer/camera/camera.cpp
@@ -1,4 +1,4 @@
-// Copyright 2022-2023 the openage authors. See copying.md for legal info.
+// Copyright 2022-2024 the openage authors. See copying.md for legal info.
 
 #include "camera.h"
 
@@ -28,10 +28,7 @@ Camera::Camera(const std::shared_ptr<Renderer> &renderer,
 	proj{Eigen::Matrix4f::Identity()} {
 	this->look_at_scene(Eigen::Vector3f(0.0f, 0.0f, 0.0f));
 
-	resources::UBOInput view_input{"view", resources::ubo_input_t::M4F32};
-	resources::UBOInput proj_input{"proj", resources::ubo_input_t::M4F32};
-	auto ubo_info = resources::UniformBufferInfo{resources::ubo_layout_t::STD140, {view_input, proj_input}};
-	this->uniform_buffer = renderer->add_uniform_buffer(ubo_info);
+	this->init_uniform_buffer(renderer);
 
 	log::log(INFO << "Created new camera at position "
 	              << "(" << this->scene_pos[0]
@@ -55,10 +52,7 @@ Camera::Camera(const std::shared_ptr<Renderer> &renderer,
 	viewport_changed{true},
 	view{Eigen::Matrix4f::Identity()},
 	proj{Eigen::Matrix4f::Identity()} {
-	resources::UBOInput view_input{"view", resources::ubo_input_t::M4F32};
-	resources::UBOInput proj_input{"proj", resources::ubo_input_t::M4F32};
-	auto ubo_info = resources::UniformBufferInfo{resources::ubo_layout_t::STD140, {view_input, proj_input}};
-	this->uniform_buffer = renderer->add_uniform_buffer(ubo_info);
+	this->init_uniform_buffer(renderer);
 
 	log::log(INFO << "Created new camera at position "
 	              << "(" << this->scene_pos[0]
@@ -269,4 +263,15 @@ const std::shared_ptr<renderer::UniformBuffer> &Camera::get_uniform_buffer() con
 	return this->uniform_buffer;
 }
 
+void Camera::init_uniform_buffer(const std::shared_ptr<Renderer> &renderer) {
+	resources::UBOInput view_input{"view", resources::ubo_input_t::M4F32};
+	resources::UBOInput proj_input{"proj", resources::ubo_input_t::M4F32};
+	resources::UBOInput inv_zoom_input{"inv_zoom", resources::ubo_input_t::F32};
+	resources::UBOInput inv_viewport_size{"inv_viewport_size", resources::ubo_input_t::V2F32};
+	auto ubo_info = resources::UniformBufferInfo{
+		resources::ubo_layout_t::STD140,
+		{view_input, proj_input, inv_zoom_input, inv_viewport_size}};
+	this->uniform_buffer = renderer->add_uniform_buffer(ubo_info);
+}
+
 } // namespace openage::renderer::camera
diff --git a/libopenage/renderer/camera/camera.h b/libopenage/renderer/camera/camera.h
index 9cdd559e6f..c8c5c23076 100644
--- a/libopenage/renderer/camera/camera.h
+++ b/libopenage/renderer/camera/camera.h
@@ -43,6 +43,7 @@ class Camera {
 	 * The camera uses default values. Its centered on the origin of the scene (0.0f, 0.0f, 0.0f)
 	 * and has a zoom level of 1.0f.
 	 *
+	 * @param renderer openage renderer instance.
 	 * @param viewport_size Initial viewport size of the camera (width x height).
 	 */
 	Camera(const std::shared_ptr<Renderer> &renderer,
@@ -51,6 +52,7 @@ class Camera {
 	/**
 	 * Create a new camera for the renderer.
 	 *
+	 * @param renderer openage renderer instance.
 	 * @param viewport_size Viewport size of the camera (width x height).
 	 * @param scene_pos Position of the camera in the scene.
 	 * @param zoom Zoom level of the camera (defaults to 1.0f).
@@ -187,6 +189,13 @@ class Camera {
 	const std::shared_ptr<renderer::UniformBuffer> &get_uniform_buffer() const;
 
 private:
+	/**
+	 * Create the uniform buffer for the camera.
+	 *
+	 * @param renderer openage renderer instance.
+	 */
+	void init_uniform_buffer(const std::shared_ptr<Renderer> &renderer);
+
 	/**
 	 * Position in the 3D scene.
 	 */
diff --git a/libopenage/renderer/stages/camera/manager.cpp b/libopenage/renderer/stages/camera/manager.cpp
index 580f7db597..39eddd2b52 100644
--- a/libopenage/renderer/stages/camera/manager.cpp
+++ b/libopenage/renderer/stages/camera/manager.cpp
@@ -1,4 +1,4 @@
-// Copyright 2023-2023 the openage authors. See copying.md for legal info.
+// Copyright 2023-2024 the openage authors. See copying.md for legal info.
 
 #include "manager.h"
 
@@ -97,11 +97,25 @@ void CameraManager::update_motion() {
 }
 
 void CameraManager::update_uniforms() {
+	// transformation matrices
 	this->uniforms->update(
 		"view",
-		camera->get_view_matrix(),
+		this->camera->get_view_matrix(),
 		"proj",
-		camera->get_projection_matrix());
+		this->camera->get_projection_matrix());
+
+	// zoom scaling
+	this->uniforms->update(
+		"inv_zoom",
+		1.0f / this->camera->get_zoom());
+
+	auto viewport_size = this->camera->get_viewport_size();
+	Eigen::Vector2f viewport_size_vec{
+		1.0f / static_cast<float>(viewport_size[0]),
+		1.0f / static_cast<float>(viewport_size[1])};
+	this->uniforms->update("inv_viewport_size", viewport_size_vec);
+
+	// update the uniform buffer
 	this->camera->get_uniform_buffer()->update_uniforms(this->uniforms);
 }
 

From f8d0f08a2c6d3a10b1ff106c658066cfe7db7094 Mon Sep 17 00:00:00 2001
From: heinezen <heinezen@hotmail.de>
Date: Sun, 21 Apr 2024 00:05:03 +0200
Subject: [PATCH 2/9] renderer: Calculate zoom scale from uniform buffer
 values.

---
 assets/shaders/world2d.vert.glsl              | 28 +++++++++++++++----
 libopenage/renderer/stages/world/object.cpp   | 19 +++++++++++--
 .../renderer/stages/world/render_stage.cpp    |  4 +--
 3 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/assets/shaders/world2d.vert.glsl b/assets/shaders/world2d.vert.glsl
index edb557e4a9..3c763d4ae3 100644
--- a/assets/shaders/world2d.vert.glsl
+++ b/assets/shaders/world2d.vert.glsl
@@ -36,21 +36,37 @@ uniform bool flip_y;
 
 // offset from the subtex anchor
 // moves the subtex relative to the subtex center
-uniform vec2 anchor_offset;
+// uniform vec2 anchor_offset;
 
 // scales the vertex positions so that they
 // match the subtex dimensions
-uniform vec2 scale;
+// uniform vec2 scale;
+
+uniform float scalefactor;
+uniform float zoom;
+uniform vec2 screen_size;
+uniform vec2 subtex_size;
+uniform vec2 anchor;
 
 void main() {
     // translate the position of the object from world space to clip space
     // this is the position where we want to draw the subtex in 2D
 	vec4 obj_clip_pos = proj * view * model * vec4(obj_world_position, 1.0);
 
+    float obj_scale = scalefactor * inv_zoom;
+    vec2 obj_scale_vec = vec2(
+        obj_scale * (subtex_size.x / screen_size.x),
+        obj_scale * (subtex_size.y / screen_size.y)
+    );
+    vec2 obj_anchor_vec = vec2(
+        obj_scale * (anchor.x / screen_size.x),
+        obj_scale * (anchor.y / screen_size.y)
+    );
+
     // if the subtex is flipped, we also need to flip the anchor offset
     // essentially, we invert the coordinates for the flipped axis
-    float anchor_x = float(flip_x) * -1.0 * anchor_offset.x + float(!flip_x) * anchor_offset.x;
-    float anchor_y = float(flip_y) * -1.0 * anchor_offset.y + float(!flip_y) * anchor_offset.y;
+    float anchor_x = float(flip_x) * -1.0 * obj_anchor_vec.x + float(!flip_x) * obj_anchor_vec.x;
+    float anchor_y = float(flip_y) * -1.0 * obj_anchor_vec.y + float(!flip_y) * obj_anchor_vec.y;
 
     // offset the clip position by the offset of the subtex anchor
     // imagine this as pinning the subtex to the object position at the subtex anchor point
@@ -58,8 +74,8 @@ void main() {
 
     // create a move matrix for positioning the vertices
     // uses the scale and the transformed object position in clip space
-    mat4 move = mat4(scale.x,        0.0,            0.0,            0.0,
-                     0.0,            scale.y,        0.0,            0.0,
+    mat4 move = mat4(obj_scale_vec.x,        0.0,            0.0,            0.0,
+                     0.0,            obj_scale_vec.y,        0.0,            0.0,
                      0.0,            0.0,            1.0,            0.0,
                      obj_clip_pos.x, obj_clip_pos.y, obj_clip_pos.z, 1.0);
 
diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp
index 23915d420f..7709d2223a 100644
--- a/libopenage/renderer/stages/world/object.cpp
+++ b/libopenage/renderer/stages/world/object.cpp
@@ -148,14 +148,29 @@ void WorldObject::update_uniforms(const time::time_t &time) {
 	auto scale_vec = Eigen::Vector2f{
 		scale * (static_cast<float>(subtex_size[0]) / screen_size[0]),
 		scale * (static_cast<float>(subtex_size[1]) / screen_size[1])};
-	this->uniforms->update(this->scale, scale_vec);
+	// this->uniforms->update(this->scale, scale_vec);
 
 	// Move subtexture in scene so that its anchor point is at the object's position
 	auto anchor = tex_info->get_subtex_info(subtex_idx).get_anchor_params();
 	auto anchor_offset = Eigen::Vector2f{
 		scale * (static_cast<float>(anchor[0]) / screen_size[0]),
 		scale * (static_cast<float>(anchor[1]) / screen_size[1])};
-	this->uniforms->update(this->anchor_offset, anchor_offset);
+	// this->uniforms->update(this->anchor_offset, anchor_offset);
+
+	this->uniforms->update("scalefactor", animation_info->get_scalefactor());
+	// this->uniforms->update("zoom", this->camera->get_zoom());
+	Eigen::Vector2f screen_size_vec{
+		static_cast<float>(screen_size[0]),
+		static_cast<float>(screen_size[1])};
+	this->uniforms->update("screen_size", screen_size_vec);
+	Eigen::Vector2f subtex_size_vec{
+		static_cast<float>(subtex_size[0]),
+		static_cast<float>(subtex_size[1])};
+	this->uniforms->update("subtex_size", subtex_size_vec);
+	Eigen::Vector2f anchor_vec{
+		static_cast<float>(anchor[0]),
+		static_cast<float>(anchor[1])};
+	this->uniforms->update("anchor", anchor_vec);
 }
 
 uint32_t WorldObject::get_id() {
diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp
index 85e5da7048..e97b52cabf 100644
--- a/libopenage/renderer/stages/world/render_stage.cpp
+++ b/libopenage/renderer/stages/world/render_stage.cpp
@@ -135,8 +135,8 @@ void WorldRenderStage::init_uniform_ids() {
 	WorldObject::flip_y = this->display_shader->get_uniform_id("flip_y");
 	WorldObject::tex = this->display_shader->get_uniform_id("tex");
 	WorldObject::tile_params = this->display_shader->get_uniform_id("tile_params");
-	WorldObject::scale = this->display_shader->get_uniform_id("scale");
-	WorldObject::anchor_offset = this->display_shader->get_uniform_id("anchor_offset");
+	// WorldObject::scale = this->display_shader->get_uniform_id("scale");
+	// WorldObject::anchor_offset = this->display_shader->get_uniform_id("anchor_offset");
 }
 
 } // namespace openage::renderer::world

From 81124bea3935d8713c99dd98b68400e83bdf6068 Mon Sep 17 00:00:00 2001
From: heinezen <heinezen@hotmail.de>
Date: Sun, 21 Apr 2024 15:17:38 +0200
Subject: [PATCH 3/9] renderer: Check if uniform buffer conforms to uniform
 block definition.

---
 libopenage/renderer/opengl/shader_program.cpp | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/libopenage/renderer/opengl/shader_program.cpp b/libopenage/renderer/opengl/shader_program.cpp
index 3ccd49ce80..31b0d17778 100644
--- a/libopenage/renderer/opengl/shader_program.cpp
+++ b/libopenage/renderer/opengl/shader_program.cpp
@@ -1,4 +1,4 @@
-// Copyright 2013-2023 the openage authors. See copying.md for legal info.
+// Copyright 2013-2024 the openage authors. See copying.md for legal info.
 
 #include "shader_program.h"
 
@@ -445,7 +445,12 @@ void GlShaderProgram::bind_uniform_buffer(const char *block_name, std::shared_pt
 	auto gl_buffer = std::dynamic_pointer_cast<GlUniformBuffer>(buffer);
 	auto &block = this->uniform_blocks[block_name];
 
-	// TODO: Check if the uniform buffer matches the block definition
+	// Check if the uniform buffer matches the block definition
+	for (auto const &pair : block.uniforms) {
+		auto const &unif = pair.second;
+		ENSURE(gl_buffer->has_uniform(pair.first.c_str()),
+		       "Uniform buffer does not contain uniform '" << pair.first << "' required by block " << block_name);
+	}
 
 	block.binding_point = gl_buffer->get_binding_point();
 	glUniformBlockBinding(*this->handle, block.index, block.binding_point);

From 24da277e08bed71bdf99acecf6557c59278c43dc Mon Sep 17 00:00:00 2001
From: heinezen <heinezen@hotmail.de>
Date: Sun, 21 Apr 2024 15:19:48 +0200
Subject: [PATCH 4/9] renderer: Fix alignment of uniform buffer inputs.

---
 libopenage/renderer/opengl/renderer.cpp       | 16 +++++++++++-----
 libopenage/renderer/resources/buffer_info.cpp | 10 ++++++++--
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/libopenage/renderer/opengl/renderer.cpp b/libopenage/renderer/opengl/renderer.cpp
index a06cc16edf..d26ba7b96c 100644
--- a/libopenage/renderer/opengl/renderer.cpp
+++ b/libopenage/renderer/opengl/renderer.cpp
@@ -1,4 +1,4 @@
-// Copyright 2017-2023 the openage authors. See copying.md for legal info.
+// Copyright 2017-2024 the openage authors. See copying.md for legal info.
 
 #include "renderer.h"
 
@@ -33,10 +33,10 @@ GlRenderer::GlRenderer(const std::shared_ptr<GlContext> &ctx,
 	// global GL alpha blending settings
 	// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	glBlendFuncSeparate(
-		GL_SRC_ALPHA, // source (overlaying) RGB factor
+		GL_SRC_ALPHA,           // source (overlaying) RGB factor
 		GL_ONE_MINUS_SRC_ALPHA, // destination (underlying) RGB factor
-		GL_ONE, // source (overlaying) alpha factor
-		GL_ONE_MINUS_SRC_ALPHA // destination (underlying) alpha factor
+		GL_ONE,                 // source (overlaying) alpha factor
+		GL_ONE_MINUS_SRC_ALPHA  // destination (underlying) alpha factor
 	);
 
 	// global GL depth testing settings
@@ -90,6 +90,11 @@ std::shared_ptr<UniformBuffer> GlRenderer::add_uniform_buffer(resources::Uniform
 	size_t offset = 0;
 	for (auto const &input : inputs) {
 		auto type = GL_UBO_INPUT_TYPE.get(input.type);
+		auto size = resources::UniformBufferInfo::get_size(input, info.get_layout());
+
+		// align offset to the size of the type
+		offset += offset % size;
+
 		uniforms.emplace(
 			std::make_pair(input.name,
 		                   GlInBlockUniform{type,
@@ -97,7 +102,8 @@ std::shared_ptr<UniformBuffer> GlRenderer::add_uniform_buffer(resources::Uniform
 		                                    resources::UniformBufferInfo::get_size(input, info.get_layout()),
 		                                    resources::UniformBufferInfo::get_stride_size(input.type, info.get_layout()),
 		                                    input.count}));
-		offset += resources::UniformBufferInfo::get_size(input, info.get_layout());
+
+		offset += size;
 	}
 
 	return std::make_shared<GlUniformBuffer>(this->gl_context,
diff --git a/libopenage/renderer/resources/buffer_info.cpp b/libopenage/renderer/resources/buffer_info.cpp
index c3215d63ba..de9a1751c8 100644
--- a/libopenage/renderer/resources/buffer_info.cpp
+++ b/libopenage/renderer/resources/buffer_info.cpp
@@ -1,4 +1,4 @@
-// Copyright 2023-2023 the openage authors. See copying.md for legal info.
+// Copyright 2023-2024 the openage authors. See copying.md for legal info.
 
 #include "buffer_info.h"
 
@@ -27,7 +27,13 @@ const std::vector<UBOInput> &UniformBufferInfo::get_inputs() const {
 size_t UniformBufferInfo::get_size() const {
 	size_t size = 0;
 	for (const auto &input : this->inputs) {
-		size += this->get_size(input, this->layout);
+		// size of the input type
+		size_t input_size = this->get_size(input, this->layout);
+
+		// inputs must additionally be aligned to a multiple of their size
+		size_t align_size = size % input_size;
+
+		size += input_size + align_size;
 	}
 	return size;
 }

From 67b0fa4b60f37c340f9cb13d1a4594985e769daa Mon Sep 17 00:00:00 2001
From: heinezen <heinezen@hotmail.de>
Date: Sun, 21 Apr 2024 15:20:36 +0200
Subject: [PATCH 5/9] renderer: Calculate subtex/anchor scale from uniform
 buffer values.

---
 assets/shaders/world2d.vert.glsl                  | 8 ++++----
 libopenage/renderer/stages/world/object.cpp       | 4 ++--
 libopenage/renderer/stages/world/render_stage.cpp | 2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/assets/shaders/world2d.vert.glsl b/assets/shaders/world2d.vert.glsl
index 3c763d4ae3..e3a8e4a773 100644
--- a/assets/shaders/world2d.vert.glsl
+++ b/assets/shaders/world2d.vert.glsl
@@ -55,12 +55,12 @@ void main() {
 
     float obj_scale = scalefactor * inv_zoom;
     vec2 obj_scale_vec = vec2(
-        obj_scale * (subtex_size.x / screen_size.x),
-        obj_scale * (subtex_size.y / screen_size.y)
+        obj_scale * (subtex_size.x * inv_viewport_size.x),
+        obj_scale * (subtex_size.y * inv_viewport_size.y)
     );
     vec2 obj_anchor_vec = vec2(
-        obj_scale * (anchor.x / screen_size.x),
-        obj_scale * (anchor.y / screen_size.y)
+        obj_scale * (anchor.x * inv_viewport_size.x),
+        obj_scale * (anchor.y * inv_viewport_size.y)
     );
 
     // if the subtex is flipped, we also need to flip the anchor offset
diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp
index 7709d2223a..93f7c7a8bb 100644
--- a/libopenage/renderer/stages/world/object.cpp
+++ b/libopenage/renderer/stages/world/object.cpp
@@ -1,4 +1,4 @@
-// Copyright 2022-2023 the openage authors. See copying.md for legal info.
+// Copyright 2022-2024 the openage authors. See copying.md for legal info.
 
 #include "object.h"
 
@@ -162,7 +162,7 @@ void WorldObject::update_uniforms(const time::time_t &time) {
 	Eigen::Vector2f screen_size_vec{
 		static_cast<float>(screen_size[0]),
 		static_cast<float>(screen_size[1])};
-	this->uniforms->update("screen_size", screen_size_vec);
+	// this->uniforms->update("screen_size", screen_size_vec);
 	Eigen::Vector2f subtex_size_vec{
 		static_cast<float>(subtex_size[0]),
 		static_cast<float>(subtex_size[1])};
diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp
index e97b52cabf..b107f8d863 100644
--- a/libopenage/renderer/stages/world/render_stage.cpp
+++ b/libopenage/renderer/stages/world/render_stage.cpp
@@ -1,4 +1,4 @@
-// Copyright 2022-2023 the openage authors. See copying.md for legal info.
+// Copyright 2022-2024 the openage authors. See copying.md for legal info.
 
 #include "render_stage.h"
 

From 154a2eef7d7cead774160dea258c3cd72f44c50f Mon Sep 17 00:00:00 2001
From: heinezen <heinezen@hotmail.de>
Date: Sun, 21 Apr 2024 15:30:18 +0200
Subject: [PATCH 6/9] renderer: Use uniform IDs to set new uniforms in world
 stage.

---
 assets/shaders/world2d.vert.glsl                  | 14 +++++++-------
 libopenage/renderer/stages/world/object.cpp       |  6 +++---
 libopenage/renderer/stages/world/object.h         |  3 +++
 libopenage/renderer/stages/world/render_stage.cpp |  3 +++
 4 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/assets/shaders/world2d.vert.glsl b/assets/shaders/world2d.vert.glsl
index e3a8e4a773..86a6565656 100644
--- a/assets/shaders/world2d.vert.glsl
+++ b/assets/shaders/world2d.vert.glsl
@@ -42,25 +42,25 @@ uniform bool flip_y;
 // match the subtex dimensions
 // uniform vec2 scale;
 
-uniform float scalefactor;
+uniform float scale;
 uniform float zoom;
 uniform vec2 screen_size;
 uniform vec2 subtex_size;
-uniform vec2 anchor;
+uniform vec2 anchor_offset;
 
 void main() {
     // translate the position of the object from world space to clip space
     // this is the position where we want to draw the subtex in 2D
 	vec4 obj_clip_pos = proj * view * model * vec4(obj_world_position, 1.0);
 
-    float obj_scale = scalefactor * inv_zoom;
+    float obj_scale = scale * inv_zoom;
     vec2 obj_scale_vec = vec2(
-        obj_scale * (subtex_size.x * inv_viewport_size.x),
-        obj_scale * (subtex_size.y * inv_viewport_size.y)
+        obj_scale * subtex_size.x * inv_viewport_size.x,
+        obj_scale * subtex_size.y * inv_viewport_size.y
     );
     vec2 obj_anchor_vec = vec2(
-        obj_scale * (anchor.x * inv_viewport_size.x),
-        obj_scale * (anchor.y * inv_viewport_size.y)
+        obj_scale * anchor_offset.x * inv_viewport_size.x,
+        obj_scale * anchor_offset.y * inv_viewport_size.y
     );
 
     // if the subtex is flipped, we also need to flip the anchor offset
diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp
index 93f7c7a8bb..e26aaab9e7 100644
--- a/libopenage/renderer/stages/world/object.cpp
+++ b/libopenage/renderer/stages/world/object.cpp
@@ -157,7 +157,7 @@ void WorldObject::update_uniforms(const time::time_t &time) {
 		scale * (static_cast<float>(anchor[1]) / screen_size[1])};
 	// this->uniforms->update(this->anchor_offset, anchor_offset);
 
-	this->uniforms->update("scalefactor", animation_info->get_scalefactor());
+	this->uniforms->update(this->scale, animation_info->get_scalefactor());
 	// this->uniforms->update("zoom", this->camera->get_zoom());
 	Eigen::Vector2f screen_size_vec{
 		static_cast<float>(screen_size[0]),
@@ -166,11 +166,11 @@ void WorldObject::update_uniforms(const time::time_t &time) {
 	Eigen::Vector2f subtex_size_vec{
 		static_cast<float>(subtex_size[0]),
 		static_cast<float>(subtex_size[1])};
-	this->uniforms->update("subtex_size", subtex_size_vec);
+	this->uniforms->update(this->subtex_size, subtex_size_vec);
 	Eigen::Vector2f anchor_vec{
 		static_cast<float>(anchor[0]),
 		static_cast<float>(anchor[1])};
-	this->uniforms->update("anchor", anchor_vec);
+	this->uniforms->update(this->anchor_offset, anchor_vec);
 }
 
 uint32_t WorldObject::get_id() {
diff --git a/libopenage/renderer/stages/world/object.h b/libopenage/renderer/stages/world/object.h
index e2fc865dd6..eb075dd4c3 100644
--- a/libopenage/renderer/stages/world/object.h
+++ b/libopenage/renderer/stages/world/object.h
@@ -131,7 +131,10 @@ class WorldObject {
 	inline static uniform_id_t flip_y;
 	inline static uniform_id_t tex;
 	inline static uniform_id_t tile_params;
+	// inline static uniform_id_t scale;
+	// inline static uniform_id_t anchor_offset;
 	inline static uniform_id_t scale;
+	inline static uniform_id_t subtex_size;
 	inline static uniform_id_t anchor_offset;
 
 private:
diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp
index b107f8d863..c8c8770414 100644
--- a/libopenage/renderer/stages/world/render_stage.cpp
+++ b/libopenage/renderer/stages/world/render_stage.cpp
@@ -137,6 +137,9 @@ void WorldRenderStage::init_uniform_ids() {
 	WorldObject::tile_params = this->display_shader->get_uniform_id("tile_params");
 	// WorldObject::scale = this->display_shader->get_uniform_id("scale");
 	// WorldObject::anchor_offset = this->display_shader->get_uniform_id("anchor_offset");
+	WorldObject::scale = this->display_shader->get_uniform_id("scale");
+	WorldObject::subtex_size = this->display_shader->get_uniform_id("subtex_size");
+	WorldObject::anchor_offset = this->display_shader->get_uniform_id("anchor_offset");
 }
 
 } // namespace openage::renderer::world

From 080849f5d9689f52d07b13c13246cc296f4b68b2 Mon Sep 17 00:00:00 2001
From: heinezen <heinezen@hotmail.de>
Date: Sun, 21 Apr 2024 16:01:46 +0200
Subject: [PATCH 7/9] renderer: Remove unused uniform code from world stage.

---
 assets/shaders/world2d.vert.glsl              | 54 ++++++++++++-------
 libopenage/renderer/stages/world/object.cpp   | 38 +++++--------
 libopenage/renderer/stages/world/object.h     |  2 -
 .../renderer/stages/world/render_stage.cpp    |  2 -
 4 files changed, 46 insertions(+), 50 deletions(-)

diff --git a/assets/shaders/world2d.vert.glsl b/assets/shaders/world2d.vert.glsl
index 86a6565656..3b698b39c1 100644
--- a/assets/shaders/world2d.vert.glsl
+++ b/assets/shaders/world2d.vert.glsl
@@ -13,6 +13,8 @@ layout (std140) uniform camera {
     // projection matrix (view to clip space)
     mat4  proj;
     // inverse zoom factor (1.0 / zoom)
+    // high zoom = upscale subtex
+    // low zoom = downscale subtex
     float inv_zoom;
     // inverse viewport size (1.0 / viewport size)
     vec2  inv_viewport_size;
@@ -34,18 +36,21 @@ uniform bool flip_y;
 // parameters for scaling and moving the subtex
 // to the correct position in clip space
 
-// offset from the subtex anchor
-// moves the subtex relative to the subtex center
-// uniform vec2 anchor_offset;
-
+// animation scalefactor
 // scales the vertex positions so that they
 // match the subtex dimensions
-// uniform vec2 scale;
-
+//
+// high animation scale = downscale subtex
+// low animation scale = upscale subtex
 uniform float scale;
-uniform float zoom;
-uniform vec2 screen_size;
+
+// size of the subtex (in pixels)
 uniform vec2 subtex_size;
+
+// offset of the subtex anchor point
+// from the subtex center (in pixels)
+// used to move the subtex so that the anchor point
+// is at the object position
 uniform vec2 anchor_offset;
 
 void main() {
@@ -53,29 +58,38 @@ void main() {
     // this is the position where we want to draw the subtex in 2D
 	vec4 obj_clip_pos = proj * view * model * vec4(obj_world_position, 1.0);
 
-    float obj_scale = scale * inv_zoom;
-    vec2 obj_scale_vec = vec2(
-        obj_scale * subtex_size.x * inv_viewport_size.x,
-        obj_scale * subtex_size.y * inv_viewport_size.y
+    // subtex has to be scaled to account for the zoom factor
+    // and the animation scale factor. essentially this is (animation scale / zoom).
+    float zoom_scale = scale * inv_zoom;
+
+    // Scale the subtex vertices
+    // we have to account for the viewport size to get the correct dimensions
+    // and then scale the subtex to the zoom factor to get the correct size
+    vec2 vert_scale = vec2(
+        zoom_scale * subtex_size.x * inv_viewport_size.x,
+        zoom_scale * subtex_size.y * inv_viewport_size.y
     );
-    vec2 obj_anchor_vec = vec2(
-        obj_scale * anchor_offset.x * inv_viewport_size.x,
-        obj_scale * anchor_offset.y * inv_viewport_size.y
+
+    // Scale the anchor offset with the same method as above
+    // to get the correct anchor position in the viewport
+    vec2 anchor_scale = vec2(
+        zoom_scale * anchor_offset.x * inv_viewport_size.x,
+        zoom_scale * anchor_offset.y * inv_viewport_size.y
     );
 
     // if the subtex is flipped, we also need to flip the anchor offset
     // essentially, we invert the coordinates for the flipped axis
-    float anchor_x = float(flip_x) * -1.0 * obj_anchor_vec.x + float(!flip_x) * obj_anchor_vec.x;
-    float anchor_y = float(flip_y) * -1.0 * obj_anchor_vec.y + float(!flip_y) * obj_anchor_vec.y;
+    float anchor_x = float(flip_x) * -1.0 * anchor_scale.x + float(!flip_x) * anchor_scale.x;
+    float anchor_y = float(flip_y) * -1.0 * anchor_scale.y + float(!flip_y) * anchor_scale.y;
 
     // offset the clip position by the offset of the subtex anchor
     // imagine this as pinning the subtex to the object position at the subtex anchor point
     obj_clip_pos += vec4(anchor_x, anchor_y, 0.0, 0.0);
 
     // create a move matrix for positioning the vertices
-    // uses the scale and the transformed object position in clip space
-    mat4 move = mat4(obj_scale_vec.x,        0.0,            0.0,            0.0,
-                     0.0,            obj_scale_vec.y,        0.0,            0.0,
+    // uses the vert scale and the transformed object position in clip space
+    mat4 move = mat4(vert_scale.x,   0.0,            0.0,            0.0,
+                     0.0,            vert_scale.y,   0.0,            0.0,
                      0.0,            0.0,            1.0,            0.0,
                      obj_clip_pos.x, obj_clip_pos.y, obj_clip_pos.z, 1.0);
 
diff --git a/libopenage/renderer/stages/world/object.cpp b/libopenage/renderer/stages/world/object.cpp
index e26aaab9e7..c58e9faa98 100644
--- a/libopenage/renderer/stages/world/object.cpp
+++ b/libopenage/renderer/stages/world/object.cpp
@@ -138,39 +138,25 @@ void WorldObject::update_uniforms(const time::time_t &time) {
 	auto coords = tex_info->get_subtex_info(subtex_idx).get_tile_params();
 	this->uniforms->update(this->tile_params, coords);
 
-	// scale and keep width x height ratio of texture
-	// when the viewport size changes
-	auto scale = animation_info->get_scalefactor() / this->camera->get_zoom();
-	auto screen_size = this->camera->get_viewport_size();
-	auto subtex_size = tex_info->get_subtex_info(subtex_idx).get_size();
-
-	// Scaling with viewport size and zoom
-	auto scale_vec = Eigen::Vector2f{
-		scale * (static_cast<float>(subtex_size[0]) / screen_size[0]),
-		scale * (static_cast<float>(subtex_size[1]) / screen_size[1])};
-	// this->uniforms->update(this->scale, scale_vec);
+	// Animation scale factor
+	// Scales the subtex up or down in the shader
+	auto scale = animation_info->get_scalefactor();
+	this->uniforms->update(this->scale, scale);
 
-	// Move subtexture in scene so that its anchor point is at the object's position
-	auto anchor = tex_info->get_subtex_info(subtex_idx).get_anchor_params();
-	auto anchor_offset = Eigen::Vector2f{
-		scale * (static_cast<float>(anchor[0]) / screen_size[0]),
-		scale * (static_cast<float>(anchor[1]) / screen_size[1])};
-	// this->uniforms->update(this->anchor_offset, anchor_offset);
-
-	this->uniforms->update(this->scale, animation_info->get_scalefactor());
-	// this->uniforms->update("zoom", this->camera->get_zoom());
-	Eigen::Vector2f screen_size_vec{
-		static_cast<float>(screen_size[0]),
-		static_cast<float>(screen_size[1])};
-	// this->uniforms->update("screen_size", screen_size_vec);
+	// Subtexture size in pixels
+	auto subtex_size = tex_info->get_subtex_info(subtex_idx).get_size();
 	Eigen::Vector2f subtex_size_vec{
 		static_cast<float>(subtex_size[0]),
 		static_cast<float>(subtex_size[1])};
 	this->uniforms->update(this->subtex_size, subtex_size_vec);
-	Eigen::Vector2f anchor_vec{
+
+	// Anchor point offset (in pixels)
+	// moves the subtex in the shader so that the anchor point is at the object's position
+	auto anchor = tex_info->get_subtex_info(subtex_idx).get_anchor_params();
+	Eigen::Vector2f anchor_offset{
 		static_cast<float>(anchor[0]),
 		static_cast<float>(anchor[1])};
-	this->uniforms->update(this->anchor_offset, anchor_vec);
+	this->uniforms->update(this->anchor_offset, anchor_offset);
 }
 
 uint32_t WorldObject::get_id() {
diff --git a/libopenage/renderer/stages/world/object.h b/libopenage/renderer/stages/world/object.h
index eb075dd4c3..a34a0c690c 100644
--- a/libopenage/renderer/stages/world/object.h
+++ b/libopenage/renderer/stages/world/object.h
@@ -131,8 +131,6 @@ class WorldObject {
 	inline static uniform_id_t flip_y;
 	inline static uniform_id_t tex;
 	inline static uniform_id_t tile_params;
-	// inline static uniform_id_t scale;
-	// inline static uniform_id_t anchor_offset;
 	inline static uniform_id_t scale;
 	inline static uniform_id_t subtex_size;
 	inline static uniform_id_t anchor_offset;
diff --git a/libopenage/renderer/stages/world/render_stage.cpp b/libopenage/renderer/stages/world/render_stage.cpp
index c8c8770414..d24bb5f896 100644
--- a/libopenage/renderer/stages/world/render_stage.cpp
+++ b/libopenage/renderer/stages/world/render_stage.cpp
@@ -135,8 +135,6 @@ void WorldRenderStage::init_uniform_ids() {
 	WorldObject::flip_y = this->display_shader->get_uniform_id("flip_y");
 	WorldObject::tex = this->display_shader->get_uniform_id("tex");
 	WorldObject::tile_params = this->display_shader->get_uniform_id("tile_params");
-	// WorldObject::scale = this->display_shader->get_uniform_id("scale");
-	// WorldObject::anchor_offset = this->display_shader->get_uniform_id("anchor_offset");
 	WorldObject::scale = this->display_shader->get_uniform_id("scale");
 	WorldObject::subtex_size = this->display_shader->get_uniform_id("subtex_size");
 	WorldObject::anchor_offset = this->display_shader->get_uniform_id("anchor_offset");

From a19b42b4aaa98524a44856bfbfb6cdf345c2bb89 Mon Sep 17 00:00:00 2001
From: heinezen <heinezen@hotmail.de>
Date: Sun, 21 Apr 2024 16:03:57 +0200
Subject: [PATCH 8/9] renderer: Use more compact shader code.

---
 assets/shaders/world2d.vert.glsl | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/assets/shaders/world2d.vert.glsl b/assets/shaders/world2d.vert.glsl
index 3b698b39c1..7987d40ec3 100644
--- a/assets/shaders/world2d.vert.glsl
+++ b/assets/shaders/world2d.vert.glsl
@@ -65,17 +65,11 @@ void main() {
     // Scale the subtex vertices
     // we have to account for the viewport size to get the correct dimensions
     // and then scale the subtex to the zoom factor to get the correct size
-    vec2 vert_scale = vec2(
-        zoom_scale * subtex_size.x * inv_viewport_size.x,
-        zoom_scale * subtex_size.y * inv_viewport_size.y
-    );
+    vec2 vert_scale = zoom_scale * subtex_size * inv_viewport_size;
 
     // Scale the anchor offset with the same method as above
     // to get the correct anchor position in the viewport
-    vec2 anchor_scale = vec2(
-        zoom_scale * anchor_offset.x * inv_viewport_size.x,
-        zoom_scale * anchor_offset.y * inv_viewport_size.y
-    );
+    vec2 anchor_scale = zoom_scale * anchor_offset * inv_viewport_size;
 
     // if the subtex is flipped, we also need to flip the anchor offset
     // essentially, we invert the coordinates for the flipped axis

From 185dd98ed9e01c97740e67e89a72feaa3c95a41f Mon Sep 17 00:00:00 2001
From: heinezen <heinezen@hotmail.de>
Date: Sun, 21 Apr 2024 16:08:59 +0200
Subject: [PATCH 9/9] renderer: Add new camera uniforms in stresstest 0.

---
 libopenage/renderer/demo/stresstest_0.cpp | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/libopenage/renderer/demo/stresstest_0.cpp b/libopenage/renderer/demo/stresstest_0.cpp
index ce7da14948..01169b0849 100644
--- a/libopenage/renderer/demo/stresstest_0.cpp
+++ b/libopenage/renderer/demo/stresstest_0.cpp
@@ -49,7 +49,14 @@ void renderer_stresstest_0(const util::Path &path) {
 		"view",
 		camera->get_view_matrix(),
 		"proj",
-		camera->get_projection_matrix());
+		camera->get_projection_matrix(),
+		"inv_zoom",
+		1.0f / camera->get_zoom());
+	auto viewport_size = camera->get_viewport_size();
+	Eigen::Vector2f viewport_size_vec{
+		1.0f / static_cast<float>(viewport_size[0]),
+		1.0f / static_cast<float>(viewport_size[1])};
+	cam_unifs->update("inv_viewport_size", viewport_size_vec);
 	camera->get_uniform_buffer()->update_uniforms(cam_unifs);
 
 	// Render stages