From a1e581aff6941f668dd691d1e7af8f49a269d7d7 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 07:13:37 -0400 Subject: [PATCH 01/23] Added 4d matrix test --- tests/__init__.py | 0 tests/requirements.txt | 1 + tests/test_matrix_functions.py | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/__init__.py create mode 100644 tests/requirements.txt create mode 100644 tests/test_matrix_functions.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000..55b033e --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1 @@ +pytest \ No newline at end of file diff --git a/tests/test_matrix_functions.py b/tests/test_matrix_functions.py new file mode 100644 index 0000000..8cab2d9 --- /dev/null +++ b/tests/test_matrix_functions.py @@ -0,0 +1,40 @@ +from matrix_functions import * + +def init_vector(): + return np.array([1,2,3,4,1]) #x,y,z,w,h +def test_translate(): + vec = init_vector() + np.testing.assert_array_equal(vec @ translate([0,0,0,0]), init_vector()) + np.testing.assert_array_equal(vec @ translate([5,1,2,8]), np.array([6,3,5,12,1])) + np.testing.assert_array_equal(vec @ translate([-5,-1,-2,-8]), np.array([-4,1,1,-4,1])) + +def test_scale(): + vec = init_vector() + np.testing.assert_array_equal(vec @ scale(1), init_vector()) + np.testing.assert_array_equal(vec @ scale(2), np.array([2,4,6,8,1])) + +def test_rotate(): + vec = init_vector() + np.testing.assert_array_almost_equal(vec @ rotate_zw(0), init_vector()) + + np.testing.assert_array_almost_equal(vec @ rotate_zw(np.pi/2), np.array([-2,1,3,4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_yw(np.pi/2), np.array([-3,2,1,4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_yz(np.pi/2), np.array([-4,2,3,1,1])) + np.testing.assert_array_almost_equal(vec @ rotate_xw(np.pi/2), np.array([1,-3,2,4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_xz(np.pi/2), np.array([1,-4,3,2,1])) + np.testing.assert_array_almost_equal(vec @ rotate_xy(np.pi/2), np.array([1,2,-4,3,1])) + + + np.testing.assert_array_almost_equal(vec @ rotate_zw(-np.pi/2), np.array([2,-1,3,4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_yw(-np.pi/2), np.array([3,2,-1,4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_yz(-np.pi/2), np.array([4,2,3,-1,1])) + np.testing.assert_array_almost_equal(vec @ rotate_xw(-np.pi/2), np.array([1,3,-2,4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_xz(-np.pi/2), np.array([1,4,3,-2,1])) + np.testing.assert_array_almost_equal(vec @ rotate_xy(-np.pi/2), np.array([1,2,4,-3,1])) + + np.testing.assert_array_almost_equal(vec @ rotate_zw(np.pi), np.array([-1,-2,3,4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_yw(np.pi), np.array([-1,2,-3,4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_yz(np.pi), np.array([-1,2,3,-4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_xw(np.pi), np.array([1,-2,-3,4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_xz(np.pi), np.array([1,-2,3,-4,1])) + np.testing.assert_array_almost_equal(vec @ rotate_xy(np.pi), np.array([1,2,-3,-4,1])) \ No newline at end of file From 468033328e21508c6e34328330d0fa7918841924 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 07:17:47 -0400 Subject: [PATCH 02/23] Added 4D matrix functions --- matrix_functions.py | 74 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/matrix_functions.py b/matrix_functions.py index 21aab07..ee0ecb3 100644 --- a/matrix_functions.py +++ b/matrix_functions.py @@ -3,12 +3,13 @@ def translate(pos): - tx, ty, tz = pos + tx, ty, tz, tw = pos return np.array([ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [tx, ty, tz, 1] + [1, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + [tx, ty, tz, tw, 1] ]) @@ -41,8 +42,63 @@ def rotate_z(a): def scale(n): return np.array([ - [n, 0, 0, 0], - [0, n, 0, 0], - [0, 0, n, 0], - [0, 0, 0, 1] + [n, 0, 0, 0, 0], + [0, n, 0, 0, 0], + [0, 0, n, 0, 0], + [0, 0, 0, n, 0], + [0, 0, 0, 0, 1] + ]) + +def rotate_zw(a): + return np.array([ + [math.cos(a), math.sin(a), 0, 0, 0], + [-math.sin(a), math.cos(a), 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] + ]) + +def rotate_yw(a): + return np.array([ + [math.cos(a), 0, math.sin(a), 0, 0], + [0, 1, 0, 0, 0], + [-math.sin(a), 0, math.cos(a), 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] + ]) + +def rotate_yz(a): + return np.array([ + [math.cos(a), 0, 0, math.sin(a), 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + [-math.sin(a), 0, 0, math.cos(a), 0], + [0, 0, 0, 0, 1] + ]) + +def rotate_xw(a): + return np.array([ + [1, 0, 0, 0, 0], + [0, math.cos(a), math.sin(a), 0, 0], + [0, -math.sin(a), math.cos(a), 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] + ]) + +def rotate_xz(a): + return np.array([ + [1, 0, 0, 0, 0], + [0, math.cos(a), 0, math.sin(a), 0], + [0, 0, 1, 0, 0], + [0, -math.sin(a), 0, math.cos(a), 0], + [0, 0, 0, 0, 1] + ]) + +def rotate_xy(a): + return np.array([ + [1, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, math.cos(a), math.sin(a), 0], + [0, 0, -math.sin(a), math.cos(a), 0], + [0, 0, 0, 0, 1] ]) \ No newline at end of file From 5a492f2807e02a5c1ee7fc5c2eb67fe363234948 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 07:18:52 -0400 Subject: [PATCH 03/23] Added Tesseract object --- resources/tesseract.obj4 | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 resources/tesseract.obj4 diff --git a/resources/tesseract.obj4 b/resources/tesseract.obj4 new file mode 100644 index 0000000..8c9133f --- /dev/null +++ b/resources/tesseract.obj4 @@ -0,0 +1,81 @@ +# +# object tesseract +# + +v 0.0000 0.0000 0.0000 0.0000 +v 0.0000 1.0000 0.0000 0.0000 +v 1.0000 1.0000 0.0000 0.0000 +v 1.0000 0.0000 0.0000 0.0000 +v 0.0000 0.0000 1.0000 0.0000 +v 0.0000 1.0000 1.0000 0.0000 +v 1.0000 1.0000 1.0000 0.0000 +v 1.0000 0.0000 1.0000 0.0000 +v 0.0000 0.0000 0.0000 1.0000 +v 0.0000 1.0000 0.0000 1.0000 +v 1.0000 1.0000 0.0000 1.0000 +v 1.0000 0.0000 0.0000 1.0000 +v 0.0000 0.0000 1.0000 1.0000 +v 0.0000 1.0000 1.0000 1.0000 +v 1.0000 1.0000 1.0000 1.0000 +v 1.0000 0.0000 1.0000 1.0000 +# 16 vertices + +f 1 2 3 4 +f 3 4 8 7 +f 2 3 7 6 +f 1 2 6 5 +f 1 4 8 5 +f 5 8 7 6 +f 9 10 11 12 +f 11 12 16 15 +f 10 11 15 14 +f 9 10 14 13 +f 9 12 16 13 +f 13 16 15 14 +f 3 4 8 7 +f 8 7 15 16 +f 4 8 16 12 +f 3 4 12 11 +f 3 7 15 11 +f 11 15 16 12 +f 1 2 3 4 +f 3 4 12 11 +f 2 3 11 10 +f 1 2 10 9 +f 1 4 12 9 +f 9 12 11 10 +f 2 3 7 6 +f 7 6 14 15 +f 3 7 15 11 +f 2 3 11 10 +f 2 6 14 10 +f 10 14 15 11 +f 1 2 6 5 +f 6 5 13 14 +f 2 6 14 10 +f 1 2 10 9 +f 1 5 13 9 +f 9 13 14 10 +f 5 6 7 8 +f 7 8 16 15 +f 6 7 15 14 +f 5 6 14 13 +f 5 8 16 13 +f 13 16 15 14 +f 1 4 8 5 +f 8 5 13 16 +f 4 8 16 12 +f 1 4 12 9 +f 1 5 13 9 +f 9 13 16 12 + +c 1 2 3 4 5 6 +c 7 8 9 10 11 12 +c 13 14 15 16 17 18 +c 19 20 21 22 23 24 +c 25 26 27 28 29 30 +c 31 32 33 34 35 36 +c 37 38 39 40 41 42 +c 43 44 45 46 47 48 + +# 8 cells \ No newline at end of file From ad57f8d3775503af993209fc5f24e6547a7c8272 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 07:21:52 -0400 Subject: [PATCH 04/23] Added depth fov --- camera.py | 1 + main.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/camera.py b/camera.py index 384ef59..97b73b4 100644 --- a/camera.py +++ b/camera.py @@ -10,6 +10,7 @@ def __init__(self, render, position): self.right = np.array([1, 0, 0, 1]) self.h_fov = math.pi / 3 self.v_fov = self.h_fov * (render.HEIGHT / render.WIDTH) + self.d_fov = self.h_fov * (render.DEPTH / render.WIDTH) self.near_plane = 0.1 self.far_plane = 100 self.moving_speed = 0.3 diff --git a/main.py b/main.py index 2bdb689..c3243f1 100644 --- a/main.py +++ b/main.py @@ -8,7 +8,8 @@ class SoftwareRender: def __init__(self): pg.init() self.RES = self.WIDTH, self.HEIGHT = 1600, 900 - self.H_WIDTH, self.H_HEIGHT = self.WIDTH // 2, self.HEIGHT // 2 + self.DEPTH = 1600 + self.H_WIDTH, self.H_HEIGHT, self.H_DEPTH = self.WIDTH // 2, self.HEIGHT // 2, self.DEPTH //2 self.FPS = 60 self.screen = pg.display.set_mode(self.RES) self.clock = pg.time.Clock() From 851a4df2a001c2511c0c84b3a90e514d3a831fdb Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 07:40:27 -0400 Subject: [PATCH 05/23] Added 4th dimension to projection matrix --- projection.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/projection.py b/projection.py index 408af86..c214769 100644 --- a/projection.py +++ b/projection.py @@ -10,22 +10,27 @@ def __init__(self, render): LEFT = -RIGHT TOP = math.tan(render.camera.v_fov / 2) BOTTOM = -TOP + THERE = math.tan(render.camera.d_fov / 2) + HERE = -THERE m00 = 2 / (RIGHT - LEFT) m11 = 2 / (TOP - BOTTOM) - m22 = (FAR + NEAR) / (FAR - NEAR) - m32 = -2 * NEAR * FAR / (FAR - NEAR) + m22 = 2 / (THERE - HERE) + m33 = (FAR + NEAR) / (FAR - NEAR) + m43 = -2 * NEAR * FAR / (FAR - NEAR) self.projection_matrix = np.array([ - [m00, 0, 0, 0], - [0, m11, 0, 0], - [0, 0, m22, 1], - [0, 0, m32, 0] + [m00, 0, 0, 0, 0], + [0, m11, 0, 0, 0], + [0, 0, m22, 0, 1], + [0, 0, 0, m33, 1] + [0, 0, 0, m43, 0] ]) - HW, HH = render.H_WIDTH, render.H_HEIGHT + HW, HH, HD = render.H_WIDTH, render.H_HEIGHT, render.H_DEPTH self.to_screen_matrix = np.array([ - [HW, 0, 0, 0], - [0, -HH, 0, 0], - [0, 0, 1, 0], - [HW, HH, 0, 1] + [HW, 0, 0, 0, 0], + [0, -HH, 0, 0, 0], + [0, 0, HD, 0, 0], + [0, 0, 0, 1, 0], + [HW, HH, HD, 0, 1] ]) \ No newline at end of file From 31ed1a760020568e5eb1eb2dcbcd1352de41842b Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 07:46:17 -0400 Subject: [PATCH 06/23] Fixed 3D rotation matrix to handle 4D vector --- matrix_functions.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/matrix_functions.py b/matrix_functions.py index ee0ecb3..fd8073f 100644 --- a/matrix_functions.py +++ b/matrix_functions.py @@ -15,28 +15,31 @@ def translate(pos): def rotate_x(a): return np.array([ - [1, 0, 0, 0], - [0, math.cos(a), math.sin(a), 0], - [0, -math.sin(a), math.cos(a), 0], - [0, 0, 0, 1] + [1, 0, 0, 0, 0], + [0, math.cos(a), math.sin(a), 0, 0], + [0, -math.sin(a), math.cos(a), 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] ]) def rotate_y(a): return np.array([ - [math.cos(a), 0, -math.sin(a), 0], - [0, 1, 0, 0], - [math.sin(a), 0, math.cos(a), 0], - [0, 0, 0, 1] + [math.cos(a), 0, -math.sin(a), 0, 0], + [0, 1, 0, 0, 0], + [math.sin(a), 0, math.cos(a), 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] ]) def rotate_z(a): return np.array([ - [math.cos(a), math.sin(a), 0, 0], - [-math.sin(a), math.cos(a), 0, 0], - [0, 0, 1, 0], - [0, 0, 0, 1] + [math.cos(a), math.sin(a), 0, 0, 0], + [-math.sin(a), math.cos(a), 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] ]) From 519c6dffe31159a4d2379e7c9fef12af1f54e9a5 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 07:46:51 -0400 Subject: [PATCH 07/23] Added a default value of 0 for the 4th dim if importing a 3d object --- main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index c3243f1..7be453a 100644 --- a/main.py +++ b/main.py @@ -23,10 +23,13 @@ def create_objects(self): def get_object_from_file(self, filename): vertex, faces = [], [] + extra_dim = [0, 1] + if filename[-5:] == '.obj4': + extra_dim = [1] with open(filename) as f: for line in f: if line.startswith('v '): - vertex.append([float(i) for i in line.split()[1:]] + [1]) + vertex.append([float(i) for i in line.split()[1:]] + extra_dim) elif line.startswith('f'): faces_ = line.split()[1:] faces.append([int(face_.split('/')[0]) - 1 for face_ in faces_]) From 3cc6ade977f0bea237b64442b280da7d496314e4 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 07:47:30 -0400 Subject: [PATCH 08/23] Fixed missing , --- projection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projection.py b/projection.py index c214769..dd6e139 100644 --- a/projection.py +++ b/projection.py @@ -22,7 +22,7 @@ def __init__(self, render): [m00, 0, 0, 0, 0], [0, m11, 0, 0, 0], [0, 0, m22, 0, 1], - [0, 0, 0, m33, 1] + [0, 0, 0, m33, 1], [0, 0, 0, m43, 0] ]) From 946a6b79ef06e794fc8c7deba537d9da8c488105 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 07:55:16 -0400 Subject: [PATCH 09/23] Updated all values to use 4th dimension --- camera.py | 38 ++++++++++++++++++++------------------ main.py | 2 +- object_3d.py | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/camera.py b/camera.py index 97b73b4..5e6f6fb 100644 --- a/camera.py +++ b/camera.py @@ -5,9 +5,9 @@ class Camera: def __init__(self, render, position): self.render = render self.position = np.array([*position, 1.0]) - self.forward = np.array([0, 0, 1, 1]) - self.up = np.array([0, 1, 0, 1]) - self.right = np.array([1, 0, 0, 1]) + self.forward = np.array([0, 0, 1, 0, 1]) + self.up = np.array([0, 1, 0, 0, 1]) + self.right = np.array([1, 0, 0, 0, 1]) self.h_fov = math.pi / 3 self.v_fov = self.h_fov * (render.HEIGHT / render.WIDTH) self.d_fov = self.h_fov * (render.DEPTH / render.WIDTH) @@ -51,9 +51,9 @@ def camera_pitch(self, angle): self.anglePitch += angle def axiiIdentity(self): - self.forward = np.array([0, 0, 1, 1]) - self.up = np.array([0, 1, 0, 1]) - self.right = np.array([1, 0, 0, 1]) + self.forward = np.array([0, 0, 1, 0, 1]) + self.up = np.array([0, 1, 0, 0, 1]) + self.right = np.array([1, 0, 0, 0, 1]) def camera_update_axii(self): # rotate = rotate_y(self.angleYaw) @ rotate_x(self.anglePitch) @@ -68,21 +68,23 @@ def camera_matrix(self): return self.translate_matrix() @ self.rotate_matrix() def translate_matrix(self): - x, y, z, w = self.position + x, y, z, w, h = self.position return np.array([ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [-x, -y, -z, 1] + [1, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + [-x, -y, -z, -w, 1] ]) def rotate_matrix(self): - rx, ry, rz, w = self.right - fx, fy, fz, w = self.forward - ux, uy, uz, w = self.up + rx, ry, rz, rw, h = self.right + fx, fy, fz, fw, h = self.forward + ux, uy, uz, uw, h = self.up return np.array([ - [rx, ux, fx, 0], - [ry, uy, fy, 0], - [rz, uz, fz, 0], - [0, 0, 0, 1] + [rx, ux, fx, 0, 0], + [ry, uy, fy, 0, 0], + [rz, uz, fz, 0, 0], + [rw, uw, fw, 0, 0], + [0, 0, 0, 0, 1] ]) \ No newline at end of file diff --git a/main.py b/main.py index 7be453a..1858dbe 100644 --- a/main.py +++ b/main.py @@ -16,7 +16,7 @@ def __init__(self): self.create_objects() def create_objects(self): - self.camera = Camera(self, [-5, 6, -55]) + self.camera = Camera(self, [-5, 6, -55, 0]) self.projection = Projection(self) self.object = self.get_object_from_file('resources/t_34_obj.obj') self.object.rotate_y(-math.pi / 4) diff --git a/object_3d.py b/object_3d.py index 031f624..f1b94cd 100644 --- a/object_3d.py +++ b/object_3d.py @@ -13,7 +13,7 @@ def __init__(self, render, vertices='', faces=''): self.render = render self.vertices = np.array(vertices) self.faces = faces - self.translate([0.0001, 0.0001, 0.0001]) + self.translate([0.0001, 0.0001, 0.0001, 0.0001]) self.font = pg.font.SysFont('Arial', 30, bold=True) self.color_faces = [(pg.Color('orange'), face) for face in self.faces] From eb6d752e0ea6f3247ba336b1687db8ce0977b8e7 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 09:14:10 -0400 Subject: [PATCH 10/23] Fixed loss of w coord --- camera.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/camera.py b/camera.py index 5e6f6fb..311b39b 100644 --- a/camera.py +++ b/camera.py @@ -85,6 +85,6 @@ def rotate_matrix(self): [rx, ux, fx, 0, 0], [ry, uy, fy, 0, 0], [rz, uz, fz, 0, 0], - [rw, uw, fw, 0, 0], + [rw, uw, fw, 1, 0], [0, 0, 0, 0, 1] ]) \ No newline at end of file From ffa5c9f802c065baaebb0427ce63a72d55138f42 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 09:22:51 -0400 Subject: [PATCH 11/23] Updated any_func to include 3rd coord --- object_3d.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/object_3d.py b/object_3d.py index f1b94cd..2d97d7e 100644 --- a/object_3d.py +++ b/object_3d.py @@ -4,8 +4,8 @@ @njit(fastmath=True) -def any_func(arr, a, b): - return np.any((arr == a) | (arr == b)) +def any_func(arr, a, b, c): + return np.any((arr == a) | (arr == b) | (arr == c)) class Object3D: @@ -39,7 +39,7 @@ def screen_projection(self): for index, color_face in enumerate(self.color_faces): color, face = color_face polygon = vertices[face] - if not any_func(polygon, self.render.H_WIDTH, self.render.H_HEIGHT): + if not any_func(polygon, self.render.H_WIDTH, self.render.H_HEIGHT, self.render.H_DEPTH): pg.draw.polygon(self.render.screen, color, polygon, 1) if self.label: text = self.font.render(self.label[index], True, pg.Color('white')) @@ -47,7 +47,7 @@ def screen_projection(self): if self.draw_vertices: for vertex in vertices: - if not any_func(vertex, self.render.H_WIDTH, self.render.H_HEIGHT): + if not any_func(vertex, self.render.H_WIDTH, self.render.H_HEIGHT, self.render.H_DEPTH): pg.draw.circle(self.render.screen, pg.Color('white'), vertex, 2) def translate(self, pos): From f356ec4fa32578f802b2603d4f5f00cabe0cb654 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 09:28:03 -0400 Subject: [PATCH 12/23] Updated with 4D translation --- camera.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/camera.py b/camera.py index 311b39b..6647283 100644 --- a/camera.py +++ b/camera.py @@ -8,6 +8,7 @@ def __init__(self, render, position): self.forward = np.array([0, 0, 1, 0, 1]) self.up = np.array([0, 1, 0, 0, 1]) self.right = np.array([1, 0, 0, 0, 1]) + self.there = np.array([0, 0, 0, 1, 1]) self.h_fov = math.pi / 3 self.v_fov = self.h_fov * (render.HEIGHT / render.WIDTH) self.d_fov = self.h_fov * (render.DEPTH / render.WIDTH) @@ -34,6 +35,10 @@ def control(self): self.position += self.up * self.moving_speed if key[pg.K_e]: self.position -= self.up * self.moving_speed + if key[pg.K_SPACE]: + self.position += self.there * self.moving_speed + if key[pg.K_LCTRL]: + self.position -= self.there * self.moving_speed if key[pg.K_LEFT]: self.camera_yaw(-self.rotation_speed) @@ -54,6 +59,7 @@ def axiiIdentity(self): self.forward = np.array([0, 0, 1, 0, 1]) self.up = np.array([0, 1, 0, 0, 1]) self.right = np.array([1, 0, 0, 0, 1]) + self.there = np.array([0, 0, 0, 1, 1]) def camera_update_axii(self): # rotate = rotate_y(self.angleYaw) @ rotate_x(self.anglePitch) @@ -62,6 +68,7 @@ def camera_update_axii(self): self.forward = self.forward @ rotate self.right = self.right @ rotate self.up = self.up @ rotate + self.there = self.there @ rotate def camera_matrix(self): self.camera_update_axii() From 24eb11c6f9c474013b96d18846baa4ed2c4b23d4 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 09:49:27 -0400 Subject: [PATCH 13/23] Updated with 4D rotation --- camera.py | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/camera.py b/camera.py index 6647283..93dabe2 100644 --- a/camera.py +++ b/camera.py @@ -21,6 +21,11 @@ def __init__(self, render, position): self.angleYaw = 0 self.angleRoll = 0 + self.angleYawRoll = 0 #yz + self.anglePitchRoll = 0 #xz + self.anglePitchYaw = 0 #xy + self.four_rotation = False + def control(self): key = pg.key.get_pressed() if key[pg.K_a]: @@ -41,13 +46,35 @@ def control(self): self.position -= self.there * self.moving_speed if key[pg.K_LEFT]: + self.four_rotation = False self.camera_yaw(-self.rotation_speed) if key[pg.K_RIGHT]: + self.four_rotation = False self.camera_yaw(self.rotation_speed) if key[pg.K_UP]: + self.four_rotation = False self.camera_pitch(-self.rotation_speed) if key[pg.K_DOWN]: + self.four_rotation = False self.camera_pitch(self.rotation_speed) + if key[pg.K_i]: + self.four_rotation = True + self.camera_PitchYaw(-self.rotation_speed) + if key[pg.K_k]: + self.four_rotation = True + self.camera_PitchYaw(self.rotation_speed) + if key[pg.K_j]: + self.four_rotation = True + self.camera_YawRoll(-self.rotation_speed) + if key[pg.K_l]: + self.four_rotation = True + self.camera_YawRoll(self.rotation_speed) + if key[pg.K_u]: + self.four_rotation = True + self.camera_PitchRoll(-self.rotation_speed) + if key[pg.K_o]: + self.four_rotation = True + self.camera_PitchRoll(self.rotation_speed) def camera_yaw(self, angle): self.angleYaw += angle @@ -55,6 +82,15 @@ def camera_yaw(self, angle): def camera_pitch(self, angle): self.anglePitch += angle + def camera_YawRoll(self, angle): #yz + self.angleYawRoll += angle + + def camera_PitchRoll(self, angle): #xz + self.anglePitchRoll += angle + + def camera_PitchYaw(self, angle): #xy + self.anglePitchYaw += angle + def axiiIdentity(self): self.forward = np.array([0, 0, 1, 0, 1]) self.up = np.array([0, 1, 0, 0, 1]) @@ -63,7 +99,10 @@ def axiiIdentity(self): def camera_update_axii(self): # rotate = rotate_y(self.angleYaw) @ rotate_x(self.anglePitch) - rotate = rotate_x(self.anglePitch) @ rotate_y(self.angleYaw) # this concatenation gives right visual + if not self.four_rotation: + rotate = rotate_x(self.anglePitch) @ rotate_y(self.angleYaw) # this concatenation gives right visual + else: + rotate = rotate_xy(self.anglePitchYaw) @ rotate_yz(self.angleYawRoll) @ rotate_xz(self.anglePitchRoll) self.axiiIdentity() self.forward = self.forward @ rotate self.right = self.right @ rotate @@ -88,10 +127,11 @@ def rotate_matrix(self): rx, ry, rz, rw, h = self.right fx, fy, fz, fw, h = self.forward ux, uy, uz, uw, h = self.up + tx, ty, tz, tw, h = self.there return np.array([ - [rx, ux, fx, 0, 0], - [ry, uy, fy, 0, 0], - [rz, uz, fz, 0, 0], - [rw, uw, fw, 1, 0], + [rx, ux, fx, tx, 0], + [ry, uy, fy, ty, 0], + [rz, uz, fz, tz, 0], + [rw, uw, fw, tw, 0], [0, 0, 0, 0, 1] ]) \ No newline at end of file From c62ca72af3413a0907b080563c1e749d221c3baf Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 09:57:09 -0400 Subject: [PATCH 14/23] Added object list --- main.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 1858dbe..b71e80a 100644 --- a/main.py +++ b/main.py @@ -13,13 +13,20 @@ def __init__(self): self.FPS = 60 self.screen = pg.display.set_mode(self.RES) self.clock = pg.time.Clock() + self.objects = [] self.create_objects() def create_objects(self): self.camera = Camera(self, [-5, 6, -55, 0]) self.projection = Projection(self) - self.object = self.get_object_from_file('resources/t_34_obj.obj') - self.object.rotate_y(-math.pi / 4) + self.objects.append(self.get_object_from_file('resources/tesseract.obj4')) + self.objects[-1].rotate_y(-math.pi / 4) + self.objects[-1].scale(10) + self.objects[-1].translate([10,10,10,0]) + + self.objects.append(self.get_object_from_file('resources/t_34_obj.obj')) + self.objects[-1].rotate_y(-math.pi / 4) + self.objects[-1].scale(1/5) def get_object_from_file(self, filename): vertex, faces = [], [] @@ -37,7 +44,8 @@ def get_object_from_file(self, filename): def draw(self): self.screen.fill(pg.Color('darkslategray')) - self.object.draw() + for object in self.objects: + object.draw() def run(self): while True: From bde0c4fa7bef9b7c1f6af512d72b1e656a81b15f Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 10:35:03 -0400 Subject: [PATCH 15/23] Refactored project structure --- main.py | 59 +-------------------------------------- object_3d.py => object.py | 4 +-- render.py | 56 +++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 60 deletions(-) rename object_3d.py => object.py (98%) create mode 100644 render.py diff --git a/main.py b/main.py index b71e80a..4cefde5 100644 --- a/main.py +++ b/main.py @@ -1,61 +1,4 @@ -from object_3d import * -from camera import * -from projection import * -import pygame as pg - - -class SoftwareRender: - def __init__(self): - pg.init() - self.RES = self.WIDTH, self.HEIGHT = 1600, 900 - self.DEPTH = 1600 - self.H_WIDTH, self.H_HEIGHT, self.H_DEPTH = self.WIDTH // 2, self.HEIGHT // 2, self.DEPTH //2 - self.FPS = 60 - self.screen = pg.display.set_mode(self.RES) - self.clock = pg.time.Clock() - self.objects = [] - self.create_objects() - - def create_objects(self): - self.camera = Camera(self, [-5, 6, -55, 0]) - self.projection = Projection(self) - self.objects.append(self.get_object_from_file('resources/tesseract.obj4')) - self.objects[-1].rotate_y(-math.pi / 4) - self.objects[-1].scale(10) - self.objects[-1].translate([10,10,10,0]) - - self.objects.append(self.get_object_from_file('resources/t_34_obj.obj')) - self.objects[-1].rotate_y(-math.pi / 4) - self.objects[-1].scale(1/5) - - def get_object_from_file(self, filename): - vertex, faces = [], [] - extra_dim = [0, 1] - if filename[-5:] == '.obj4': - extra_dim = [1] - with open(filename) as f: - for line in f: - if line.startswith('v '): - vertex.append([float(i) for i in line.split()[1:]] + extra_dim) - elif line.startswith('f'): - faces_ = line.split()[1:] - faces.append([int(face_.split('/')[0]) - 1 for face_ in faces_]) - return Object3D(self, vertex, faces) - - def draw(self): - self.screen.fill(pg.Color('darkslategray')) - for object in self.objects: - object.draw() - - def run(self): - while True: - self.draw() - self.camera.control() - [exit() for i in pg.event.get() if i.type == pg.QUIT] - pg.display.set_caption(str(self.clock.get_fps())) - pg.display.flip() - self.clock.tick(self.FPS) - +from render import SoftwareRender if __name__ == '__main__': app = SoftwareRender() diff --git a/object_3d.py b/object.py similarity index 98% rename from object_3d.py rename to object.py index 2d97d7e..90f291a 100644 --- a/object_3d.py +++ b/object.py @@ -8,7 +8,7 @@ def any_func(arr, a, b, c): return np.any((arr == a) | (arr == b) | (arr == c)) -class Object3D: +class Object: def __init__(self, render, vertices='', faces=''): self.render = render self.vertices = np.array(vertices) @@ -66,7 +66,7 @@ def rotate_z(self, angle): self.vertices = self.vertices @ rotate_z(angle) -class Axes(Object3D): +class Axes(Object): def __init__(self, render): super().__init__(render) self.vertices = np.array([(0, 0, 0, 1), (1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1)]) diff --git a/render.py b/render.py new file mode 100644 index 0000000..6272071 --- /dev/null +++ b/render.py @@ -0,0 +1,56 @@ +from object import * +from camera import * +from projection import * +import pygame as pg + +class SoftwareRender: + def __init__(self): + pg.init() + self.RES = self.WIDTH, self.HEIGHT = 1600, 900 + self.DEPTH = 1600 + self.H_WIDTH, self.H_HEIGHT, self.H_DEPTH = self.WIDTH // 2, self.HEIGHT // 2, self.DEPTH //2 + self.FPS = 60 + self.screen = pg.display.set_mode(self.RES) + self.clock = pg.time.Clock() + self.objects = [] + self.create_objects() + + def create_objects(self): + self.camera = Camera(self, [-5, 6, -55, 0]) + self.projection = Projection(self) + self.objects.append(self.get_object_from_file('resources/tesseract.obj4')) + self.objects[-1].rotate_y(-math.pi / 4) + self.objects[-1].scale(10) + self.objects[-1].translate([10,10,10,0]) + + self.objects.append(self.get_object_from_file('resources/t_34_obj.obj')) + self.objects[-1].rotate_y(-math.pi / 4) + self.objects[-1].scale(1/5) + + def get_object_from_file(self, filename): + vertex, faces = [], [] + extra_dim = [0, 1] + if filename[-5:] == '.obj4': + extra_dim = [1] + with open(filename) as f: + for line in f: + if line.startswith('v '): + vertex.append([float(i) for i in line.split()[1:]] + extra_dim) + elif line.startswith('f'): + faces_ = line.split()[1:] + faces.append([int(face_.split('/')[0]) - 1 for face_ in faces_]) + return Object(self, vertex, faces) + + def draw(self): + self.screen.fill(pg.Color('darkslategray')) + for object in self.objects: + object.draw() + + def run(self): + while True: + self.draw() + self.camera.control() + [exit() for i in pg.event.get() if i.type == pg.QUIT] + pg.display.set_caption(str(self.clock.get_fps())) + pg.display.flip() + self.clock.tick(self.FPS) From c09b8bf7e2e423728580766133af22d56bf21654 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 10:59:19 -0400 Subject: [PATCH 16/23] Added objects from function --- main.py | 8 ++++++++ render.py | 32 ++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/main.py b/main.py index 4cefde5..16f08f0 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,13 @@ from render import SoftwareRender +import math if __name__ == '__main__': app = SoftwareRender() + tesseract_id = app.load_object_from_file('resources/tesseract.obj4') + tank_id = app.load_object_from_file('resources/t_34_obj.obj') + app.get_object(tesseract_id).rotate_y(-math.pi / 4) + app.get_object(tesseract_id).scale(10) + app.get_object(tesseract_id).translate([10,10,10,0]) + app.get_object(tank_id).rotate_y(-math.pi / 4) + app.get_object(tank_id).scale(1/5) app.run() \ No newline at end of file diff --git a/render.py b/render.py index 6272071..4df5747 100644 --- a/render.py +++ b/render.py @@ -12,20 +12,28 @@ def __init__(self): self.FPS = 60 self.screen = pg.display.set_mode(self.RES) self.clock = pg.time.Clock() - self.objects = [] - self.create_objects() + self.objects = {} + self.autoincrement_obj_id = 0 + self.create_default_scene() - def create_objects(self): + def create_default_scene(self): self.camera = Camera(self, [-5, 6, -55, 0]) self.projection = Projection(self) - self.objects.append(self.get_object_from_file('resources/tesseract.obj4')) - self.objects[-1].rotate_y(-math.pi / 4) - self.objects[-1].scale(10) - self.objects[-1].translate([10,10,10,0]) - - self.objects.append(self.get_object_from_file('resources/t_34_obj.obj')) - self.objects[-1].rotate_y(-math.pi / 4) - self.objects[-1].scale(1/5) + + def load_object_from_file(self, filename) -> int: + return self.add_object(self.get_object_from_file(filename)) + + def add_object(self, object:Object) -> int: + id = self.autoincrement_obj_id + self.objects[id] = object + self.autoincrement_obj_id += 1 + return id + + def pop_object(self, id:int) -> Object: + return self.objects.pop(id) + + def get_object(self, id:int) -> Object: + return self.objects[id] def get_object_from_file(self, filename): vertex, faces = [], [] @@ -43,7 +51,7 @@ def get_object_from_file(self, filename): def draw(self): self.screen.fill(pg.Color('darkslategray')) - for object in self.objects: + for object in self.objects.values(): object.draw() def run(self): From ce85335a685b1f0d760d36a61f018e448d780418 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 11:04:54 -0400 Subject: [PATCH 17/23] Bugfix: Axes has no verticies on init --- object.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/object.py b/object.py index 90f291a..2ed2e06 100644 --- a/object.py +++ b/object.py @@ -68,8 +68,7 @@ def rotate_z(self, angle): class Axes(Object): def __init__(self, render): - super().__init__(render) - self.vertices = np.array([(0, 0, 0, 1), (1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1)]) + super().__init__(render,vertices=np.array([(0, 0, 0, 1), (1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1)])) self.faces = np.array([(0, 1), (0, 2), (0, 3)]) self.colors = [pg.Color('red'), pg.Color('green'), pg.Color('blue')] self.color_faces = [(color, face) for color, face in zip(self.colors, self.faces)] From 991f223ff893d52230f95a3776c523dc2d339902 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 11:08:26 -0400 Subject: [PATCH 18/23] Added W axis --- object.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/object.py b/object.py index 2ed2e06..3dfaf6d 100644 --- a/object.py +++ b/object.py @@ -66,11 +66,20 @@ def rotate_z(self, angle): self.vertices = self.vertices @ rotate_z(angle) -class Axes(Object): +class Axes3(Object): def __init__(self, render): - super().__init__(render,vertices=np.array([(0, 0, 0, 1), (1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1)])) + super().__init__(render,vertices=np.array([(0, 0, 0, 0, 1), (1, 0, 0, 0, 1), (0, 1, 0, 0, 1), (0, 0, 1, 0, 1)])) self.faces = np.array([(0, 1), (0, 2), (0, 3)]) self.colors = [pg.Color('red'), pg.Color('green'), pg.Color('blue')] self.color_faces = [(color, face) for color, face in zip(self.colors, self.faces)] self.draw_vertices = False self.label = 'XYZ' + +class Axes4(Object): + def __init__(self, render): + super().__init__(render,vertices=np.array([(0, 0, 0, 0, 1), (1, 0, 0, 0, 1), (0, 1, 0, 0, 1), (0, 0, 1, 0, 1), (0, 0, 0, 1, 1)])) + self.faces = np.array([(0, 1), (0, 2), (0, 3), (0, 4)]) + self.colors = [pg.Color('red'), pg.Color('green'), pg.Color('blue'), pg.Color('yellow')] + self.color_faces = [(color, face) for color, face in zip(self.colors, self.faces)] + self.draw_vertices = False + self.label = 'XYZW' \ No newline at end of file From 962a1ef82f0fd2556c567bf6d55db7439dbc04f3 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 11:16:14 -0400 Subject: [PATCH 19/23] Added axes --- main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.py b/main.py index 16f08f0..f3226be 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,12 @@ from render import SoftwareRender +from object import Axes4 import math if __name__ == '__main__': app = SoftwareRender() tesseract_id = app.load_object_from_file('resources/tesseract.obj4') tank_id = app.load_object_from_file('resources/t_34_obj.obj') + axis_id = app.add_object(Axes4(app)) app.get_object(tesseract_id).rotate_y(-math.pi / 4) app.get_object(tesseract_id).scale(10) app.get_object(tesseract_id).translate([10,10,10,0]) From 5274a85555d24c0ca335c66fcd41456db924a0c3 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 11:17:28 -0400 Subject: [PATCH 20/23] Disabled axis movement flag --- object.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/object.py b/object.py index 3dfaf6d..e6f7b9a 100644 --- a/object.py +++ b/object.py @@ -74,6 +74,7 @@ def __init__(self, render): self.color_faces = [(color, face) for color, face in zip(self.colors, self.faces)] self.draw_vertices = False self.label = 'XYZ' + self.movement_flag = False class Axes4(Object): def __init__(self, render): @@ -82,4 +83,5 @@ def __init__(self, render): self.colors = [pg.Color('red'), pg.Color('green'), pg.Color('blue'), pg.Color('yellow')] self.color_faces = [(color, face) for color, face in zip(self.colors, self.faces)] self.draw_vertices = False - self.label = 'XYZW' \ No newline at end of file + self.label = 'XYZW' + self.movement_flag = False \ No newline at end of file From 9bb206fcb974ce988dc81d9fc3d115d17a99f90f Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 11:22:16 -0400 Subject: [PATCH 21/23] Removed demo movement function --- object.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/object.py b/object.py index e6f7b9a..a22468a 100644 --- a/object.py +++ b/object.py @@ -17,16 +17,11 @@ def __init__(self, render, vertices='', faces=''): self.font = pg.font.SysFont('Arial', 30, bold=True) self.color_faces = [(pg.Color('orange'), face) for face in self.faces] - self.movement_flag, self.draw_vertices = True, False + self.draw_vertices = False self.label = '' def draw(self): self.screen_projection() - self.movement() - - def movement(self): - if self.movement_flag: - self.rotate_y(-(pg.time.get_ticks() % 0.005)) def screen_projection(self): vertices = self.vertices @ self.render.camera.camera_matrix() @@ -74,7 +69,6 @@ def __init__(self, render): self.color_faces = [(color, face) for color, face in zip(self.colors, self.faces)] self.draw_vertices = False self.label = 'XYZ' - self.movement_flag = False class Axes4(Object): def __init__(self, render): @@ -83,5 +77,4 @@ def __init__(self, render): self.colors = [pg.Color('red'), pg.Color('green'), pg.Color('blue'), pg.Color('yellow')] self.color_faces = [(color, face) for color, face in zip(self.colors, self.faces)] self.draw_vertices = False - self.label = 'XYZW' - self.movement_flag = False \ No newline at end of file + self.label = 'XYZW' \ No newline at end of file From 98b52d7e7ac1f8060ab72e831ff2d85317e52c95 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 14:51:17 -0400 Subject: [PATCH 22/23] Reorganized files into package structure --- __pycache__/camera.cpython-39.pyc | Bin 3075 -> 0 bytes __pycache__/matrix_functions.cpython-39.pyc | Bin 1239 -> 0 bytes __pycache__/object_3d.cpython-39.pyc | Bin 3966 -> 0 bytes __pycache__/projection.cpython-39.pyc | Bin 998 -> 0 bytes main.py | 4 ++-- pyproject.toml | 21 ++++++++++++++++++ requirements-dev.txt | 4 ++++ src/obj4drender/__init__.py | 0 camera.py => src/obj4drender/camera.py | 2 +- .../obj4drender/matrix_functions.py | 0 object.py => src/obj4drender/object.py | 2 +- .../obj4drender/projection.py | 0 render.py => src/obj4drender/render.py | 6 ++--- tests/test_matrix_functions.py | 2 +- 14 files changed, 33 insertions(+), 8 deletions(-) delete mode 100644 __pycache__/camera.cpython-39.pyc delete mode 100644 __pycache__/matrix_functions.cpython-39.pyc delete mode 100644 __pycache__/object_3d.cpython-39.pyc delete mode 100644 __pycache__/projection.cpython-39.pyc create mode 100644 pyproject.toml create mode 100644 requirements-dev.txt create mode 100644 src/obj4drender/__init__.py rename camera.py => src/obj4drender/camera.py (99%) rename matrix_functions.py => src/obj4drender/matrix_functions.py (100%) rename object.py => src/obj4drender/object.py (98%) rename projection.py => src/obj4drender/projection.py (100%) rename render.py => src/obj4drender/render.py (94%) diff --git a/__pycache__/camera.cpython-39.pyc b/__pycache__/camera.cpython-39.pyc deleted file mode 100644 index cccc38667f4f4d518cb1b6d7278b93c44d282fbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3075 zcmbVO%WoS+7@yf)+v{hXM<1a)Bu+RL0aT!+sz_1NHYLdPk*Z)tS}mTnW8w|J z_NnE<0l^J8CEUVaQ2qt3+~x?Uhzm!Adf@lXt{vO-#IEL>?=`P)e)G+^`Fw`qn_qOR zZ{->LgM`V?gm4`tcpXGA!CS1tQ5!8|o84l<6xLHFtS3gr6#PCbB~IYS$|bJ&N|o5j z&wy|pCD;b>bVn6KaA7=UXs)}eSRx^kkP{*$Y}84S78%qjkrg@Aw#bVD>a>^>MbsHF zFBVW|#Uh4ZQpt69&y#MICO-Ozw@}tmg6}~Fe83zQ@C8wcpwqGy z%VsPmV%du2WSDB&B5{GCZF<0(=>czMP_h@;66tax37Quv(1Nf*=LGzmqR4>GYr3H6 zqF|VRwp_>b@cp%RY)KAAlM~G)Ada-eNA_5Isu=s8(7NkC{y^U^YbS!FOZxk5t^VxQ zul~II?3*>+3B^r%zVM_n{EkYvQo225ciKTCY_xrqsys@z`tal@}WLC5oi zD#&)|(nztKas7JByVD4(yUN!5=k9(bt+{*cR;y$xEAU!1N#K>hEjwoNB~<_1T)(>W zAn;_cb3b%_;kMeox8BCWb~f78?w;p|!OpElxY_+;=YG2uVo{!RX~XgSdc*g2sv0}1 z9jx7P8h#^m9Exl3G6>^IzQl|A&w)!uzd?0>E<)Yvs8y9VVe}E~$M9Q)C1g!N?}!cg zfP*)enOqsbrD*{|36$g#yTT0SSlXU~{o`5t zw&(uSJ`ek^v-XMh1=xQdu){gDEN0me=Qvl#q|=6dS%}4ebdTg*EP5)r z<$QAE=C;a28}9VneR-CwsV(Q82C=o}Jh-EBvAv^_h*le)J}j3ExeQC(`nWjYyphk4un~6vksGd z1?m!)=TRL;Q^Y~0b2Kwa`35{zQ35>z@6V40*662T{NJ(9p;t*=&klJJx_2gqT$~@9NQ(Pd>}d!{3U{;aX zDc#QELM_B-?{);N4lU{fvmD@hT%xz74M#bg6ti@yO*Pcm%ZV3^VR8P0u!RnVKkN z_%w<>TUWs#-fYJj@}V&_hoct&fCu;iZlD0!fM@Y?Kryp;{?zdw>E}@%FwBN` zDiSo9jiMv*8JOuvK;no?VwfDJhICaKknCZ4m_d}xLtIt^dyo*kZVikCcAfGWnteltU>*^jkVdXL$1Y7%fwnE0=Qg9`KPK9Yd;gg1RcFoy9jea?XZ diff --git a/__pycache__/matrix_functions.cpython-39.pyc b/__pycache__/matrix_functions.cpython-39.pyc deleted file mode 100644 index 390113184b2175db7617997e0e7911c11ff67935..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1239 zcma)5O>5gg5Zy1?vK+UCQa3&J=pI6$w-QRhh87B@U`oLVjN(;XgS|4lYhnla)Y9LP zFdw4@0^fd80yF6zA~8c|S2?q5@Ru3UP1yGPbN6ld#l+f#0~;wB%@P%N6B+BUmyDP5 zSXmQ(nA(ravv81{+lxrYqc^=#tR_1uSoRAW0$lsQ?f^M=)tGPB6W9$a7^ zfgv=Yg4Wy!?sN+>2fQKvinksFJGLaV?24!4nt~VTC7TGBby1U)>zD^_fz>USqOY;t zj<^G+D!MXH*KvmrCKpi5x15g?lXEjw8O>?rI4aB$?(ubEp|H{FF+>Ja#1+=2$Fz2* zpF#ZZ!YaU3Nlg%j0}sNe%EXx~e7kl~m@5J0rjcKbaP(6&*whCAua6;L0S2(Njey&b z{R=Qs;uKtVq6D&ohLFl=uLE>f#{Et>z$l3S1bq2&AF$&W0Y85TFt*PDK7k2JCj~xn zfKaw`oE7tu=dDP1zxc5njWzhb1ASNbY4prEn#HeRx#BPYO$P|+1%Bk~C*X2VE$54M oAu3e4Q-ovLA$NQC&UVczgmpSk3jL!R6nKJ~dD_zfI?0A#-6ga7~l diff --git a/__pycache__/object_3d.cpython-39.pyc b/__pycache__/object_3d.cpython-39.pyc deleted file mode 100644 index 60c59963a948d5a0dc9f7459bab736bbf8d1bb7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3966 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.0", +] +build-backend = "setuptools.build_meta" + +[project.urls] +Homepage = "https://github.com/tantock/Software_3D_engine" + diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..2162b83 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,4 @@ +build +setuptools +setuptools_scm +wheel \ No newline at end of file diff --git a/src/obj4drender/__init__.py b/src/obj4drender/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/camera.py b/src/obj4drender/camera.py similarity index 99% rename from camera.py rename to src/obj4drender/camera.py index 93dabe2..61e615b 100644 --- a/camera.py +++ b/src/obj4drender/camera.py @@ -1,5 +1,5 @@ import pygame as pg -from matrix_functions import * +from src.obj4drender.matrix_functions import * class Camera: def __init__(self, render, position): diff --git a/matrix_functions.py b/src/obj4drender/matrix_functions.py similarity index 100% rename from matrix_functions.py rename to src/obj4drender/matrix_functions.py diff --git a/object.py b/src/obj4drender/object.py similarity index 98% rename from object.py rename to src/obj4drender/object.py index a22468a..5296ff8 100644 --- a/object.py +++ b/src/obj4drender/object.py @@ -1,5 +1,5 @@ import pygame as pg -from matrix_functions import * +from src.obj4drender.matrix_functions import * from numba import njit diff --git a/projection.py b/src/obj4drender/projection.py similarity index 100% rename from projection.py rename to src/obj4drender/projection.py diff --git a/render.py b/src/obj4drender/render.py similarity index 94% rename from render.py rename to src/obj4drender/render.py index 4df5747..5fc14fe 100644 --- a/render.py +++ b/src/obj4drender/render.py @@ -1,6 +1,6 @@ -from object import * -from camera import * -from projection import * +from src.obj4drender.object import * +from src.obj4drender.camera import * +from src.obj4drender.projection import * import pygame as pg class SoftwareRender: diff --git a/tests/test_matrix_functions.py b/tests/test_matrix_functions.py index 8cab2d9..6220618 100644 --- a/tests/test_matrix_functions.py +++ b/tests/test_matrix_functions.py @@ -1,4 +1,4 @@ -from matrix_functions import * +from src.obj4drender.matrix_functions import * def init_vector(): return np.array([1,2,3,4,1]) #x,y,z,w,h From 696b7404b85358140e2c28dbdf7236fe6ae53836 Mon Sep 17 00:00:00 2001 From: tantock Date: Mon, 4 Aug 2025 14:51:23 -0400 Subject: [PATCH 23/23] Updated license --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index c12f423..1fc9bd5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 StanislavPetrovV +Copyright (c) 2025 tantock Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal