Re-introduce build-in type code for core types

This commit is contained in:
Bastiaan Olij
2021-09-01 13:11:10 +10:00
parent 3a5bd21092
commit 46c63af715
34 changed files with 7409 additions and 14 deletions

355
src/variant/aabb.cpp Normal file
View File

@@ -0,0 +1,355 @@
#include <godot_cpp/variant/aabb.hpp>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
real_t AABB::get_area() const {
return size.x * size.y * size.z;
}
bool AABB::operator==(const AABB &p_rval) const {
return ((position == p_rval.position) && (size == p_rval.size));
}
bool AABB::operator!=(const AABB &p_rval) const {
return ((position != p_rval.position) || (size != p_rval.size));
}
void AABB::merge_with(const AABB &p_aabb) {
Vector3 beg_1, beg_2;
Vector3 end_1, end_2;
Vector3 min, max;
beg_1 = position;
beg_2 = p_aabb.position;
end_1 = Vector3(size.x, size.y, size.z) + beg_1;
end_2 = Vector3(p_aabb.size.x, p_aabb.size.y, p_aabb.size.z) + beg_2;
min.x = (beg_1.x < beg_2.x) ? beg_1.x : beg_2.x;
min.y = (beg_1.y < beg_2.y) ? beg_1.y : beg_2.y;
min.z = (beg_1.z < beg_2.z) ? beg_1.z : beg_2.z;
max.x = (end_1.x > end_2.x) ? end_1.x : end_2.x;
max.y = (end_1.y > end_2.y) ? end_1.y : end_2.y;
max.z = (end_1.z > end_2.z) ? end_1.z : end_2.z;
position = min;
size = max - min;
}
bool AABB::is_equal_approx(const AABB &p_aabb) const {
return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size);
}
AABB AABB::intersection(const AABB &p_aabb) const {
Vector3 src_min = position;
Vector3 src_max = position + size;
Vector3 dst_min = p_aabb.position;
Vector3 dst_max = p_aabb.position + p_aabb.size;
Vector3 min, max;
if (src_min.x > dst_max.x || src_max.x < dst_min.x) {
return AABB();
} else {
min.x = (src_min.x > dst_min.x) ? src_min.x : dst_min.x;
max.x = (src_max.x < dst_max.x) ? src_max.x : dst_max.x;
}
if (src_min.y > dst_max.y || src_max.y < dst_min.y) {
return AABB();
} else {
min.y = (src_min.y > dst_min.y) ? src_min.y : dst_min.y;
max.y = (src_max.y < dst_max.y) ? src_max.y : dst_max.y;
}
if (src_min.z > dst_max.z || src_max.z < dst_min.z) {
return AABB();
} else {
min.z = (src_min.z > dst_min.z) ? src_min.z : dst_min.z;
max.z = (src_max.z < dst_max.z) ? src_max.z : dst_max.z;
}
return AABB(min, max - min);
}
bool AABB::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip, Vector3 *r_normal) const {
Vector3 c1, c2;
Vector3 end = position + size;
real_t near = -1e20;
real_t far = 1e20;
int axis = 0;
for (int i = 0; i < 3; i++) {
if (p_dir[i] == 0) {
if ((p_from[i] < position[i]) || (p_from[i] > end[i])) {
return false;
}
} else { // ray not parallel to planes in this direction
c1[i] = (position[i] - p_from[i]) / p_dir[i];
c2[i] = (end[i] - p_from[i]) / p_dir[i];
if (c1[i] > c2[i]) {
SWAP(c1, c2);
}
if (c1[i] > near) {
near = c1[i];
axis = i;
}
if (c2[i] < far) {
far = c2[i];
}
if ((near > far) || (far < 0)) {
return false;
}
}
}
if (r_clip) {
*r_clip = c1;
}
if (r_normal) {
*r_normal = Vector3();
(*r_normal)[axis] = p_dir[axis] ? -1 : 1;
}
return true;
}
bool AABB::intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip, Vector3 *r_normal) const {
real_t min = 0, max = 1;
int axis = 0;
real_t sign = 0;
for (int i = 0; i < 3; i++) {
real_t seg_from = p_from[i];
real_t seg_to = p_to[i];
real_t box_begin = position[i];
real_t box_end = box_begin + size[i];
real_t cmin, cmax;
real_t csign;
if (seg_from < seg_to) {
if (seg_from > box_end || seg_to < box_begin) {
return false;
}
real_t length = seg_to - seg_from;
cmin = (seg_from < box_begin) ? ((box_begin - seg_from) / length) : 0;
cmax = (seg_to > box_end) ? ((box_end - seg_from) / length) : 1;
csign = -1.0;
} else {
if (seg_to > box_end || seg_from < box_begin) {
return false;
}
real_t length = seg_to - seg_from;
cmin = (seg_from > box_end) ? (box_end - seg_from) / length : 0;
cmax = (seg_to < box_begin) ? (box_begin - seg_from) / length : 1;
csign = 1.0;
}
if (cmin > min) {
min = cmin;
axis = i;
sign = csign;
}
if (cmax < max) {
max = cmax;
}
if (max < min) {
return false;
}
}
Vector3 rel = p_to - p_from;
if (r_normal) {
Vector3 normal;
normal[axis] = sign;
*r_normal = normal;
}
if (r_clip) {
*r_clip = p_from + rel * min;
}
return true;
}
bool AABB::intersects_plane(const Plane &p_plane) const {
Vector3 points[8] = {
Vector3(position.x, position.y, position.z),
Vector3(position.x, position.y, position.z + size.z),
Vector3(position.x, position.y + size.y, position.z),
Vector3(position.x, position.y + size.y, position.z + size.z),
Vector3(position.x + size.x, position.y, position.z),
Vector3(position.x + size.x, position.y, position.z + size.z),
Vector3(position.x + size.x, position.y + size.y, position.z),
Vector3(position.x + size.x, position.y + size.y, position.z + size.z),
};
bool over = false;
bool under = false;
for (int i = 0; i < 8; i++) {
if (p_plane.distance_to(points[i]) > 0) {
over = true;
} else {
under = true;
}
}
return under && over;
}
Vector3 AABB::get_longest_axis() const {
Vector3 axis(1, 0, 0);
real_t max_size = size.x;
if (size.y > max_size) {
axis = Vector3(0, 1, 0);
max_size = size.y;
}
if (size.z > max_size) {
axis = Vector3(0, 0, 1);
}
return axis;
}
int AABB::get_longest_axis_index() const {
int axis = 0;
real_t max_size = size.x;
if (size.y > max_size) {
axis = 1;
max_size = size.y;
}
if (size.z > max_size) {
axis = 2;
}
return axis;
}
Vector3 AABB::get_shortest_axis() const {
Vector3 axis(1, 0, 0);
real_t max_size = size.x;
if (size.y < max_size) {
axis = Vector3(0, 1, 0);
max_size = size.y;
}
if (size.z < max_size) {
axis = Vector3(0, 0, 1);
}
return axis;
}
int AABB::get_shortest_axis_index() const {
int axis = 0;
real_t max_size = size.x;
if (size.y < max_size) {
axis = 1;
max_size = size.y;
}
if (size.z < max_size) {
axis = 2;
}
return axis;
}
AABB AABB::merge(const AABB &p_with) const {
AABB aabb = *this;
aabb.merge_with(p_with);
return aabb;
}
AABB AABB::expand(const Vector3 &p_vector) const {
AABB aabb = *this;
aabb.expand_to(p_vector);
return aabb;
}
AABB AABB::grow(real_t p_by) const {
AABB aabb = *this;
aabb.grow_by(p_by);
return aabb;
}
void AABB::get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const {
ERR_FAIL_INDEX(p_edge, 12);
switch (p_edge) {
case 0: {
r_from = Vector3(position.x + size.x, position.y, position.z);
r_to = Vector3(position.x, position.y, position.z);
} break;
case 1: {
r_from = Vector3(position.x + size.x, position.y, position.z + size.z);
r_to = Vector3(position.x + size.x, position.y, position.z);
} break;
case 2: {
r_from = Vector3(position.x, position.y, position.z + size.z);
r_to = Vector3(position.x + size.x, position.y, position.z + size.z);
} break;
case 3: {
r_from = Vector3(position.x, position.y, position.z);
r_to = Vector3(position.x, position.y, position.z + size.z);
} break;
case 4: {
r_from = Vector3(position.x, position.y + size.y, position.z);
r_to = Vector3(position.x + size.x, position.y + size.y, position.z);
} break;
case 5: {
r_from = Vector3(position.x + size.x, position.y + size.y, position.z);
r_to = Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
} break;
case 6: {
r_from = Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
r_to = Vector3(position.x, position.y + size.y, position.z + size.z);
} break;
case 7: {
r_from = Vector3(position.x, position.y + size.y, position.z + size.z);
r_to = Vector3(position.x, position.y + size.y, position.z);
} break;
case 8: {
r_from = Vector3(position.x, position.y, position.z + size.z);
r_to = Vector3(position.x, position.y + size.y, position.z + size.z);
} break;
case 9: {
r_from = Vector3(position.x, position.y, position.z);
r_to = Vector3(position.x, position.y + size.y, position.z);
} break;
case 10: {
r_from = Vector3(position.x + size.x, position.y, position.z);
r_to = Vector3(position.x + size.x, position.y + size.y, position.z);
} break;
case 11: {
r_from = Vector3(position.x + size.x, position.y, position.z + size.z);
r_to = Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
} break;
}
}
AABB::operator String() const {
return position.operator String() + " - " + size.operator String();
}
} // namespace godot

