GameObject: Document many of its functions.
Also rename `get_dimensions` to `get_local_dimensions`, add `get_world_dimensions` for consistency, and add `children_recursive_and_self`.
This commit is contained in:
parent
f71ae37821
commit
40b70003ec
|
@ -92,7 +92,8 @@ proc get_local_Z_vector*(self: GameObject): Vec3
|
|||
proc get_world_X_vector*(self: GameObject): Vec3
|
||||
proc get_world_Y_vector*(self: GameObject): Vec3
|
||||
proc get_world_Z_vector*(self: GameObject): Vec3
|
||||
proc get_dimensions*(self: GameObject): Vec3
|
||||
proc get_local_dimensions*(self: GameObject): Vec3
|
||||
proc get_world_dimensions*(self: GameObject): Vec3
|
||||
proc get_world_scale*(self: GameObject): float
|
||||
proc get_world_scale_vector*(self: GameObject): Vec3
|
||||
proc get_local_size*(self: GameObject): float
|
||||
|
@ -392,6 +393,9 @@ proc clone*(self: GameObject,
|
|||
scene: Scene=self.scene,
|
||||
instance_body: bool=true
|
||||
): GameObject =
|
||||
## Makes a clone of the object and its children (unless `recursive` is
|
||||
## false).
|
||||
|
||||
case self.otype:
|
||||
of TGameObject:
|
||||
var n = new GameObject
|
||||
|
@ -440,9 +444,17 @@ proc clone_impl*(self: GameObject, n: var GameObject, recursive: bool,
|
|||
return n
|
||||
|
||||
proc set_parent*(self: GameObject, parent: GameObject, keep_transform: bool=true) =
|
||||
## Sets the parent of the object, while keeping the same transform in world
|
||||
## space (unless you set `keep_transform` to false).
|
||||
|
||||
# TODO: there should be no distinction between this and parent_to
|
||||
self.scene.make_parent(parent, self, keep_transform=keep_transform)
|
||||
|
||||
proc parent_to*(self: GameObject, parent: GameObject, keep_transform: bool=true) =
|
||||
## Sets the parent of the object, while adding it to the same scene if
|
||||
## needed, as well as keeping the same transform in world space (unless you
|
||||
## set `keep_transform` to false).
|
||||
|
||||
# TODO move this to make_parent
|
||||
if self.scene == nil:
|
||||
parent.scene.add_object(self)
|
||||
|
@ -452,12 +464,17 @@ proc clear_parent*(self: GameObject, keep_transform: bool=true) =
|
|||
self.scene.clear_parent(self, keep_transform=keep_transform)
|
||||
|
||||
proc get_top_ancestor*(self: GameObject, top_level_parents: seq[GameObject] = @[]): GameObject =
|
||||
## Find the topmost ancestor (e.g. parent of parent of parent...) or an
|
||||
## object contained in `top_level_parents`, whatever happens first.
|
||||
var ob = self
|
||||
while ob.parent != nil and ob.parent notin top_level_parents:
|
||||
ob = ob.parent
|
||||
return ob
|
||||
|
||||
iterator children_recursive*(self: GameObject, include_self: static[bool] = false): GameObject =
|
||||
## Iterate all the descendants of the object, i.e. its children, the
|
||||
## children's children an so on.
|
||||
|
||||
# NOTE: This was written before the knowledge of closure iterators
|
||||
# (by default iterators are inline and don't allow recursion)
|
||||
when include_self:
|
||||
|
@ -483,11 +500,20 @@ iterator children_recursive*(self: GameObject, include_self: static[bool] = fals
|
|||
else:
|
||||
break
|
||||
|
||||
template children_recursive_and_self*(self: GameObject): GameObject =
|
||||
## Iterate all the descendants of the object, and include itself in the
|
||||
## iteration.
|
||||
children_recursive(self, include_self = true)
|
||||
|
||||
proc remove*(self: GameObject, recursive: bool = true) =
|
||||
## Remove the object from the scene it is in, without destroying it.
|
||||
## It will also remove its children unless you set `recursive` to false.
|
||||
if self.scene.nonNil:
|
||||
self.scene.remove_object(self, recursive)
|
||||
|
||||
proc destroy*(self: GameObject, recursive: bool = true) =
|
||||
## Destroy the object and free all unused resources previously used by it.
|
||||
## It will also destroy its children unless you set `recursive` to false.
|
||||
if self.is_mesh and self.get_mesh.data.nonNil:
|
||||
self.get_mesh.data.gpu_buffers_delete()
|
||||
self.get_mesh.materials.setLen 0
|
||||
|
@ -518,27 +544,41 @@ proc convert_bone_child_to_bone_parent*(self: GameObject) =
|
|||
bone.parent_object = self
|
||||
|
||||
proc get_local_X_vector*(self: GameObject): Vec3 =
|
||||
## Get the vector of the X axis of the object in local space.
|
||||
return self.get_local_matrix[0].xyz
|
||||
|
||||
proc get_local_Y_vector*(self: GameObject): Vec3 =
|
||||
## Get the vector of the Y axis of the object in local space.
|
||||
return self.get_local_matrix[1].xyz
|
||||
|
||||
proc get_local_Z_vector*(self: GameObject): Vec3 =
|
||||
## Get the vector of the Z axis of the object in local space.
|
||||
return self.get_local_matrix[2].xyz
|
||||
|
||||
proc get_world_X_vector*(self: GameObject): Vec3 =
|
||||
## Get the vector of the X axis of the object in world space.
|
||||
return self.get_world_matrix[0].xyz
|
||||
|
||||
proc get_world_Y_vector*(self: GameObject): Vec3 =
|
||||
## Get the vector of the Y axis of the object in world space.
|
||||
return self.get_world_matrix[1].xyz
|
||||
|
||||
proc get_world_Z_vector*(self: GameObject): Vec3 =
|
||||
## Get the vector of the Z axis of the object in world space.
|
||||
return self.get_world_matrix[2].xyz
|
||||
|
||||
proc get_dimensions*(self: GameObject): Vec3 =
|
||||
proc get_local_dimensions*(self: GameObject): Vec3 =
|
||||
## Calculate the local dimensions of the object, i.e. the size of the
|
||||
## bounding box with the scale of the object.
|
||||
let (a,b) = self.bound_box
|
||||
return (b-a) * self.scale
|
||||
|
||||
proc get_world_dimensions*(self: GameObject): Vec3 =
|
||||
## Calculate the world dimensions of the object, i.e. the size of the
|
||||
## bounding box in world scale.
|
||||
let (a,b) = self.bound_box
|
||||
return (b-a) * self.get_world_scale_vector
|
||||
|
||||
proc get_world_scale*(self: GameObject): float =
|
||||
# TODO: use the diagonal of a sphere instead?
|
||||
# i.e. length((wm*vec3(1).normalize,0).xyz)
|
||||
|
@ -550,46 +590,46 @@ proc get_world_scale*(self: GameObject): float =
|
|||
return s
|
||||
|
||||
proc get_world_scale_vector*(self: GameObject): Vec3 =
|
||||
## Gets the world scale vector in local coordinates (i.e. relative to the
|
||||
## current object orientation).
|
||||
let rotation = self.get_world_rotation
|
||||
let wm = self.world_matrix
|
||||
let rot_inv = inverse(rotation)
|
||||
var wm3 = wm.to_mat3
|
||||
let wm3_b = rot_inv.to_mat3
|
||||
wm3 = wm3_b * wm3
|
||||
let scale_x_sign = copy_sign(1.0, wm3[0,0])
|
||||
let scale_y_sign = copy_sign(1.0, wm3[1,1])
|
||||
let scale_z_sign = copy_sign(1.0, wm3[2,2])
|
||||
return vec3(
|
||||
wm[0].xyz.length * scale_x_sign,
|
||||
wm[1].xyz.length * scale_y_sign,
|
||||
wm[2].xyz.length * scale_z_sign,
|
||||
copy_sign(wm[0].xyz.length, wm3[0,0]),
|
||||
copy_sign(wm[1].xyz.length, wm3[1,1]),
|
||||
copy_sign(wm[2].xyz.length, wm3[2,2]),
|
||||
)
|
||||
|
||||
proc get_local_size*(self: GameObject): float =
|
||||
let d = self.get_dimensions()
|
||||
## Calculates the size of the largest dimension of the object in local
|
||||
## coordinates.
|
||||
let d = self.get_local_dimensions()
|
||||
return max(max(d.x, d.y), d.z)
|
||||
|
||||
proc set_local_size*(self: GameObject, size: SomeFloat) =
|
||||
## Sets the size of the object in local cordinates, given by the desired
|
||||
## largest dimension of the object. The other two dimensions are scaled
|
||||
## proportionally. If the object dimensions are zero, no action is taken.
|
||||
let current_size = self.get_local_size
|
||||
if abs(current_size) > 1e-8:
|
||||
self.scale = self.scale * size / current_size
|
||||
return
|
||||
|
||||
proc get_world_size*(self: GameObject): float =
|
||||
let d = self.get_dimensions()
|
||||
let size = max(max(d.x, d.y), d.z)
|
||||
if self.parent != nil:
|
||||
let parent_z_scale = self.parent.get_world_Z_vector.length
|
||||
return size * parent_z_scale
|
||||
return size
|
||||
## Calculates the size of the largest dimension of the object in world
|
||||
## coordinates.
|
||||
let d = self.get_world_dimensions()
|
||||
return max(max(d.x, d.y), d.z)
|
||||
|
||||
proc set_world_size*(self: GameObject, size: SomeFloat) =
|
||||
var size = size
|
||||
if self.parent != nil:
|
||||
let parent_z_scale = self.parent.get_world_Z_vector.length
|
||||
if abs(parent_z_scale) > 1e-8:
|
||||
size /= parent_z_scale
|
||||
let current_size = self.get_local_size
|
||||
## Sets the size of the object in world cordinates, given by the desired
|
||||
## largest dimension of the object. The other two dimensions are scaled
|
||||
## proportionally. If the object dimensions are zero, no action is taken.
|
||||
let current_size = self.get_world_size
|
||||
if abs(current_size) > 1e-8:
|
||||
self.scale = self.scale * size / current_size
|
||||
return
|
||||
|
@ -602,11 +642,14 @@ proc set_name*(self: GameObject, name: string) =
|
|||
self.scene.set_ob_name(self, name)
|
||||
|
||||
proc local_to_world*(self: GameObject, point: Vec3): Vec3 =
|
||||
## Transforms a point in local coordinates to world coordinates.
|
||||
return self.get_world_matrix * point
|
||||
|
||||
proc world_to_local*(self: GameObject, point: Vec3): Vec3 =
|
||||
# TODO: check that determinant is not zero?
|
||||
# does the compiler optimize multiple calls to .determinant?
|
||||
let wm = self.get_world_matrix.inverse
|
||||
return wm * point
|
||||
## Transforms a point in world coordinates to local coordinates. If the
|
||||
## object has a scale of 0, the point is not transformed.
|
||||
let wm = self.get_world_matrix
|
||||
if wm.determinant != 0.0:
|
||||
return wm.inverse * point
|
||||
return point
|
||||
|
||||
|
|
Loading…
Reference in a new issue