diff --git a/godot.nimble b/godot.nimble index ba9987f..e562fca 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.5" +version = "0.7.6" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/core/basis.nim b/godot/core/basis.nim index 1d4f33c..538ca60 100644 --- a/godot/core/basis.nim +++ b/godot/core/basis.nim @@ -4,6 +4,8 @@ import math import godotbase, vector3, quats import godotcoretypes +{.push stackTrace: off.} + proc setCells*(basis: var Basis, xx, xy, xz, yx, yy, yz, zx, zy, zz: float32) = basis.elements[0].x = xx basis.elements[0].y = xy @@ -449,3 +451,5 @@ proc rotate*(self: var Vector3; axis: Vector3; phi: float32) = proc rotated*(self: Vector3; axis: Vector3; phi: float32): Vector3 = result = self result.rotate(axis, phi) + +{.pop.} # stackTrace: off \ No newline at end of file diff --git a/godot/core/godotbase.nim b/godot/core/godotbase.nim index 7871a87..38cca0f 100644 --- a/godot/core/godotbase.nim +++ b/godot/core/godotbase.nim @@ -1,30 +1,61 @@ # Copyright (c) 2018 Xored Software, Inc. -import math +import math, godotinternal # math helpers +{.push stackTrace: off.} const EPSILON = 0.00001'f32 -proc isEqualApprox*(a, b: float32): bool {.inline.} = +proc isEqualApprox*(a, b: float32): bool {.inline, noinit.} = abs(a - b) < EPSILON -proc isEqualApprox*(a, b: float64): bool {.inline.} = +proc isEqualApprox*(a, b: float64): bool {.inline, noinit.} = abs(a - b) < EPSILON -proc sign*(a: float32): float32 {.inline.} = +proc sign*(a: float32): float32 {.inline, noinit.} = if a < 0: -1.0'f32 else: 1.0'f32 -proc sign*(a: float64): float64 {.inline.} = +proc sign*(a: float64): float64 {.inline, noinit.} = if a < 0: -1.0'f64 else: 1.0'f64 -proc stepify*(value, step: float64): float64 = +proc stepify*(value, step: float64): float64 {.inline, noinit.} = if step != 0'f64: floor(value / step + 0.5'f64) * step else: value -proc stepify*(value, step: float32): float32 = +proc stepify*(value, step: float32): float32 {.inline, noinit.} = if step != 0'f32: floor(value / step + 0.5'f32) * step else: value + +proc min*(x, y: float32): float32 {.inline, noinit.} = + if x <= y: x else: y + +proc abs*(x: float32): float32 {.inline, noinit.} = + if x < 0.0: -x else: x + +proc max*(x, y: float32): float32 {.inline, noinit.} = + if y <= x: x else: y + +{.pop.} # stackTrace: off + +template printWarning*(warning: typed) = + ## Prints ``warning`` to Godot log, adding filename and line information. + let (filename, line) = instantiationInfo() + godotPrintWarning(cstring($warning), cstring"", cstring(filename), line.cint) + +template printError*(error: typed) = + ## Prints ``error`` to Godot log, adding filename and line information. + let (filename, line) = instantiationInfo() + godotPrintError(cstring($error), cstring"", cstring(filename), line.cint) + +proc print*(parts: varargs[string, `$`]) = + ## Prints concatenated ``parts`` to Godot log. + var combined = "" + for v in parts: + combined.add(v) + var s = combined.toGodotString() + godotPrint(s) + s.deinit() diff --git a/godot/core/rect2.nim b/godot/core/rect2.nim index 6e7c99e..2e73571 100644 --- a/godot/core/rect2.nim +++ b/godot/core/rect2.nim @@ -4,41 +4,145 @@ import vector2 import internal.godotinternaltypes, internal.godotstrings import godotcoretypes, gdnativeapi -proc initRect2*(pos, size: Vector2): Rect2 {.inline.} = +{.push stackTrace: off.} + +proc initRect2*(): Rect2 {.inline, noinit.} = + Rect2() + +proc initRect2*(pos, size: Vector2): Rect2 {.inline, noinit.} = Rect2(position: pos, size: size) -proc initRect2*(x, y, sizeX, sizeY: float32): Rect2 {.inline.} = +proc initRect2*(x, y, sizeX, sizeY: float32): Rect2 {.inline, noinit.} = Rect2(position: vec2(x, y), size: vec2(sizeX, sizeY)) proc `$`*(self: Rect2): string {.inline.} = $getGDNativeAPI().rect2AsString(self) -proc area*(self: Rect2): float32 {.inline.} = - getGDNativeAPI().rect2GetArea(self) +proc area*(self: Rect2): float32 {.inline, noinit.} = + self.size.x * self.size.y -proc intersects*(a, b: Rect2): bool {.inline.} = - getGDNativeAPI().rect2Intersects(a, b) +proc intersects*(a, b: Rect2): bool {.inline, noinit.} = + if a.position.x >= (b.position.x + b.size.x): + return false + if a.position.x + a.size.x <= b.position.x: + return false + if a.position.y >= (b.position.y + b.size.y): + return false + if a.position.y + a.size.y <= b.position.y: + return false + result = true -proc encloses*(a, b: Rect2): bool {.inline.} = - getGDNativeAPI().rect2Encloses(a, b) +proc distanceTo*(self: Rect2, p: Vector2): float32 {.noinit.} = + var inside = true + if p.x < self.position.x: + let d = self.position.x - p.x + result = d + inside = false + if p.y < self.position.y: + let d = self.position.y - p.y + result = if inside: d else: min(result, d) + inside = false + if p.x >= (self.position.x + self.size.x): + let d = p.x - (self.position.x + self.size.x) + result = if inside: d else: min(result, d) + inside = false + if p.y >= (self.position.y + self.size.y): + let d = p.y - (self.position.y + self.size.y) + result = if inside: d else: min(result, d) + inside = false -proc hasNoArea*(self: Rect2): bool {.inline.} = - getGDNativeAPI().rect2HasNoArea(self) + if inside: + result = 0'f32 -proc clip*(self, b: Rect2): Rect2 {.inline.} = - getGDNativeAPI().rect2Clip(self, b) +proc encloses*(a, b: Rect2): bool {.inline, noinit.} = + b.position.x >= a.position.x and b.position.y >= a.position.y and + (b.position.x + b.size.x) < (a.position.x + a.size.x) and + (b.position.y + b.size.y) < (a.position.y + a.size.y) -proc merge*(self, b: Rect2): Rect2 {.inline.} = - getGDNativeAPI().rect2Merge(self, b) +proc hasNoArea*(self: Rect2): bool {.inline, noinit.} = + self.size.x <= 0 or self.size.y <= 0 -proc contains*(self: Rect2; point: Vector2): bool {.inline.} = - getGDNativeAPI().rect2HasPoint(self, point) +proc clip*(self, b: Rect2): Rect2 {.inline, noinit.} = + if not self.intersects(b): + return initRect2() -proc grow*(self: Rect2; by: float32): Rect2 {.inline.} = - getGDNativeAPI().rect2Grow(self, by) + result = self -proc expand*(self: Rect2; to: Vector2): Rect2 {.inline.} = - getGDNativeAPI().rect2Expand(self, to) + result.position.x = max(b.position.x, self.position.x) + result.position.y = max(b.position.y, self.position.y) -proc `==`*(a, b: Rect2): bool {.inline.} = - getGDNativeAPI().rect2OperatorEqual(a, b) + let bEnd = b.position + b.size + let selfEnd = self.position + self.size + + result.size.x = min(bEnd.x, selfEnd.x) - result.position.x + result.size.y = min(bEnd.y, selfEnd.y) - result.position.y + +proc merge*(self, b: Rect2): Rect2 {.inline, noinit.} = + result.position.x = min(b.position.x, self.position.x) + result.position.y = min(b.position.y, self.position.y) + + result.size.x = max(b.position.x + b.size.x, self.position.x + self.size.x) + result.size.y = max(b.position.y + b.size.y, self.position.y + self.size.y) + result.size -= result.position + +proc contains*(self: Rect2; point: Vector2): bool {.inline, noinit.} = + if point.x < self.position.x: + return false + if point.y < self.position.y: + return false + + if point.x >= self.position.x + self.size.x: + return false + if point.y >= self.position.y + self.size.y: + return false + + result = true + +proc grow*(self: Rect2; by: float32): Rect2 {.inline, noinit.} = + ## Returns Rect2 enlarged by the specified size in every direction. + result = self + + result.position.x -= by + result.position.y -= by + + result.size.x += by * 2 + result.size.y += by * 2 + +proc growIndividual*(self: Rect2, left, top: float32, + right, bottom: float32): Rect2 {.inline, noinit.} = + result = self + result.position.x -= left + result.position.y -= top + result.size.x += left + right + result.size.y += top + bottom + +proc expandTo*(self: var Rect2, to: Vector2) {.inline.} = + var startPoint = self.position + var endPoint = self.position + self.size + + if to.x < startPoint.x: + startPoint.x = to.x + if to.y < startPoint.y: + startPoint.y = to.y + + if to.x > endPoint.x: + endPoint.x = to.x + if to.y > endPoint.y: + endPoint.y = to.y + + self.position = startPoint + self.size = endPoint - startPoint + +proc expand*(self: Rect2; to: Vector2): Rect2 {.inline, noinit.} = + result = self + result.expandTo(to) + +proc abs*(self: Rect2): Rect2 {.inline, noinit.} = + Rect2(position: vec2(self.position.x + min(self.size.x, 0'f32), + self.position.y + min(self.size.y, 0'f32)), + size: abs(self.size)) + +proc `==`*(a, b: Rect2): bool {.inline, noinit.} = + a.position == b.position and a.size == b.size + +{.pop.} # stackTrace: off \ No newline at end of file diff --git a/godot/core/vector2.nim b/godot/core/vector2.nim index b665dbd..f15bd2f 100644 --- a/godot/core/vector2.nim +++ b/godot/core/vector2.nim @@ -1,125 +1,199 @@ # Copyright (c) 2018 Xored Software, Inc. +import math, godotbase + import internal.godotinternaltypes, internal.godotstrings import godotcoretypes, gdnativeapi -proc vec2*(): Vector2 {.inline.} = +{.push stackTrace: off.} + +proc vec2*(): Vector2 {.inline, noinit.} = Vector2() -proc vec2*(x, y: float32): Vector2 {.inline.} = +proc vec2*(x, y: float32): Vector2 {.inline, noinit.} = Vector2(x: x, y: y) -proc `$`*(self: Vector2): string {.inline.} = +proc `$`*(self: Vector2): string {.inline, noinit.} = $getGDNativeAPI().vector2AsString(self) -proc normalized*(self: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2Normalized(self) +proc `+`*(self, other: Vector2): Vector2 {.inline, noinit.} = + Vector2(x: self.x + other.x, y: self.y + other.y) -proc length*(self: Vector2): float32 {.inline.} = - getGDNativeAPI().vector2Length(self) +proc `+=`*(self: var Vector2, other: Vector2) {.inline, noinit.} = + self.x += other.x + self.y += other.y -proc angle*(self: Vector2): float32 {.inline.} = - getGDNativeAPI().vector2Angle(self) +proc `-`*(self, other: Vector2): Vector2 {.inline, noinit.} = + Vector2(x: self.x - other.x, y: self.y - other.y) -proc lengthSquared*(self: Vector2): float32 {.inline.} = - getGDNativeAPI().vector2LengthSquared(self) +proc `-=`*(self: var Vector2, other: Vector2) {.inline, noinit.} = + self.x -= other.x + self.y -= other.y -proc isNormalized*(self: Vector2): bool {.inline.} = - getGDNativeAPI().vector2IsNormalized(self) +proc `*`*(self, other: Vector2): Vector2 {.inline, noinit.} = + Vector2(x: self.x * other.x, y: self.y * other.y) -proc distanceTo*(self, to: Vector2): float32 {.inline.} = - getGDNativeAPI().vector2DistanceTo(self, to) +proc `*=`*(self: var Vector2, other: Vector2) {.inline, noinit.} = + self.x *= other.x + self.y *= other.y -proc distanceSquaredTo*(self, to: Vector2): float32 {.inline.} = - getGDNativeAPI().vector2DistanceSquaredTo(self, to) +proc `*`*(self: Vector2, scalar: float32): Vector2 {.inline, noinit.} = + Vector2(x: self.x * scalar, y: self.y * scalar) -proc angleTo*(self, to: Vector2): float32 {.inline.} = - getGDNativeAPI().vector2AngleTo(self, to) +proc `*`*(scalar: float32, v: Vector2): Vector2 {.inline, noinit.} = + v * scalar -proc angleToPoint*(self, to: Vector2): float32 {.inline.} = - getGDNativeAPI().vector2AngleToPoint(self, to) +proc `*=`*(self: var Vector2, scalar: float32) {.inline, noinit.} = + self.x *= scalar + self.y *= scalar -proc lerp*(self, b: Vector2; t: float32): Vector2 {.inline.} = - getGDNativeAPI().vector2LinearInterpolate(self, b, t) +proc `/`*(self, other: Vector2): Vector2 {.inline, noinit.} = + Vector2(x: self.x / other.x, y: self.y / other.y) -proc cubicInterpolate*(self, b, preA, postB: Vector2; - t: float32): Vector2 {.inline.} = - getGDNativeAPI().vector2CubicInterpolate(self, b, preA, postB, t) +proc `/=`*(self: var Vector2, other: Vector2) {.inline, noinit.} = + self.x /= other.x + self.y /= other.y -proc rotated*(self: Vector2; phi: float32): Vector2 {.inline.} = - getGDNativeAPI().vector2Rotated(self, phi) +proc `/`*(self: Vector2; scalar: float32): Vector2 {.inline, noinit.} = + Vector2(x: self.x / scalar, y: self.y / scalar) -proc tangent*(self: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2Tangent(self) - -proc floor*(self: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2Floor(self) - -proc snapped*(self: Vector2; by: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2Snapped(self, by) - -proc aspect*(self: Vector2): float32 {.inline.} = - getGDNativeAPI().vector2Aspect(self) - -proc dot*(a, b: Vector2): float32 {.inline.} = - getGDNativeAPI().vector2Dot(a, b) - -proc slide*(self, n: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2Slide(self, n) - -proc bounce*(self, n: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2Bounce(self, n) - -proc reflect*(self, n: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2Reflect(self, n) - -proc abs*(self: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2Abs(self) - -proc clamped*(self: Vector2; length: float32): Vector2 {.inline.} = - getGDNativeAPI().vector2Clamped(self, length) - -proc `+`*(self, other: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2OperatorAdd(self, other) - -proc `+=`*(self: var Vector2, other: Vector2) {.inline.} = - self = self + other - -proc `-`*(self, other: Vector2): Vector2 = - getGDNativeAPI().vector2OperatorSubtract(self, other) - -proc `-=`*(self: var Vector2, other: Vector2) {.inline.} = - self = self - other - -proc `*`*(self, other: Vector2): Vector2 = - getGDNativeAPI().vector2OperatorMultiplyVector(self, other) - -proc `*=`*(self: var Vector2, other: Vector2) {.inline.} = - self = self * other - -proc `*`*(self: Vector2, scalar: float32): Vector2 = - getGDNativeAPI().vector2OperatorMultiplyScalar(self, scalar) - -proc `*=`*(self: var Vector2, scalar: float32) {.inline.} = - self = self * scalar - -proc `/`*(self, other: Vector2): Vector2 = - getGDNativeAPI().vector2OperatorDivideVector(self, other) - -proc `/=`*(self: var Vector2, other: Vector2) {.inline.} = - self = self / other - -proc `/`*(self: Vector2; scalar: float32): Vector2 = - getGDNativeAPI().vector2OperatorDivideScalar(self, scalar) - -proc `/=`*(self: var Vector2; scalar: float32) {.inline.} = +proc `/=`*(self: var Vector2; scalar: float32) {.inline, noinit.} = self = self / scalar -proc `==`*(self, other: Vector2): bool {.inline.} = - getGDNativeAPI().vector2OperatorEqual(self, other) +proc `==`*(self, other: Vector2): bool {.inline, noinit.} = + self.x == other.x and self.y == other.y -proc `<`*(self, other: Vector2): bool {.inline.} = - getGDNativeAPI().vector2OperatorLess(self, other) +proc `<`*(self, other: Vector2): bool {.inline, noinit.} = + if self.x == other.x: + self.y < other.y + else: + self.x < other.x -proc `-`*(self: Vector2): Vector2 {.inline.} = - getGDNativeAPI().vector2OperatorNeg(self) +proc `>`*(self, other: Vector2): bool {.inline, noinit.} = + if self.x == other.x: + self.y > other.y + else: + self.x > other.x + +proc `-`*(self: Vector2): Vector2 {.inline, noinit.} = + Vector2(x: -self.x, y: -self.y) + +proc length*(self: Vector2): float32 {.inline, noinit.} = + sqrt(self.x * self.x + self.y * self.y) + +proc lengthSquared*(self: Vector2): float32 {.inline, noinit.} = + self.x * self.x + self.y * self.y + +proc normalize(self: var Vector2) {.inline.} = + var len = self.x * self.x + self.y * self.y + if len != 0: + len = sqrt(len) + self.x /= len + self.y /= len + +proc normalized*(self: Vector2): Vector2 {.inline, noinit.} = + result = self + result.normalize() + +proc angle*(self: Vector2): float32 {.inline, noinit.} = + arctan2(self.y, self.x) + +proc isNormalized*(self: Vector2): bool {.inline, noinit.} = + isEqualApprox(self.lengthSquared(), 1.0) + +proc distanceTo*(self, to: Vector2): float32 {.inline, noinit.} = + sqrt((self.x - to.x) * (self.x - to.x) + (self.y - to.y) * (self.y - to.y)) + +proc distanceSquaredTo*(self, to: Vector2): float32 {.inline, noinit.} = + (self.x - to.x) * (self.x - to.x) + (self.y - to.y) * (self.y - to.y) + +proc dot*(a, b: Vector2): float32 {.inline, noinit.} = + a.x * b.x + a.y * b.y + +proc cross*(a, b: Vector2): float32 {.inline, noinit.} = + a.x * b.y - a.y * b.x + +proc cross*(self: Vector2, scalar: float32): Vector2 {.inline, noinit.} = + Vector2(x: scalar * self.y, y: -scalar * self.x) + +proc angleTo*(self, to: Vector2): float32 {.noinit.} = + arctan2(cross(self, to), dot(self, to)) + +proc angleToPoint*(self, to: Vector2): float32 {.inline, noinit.} = + arctan2(self.y - to.y, self.x - to.x) + +proc floor*(self: Vector2): Vector2 {.inline, noinit.} = + Vector2(x: floor(self.x), y: floor(self.y)) + +proc planeProject*(self: Vector2, d: float32, + vec: Vector2): Vector2 {.noinit.} = + vec - self * (self.dot(vec) - d) + +proc project*(self, other: Vector2): Vector2 {.noinit.} = + self * (other.dot(self) / self.dot(self)) + +proc lerp*(self, b: Vector2; t: float32): Vector2 {.inline, noinit.} = + result = self + result.x += t * (b.x - self.x) + result.y += t * (b.y - self.y) + +proc cubicInterpolate*(self, b, preA, postB: Vector2; + t: float32): Vector2 {.noinit.} = + let p0 = preA + let p1 = self + let p2 = b + let p3 = postB + + let t2 = t * t + let t3 = t2 * t + + result = 0.5'f32 * ((p1 * 2.0'f32)) + + (-p0 + p2) * t + + (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3 + +proc setRotation*(self: var Vector2, radians: float32) {.inline, noinit.} = + self.x = cos(radians) + self.y = sin(radians) + +proc rotated*(self: Vector2; phi: float32): Vector2 {.inline, noinit.} = + result.setRotation(phi) + result *= self.length() + +proc tangent*(self: Vector2): Vector2 {.inline, noinit.} = + Vector2(x: self.y, y: -self.x) + +proc snapped*(self: Vector2; by: Vector2): Vector2 {.inline, noinit.} = + Vector2(x: stepify(self.x, by.x), y: stepify(self.y, by.y)) + +proc aspect*(self: Vector2): float32 {.inline, noinit.} = + self.x / self.y + +proc slide*(self, n: Vector2): Vector2 {.noinit.} = + when not defined(release): + if not n.isNormalized(): + printError("Normal not normalized in slide. " & getStackTrace()) + return vec2() + result = self - n * self.dot(n) + +proc reflect*(self, n: Vector2): Vector2 {.noinit.} = + when not defined(release): + if not n.isNormalized(): + printError("Normal not normalized in bounce. " & getStackTrace()) + return vec2() + result = 2.0 * n * self.dot(n) - self + +proc bounce*(self, n: Vector2): Vector2 {.inline, noinit.} = + -self.reflect(n) + +proc abs*(self: Vector2): Vector2 {.inline, noinit.} = + Vector2(x: abs(self.x), y: abs(self.y)) + +proc clamped*(self: Vector2; length: float32): Vector2 {.noinit.} = + let len = self.length() + result = self + if len > 0 and length < len: + result /= len + result *= length + +{.pop.} # stackTrace: off diff --git a/godot/core/vector3.nim b/godot/core/vector3.nim index f90bcfa..4ed9922 100644 --- a/godot/core/vector3.nim +++ b/godot/core/vector3.nim @@ -3,6 +3,8 @@ import math import godotbase, godotcoretypes +{.push stackTrace: off.} + proc vec3*(): Vector3 {.inline.} = Vector3() @@ -233,3 +235,5 @@ proc cubicInterpolate*(self, b, preA, postB: Vector3; (-p0 + p2) * t + (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3) + +{.pop.} # stackTrace: off \ No newline at end of file diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index b989bda..3d64f1f 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -2,7 +2,7 @@ import tables, typetraits, macros import gdnativeapi -import core.godotcoretypes +import core.godotcoretypes, core.godotbase import core.vector2, core.rect2, core.vector3, core.transform2d, core.planes, core.quats, core.aabb, @@ -92,25 +92,6 @@ type proc isFinalized*(obj: NimGodotObject): bool {.inline.} = obj.isFinalized -template printWarning*(warning: typed) = - ## Prints ``warning`` to Godot log, adding filename and line information. - let (filename, line) = instantiationInfo() - godotPrintWarning(cstring($warning), cstring"", cstring(filename), line.cint) - -template printError*(error: typed) = - ## Prints ``error`` to Godot log, adding filename and line information. - let (filename, line) = instantiationInfo() - godotPrintError(cstring($error), cstring"", cstring(filename), line.cint) - -proc print*(parts: varargs[string, `$`]) = - ## Prints concatenated ``parts`` to Godot log. - var combined = "" - for v in parts: - combined.add(v) - var s = combined.toGodotString() - godotPrint(s) - s.deinit() - var classRegistry {.threadvar.}: TableRef[cstring, ObjectInfo] var classRegistryStatic* {.compileTime.}: TableRef[cstring, ObjectInfo] ## Compile-time variable used for implementation of several procedures