1113
src/variant/basis.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -192,6 +192,14 @@ bool String::operator!=(const char32_t *p_str) const {
return *this != String(p_str);
}
const char32_t &String::operator[](int p_index) const {
return *internal::interface->string_operator_index_const((GDNativeStringPtr) this, p_index);
}
char32_t &String::operator[](int p_index) {
return *internal::interface->string_operator_index((GDNativeStringPtr) this, p_index);
}
bool operator==(const char *p_chr, const String &p_str) {
return p_str == String(p_chr);
}

532
src/variant/color.cpp Normal file
View File

@@ -0,0 +1,532 @@
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/variant/color.hpp>
#include <godot_cpp/variant/color_names.inc.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
uint32_t Color::to_argb32() const {
uint32_t c = (uint8_t)Math::round(a * 255);
c <<= 8;
c |= (uint8_t)Math::round(r * 255);
c <<= 8;
c |= (uint8_t)Math::round(g * 255);
c <<= 8;
c |= (uint8_t)Math::round(b * 255);
return c;
}
uint32_t Color::to_abgr32() const {
uint32_t c = (uint8_t)Math::round(a * 255);
c <<= 8;
c |= (uint8_t)Math::round(b * 255);
c <<= 8;
c |= (uint8_t)Math::round(g * 255);
c <<= 8;
c |= (uint8_t)Math::round(r * 255);
return c;
}
uint32_t Color::to_rgba32() const {
uint32_t c = (uint8_t)Math::round(r * 255);
c <<= 8;
c |= (uint8_t)Math::round(g * 255);
c <<= 8;
c |= (uint8_t)Math::round(b * 255);
c <<= 8;
c |= (uint8_t)Math::round(a * 255);
return c;
}
uint64_t Color::to_abgr64() const {
uint64_t c = (uint16_t)Math::round(a * 65535);
c <<= 16;
c |= (uint16_t)Math::round(b * 65535);
c <<= 16;
c |= (uint16_t)Math::round(g * 65535);
c <<= 16;
c |= (uint16_t)Math::round(r * 65535);
return c;
}
uint64_t Color::to_argb64() const {
uint64_t c = (uint16_t)Math::round(a * 65535);
c <<= 16;
c |= (uint16_t)Math::round(r * 65535);
c <<= 16;
c |= (uint16_t)Math::round(g * 65535);
c <<= 16;
c |= (uint16_t)Math::round(b * 65535);
return c;
}
uint64_t Color::to_rgba64() const {
uint64_t c = (uint16_t)Math::round(r * 65535);
c <<= 16;
c |= (uint16_t)Math::round(g * 65535);
c <<= 16;
c |= (uint16_t)Math::round(b * 65535);
c <<= 16;
c |= (uint16_t)Math::round(a * 65535);
return c;
}
float Color::get_h() const {
float min = Math::min(r, g);
min = Math::min(min, b);
float max = Math::max(r, g);
max = Math::max(max, b);
float delta = max - min;
if (delta == 0) {
return 0;
}
float h;
if (r == max) {
h = (g - b) / delta; // between yellow & magenta
} else if (g == max) {
h = 2 + (b - r) / delta; // between cyan & yellow
} else {
h = 4 + (r - g) / delta; // between magenta & cyan
}
h /= 6.0;
if (h < 0) {
h += 1.0;
}
return h;
}
float Color::get_s() const {
float min = Math::min(r, g);
min = Math::min(min, b);
float max = Math::max(r, g);
max = Math::max(max, b);
float delta = max - min;
return (max != 0) ? (delta / max) : 0;
}
float Color::get_v() const {
float max = Math::max(r, g);
max = Math::max(max, b);
return max;
}
void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
int i;
float f, p, q, t;
a = p_alpha;
if (p_s == 0) {
// Achromatic (grey)
r = g = b = p_v;
return;
}
p_h *= 6.0;
p_h = Math::fmod(p_h, 6);
i = Math::floor(p_h);
f = p_h - i;
p = p_v * (1 - p_s);
q = p_v * (1 - p_s * f);
t = p_v * (1 - p_s * (1 - f));
switch (i) {
case 0: // Red is the dominant color
r = p_v;
g = t;
b = p;
break;
case 1: // Green is the dominant color
r = q;
g = p_v;
b = p;
break;
case 2:
r = p;
g = p_v;
b = t;
break;
case 3: // Blue is the dominant color
r = p;
g = q;
b = p_v;
break;
case 4:
r = t;
g = p;
b = p_v;
break;
default: // (5) Red is the dominant color
r = p_v;
g = p;
b = q;
break;
}
}
bool Color::is_equal_approx(const Color &p_color) const {
return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a);
}
void Color::invert() {
r = 1.0 - r;
g = 1.0 - g;
b = 1.0 - b;
}
Color Color::hex(uint32_t p_hex) {
float a = (p_hex & 0xFF) / 255.0;
p_hex >>= 8;
float b = (p_hex & 0xFF) / 255.0;
p_hex >>= 8;
float g = (p_hex & 0xFF) / 255.0;
p_hex >>= 8;
float r = (p_hex & 0xFF) / 255.0;
return Color(r, g, b, a);
}
Color Color::hex64(uint64_t p_hex) {
float a = (p_hex & 0xFFFF) / 65535.0;
p_hex >>= 16;
float b = (p_hex & 0xFFFF) / 65535.0;
p_hex >>= 16;
float g = (p_hex & 0xFFFF) / 65535.0;
p_hex >>= 16;
float r = (p_hex & 0xFFFF) / 65535.0;
return Color(r, g, b, a);
}
Color Color::from_rgbe9995(uint32_t p_rgbe) {
float r = p_rgbe & 0x1ff;
float g = (p_rgbe >> 9) & 0x1ff;
float b = (p_rgbe >> 18) & 0x1ff;
float e = (p_rgbe >> 27);
float m = Math::pow(2, e - 15.0 - 9.0);
float rd = r * m;
float gd = g * m;
float bd = b * m;
return Color(rd, gd, bd, 1.0f);
}
static int _parse_col4(const String &p_str, int p_ofs) {
char character = p_str[p_ofs];
if (character >= '0' && character <= '9') {
return character - '0';
} else if (character >= 'a' && character <= 'f') {
return character + (10 - 'a');
} else if (character >= 'A' && character <= 'F') {
return character + (10 - 'A');
}
return -1;
}
static int _parse_col8(const String &p_str, int p_ofs) {
return _parse_col4(p_str, p_ofs) * 16 + _parse_col4(p_str, p_ofs + 1);
}
Color Color::inverted() const {
Color c = *this;
c.invert();
return c;
}
Color Color::html(const String &p_rgba) {
String color = p_rgba;
if (color.length() == 0) {
return Color();
}
if (color[0] == '#') {
color = color.substr(1);
}
// If enabled, use 1 hex digit per channel instead of 2.
// Other sizes aren't in the HTML/CSS spec but we could add them if desired.
bool is_shorthand = color.length() < 5;
bool alpha = false;
if (color.length() == 8) {
alpha = true;
} else if (color.length() == 6) {
alpha = false;
} else if (color.length() == 4) {
alpha = true;
} else if (color.length() == 3) {
alpha = false;
} else {
ERR_FAIL_V(Color());
}
float r, g, b, a = 1.0;
if (is_shorthand) {
r = _parse_col4(color, 0) / 15.0;
g = _parse_col4(color, 1) / 15.0;
b = _parse_col4(color, 2) / 15.0;
if (alpha) {
a = _parse_col4(color, 3) / 15.0;
}
} else {
r = _parse_col8(color, 0) / 255.0;
g = _parse_col8(color, 2) / 255.0;
b = _parse_col8(color, 4) / 255.0;
if (alpha) {
a = _parse_col8(color, 6) / 255.0;
}
}
ERR_FAIL_COND_V(r < 0, Color());
ERR_FAIL_COND_V(g < 0, Color());
ERR_FAIL_COND_V(b < 0, Color());
ERR_FAIL_COND_V(a < 0, Color());
return Color(r, g, b, a);
}
bool Color::html_is_valid(const String &p_color) {
String color = p_color;
if (color.length() == 0) {
return false;
}
if (color[0] == '#') {
color = color.substr(1);
}
// Check if the amount of hex digits is valid.
int len = color.length();
if (!(len == 3 || len == 4 || len == 6 || len == 8)) {
return false;
}
// Check if each hex digit is valid.
for (int i = 0; i < len; i++) {
if (_parse_col4(color, i) == -1) {
return false;
}
}
return true;
}
Color Color::named(const String &p_name) {
int idx = find_named_color(p_name);
if (idx == -1) {
ERR_FAIL_V(Color());
return Color();
}
return get_named_color(idx);
}
Color Color::named(const String &p_name, const Color &p_default) {
int idx = find_named_color(p_name);
if (idx == -1) {
return p_default;
}
return get_named_color(idx);
}
int Color::find_named_color(const String &p_name) {
String name = p_name;
// Normalize name
name = name.replace(" ", "");
name = name.replace("-", "");
name = name.replace("_", "");
name = name.replace("'", "");
name = name.replace(".", "");
name = name.to_lower();
int idx = 0;
while (named_colors[idx].name != nullptr) {
if (name == String(named_colors[idx].name)) {
return idx;
}
idx++;
}
return -1;
}
int Color::get_named_color_count() {
int idx = 0;
while (named_colors[idx].name != nullptr) {
idx++;
}
return idx;
}
String Color::get_named_color_name(int p_idx) {
return named_colors[p_idx].name;
}
Color Color::get_named_color(int p_idx) {
return named_colors[p_idx].color;
}
// For a version that errors on invalid values instead of returning
// a default color, use the Color(String) constructor instead.
Color Color::from_string(const String &p_string, const Color &p_default) {
if (html_is_valid(p_string)) {
return html(p_string);
} else {
return named(p_string, p_default);
}
}
String _to_hex(float p_val) {
int v = Math::round(p_val * 255);
v = Math::clamp(v, 0, 255);
String ret;
for (int i = 0; i < 2; i++) {
char32_t c[2] = { 0, 0 };
int lv = v & 0xF;
if (lv < 10) {
c[0] = '0' + lv;
} else {
c[0] = 'a' + lv - 10;
}
v >>= 4;
String cs = (const char32_t *)c;
ret = cs + ret;
}
return ret;
}
String Color::to_html(bool p_alpha) const {
String txt;
txt = txt + _to_hex(g);
txt = txt + _to_hex(b);
txt = txt + _to_hex(r);
if (p_alpha) {
txt = txt + _to_hex(a);
}
return txt;
}
Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) {
Color result;
result.set_hsv(p_h, p_s, p_v, p_a);
return result;
}
Color::operator String() const {
return String::num(r, 3) + ", " + String::num(g, 3) + ", " + String::num(b, 3) + ", " + String::num(a, 3);
}
Color Color::operator+(const Color &p_color) const {
return Color(
r + p_color.r,
g + p_color.g,
b + p_color.b,
a + p_color.a);
}
void Color::operator+=(const Color &p_color) {
r = r + p_color.r;
g = g + p_color.g;
b = b + p_color.b;
a = a + p_color.a;
}
Color Color::operator-(const Color &p_color) const {
return Color(
r - p_color.r,
g - p_color.g,
b - p_color.b,
a - p_color.a);
}
void Color::operator-=(const Color &p_color) {
r = r - p_color.r;
g = g - p_color.g;
b = b - p_color.b;
a = a - p_color.a;
}
Color Color::operator*(const Color &p_color) const {
return Color(
r * p_color.r,
g * p_color.g,
b * p_color.b,
a * p_color.a);
}
Color Color::operator*(float p_scalar) const {
return Color(
r * p_scalar,
g * p_scalar,
b * p_scalar,
a * p_scalar);
}
void Color::operator*=(const Color &p_color) {
r = r * p_color.r;
g = g * p_color.g;
b = b * p_color.b;
a = a * p_color.a;
}
void Color::operator*=(float p_scalar) {
r = r * p_scalar;
g = g * p_scalar;
b = b * p_scalar;
a = a * p_scalar;
}
Color Color::operator/(const Color &p_color) const {
return Color(
r / p_color.r,
g / p_color.g,
b / p_color.b,
a / p_color.a);
}
Color Color::operator/(float p_scalar) const {
return Color(
r / p_scalar,
g / p_scalar,
b / p_scalar,
a / p_scalar);
}
void Color::operator/=(const Color &p_color) {
r = r / p_color.r;
g = g / p_color.g;
b = b / p_color.b;
a = a / p_color.a;
}
void Color::operator/=(float p_scalar) {
r = r / p_scalar;
g = g / p_scalar;
b = b / p_scalar;
a = a / p_scalar;
}
Color Color::operator-() const {
return Color(
1.0 - r,
1.0 - g,
1.0 - b,
1.0 - a);
}
} // namespace godot

View File

@@ -0,0 +1,97 @@
// extra functions for packed arrays
#include <godot_cpp/godot.hpp>
#include <godot_cpp/variant/packed_byte_array.hpp>
#include <godot_cpp/variant/packed_color_array.hpp>
#include <godot_cpp/variant/packed_float32_array.hpp>
#include <godot_cpp/variant/packed_float64_array.hpp>
#include <godot_cpp/variant/packed_int32_array.hpp>
#include <godot_cpp/variant/packed_int64_array.hpp>
#include <godot_cpp/variant/packed_string_array.hpp>
#include <godot_cpp/variant/packed_vector2_array.hpp>
#include <godot_cpp/variant/packed_vector3_array.hpp>
namespace godot {
const uint8_t &PackedByteArray::operator[](int p_index) const {
return *internal::interface->packed_byte_array_operator_index_const((GDNativeTypePtr *)this, p_index);
}
uint8_t &PackedByteArray::operator[](int p_index) {
return *internal::interface->packed_byte_array_operator_index((GDNativeTypePtr *)this, p_index);
}
const Color &PackedColorArray::operator[](int p_index) const {
const Color *color = (const Color *) internal::interface->packed_color_array_operator_index_const((GDNativeTypePtr *)this, p_index);
return *color;
}
Color &PackedColorArray::operator[](int p_index) {
Color *color = (Color *) internal::interface->packed_color_array_operator_index((GDNativeTypePtr *)this, p_index);
return *color;
}
const float &PackedFloat32Array::operator[](int p_index) const {
return *internal::interface->packed_float32_array_operator_index_const((GDNativeTypePtr *)this, p_index);
}
float &PackedFloat32Array::operator[](int p_index) {
return *internal::interface->packed_float32_array_operator_index((GDNativeTypePtr *)this, p_index);
}
const double &PackedFloat64Array::operator[](int p_index) const {
return *internal::interface->packed_float64_array_operator_index_const((GDNativeTypePtr *)this, p_index);
}
double &PackedFloat64Array::operator[](int p_index) {
return *internal::interface->packed_float64_array_operator_index((GDNativeTypePtr *)this, p_index);
}
const int32_t &PackedInt32Array::operator[](int p_index) const {
return *internal::interface->packed_int32_array_operator_index_const((GDNativeTypePtr *)this, p_index);
}
int32_t &PackedInt32Array::operator[](int p_index) {
return *internal::interface->packed_int32_array_operator_index((GDNativeTypePtr *)this, p_index);
}
const int64_t &PackedInt64Array::operator[](int p_index) const {
return *internal::interface->packed_int64_array_operator_index_const((GDNativeTypePtr *)this, p_index);
}
int64_t &PackedInt64Array::operator[](int p_index) {
return *internal::interface->packed_int64_array_operator_index((GDNativeTypePtr *)this, p_index);
}
const String &PackedStringArray::operator[](int p_index) const {
const String *string = (const String *) internal::interface->packed_string_array_operator_index_const((GDNativeTypePtr *)this, p_index);
return *string;
}
String &PackedStringArray::operator[](int p_index) {
String *string = (String *) internal::interface->packed_string_array_operator_index((GDNativeTypePtr *)this, p_index);
return *string;
}
const Vector2 &PackedVector2Array::operator[](int p_index) const {
const Vector2 *vec = (const Vector2 *) internal::interface->packed_vector2_array_operator_index_const((GDNativeTypePtr *)this, p_index);
return *vec;
}
Vector2 &PackedVector2Array::operator[](int p_index) {
Vector2 *vec = (Vector2 *) internal::interface->packed_vector2_array_operator_index((GDNativeTypePtr *)this, p_index);
return *vec;
}
const Vector3 &PackedVector3Array::operator[](int p_index) const {
const Vector3 *vec = (const Vector3 *) internal::interface->packed_vector3_array_operator_index_const((GDNativeTypePtr *)this, p_index);
return *vec;
}
Vector3 &PackedVector3Array::operator[](int p_index) {
Vector3 *vec = (Vector3 *) internal::interface->packed_vector3_array_operator_index((GDNativeTypePtr *)this, p_index);
return *vec;
}
} // namespace godot

127
src/variant/plane.cpp Normal file
View File

@@ -0,0 +1,127 @@
#include <godot_cpp/variant/plane.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
void Plane::set_normal(const Vector3 &p_normal) {
normal = p_normal;
}
void Plane::normalize() {
real_t l = normal.length();
if (l == 0) {
*this = Plane(0, 0, 0, 0);
return;
}
normal /= l;
d /= l;
}
Plane Plane::normalized() const {
Plane p = *this;
p.normalize();
return p;
}
Vector3 Plane::get_any_perpendicular_normal() const {
static const Vector3 p1 = Vector3(1, 0, 0);
static const Vector3 p2 = Vector3(0, 1, 0);
Vector3 p;
if (Math::abs(normal.dot(p1)) > 0.99) { // if too similar to p1
p = p2; // use p2
} else {
p = p1; // use p1
}
p -= normal * normal.dot(p);
p.normalize();
return p;
}
/* intersections */
bool Plane::intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r_result) const {
const Plane &p_plane0 = *this;
Vector3 normal0 = p_plane0.normal;
Vector3 normal1 = p_plane1.normal;
Vector3 normal2 = p_plane2.normal;
real_t denom = vec3_cross(normal0, normal1).dot(normal2);
if (Math::is_zero_approx(denom)) {
return false;
}
if (r_result) {
*r_result = ((vec3_cross(normal1, normal2) * p_plane0.d) +
(vec3_cross(normal2, normal0) * p_plane1.d) +
(vec3_cross(normal0, normal1) * p_plane2.d)) /
denom;
}
return true;
}
bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const {
Vector3 segment = p_dir;
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
if (Math::is_zero_approx(den)) {
return false;
}
real_t dist = (normal.dot(p_from) - d) / den;
//printf("dist is %i\n",dist);
if (dist > CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
return false;
}
dist = -dist;
*p_intersection = p_from + segment * dist;
return true;
}
bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 *p_intersection) const {
Vector3 segment = p_begin - p_end;
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
if (Math::is_zero_approx(den)) {
return false;
}
real_t dist = (normal.dot(p_begin) - d) / den;
//printf("dist is %i\n",dist);
if (dist < -CMP_EPSILON || dist > (1.0 + CMP_EPSILON)) {
return false;
}
dist = -dist;
*p_intersection = p_begin + segment * dist;
return true;
}
/* misc */
bool Plane::is_equal_approx_any_side(const Plane &p_plane) const {
return (normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d)) || (normal.is_equal_approx(-p_plane.normal) && Math::is_equal_approx(d, -p_plane.d));
}
bool Plane::is_equal_approx(const Plane &p_plane) const {
return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
}
Plane::operator String() const {
return normal.operator String() + ", " + String::num(d,3);
}
} // namespace godot

203
src/variant/quaternion.cpp Normal file
View File

@@ -0,0 +1,203 @@
#include <godot_cpp/variant/quaternion.hpp>
#include <godot_cpp/variant/basis.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
// get_euler_xyz returns a vector containing the Euler angles in the format
// (ax,ay,az), where ax is the angle of rotation around x axis,
// and similar for other axes.
// This implementation uses XYZ convention (Z is the first rotation).
Vector3 Quaternion::get_euler_xyz() const {
Basis m(*this);
return m.get_euler_xyz();
}
// get_euler_yxz returns a vector containing the Euler angles in the format
// (ax,ay,az), where ax is the angle of rotation around x axis,
// and similar for other axes.
// This implementation uses YXZ convention (Z is the first rotation).
Vector3 Quaternion::get_euler_yxz() const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_normalized(), Vector3(0, 0, 0));
#endif
Basis m(*this);
return m.get_euler_yxz();
}
void Quaternion::operator*=(const Quaternion &p_q) {
x = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y;
y = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z;
z = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x;
w = w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z;
}
Quaternion Quaternion::operator*(const Quaternion &p_q) const {
Quaternion r = *this;
r *= p_q;
return r;
}
bool Quaternion::is_equal_approx(const Quaternion &p_quat) const {
return Math::is_equal_approx(x, p_quat.x) && Math::is_equal_approx(y, p_quat.y) && Math::is_equal_approx(z, p_quat.z) && Math::is_equal_approx(w, p_quat.w);
}
real_t Quaternion::length() const {
return Math::sqrt(length_squared());
}
void Quaternion::normalize() {
*this /= length();
}
Quaternion Quaternion::normalized() const {
return *this / length();
}
bool Quaternion::is_normalized() const {
return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); //use less epsilon
}
Quaternion Quaternion::inverse() const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_normalized(), Quaternion());
#endif
return Quaternion(-x, -y, -z, w);
}
Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_normalized(), Quaternion());
ERR_FAIL_COND_V(!p_to.is_normalized(), Quaternion());
#endif
Quaternion to1;
real_t omega, cosom, sinom, scale0, scale1;
// calc cosine
cosom = dot(p_to);
// adjust signs (if necessary)
if (cosom < 0.0) {
cosom = -cosom;
to1.x = -p_to.x;
to1.y = -p_to.y;
to1.z = -p_to.z;
to1.w = -p_to.w;
} else {
to1.x = p_to.x;
to1.y = p_to.y;
to1.z = p_to.z;
to1.w = p_to.w;
}
// calculate coefficients
if ((1.0 - cosom) > CMP_EPSILON) {
// standard case (slerp)
omega = Math::acos(cosom);
sinom = Math::sin(omega);
scale0 = Math::sin((1.0 - p_weight) * omega) / sinom;
scale1 = Math::sin(p_weight * omega) / sinom;
} else {
// "from" and "to" quaternions are very close
// ... so we can do a linear interpolation
scale0 = 1.0 - p_weight;
scale1 = p_weight;
}
// calculate final values
return Quaternion(
scale0 * x + scale1 * to1.x,
scale0 * y + scale1 * to1.y,
scale0 * z + scale1 * to1.z,
scale0 * w + scale1 * to1.w);
}
Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_normalized(), Quaternion());
ERR_FAIL_COND_V(!p_to.is_normalized(), Quaternion());
#endif
const Quaternion &from = *this;
real_t dot = from.dot(p_to);
if (Math::abs(dot) > 0.9999) {
return from;
}
real_t theta = Math::acos(dot),
sinT = 1.0 / Math::sin(theta),
newFactor = Math::sin(p_weight * theta) * sinT,
invFactor = Math::sin((1.0 - p_weight) * theta) * sinT;
return Quaternion(invFactor * from.x + newFactor * p_to.x,
invFactor * from.y + newFactor * p_to.y,
invFactor * from.z + newFactor * p_to.z,
invFactor * from.w + newFactor * p_to.w);
}
Quaternion Quaternion::cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_normalized(), Quaternion());
ERR_FAIL_COND_V(!p_b.is_normalized(), Quaternion());
#endif
//the only way to do slerp :|
real_t t2 = (1.0 - p_weight) * p_weight * 2;
Quaternion sp = this->slerp(p_b, p_weight);
Quaternion sq = p_pre_a.slerpni(p_post_b, p_weight);
return sp.slerpni(sq, t2);
}
Quaternion::operator String() const {
return String::num(x, 5) + ", " + String::num(y, 5) + ", " + String::num(z, 5) + ", " + String::num(w, 5);
}
Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
#ifdef MATH_CHECKS
ERR_FAIL_COND(!p_axis.is_normalized());
#endif
real_t d = p_axis.length();
if (d == 0) {
x = 0;
y = 0;
z = 0;
w = 0;
} else {
real_t sin_angle = Math::sin(p_angle * 0.5);
real_t cos_angle = Math::cos(p_angle * 0.5);
real_t s = sin_angle / d;
x = p_axis.x * s;
y = p_axis.y * s;
z = p_axis.z * s;
w = cos_angle;
}
}
// Euler constructor expects a vector containing the Euler angles in the format
// (ax, ay, az), where ax is the angle of rotation around x axis,
// and similar for other axes.
// This implementation uses YXZ convention (Z is the first rotation).
Quaternion::Quaternion(const Vector3 &p_euler) {
real_t half_a1 = p_euler.y * 0.5;
real_t half_a2 = p_euler.x * 0.5;
real_t half_a3 = p_euler.z * 0.5;
// R = Y(a1).X(a2).Z(a3) convention for Euler angles.
// Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6)
// a3 is the angle of the first rotation, following the notation in this reference.
real_t cos_a1 = Math::cos(half_a1);
real_t sin_a1 = Math::sin(half_a1);
real_t cos_a2 = Math::cos(half_a2);
real_t sin_a2 = Math::sin(half_a2);
real_t cos_a3 = Math::cos(half_a3);
real_t sin_a3 = Math::sin(half_a3);
x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3;
y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3;
z = -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3;
w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3;
}
} // namespace godot

241
src/variant/rect2.cpp Normal file
View File

