From a5c9bb3c7088333b7b27c417b4e2f9828decb696 Mon Sep 17 00:00:00 2001 From: Alberto Torres Date: Tue, 21 Jan 2025 12:56:34 +0100 Subject: [PATCH] Make Quat distinct, replace GameObject.rotation by a union (with quat and euler). Replace `@` quat multiplication by `*` to avoid confusion. --- src/bundle.nim | 4 +-- src/gpu_formats/texture_decode.nim | 2 +- src/graphics/framebuffer.nim | 2 +- src/graphics/render.nim | 2 +- src/graphics/texture.nim | 2 +- src/graphics/ubo.nim | 2 +- src/input.nim | 2 +- src/loaders/blend.nim | 11 +++--- src/loaders/blend_mesh.nim | 2 +- src/loaders/blend_nodes.nim | 2 +- src/math_utils/g3.nim | 2 +- src/objects/camera.nim | 4 +-- src/objects/cubemap_probe.nim | 2 +- src/objects/gameobject.nim | 39 ++++++++++----------- src/objects/light.nim | 2 +- src/objects/mesh.nim | 2 +- src/platform/android.nim | 2 +- src/platform/generic.nim | 2 +- src/platform/glfm_wrap.nim | 2 +- src/platform/glfw_wrap.nim | 2 +- src/quat.nim | 55 +++++++++++++++++++++++------- src/scene.nim | 6 ++-- src/screen.nim | 2 +- src/shadows/simple_shadow.nim | 2 +- src/types.nim | 12 +++++-- src/util.nim | 2 +- 26 files changed, 103 insertions(+), 66 deletions(-) diff --git a/src/bundle.nim b/src/bundle.nim index ca6c897..49f28a8 100644 --- a/src/bundle.nim +++ b/src/bundle.nim @@ -61,7 +61,7 @@ import ./screen import ./types import ./util import std/tables -import vmath except Quat +import vmath except Quat, quat export attributes export blend @@ -89,7 +89,7 @@ export texture export types export ubo export util -export vmath except Quat +export vmath except Quat, quat import platform/platform when defined(android): diff --git a/src/gpu_formats/texture_decode.nim b/src/gpu_formats/texture_decode.nim index 40543a5..f11f30a 100644 --- a/src/gpu_formats/texture_decode.nim +++ b/src/gpu_formats/texture_decode.nim @@ -37,7 +37,7 @@ proc swap_lines(p: pointer, line_stride, line_count: int) {.gcsafe.} # End forward declarations import std/strformat -import vmath except Quat +import vmath except Quat, quat import arr_ref import float16 diff --git a/src/graphics/framebuffer.nim b/src/graphics/framebuffer.nim index 5f337df..fbaf0f9 100644 --- a/src/graphics/framebuffer.nim +++ b/src/graphics/framebuffer.nim @@ -33,7 +33,7 @@ import ../types import std/options import std/tables -import vmath except Quat +import vmath except Quat, quat # Forward declarations proc newFramebuffer*(engine: MyouEngine, diff --git a/src/graphics/render.nim b/src/graphics/render.nim index 54ad811..5fc67f3 100644 --- a/src/graphics/render.nim +++ b/src/graphics/render.nim @@ -33,7 +33,7 @@ import ../types import ../platform/gl import arr_ref -import vmath except Quat +import vmath except Quat, quat # Forward declarations func newRenderCameraData*(world_matrix, proj_matrix: Mat4, cull_planes: array[6, Vec4], viewport_size: Vec2): RenderCameraData diff --git a/src/graphics/texture.nim b/src/graphics/texture.nim index c22a18f..b135e76 100644 --- a/src/graphics/texture.nim +++ b/src/graphics/texture.nim @@ -31,7 +31,7 @@ # version of this file under either the CPAL or the [AGPL-3] License. import ../types -import vmath except Quat +import vmath except Quat, quat import arr_ref # import tinyre import std/tables diff --git a/src/graphics/ubo.nim b/src/graphics/ubo.nim index 664967b..4fb9c68 100644 --- a/src/graphics/ubo.nim +++ b/src/graphics/ubo.nim @@ -33,7 +33,7 @@ import ../types import std/tables import std/strformat -import vmath except Quat +import vmath except Quat, quat import ../platform/gl import arr_ref export arr_ref diff --git a/src/input.nim b/src/input.nim index 604db5f..c83610c 100644 --- a/src/input.nim +++ b/src/input.nim @@ -30,7 +30,7 @@ # License. If you do not delete the provisions above, a recipient may use your # version of this file under either the CPAL or the [AGPL-3] License. -import vmath except Quat +import vmath except Quat, quat type KeyCode* = enum KeyUnknown = - 1, KeySpace = 32, KeyApostrophe = 39, KeyComma = 44, KeyMinus, diff --git a/src/loaders/blend.nim b/src/loaders/blend.nim index 54a1130..ffbcc8c 100644 --- a/src/loaders/blend.nim +++ b/src/loaders/blend.nim @@ -45,8 +45,9 @@ import std/strformat import std/bitops import std/options import std/json -import vmath except Quat +import vmath except Quat, quat import ../quat +import ../util import ../../libs/loadable/loadable import ../graphics/material @@ -432,7 +433,7 @@ proc loadObjectImpl(self: BlendLoader, scene: Scene, obn: FNode): (GameObject, s ubos = scene.get_lighting_UBOs, double_sided = not backface_culling, ) - + for v in varyings: if v.vtype == Tangent and v.attname notin tangents: tangents.add v.attname @@ -563,13 +564,13 @@ proc loadObjectImpl(self: BlendLoader, scene: Scene, obn: FNode): (GameObject, s of BEulerZYX: EulerZYX ob.rotation = if ob.rotation_order == Quaternion: let q = obn.quat.f32 - quat(q[1], q[2], q[3], q[0]) + Rotation(quat: quat(q[1], q[2], q[3], q[0])) elif ob.rotation_order == AxisAngle: assert false, "not implemented" - quat() + Rotation() else: let r = obn.rot.f32 - quat(r[0], r[1], r[2], 1) + Rotation(euler: vec3(r[0], r[1], r[2])) ob.scale = obn.size.f32.vec3 let restrictflag = obn.restrictflag.i16[0] ob.visible = (restrictflag and 4) == 0 diff --git a/src/loaders/blend_mesh.nim b/src/loaders/blend_mesh.nim index 9ac853f..d069009 100644 --- a/src/loaders/blend_mesh.nim +++ b/src/loaders/blend_mesh.nim @@ -36,7 +36,7 @@ import std/strformat import std/strutils import std/tables import tinyre -import vmath except Quat +import vmath except Quat, quat # import sugar import ../types diff --git a/src/loaders/blend_nodes.nim b/src/loaders/blend_nodes.nim index 24297fb..e398b6c 100644 --- a/src/loaders/blend_nodes.nim +++ b/src/loaders/blend_nodes.nim @@ -47,7 +47,7 @@ import ../types import ./blend_curve_maps import ./blend_format import ./glsl_functions -import vmath except Quat +import vmath except Quat, quat type Expr = object str: string diff --git a/src/math_utils/g3.nim b/src/math_utils/g3.nim index 2246680..0ed1cc6 100644 --- a/src/math_utils/g3.nim +++ b/src/math_utils/g3.nim @@ -31,7 +31,7 @@ # version of this file under either the CPAL or the [AGPL-3] License. -import vmath except Quat +import vmath except Quat, quat func plane_from_norm_point*(normal, point: Vec3): Vec4 = ## Calculates a plane from a normal and a point in the plane. diff --git a/src/objects/camera.nim b/src/objects/camera.nim index b1a5270..cf22e01 100644 --- a/src/objects/camera.nim +++ b/src/objects/camera.nim @@ -32,7 +32,7 @@ import ../types import std/options -import vmath except Quat +import vmath except Quat, quat import ../quat import ../util @@ -122,7 +122,7 @@ proc get_ray_direction_local*(self: Camera, x, y: float32): Vec3 = ## relative to the camera. The upper left corner of the viewport has ## coordinates (0,0), and the lower right corner (1,1). assert self.rotation_order == Quaternion - return self.rotation * (self.projection_matrix_inverse * + return self.rotation.quat * (self.projection_matrix_inverse * vec3(x * 2 - 1, 1 - y * 2, 1)) # proc get_position_at_depth*(self: camera, x, y: float32): Vec3 = diff --git a/src/objects/cubemap_probe.nim b/src/objects/cubemap_probe.nim index b48d59c..79b7132 100644 --- a/src/objects/cubemap_probe.nim +++ b/src/objects/cubemap_probe.nim @@ -32,7 +32,7 @@ import ../types import std/strformat -import vmath except Quat +import vmath except Quat, quat when defined(nimdoc): type TYPES* = ProbeInfluenceType | ProbeParallaxType | CubemapProbe | CubemapProbeUniform | SH9Uniform diff --git a/src/objects/gameobject.nim b/src/objects/gameobject.nim index 488f545..d10fae9 100644 --- a/src/objects/gameobject.nim +++ b/src/objects/gameobject.nim @@ -31,7 +31,7 @@ # version of this file under either the CPAL or the [AGPL-3] License. import ../types -import vmath except Quat +import vmath except Quat, quat import ../quat when defined(nimdoc): @@ -123,7 +123,7 @@ proc initGameObject*(self: GameObject, engine: MyouEngine, name: string="", scen # Remember to add any new mutable reference to clone() self.engine = engine self.name = name - self.rotation = quat() + self.rotation.quat = quat() self.rotation_order = EulerXYZ self.scale = vec3(1, 1, 1) self.object_color = vec4(1, 1, 1, 1) @@ -179,9 +179,9 @@ proc update_matrices*(self: GameObject) = ## and parent matrix. It assumes the parent object and/or bone has its world ## matrix already up to date. var q = if self.rotation_order == Quaternion: - self.rotation + self.rotation.quat else: - to_quat(self.rotation.xyz, self.rotation_order) + to_quat(self.rotation.euler, self.rotation_order) # var q = self.rotation q = normalize(q) let (x,y,z,w) = q.toTuple @@ -238,17 +238,18 @@ proc set_rotation_order*(self: GameObject, order: RotationOrder) = ## Change the rotation mode and order of the object. if order == self.rotation_order: return - var q = self.rotation - if self.rotation_order != Quaternion: - q = q.xyz.to_quat(self.rotation_order) + var q = if self.rotation_order != Quaternion: + self.rotation.euler.to_quat(self.rotation_order) + else: + self.rotation.quat self.rotation = case order: - of Quaternion: q - of EulerXYZ: vec4(q.to_euler_XYZ, 0) - of EulerXZY: vec4(q.to_euler_XZY, 0) - of EulerYXZ: vec4(q.to_euler_YXZ, 0) - of EulerYZX: vec4(q.to_euler_YZX, 0) - of EulerZXY: vec4(q.to_euler_ZXY, 0) - of EulerZYX: vec4(q.to_euler_ZYX, 0) + of Quaternion: Rotation(quat: q) + of EulerXYZ: Rotation(euler: q.to_euler_XYZ) + of EulerXZY: Rotation(euler: q.to_euler_XZY) + of EulerYXZ: Rotation(euler: q.to_euler_YXZ) + of EulerYZX: Rotation(euler: q.to_euler_YZX) + of EulerZXY: Rotation(euler: q.to_euler_ZXY) + of EulerZYX: Rotation(euler: q.to_euler_ZYX) of AxisAngle: raise newException(ValueError, "axis angle not supported yet") self.rotation_order = order @@ -263,9 +264,9 @@ proc get_local_matrix*(self: GameObject): Mat4 = ## Calculates and returns the transformation matrix in local space. If the ## object has no parent, this is equivalent to the world matrix. var q = if self.rotation_order == Quaternion: - self.rotation + self.rotation.quat else: - to_quat(self.rotation.xyz, self.rotation_order) + to_quat(self.rotation.euler, self.rotation_order) q = normalize(q) var (x,y,z,w) = q.toTuple let scl = self.scale @@ -368,7 +369,7 @@ proc rotate_quat*(self: GameObject, q: Quat, relative_object: GameObject=nil): G let rotation_order = self.rotation_order if rotation_order != Quaternion: self.set_rotation_order(Quaternion) - self.rotation = inv_par @ rel @ q @ inv_rel @ par @ self.rotation + self.rotation.quat = inv_par * rel * q * inv_rel * par * self.rotation.quat if rotation_order != Quaternion: self.set_rotation_order(rotation_order) return self @@ -415,10 +416,10 @@ proc set_world_position_rotation*( # TODO: does it work well with parents? let wm = inverse(self.parent.get_world_matrix * self.matrix_parent_inverse) self.position = wm * position - self.rotation = wm.to_mat3_rotation.to_quat @ rotation + self.rotation.quat = wm.to_mat3_rotation.to_quat * rotation else: self.position = position - self.rotation = rotation + self.rotation.quat = rotation self.rotation_order = Quaternion proc set_world_position*(self: GameObject, position: Vec3) = diff --git a/src/objects/light.nim b/src/objects/light.nim index b8e66d1..e5a035c 100644 --- a/src/objects/light.nim +++ b/src/objects/light.nim @@ -31,7 +31,7 @@ # version of this file under either the CPAL or the [AGPL-3] License. import ../types -import vmath except Quat +import vmath except Quat, quat import ../util import ../graphics/material diff --git a/src/objects/mesh.nim b/src/objects/mesh.nim index 2d1fdfc..74dfd06 100644 --- a/src/objects/mesh.nim +++ b/src/objects/mesh.nim @@ -35,7 +35,7 @@ # TODO: Split mesh object and mesh data import ../types -import vmath except Quat +import vmath except Quat, quat import arr_ref when defined(nimdoc): diff --git a/src/platform/android.nim b/src/platform/android.nim index 4cf5d50..80a4a90 100644 --- a/src/platform/android.nim +++ b/src/platform/android.nim @@ -33,7 +33,7 @@ import ../types -import vmath except Quat +import vmath except Quat, quat import std/strutils type Window* = ref object of RootObj diff --git a/src/platform/generic.nim b/src/platform/generic.nim index d9fb18f..fd1bf73 100644 --- a/src/platform/generic.nim +++ b/src/platform/generic.nim @@ -33,7 +33,7 @@ import ../types -import vmath except Quat +import vmath except Quat, quat import std/strutils type Window* = ref object of RootObj diff --git a/src/platform/glfm_wrap.nim b/src/platform/glfm_wrap.nim index 1d708e6..fe6fd78 100644 --- a/src/platform/glfm_wrap.nim +++ b/src/platform/glfm_wrap.nim @@ -33,7 +33,7 @@ import ../types -import vmath except Quat +import vmath except Quat, quat import glfm type Window* = ptr GLFMDisplay diff --git a/src/platform/glfw_wrap.nim b/src/platform/glfw_wrap.nim index 9de3385..78bf898 100644 --- a/src/platform/glfw_wrap.nim +++ b/src/platform/glfw_wrap.nim @@ -33,7 +33,7 @@ import ../types -import vmath except Quat +import vmath except Quat, quat import nglfw as glfw type Window* = glfw.Window diff --git a/src/quat.nim b/src/quat.nim index ddd6903..772554b 100644 --- a/src/quat.nim +++ b/src/quat.nim @@ -2,7 +2,7 @@ # TODO: make own vmath module with proper quats and more matrix types -import vmath except Quat +import vmath except Quat, quat type RotationOrder* = enum Quaternion @@ -16,20 +16,33 @@ type RotationOrder* = enum type - GQuat*[T] = GVec4[T] + GQuat*[T] = object + x*, y*, z*, w*: float32 Quat* = GQuat[float32] DQuat* = GQuat[float64] -template gquat*[T](x,y,z,w: T): GQuat[T] = - gvec4[T](x,y,z,w) +proc gquat*[T](x,y,z,w: T): GQuat[T] {.inline.} = + GQuat[T](x:x, y:y, z:z, w:w) -proc `@`*[T](a,b: GQuat[T]): GQuat[T] = - return gquat[T]( - a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y, - a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z, - a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x, - a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, - ) +proc quat*(x,y,z,w: float32): Quat {.inline.} = + Quat(x:x, y:y, z:z, w:w) + +proc dquat*(x,y,z,w: float64): DQuat {.inline.} = + DQuat(x:x, y:y, z:z, w:w) + +template quat*(): Quat = quat(0,0,0,1) +template dquat*(): DQuat = dquat(0,0,0,1) +template quat*(v: Vec4): Quat = cast[Quat](v) +template dquat*(v: DVec4): DQuat = cast[DQuat](v) + +template `[]`*[T](q: GQuat[T], i: int): T = cast[array[4, T]](q)[i] +template `[]=`*[T](q: var GQuat[T], i: int, v: T) = + case i: + of 0: q.x = v + of 1: q.y = v + of 2: q.z = v + of 3: q.w = v + else: raise RangeDefect.newException "Index out of range" # https://stackoverflow.com/questions/28673777/convert-quaternion-from-right-handed-to-left-handed-coordinate-system # S=s, B=−b, C=−d and D=−c. @@ -73,6 +86,12 @@ func inverse*[T](a: GQuat[T]): GQuat[T] = return return gquat[T](-a.x, -a.y, -a.z, a.w) * (1/dot) +proc normalize*[T](q: GQuat[T]): GQuat[T] = + let length = sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w) + if length == 0: + return q + return gquat[T](q.x / length , q.y / length, q.z / length, q.w / length) + func to_mat3*[T](q: GQuat[T]): GMat3[T] = let xx = q.x * q.x * 2 let yx = q.y * q.x * 2 @@ -109,6 +128,16 @@ func `*`*[T](q: GQuat[T], a: GVec3[T]): GVec3[T] = result.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z result.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x +proc `*`*[T](a, b: GQuat[T]): GQuat[T] = + GQuat[T]( + x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, + y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x, + z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w, + w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, + ) + +proc `*`*[T](q: GQuat[T], s: T): GQuat[T] = + GQuat[T](x: q.x*s, y: q.y*s, z: q.z*s, w: q.w*s) template to_tuple*[T](v: GQuat[T]): (T, T, T, T) = # (v.x, v.y, v.z, v.w) @@ -232,10 +261,10 @@ proc rotationTo*(a,b: Vec3): Quat = var v = cross(vec3(1,0,0), a) if v.length < 0.000001: v = cross(vec3(0,1,0), a) - return fromAxisAngle(v.normalize, PI) + return cast[Quat](fromAxisAngle(v.normalize, PI)) elif dot > 0.999999: return quat(0,0,0,1) else: let v = cross(a, b) - return quat(v.x, v.y, v.z, 1.0+dot) + return quat(v.x, v.y, v.z, 1.0+dot).normalize diff --git a/src/scene.nim b/src/scene.nim index 1b26b9c..da60c2b 100644 --- a/src/scene.nim +++ b/src/scene.nim @@ -62,7 +62,7 @@ proc ensure_cubemaps*(self: Scene) proc render_all_cubemaps*(self: Scene, use_roughness_prefiltering: bool, mipmap_shader: Material = nil) # End forward declarations -import vmath except Quat +import vmath except Quat, quat import ./quat import std/algorithm import std/math @@ -256,7 +256,7 @@ proc make_parent*(self: Scene, parent: GameObject, child: GameObject, let rotation = parent.get_world_rotation let rotation_order = child.rotation_order child.set_rotation_order(Quaternion) - var rot = inverse(rotation) * child.rotation + var rot = inverse(rotation) * child.rotation.quat let rot_inv = inverse(rot) var scale = child.scale # get local rotation matrix and scale it with parent world scale vector @@ -294,7 +294,7 @@ proc clear_parent*(self: Scene, child: GameObject, keep_transform = true) = let rotation_order = child.rotation_order let (position, rotation) = child.get_world_position_rotation child.position = position - child.rotation = rotation + child.rotation.quat = rotation child.rotation_order = Quaternion var scale = child.scale let world_matrix = child.world_matrix diff --git a/src/screen.nim b/src/screen.nim index a3b52b7..1dfb127 100644 --- a/src/screen.nim +++ b/src/screen.nim @@ -44,7 +44,7 @@ proc emulateMouseWithTouch*(screen: Screen, touch: int32, ending: bool, x, y: fl import std/bitops import std/sequtils import std/math -import vmath except Quat +import vmath except Quat, quat import ./graphics/framebuffer import ./objects/camera import ./platform/platform diff --git a/src/shadows/simple_shadow.nim b/src/shadows/simple_shadow.nim index 979d3d4..cbd8927 100644 --- a/src/shadows/simple_shadow.nim +++ b/src/shadows/simple_shadow.nim @@ -32,7 +32,7 @@ import std/strutils import ../types -import vmath except Quat +import vmath except Quat, quat import ../graphics/framebuffer import ../graphics/material import ../graphics/render diff --git a/src/types.nim b/src/types.nim index 920de0e..cd204ac 100644 --- a/src/types.nim +++ b/src/types.nim @@ -32,7 +32,7 @@ import std/tables import std/options -import vmath except Quat +import vmath except Quat, quat import json import arr_ref import ./platform/gl @@ -90,6 +90,12 @@ type # gameobject.nim + Rotation* {.union.} = object + euler*: Vec3 + quat*: Quat + axis_angle*: tuple[axis: Vec3, angle: float32] + vec4*: Vec4 + ObjectType* = enum ## private TGameObject TMesh @@ -103,7 +109,7 @@ type engine* {.cursor.}: MyouEngine ## private debug*: bool ## private position*: Vec3 - rotation*: Quat + rotation*: Rotation radius*: float rotation_order*: RotationOrder scale*: Vec3 @@ -949,7 +955,7 @@ type BlendLoader* = ref object of Loader (string, seq[Varying], OrderedTable[string, string], OrderedTable[string, TexturePixels])] ## private resource*: LoadableResource textures*: Table[string, Texture] - + template enqueue*(renderer: RenderManager, fun: untyped) = ## Run a proc after the renderer has been initialized. ## diff --git a/src/util.nim b/src/util.nim index 615d54f..d64dc76 100644 --- a/src/util.nim +++ b/src/util.nim @@ -31,7 +31,7 @@ # version of this file under either the CPAL or the [AGPL-3] License. import ./platform/gl -import vmath except Quat +import vmath except Quat, quat import std/math import std/algorithm import arr_ref