Added MathUtils class, reworked matrix4x4 and camera

This commit is contained in:
2026-08-19 10:27:00 -04:00
parent 741a5da1b6
commit a67ec7ef24
8 changed files with 229 additions and 19 deletions
+183 -11
View File
@@ -1,17 +1,189 @@
public class Worldbuilder.Camera : Object { using GL;
/**
* The position of the camera namespace Worldbuilder.Core {
*/
public Vector3 position { get; set; }
/** /**
* The direction the camera is facing. * Encapsulates a camera object. A camera contains a projection matrix and a view matrix.
*
* The main purpose of this class is to provide equivalents of legacy OpenGL functions
* removed in modern OpenGL. Advanced features like quaternion-based rotations are beyond
* the scope of this project.
*/ */
public Vector3 direction { get; set; } public class Camera : Object {
private Matrix4x4 projection_matrix;
private Matrix4x4 view_matrix;
private Matrix4x4 result_matrix;
private Matrix4x4 total_matrix;
public Camera (Vector3 position = Vector3 (), Vector3 direction = Vector3 (0, 0, -1)) { /**
this.position = position; * Instantiates a camera object.
this.direction = direction; *
} * The projection and view matrices are set to the identity matrix.
*/
public Camera() {
reset();
} }
private void update() {
result_matrix = projection_matrix;
result_matrix.multiply(view_matrix);
}
/**
* Resets both the projection matrix and the view matrix.
*/
public void reset() {
reset_projection();
reset_view();
}
/**
* Resets the projection matrix, setting it to the identity matrix.
*/
public void reset_projection() {
projection_matrix = Matrix4x4.identity();
update();
}
/**
* Resets the view matrix, setting it to the identity matrix.
*/
public void reset_view() {
view_matrix = Matrix4x4.identity();
update();
}
/**
* Applies the camera to the next model object that will be drawn, by
* multiplying the current projection and view matrices by the model matrix
* passed to the function (which specifies the offset and rotation of the model
* relative to the camera), and binds the matrix data to the specified
* shader uniform variable.
*
* @param uniform_id The shader uniform variable to bind to
* @param model_matrix The model matrix
*/
public void apply(int uniform_id, ref Matrix4x4 model_matrix) {
total_matrix = result_matrix;
total_matrix.multiply(model_matrix);
glUniformMatrix4fv(uniform_id, 1, (GL.GLboolean)false, total_matrix.data);
}
/**
* Sets up a perspective projection. The previous projection matrix is ignored and overwritten.
*
* Replicates the effects of the legacy ``glFrustum`` function within this camera.
* Refer to that function for the complete description of the projection parameters.
*
* @param left The coordinate of the left vertical clipping plane.
* @param right The coordinate of the right vertical clipping plane.
* @param bottom The coordinate of the bottom horizontal clipping plane.
* @param top The coordinate of the top horizontal clipping plane.
* @param near The coordinate of the near vertical clipping plane. Must be positive.
* @param far The coordinate of the far vertical clipping plane. Must be positive.
*/
public void set_frustum_projection(
float left,
float right,
float bottom,
float top,
float near, float far
) {
projection_matrix = Matrix4x4.from_data(
2f * near / (right - left), 0, (right + left) / (right - left), 0,
0, 2f * near / (top - bottom), (top + bottom) / (top - bottom), 0,
0, 0, -(far + near) / (far - near), -2f * far * near / (far - near),
0, 0, -1, 0
);
update();
}
/**
* Sets up a symmetrical perspective projection. The previous projection matrix is ignored and overwritten.
*
* Replicates the effects of the legacy ``gluPerspective`` function within this camera.
* Refer to that function for the complete description of the projection parameters.
*
* @param fovy_deg The field of view angle, in degrees, in the y direction.
* @param aspect The aspect ratio that determines the field of view in the x direction.
* The aspect ratio is the ratio of x (width) to y (height).
* @param near The coordinate of the near vertical clipping plane. Must be positive.
* @param far The coordinate of the far vertical clipping plane. Must be positive.
*/
public void set_perspective_projection(float fovy_deg, float aspect, float near, float far) {
var f = 1 / Math.tanf(MathUtils.DegToRad(fovy_deg / 2));
projection_matrix = Matrix4x4.from_data(
f / aspect, 0, 0, 0,
0, f, 0, 0,
0, 0, -(far + near) / (far - near), -2f * far * near / (far - near),
0, 0, -1, 0
);
update();
}
/**
* Sets up an orthogonal projection. The previous projection matrix is ignored and overwritten.
*
* Replicates the effects of the legacy ``glOrtho`` function within this camera.
* Refer to that function for the complete description of the projection parameters.
*
* @param left The coordinate of the left vertical clipping plane.
* @param right The coordinate of the right vertical clipping plane.
* @param bottom The coordinate of the bottom horizontal clipping plane.
* @param top The coordinate of the top horizontal clipping plane.
* @param near The coordinate of the near vertical clipping plane.
* @param far The coordinate of the far vertical clipping plane.
*/
public void set_ortho_projection(
float left,
float right,
float bottom,
float top,
float near, float far
) {
projection_matrix = Matrix4x4.from_data(
2f / (right - left), 0, 0, (right + left) / (right - left),
0, 2f / (top - bottom), 0, (top + bottom) / (top - bottom),
0, 0, -2f * far * near / (far - near), -(far + near) / (far - near),
0, 0, 0, 1
);
update();
}
/**
* Replicates the effects of the legacy ``gluLookAt`` function within this camera.
* Refer to that function for the complete description of how the camera is positioned.
*
* @param eye The 3D position of the camera
* @param center The 3D position of the point the camera is looking at
* @param up The up-direction
*/
public void look_at(ref Vector3 eye, ref Vector3 center, ref Vector3 up) {
Vector3 l = center;
l.subtract(eye);
l.normalized();
Vector3 uptemp = up;
uptemp.normalized();
Vector3 s = l.cross(uptemp);
Vector3 u = s.cross(l);
view_matrix = Matrix4x4.from_data(
s.x, s.y, s.z, 0,
u.x, u.y, u.z, 0,
-l.x, -l.y, -l.z, 0,
0, 0, 0, 1
);
Vector3 translation = Vector3();
translation.subtract(eye);
view_matrix = view_matrix.translate(translation.x, translation.y, translation.z);
update();
}
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace Worldbuilder.Core
{
public class MathUtils : Object
{
public static float DegToRad(float deg)
{
return deg * (float)Math.PI / 180f;
}
}
}
+28 -1
View File
@@ -1,7 +1,7 @@
/** /**
* A 4-by-4 matrix useful in OpenGL matrix operations. * A 4-by-4 matrix useful in OpenGL matrix operations.
*/ */
public struct Worldbuilder.Matrix4x4 public struct Worldbuilder.Core.Matrix4x4
{ {
public float data[4*4]; public float data[4*4];
@@ -17,6 +17,33 @@ public struct Worldbuilder.Matrix4x4
this (1.0f); this (1.0f);
} }
public Matrix4x4.from_data(
float a11, float a12, float a13, float a14,
float a21, float a22, float a23, float a24,
float a31, float a32, float a33, float a34,
float a41, float a42, float a43, float a44)
{
data[0] = a11;
data[1] = a21;
data[2] = a31;
data[3] = a41;
data[4] = a12;
data[5] = a22;
data[6] = a32;
data[7] = a42;
data[8] = a13;
data[9] = a23;
data[10] = a33;
data[11] = a43;
data[12] = a14;
data[13] = a24;
data[14] = a34;
data[15] = a44;
}
/** /**
* Construct a perspective transform. * Construct a perspective transform.
* *
+1 -1
View File
@@ -1,4 +1,4 @@
public class Worldbuilder.Texture2D : Object { public class Worldbuilder.Core.Texture2D : Object {
public string path { get; construct; } public string path { get; construct; }
public GL.uint id { get; private set; } public GL.uint id { get; private set; }
+1 -1
View File
@@ -1,4 +1,4 @@
public struct Worldbuilder.Vector2 { public struct Worldbuilder.Core.Vector2 {
public float x; public float x;
public float y; public float y;
+2 -2
View File
@@ -1,4 +1,5 @@
public struct Worldbuilder.Vector3 {
public struct Worldbuilder.Core.Vector3 {
public float x; public float x;
public float y; public float y;
public float z; public float z;
@@ -41,4 +42,3 @@ public struct Worldbuilder.Vector3 {
return @"<$x,$y,$z>"; return @"<$x,$y,$z>";
} }
} }
+1
View File
@@ -4,6 +4,7 @@ worldbuilder_sources = [
'window.vala', 'window.vala',
'scene_renderer.vala', 'scene_renderer.vala',
'core/math.vala',
'core/vector3.vala', 'core/vector3.vala',
'core/matrix4x4.vala', 'core/matrix4x4.vala',
'core/vector2.vala', 'core/vector2.vala',
-1
View File
@@ -12,7 +12,6 @@
<property name="content"> <property name="content">
<object class="AdwNavigationSplitView" id="split_view"> <object class="AdwNavigationSplitView" id="split_view">
<property name="show-content">content</property>
<property name="sidebar"> <property name="sidebar">
<object class="AdwNavigationPage"> <object class="AdwNavigationPage">
<property name="title" translatable="yes">Sidebar</property> <property name="title" translatable="yes">Sidebar</property>