@@ -0,0 +1,241 @@
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/transform2d.hpp>
namespace godot {
bool Rect2::is_equal_approx(const Rect2 &p_rect) const {
return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size);
}
bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
real_t min = 0, max = 1;
int axis = 0;
real_t sign = 0;
for (int i = 0; i < 2; i++) {
real_t seg_from = p_from[i];
real_t seg_to = p_to[i];
real_t box_begin = position[i];
real_t box_end = box_begin + size[i];
real_t cmin, cmax;
real_t csign;
if (seg_from < seg_to) {
if (seg_from > box_end || seg_to < box_begin) {
return false;
}
real_t length = seg_to - seg_from;
cmin = (seg_from < box_begin) ? ((box_begin - seg_from) / length) : 0;
cmax = (seg_to > box_end) ? ((box_end - seg_from) / length) : 1;
csign = -1.0;
} else {
if (seg_to > box_end || seg_from < box_begin) {
return false;
}
real_t length = seg_to - seg_from;
cmin = (seg_from > box_end) ? (box_end - seg_from) / length : 0;
cmax = (seg_to < box_begin) ? (box_begin - seg_from) / length : 1;
csign = 1.0;
}
if (cmin > min) {
min = cmin;
axis = i;
sign = csign;
}
if (cmax < max) {
max = cmax;
}
if (max < min) {
return false;
}
}
Vector2 rel = p_to - p_from;
if (r_normal) {
Vector2 normal;
normal[axis] = sign;
*r_normal = normal;
}
if (r_pos) {
*r_pos = p_from + rel * min;
}
return true;
}
bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const {
//SAT intersection between local and transformed rect2
Vector2 xf_points[4] = {
p_xform.xform(p_rect.position),
p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y)),
p_xform.xform(Vector2(p_rect.position.x, p_rect.position.y + p_rect.size.y)),
p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y)),
};
real_t low_limit;
//base rect2 first (faster)
if (xf_points[0].y > position.y) {
goto next1;
}
if (xf_points[1].y > position.y) {
goto next1;
}
if (xf_points[2].y > position.y) {
goto next1;
}
if (xf_points[3].y > position.y) {
goto next1;
}
return false;
next1:
low_limit = position.y + size.y;
if (xf_points[0].y < low_limit) {
goto next2;
}
if (xf_points[1].y < low_limit) {
goto next2;
}
if (xf_points[2].y < low_limit) {
goto next2;
}
if (xf_points[3].y < low_limit) {
goto next2;
}
return false;
next2:
if (xf_points[0].x > position.x) {
goto next3;
}
if (xf_points[1].x > position.x) {
goto next3;
}
if (xf_points[2].x > position.x) {
goto next3;
}
if (xf_points[3].x > position.x) {
goto next3;
}
return false;
next3:
low_limit = position.x + size.x;
if (xf_points[0].x < low_limit) {
goto next4;
}
if (xf_points[1].x < low_limit) {
goto next4;
}
if (xf_points[2].x < low_limit) {
goto next4;
}
if (xf_points[3].x < low_limit) {
goto next4;
}
return false;
next4:
Vector2 xf_points2[4] = {
position,
Vector2(position.x + size.x, position.y),
Vector2(position.x, position.y + size.y),
Vector2(position.x + size.x, position.y + size.y),
};
real_t maxa = p_xform.elements[0].dot(xf_points2[0]);
real_t mina = maxa;
real_t dp = p_xform.elements[0].dot(xf_points2[1]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
dp = p_xform.elements[0].dot(xf_points2[2]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
dp = p_xform.elements[0].dot(xf_points2[3]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
real_t maxb = p_xform.elements[0].dot(xf_points[0]);
real_t minb = maxb;
dp = p_xform.elements[0].dot(xf_points[1]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
dp = p_xform.elements[0].dot(xf_points[2]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
dp = p_xform.elements[0].dot(xf_points[3]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
if (mina > maxb) {
return false;
}
if (minb > maxa) {
return false;
}
maxa = p_xform.elements[1].dot(xf_points2[0]);
mina = maxa;
dp = p_xform.elements[1].dot(xf_points2[1]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
dp = p_xform.elements[1].dot(xf_points2[2]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
dp = p_xform.elements[1].dot(xf_points2[3]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
maxb = p_xform.elements[1].dot(xf_points[0]);
minb = maxb;
dp = p_xform.elements[1].dot(xf_points[1]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
dp = p_xform.elements[1].dot(xf_points[2]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
dp = p_xform.elements[1].dot(xf_points[3]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
if (mina > maxb) {
return false;
}
if (minb > maxa) {
return false;
}
return true;
}
} // namespace godot

3
src/variant/rect2i.cpp Normal file
View File

@@ -0,0 +1,3 @@
#include <godot_cpp/variant/rect2i.hpp>
// No implementation left. This is here to add the header as a compiled unit.

248
src/variant/transform2d.cpp Normal file
View File

@@ -0,0 +1,248 @@
#include <godot_cpp/variant/transform2d.hpp>
namespace godot {
void Transform2D::invert() {
// FIXME: this function assumes the basis is a rotation matrix, with no scaling.
// Transform2D::affine_inverse can handle matrices with scaling, so GDScript should eventually use that.
SWAP(elements[0][1], elements[1][0]);
elements[2] = basis_xform(-elements[2]);
}
Transform2D Transform2D::inverse() const {
Transform2D inv = *this;
inv.invert();
return inv;
}
void Transform2D::affine_invert() {
real_t det = basis_determinant();
#ifdef MATH_CHECKS
ERR_FAIL_COND(det == 0);
#endif
real_t idet = 1.0 / det;
SWAP(elements[0][0], elements[1][1]);
elements[0] *= Vector2(idet, -idet);
elements[1] *= Vector2(-idet, idet);
elements[2] = basis_xform(-elements[2]);
}
Transform2D Transform2D::affine_inverse() const {
Transform2D inv = *this;
inv.affine_invert();
return inv;
}
void Transform2D::rotate(real_t p_phi) {
*this = Transform2D(p_phi, Vector2()) * (*this);
}
real_t Transform2D::get_skew() const {
real_t det = basis_determinant();
return Math::acos(elements[0].normalized().dot(Math::sign(det) * elements[1].normalized())) - Math_PI * 0.5;
}
void Transform2D::set_skew(float p_angle) {
real_t det = basis_determinant();
elements[1] = Math::sign(det) * elements[0].rotated((Math_PI * 0.5 + p_angle)).normalized() * elements[1].length();
}
real_t Transform2D::get_rotation() const {
return Math::atan2(elements[0].y, elements[0].x);
}
void Transform2D::set_rotation(real_t p_rot) {
Size2 scale = get_scale();
real_t cr = Math::cos(p_rot);
real_t sr = Math::sin(p_rot);
elements[0][0] = cr;
elements[0][1] = sr;
elements[1][0] = -sr;
elements[1][1] = cr;
set_scale(scale);
}
Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) {
real_t cr = Math::cos(p_rot);
real_t sr = Math::sin(p_rot);
elements[0][0] = cr;
elements[0][1] = sr;
elements[1][0] = -sr;
elements[1][1] = cr;
elements[2] = p_pos;
}
Size2 Transform2D::get_scale() const {
real_t det_sign = Math::sign(basis_determinant());
return Size2(elements[0].length(), det_sign * elements[1].length());
}
void Transform2D::set_scale(const Size2 &p_scale) {
elements[0].normalize();
elements[1].normalize();
elements[0] *= p_scale.x;
elements[1] *= p_scale.y;
}
void Transform2D::scale(const Size2 &p_scale) {
scale_basis(p_scale);
elements[2] *= p_scale;
}
void Transform2D::scale_basis(const Size2 &p_scale) {
elements[0][0] *= p_scale.x;
elements[0][1] *= p_scale.y;
elements[1][0] *= p_scale.x;
elements[1][1] *= p_scale.y;
}
void Transform2D::translate(real_t p_tx, real_t p_ty) {
translate(Vector2(p_tx, p_ty));
}
void Transform2D::translate(const Vector2 &p_translation) {
elements[2] += basis_xform(p_translation);
}
void Transform2D::orthonormalize() {
// Gram-Schmidt Process
Vector2 x = elements[0];
Vector2 y = elements[1];
x.normalize();
y = (y - x * (x.dot(y)));
y.normalize();
elements[0] = x;
elements[1] = y;
}
Transform2D Transform2D::orthonormalized() const {
Transform2D on = *this;
on.orthonormalize();
return on;
}
bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
return elements[0].is_equal_approx(p_transform.elements[0]) && elements[1].is_equal_approx(p_transform.elements[1]) && elements[2].is_equal_approx(p_transform.elements[2]);
}
bool Transform2D::operator==(const Transform2D &p_transform) const {
for (int i = 0; i < 3; i++) {
if (elements[i] != p_transform.elements[i]) {
return false;
}
}
return true;
}
bool Transform2D::operator!=(const Transform2D &p_transform) const {
for (int i = 0; i < 3; i++) {
if (elements[i] != p_transform.elements[i]) {
return true;
}
}
return false;
}
void Transform2D::operator*=(const Transform2D &p_transform) {
elements[2] = xform(p_transform.elements[2]);
real_t x0, x1, y0, y1;
x0 = tdotx(p_transform.elements[0]);
x1 = tdoty(p_transform.elements[0]);
y0 = tdotx(p_transform.elements[1]);
y1 = tdoty(p_transform.elements[1]);
elements[0][0] = x0;
elements[0][1] = x1;
elements[1][0] = y0;
elements[1][1] = y1;
}
Transform2D Transform2D::operator*(const Transform2D &p_transform) const {
Transform2D t = *this;
t *= p_transform;
return t;
}
Transform2D Transform2D::scaled(const Size2 &p_scale) const {
Transform2D copy = *this;
copy.scale(p_scale);
return copy;
}
Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
Transform2D copy = *this;
copy.scale_basis(p_scale);
return copy;
}
Transform2D Transform2D::untranslated() const {
Transform2D copy = *this;
copy.elements[2] = Vector2();
return copy;
}
Transform2D Transform2D::translated(const Vector2 &p_offset) const {
Transform2D copy = *this;
copy.translate(p_offset);
return copy;
}
Transform2D Transform2D::rotated(real_t p_phi) const {
Transform2D copy = *this;
copy.rotate(p_phi);
return copy;
}
real_t Transform2D::basis_determinant() const {
return elements[0].x * elements[1].y - elements[0].y * elements[1].x;
}
Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t p_c) const {
//extract parameters
Vector2 p1 = get_origin();
Vector2 p2 = p_transform.get_origin();
real_t r1 = get_rotation();
real_t r2 = p_transform.get_rotation();
Size2 s1 = get_scale();
Size2 s2 = p_transform.get_scale();
//slerp rotation
Vector2 v1(Math::cos(r1), Math::sin(r1));
Vector2 v2(Math::cos(r2), Math::sin(r2));
real_t dot = v1.dot(v2);
dot = Math::clamp(dot, (real_t)-1.0, (real_t)1.0);
Vector2 v;
if (dot > 0.9995) {
v = v1.lerp(v2, p_c).normalized(); //linearly interpolate to avoid numerical precision issues
} else {
real_t angle = p_c * Math::acos(dot);
Vector2 v3 = (v2 - v1 * dot).normalized();
v = v1 * Math::cos(angle) + v3 * Math::sin(angle);
}
//construct matrix
Transform2D res(Math::atan2(v.y, v.x), p1.lerp(p2, p_c));
res.scale_basis(s1.lerp(s2, p_c));
return res;
}
Transform2D::operator String() const {
return elements[0].operator String() + ", " + elements[1].operator String() + ", " + elements[2].operator String();
}
} // namespace godot

185
src/variant/transform3d.cpp Normal file
View File

@@ -0,0 +1,185 @@
#include <godot_cpp/variant/transform3d.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
void Transform3D::affine_invert() {
basis.invert();
origin = basis.xform(-origin);
}
Transform3D Transform3D::affine_inverse() const {
Transform3D ret = *this;
ret.affine_invert();
return ret;
}
void Transform3D::invert() {
basis.transpose();
origin = basis.xform(-origin);
}
Transform3D Transform3D::inverse() const {
// FIXME: this function assumes the basis is a rotation matrix, with no scaling.
// Transform3D::affine_inverse can handle matrices with scaling, so GDScript should eventually use that.
Transform3D ret = *this;
ret.invert();
return ret;
}
void Transform3D::rotate(const Vector3 &p_axis, real_t p_phi) {
*this = rotated(p_axis, p_phi);
}
Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_phi) const {
return Transform3D(Basis(p_axis, p_phi), Vector3()) * (*this);
}
void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_phi) {
basis.rotate(p_axis, p_phi);
}
Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const {
Transform3D t = *this;
t.set_look_at(origin, p_target, p_up);
return t;
}
void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) {
#ifdef MATH_CHECKS
ERR_FAIL_COND(p_eye == p_target);
ERR_FAIL_COND(p_up.length() == 0);
#endif
// RefCounted: MESA source code
Vector3 v_x, v_y, v_z;
/* Make rotation matrix */
/* Z vector */
v_z = p_eye - p_target;
v_z.normalize();
v_y = p_up;
v_x = v_y.cross(v_z);
#ifdef MATH_CHECKS
ERR_FAIL_COND(v_x.length() == 0);
#endif
/* Recompute Y = Z cross X */
v_y = v_z.cross(v_x);
v_x.normalize();
v_y.normalize();
basis.set(v_x, v_y, v_z);
origin = p_eye;
}
Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const {
/* not sure if very "efficient" but good enough? */
Vector3 src_scale = basis.get_scale();
Quaternion src_rot = basis.get_rotation_quat();
Vector3 src_loc = origin;
Vector3 dst_scale = p_transform.basis.get_scale();
Quaternion dst_rot = p_transform.basis.get_rotation_quat();
Vector3 dst_loc = p_transform.origin;
Transform3D interp;
interp.basis.set_quat_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c));
interp.origin = src_loc.lerp(dst_loc, p_c);
return interp;
}
void Transform3D::scale(const Vector3 &p_scale) {
basis.scale(p_scale);
origin *= p_scale;
}
Transform3D Transform3D::scaled(const Vector3 &p_scale) const {
Transform3D t = *this;
t.scale(p_scale);
return t;
}
void Transform3D::scale_basis(const Vector3 &p_scale) {
basis.scale(p_scale);
}
void Transform3D::translate(real_t p_tx, real_t p_ty, real_t p_tz) {
translate(Vector3(p_tx, p_ty, p_tz));
}
void Transform3D::translate(const Vector3 &p_translation) {
for (int i = 0; i < 3; i++) {
origin[i] += basis[i].dot(p_translation);
}
}
Transform3D Transform3D::translated(const Vector3 &p_translation) const {
Transform3D t = *this;
t.translate(p_translation);
return t;
}
void Transform3D::orthonormalize() {
basis.orthonormalize();
}
Transform3D Transform3D::orthonormalized() const {
Transform3D _copy = *this;
_copy.orthonormalize();
return _copy;
}
bool Transform3D::is_equal_approx(const Transform3D &p_transform) const {
return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin);
}
bool Transform3D::operator==(const Transform3D &p_transform) const {
return (basis == p_transform.basis && origin == p_transform.origin);
}
bool Transform3D::operator!=(const Transform3D &p_transform) const {
return (basis != p_transform.basis || origin != p_transform.origin);
}
void Transform3D::operator*=(const Transform3D &p_transform) {
origin = xform(p_transform.origin);
basis *= p_transform.basis;
}
Transform3D Transform3D::operator*(const Transform3D &p_transform) const {
Transform3D t = *this;
t *= p_transform;
return t;
}
Transform3D::operator String() const {
return basis.operator String() + " - " + origin.operator String();
}
Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) :
basis(p_basis),
origin(p_origin) {
}
Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) :
origin(p_origin) {
basis.set_axis(0, p_x);
basis.set_axis(1, p_y);
basis.set_axis(2, p_z);
}
Transform3D::Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) {
basis = Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz);
origin = Vector3(ox, oy, oz);
}
} // namespace godot

View File

@@ -50,19 +50,6 @@ void Variant::init_bindings() {
}
String::init_bindings();
Vector2::init_bindings();
Vector2i::init_bindings();
Rect2::init_bindings();
Rect2i::init_bindings();
Vector3::init_bindings();
Vector3i::init_bindings();
Transform2D::init_bindings();
Plane::init_bindings();
Quaternion::init_bindings();
AABB::init_bindings();
Basis::init_bindings();
Transform3D::init_bindings();
Color::init_bindings();
StringName::init_bindings();
NodePath::init_bindings();
RID::init_bindings();

168
src/variant/vector2.cpp Normal file
View File

@@ -0,0 +1,168 @@
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
Vector2::operator String() const {
return String::num(x, 5) + ", " + String::num(y, 5);
}
real_t Vector2::angle() const {
return Math::atan2(y, x);
}
real_t Vector2::length() const {
return Math::sqrt(x * x + y * y);
}
real_t Vector2::length_squared() const {
return x * x + y * y;
}
void Vector2::normalize() {
real_t l = x * x + y * y;
if (l != 0) {
l = Math::sqrt(l);
x /= l;
y /= l;
}
}
Vector2 Vector2::normalized() const {
Vector2 v = *this;
v.normalize();
return v;
}
bool Vector2::is_normalized() const {
// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON);
}
real_t Vector2::distance_to(const Vector2 &p_vector2) const {
return Math::sqrt((x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y));
}
real_t Vector2::distance_squared_to(const Vector2 &p_vector2) const {
return (x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y);
}
real_t Vector2::angle_to(const Vector2 &p_vector2) const {
return Math::atan2(cross(p_vector2), dot(p_vector2));
}
real_t Vector2::angle_to_point(const Vector2 &p_vector2) const {
return Math::atan2(y - p_vector2.y, x - p_vector2.x);
}
real_t Vector2::dot(const Vector2 &p_other) const {
return x * p_other.x + y * p_other.y;
}
real_t Vector2::cross(const Vector2 &p_other) const {
return x * p_other.y - y * p_other.x;
}
Vector2 Vector2::sign() const {
return Vector2(Math::sign(x), Math::sign(y));
}
Vector2 Vector2::floor() const {
return Vector2(Math::floor(x), Math::floor(y));
}
Vector2 Vector2::ceil() const {
return Vector2(Math::ceil(x), Math::ceil(y));
}
Vector2 Vector2::round() const {
return Vector2(Math::round(x), Math::round(y));
}
Vector2 Vector2::rotated(real_t p_by) const {
real_t sine = Math::sin(p_by);
real_t cosi = Math::cos(p_by);
return Vector2(
x * cosi - y * sine,
x * sine + y * cosi);
}
Vector2 Vector2::posmod(const real_t p_mod) const {
return Vector2(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod));
}
Vector2 Vector2::posmodv(const Vector2 &p_modv) const {
return Vector2(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y));
}
Vector2 Vector2::project(const Vector2 &p_to) const {
return p_to * (dot(p_to) / p_to.length_squared());
}
Vector2 Vector2::snapped(const Vector2 &p_step) const {
return Vector2(
Math::snapped(x, p_step.x),
Math::snapped(y, p_step.y));
}
Vector2 Vector2::clamped(real_t p_len) const {
real_t l = length();
Vector2 v = *this;
if (l > 0 && p_len < l) {
v /= l;
v *= p_len;
}
return v;
}
Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const {
Vector2 p0 = p_pre_a;
Vector2 p1 = *this;
Vector2 p2 = p_b;
Vector2 p3 = p_post_b;
real_t t = p_weight;
real_t t2 = t * t;
real_t t3 = t2 * t;
Vector2 out;
out = 0.5 * ((p1 * 2.0) +
(-p0 + p2) * t +
(2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 +
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
return out;
}
Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const {
Vector2 v = *this;
Vector2 vd = p_to - v;
real_t len = vd.length();
return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
// slide returns the component of the vector along the given plane, specified by its normal vector.
Vector2 Vector2::slide(const Vector2 &p_normal) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector2());
#endif
return *this - p_normal * this->dot(p_normal);
}
Vector2 Vector2::bounce(const Vector2 &p_normal) const {
return -reflect(p_normal);
}
Vector2 Vector2::reflect(const Vector2 &p_normal) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector2());
#endif
return 2.0 * p_normal * this->dot(p_normal) - *this;
}
bool Vector2::is_equal_approx(const Vector2 &p_v) const {
return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y);
}
} // namespace godot

80
src/variant/vector2i.cpp Normal file
View File

@@ -0,0 +1,80 @@
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/variant/vector2i.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
Vector2i::operator String() const {
return String::num(x, 0) + ", " + String::num(y, 0);
}
Vector2i Vector2i::operator+(const Vector2i &p_v) const {
return Vector2i(x + p_v.x, y + p_v.y);
}
void Vector2i::operator+=(const Vector2i &p_v) {
x += p_v.x;
y += p_v.y;
}
Vector2i Vector2i::operator-(const Vector2i &p_v) const {
return Vector2i(x - p_v.x, y - p_v.y);
}
void Vector2i::operator-=(const Vector2i &p_v) {
x -= p_v.x;
y -= p_v.y;
}
Vector2i Vector2i::operator*(const Vector2i &p_v1) const {
return Vector2i(x * p_v1.x, y * p_v1.y);
}
Vector2i Vector2i::operator*(const int32_t &rvalue) const {
return Vector2i(x * rvalue, y * rvalue);
}
void Vector2i::operator*=(const int32_t &rvalue) {
x *= rvalue;
y *= rvalue;
}
Vector2i Vector2i::operator/(const Vector2i &p_v1) const {
return Vector2i(x / p_v1.x, y / p_v1.y);
}
Vector2i Vector2i::operator/(const int32_t &rvalue) const {
return Vector2i(x / rvalue, y / rvalue);
}
void Vector2i::operator/=(const int32_t &rvalue) {
x /= rvalue;
y /= rvalue;
}
Vector2i Vector2i::operator%(const Vector2i &p_v1) const {
return Vector2i(x % p_v1.x, y % p_v1.y);
}
Vector2i Vector2i::operator%(const int32_t &rvalue) const {
return Vector2i(x % rvalue, y % rvalue);
}
void Vector2i::operator%=(const int32_t &rvalue) {
x %= rvalue;
y %= rvalue;
}
Vector2i Vector2i::operator-() const {
return Vector2i(-x, -y);
}
bool Vector2i::operator==(const Vector2i &p_vec2) const {
return x == p_vec2.x && y == p_vec2.y;
}
bool Vector2i::operator!=(const Vector2i &p_vec2) const {
return x != p_vec2.x || y != p_vec2.y;
}
} // namespace godot

94
src/variant/vector3.cpp Normal file
View File

@@ -0,0 +1,94 @@
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/variant/vector3.hpp>
#include <godot_cpp/variant/basis.hpp>
namespace godot {
void Vector3::rotate(const Vector3 &p_axis, real_t p_phi) {
*this = Basis(p_axis, p_phi).xform(*this);
}
Vector3 Vector3::rotated(const Vector3 &p_axis, real_t p_phi) const {
Vector3 r = *this;
r.rotate(p_axis, p_phi);
return r;
}
void Vector3::set_axis(int p_axis, real_t p_value) {
ERR_FAIL_INDEX(p_axis, 3);
coord[p_axis] = p_value;
}
real_t Vector3::get_axis(int p_axis) const {
ERR_FAIL_INDEX_V(p_axis, 3, 0);
return operator[](p_axis);
}
int Vector3::min_axis() const {
return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2);
}
int Vector3::max_axis() const {
return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
}
void Vector3::snap(Vector3 p_step) {
x = Math::snapped(x, p_step.x);
y = Math::snapped(y, p_step.y);
z = Math::snapped(z, p_step.z);
}
Vector3 Vector3::snapped(Vector3 p_step) const {
Vector3 v = *this;
v.snap(p_step);
return v;
}
Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const {
Vector3 p0 = p_pre_a;
Vector3 p1 = *this;
Vector3 p2 = p_b;
Vector3 p3 = p_post_b;
real_t t = p_weight;
real_t t2 = t * t;
real_t t3 = t2 * t;
Vector3 out;
out = 0.5 * ((p1 * 2.0) +
(-p0 + p2) * t +
(2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 +
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
return out;
}
Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const {
Vector3 v = *this;
Vector3 vd = p_to - v;
real_t len = vd.length();
return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
Basis Vector3::outer(const Vector3 &p_b) const {
Vector3 row0(x * p_b.x, x * p_b.y, x * p_b.z);
Vector3 row1(y * p_b.x, y * p_b.y, y * p_b.z);
Vector3 row2(z * p_b.x, z * p_b.y, z * p_b.z);
return Basis(row0, row1, row2);
}
Basis Vector3::to_diagonal_matrix() const {
return Basis(x, 0, 0,
0, y, 0,
0, 0, z);
}
bool Vector3::is_equal_approx(const Vector3 &p_v) const {
return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z);
}
Vector3::operator String() const {
return (String::num(x, 5) + ", " + String::num(y, 5) + ", " + String::num(z, 5));
}
} // namespace godot

29
src/variant/vector3i.cpp Normal file
View File

@@ -0,0 +1,29 @@
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/variant/vector3i.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
void Vector3i::set_axis(int p_axis, int32_t p_value) {
ERR_FAIL_INDEX(p_axis, 3);
coord[p_axis] = p_value;
}
int32_t Vector3i::get_axis(int p_axis) const {
ERR_FAIL_INDEX_V(p_axis, 3, 0);
return operator[](p_axis);
}
int Vector3i::min_axis() const {
return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2);
}
int Vector3i::max_axis() const {
return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
}
Vector3i::operator String() const {
return (String::num(x, 0) + ", " + String::num(y, 0) + ", " + String::num(z, 5));
}
} // namespace godot