reordered the libs

This commit is contained in:
Yannik
2023-04-29 19:22:22 +02:00
parent 2fef7711a3
commit d5a83198d4
154 changed files with 300258 additions and 7 deletions

View File

@@ -0,0 +1,58 @@
/**************************************************************************/
/* low_level.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/classes/file_access.hpp>
#include <godot_cpp/classes/worker_thread_pool.hpp>
#include <godot_cpp/classes/xml_parser.hpp>
#include <godot_cpp/godot.hpp>
namespace godot {
Error XMLParser::_open_buffer(const uint8_t *p_buffer, size_t p_size) {
return (Error)internal::gde_interface->xml_parser_open_buffer(_owner, p_buffer, p_size);
}
uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
return internal::gde_interface->file_access_get_buffer(_owner, p_dst, p_length);
}
void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
internal::gde_interface->file_access_store_buffer(_owner, p_src, p_length);
}
WorkerThreadPool::TaskID WorkerThreadPool::add_native_task(void (*p_func)(void *), void *p_userdata, bool p_high_priority, const String &p_description) {
return (TaskID)internal::gde_interface->worker_thread_pool_add_native_task(_owner, p_func, p_userdata, p_high_priority, (GDExtensionConstStringPtr)&p_description);
}
WorkerThreadPool::GroupID WorkerThreadPool::add_native_group_task(void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, bool p_high_priority, const String &p_description) {
return (GroupID)internal::gde_interface->worker_thread_pool_add_native_group_task(_owner, p_func, p_userdata, p_elements, p_tasks, p_high_priority, (GDExtensionConstStringPtr)&p_description);
}
} // namespace godot

View File

@@ -0,0 +1,63 @@
/**************************************************************************/
/* wrapped.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/classes/wrapped.hpp>
#include <godot_cpp/variant/builtin_types.hpp>
#include <godot_cpp/classes/object.hpp>
namespace godot {
const StringName *Wrapped::_get_extension_class_name() const {
return nullptr;
}
void Wrapped::_postinitialize() {
const StringName *extension_class = _get_extension_class_name();
if (extension_class) {
godot::internal::gde_interface->object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(extension_class), this);
}
godot::internal::gde_interface->object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks());
}
Wrapped::Wrapped(const StringName p_godot_class) {
_owner = godot::internal::gde_interface->classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
}
Wrapped::Wrapped(GodotObject *p_godot_object) {
_owner = p_godot_object;
}
void postinitialize_handler(Wrapped *p_wrapped) {
p_wrapped->_postinitialize();
}
} // namespace godot

View File

@@ -0,0 +1,358 @@
/**************************************************************************/
/* class_db.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/godot.hpp>
#include <godot_cpp/core/memory.hpp>
#include <algorithm>
namespace godot {
std::unordered_map<StringName, ClassDB::ClassInfo> ClassDB::classes;
GDExtensionInitializationLevel ClassDB::current_level = GDEXTENSION_INITIALIZATION_CORE;
MethodDefinition D_METHOD(StringName p_name) {
return MethodDefinition(p_name);
}
MethodDefinition D_METHOD(StringName p_name, StringName p_arg1) {
MethodDefinition method(p_name);
method.args.push_front(p_arg1);
return method;
}
void ClassDB::add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix) {
ERR_FAIL_COND_MSG(classes.find(p_class) == classes.end(), String("Trying to add property '{0}{1}' to non-existing class '{2}'.").format(Array::make(p_prefix, p_name, p_class)));
internal::gde_interface->classdb_register_extension_class_property_group(internal::library, p_class._native_ptr(), p_name._native_ptr(), p_prefix._native_ptr());
}
void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix) {
ERR_FAIL_COND_MSG(classes.find(p_class) == classes.end(), String("Trying to add property '{0}{1}' to non-existing class '{2}'.").format(Array::make(p_prefix, p_name, p_class)));
internal::gde_interface->classdb_register_extension_class_property_subgroup(internal::library, p_class._native_ptr(), p_name._native_ptr(), p_prefix._native_ptr());
}
void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
ERR_FAIL_COND_MSG(classes.find(p_class) == classes.end(), String("Trying to add property '{0}' to non-existing class '{1}'.").format(Array::make(p_pinfo.name, p_class)));
ClassInfo &info = classes[p_class];
ERR_FAIL_COND_MSG(info.property_names.find(p_pinfo.name) != info.property_names.end(), String("Property '{0}' already exists in class '{1}'.").format(Array::make(p_pinfo.name, p_class)));
MethodBind *setter = nullptr;
if (p_setter != String("")) {
setter = get_method(p_class, p_setter);
ERR_FAIL_COND_MSG(!setter, String("Setter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_setter, p_class, p_pinfo.name)));
size_t exp_args = 1 + (p_index >= 0 ? 1 : 0);
ERR_FAIL_COND_MSG((int)exp_args != setter->get_argument_count(), String("Setter method '{0}::{1}()' must take a single argument.").format(Array::make(p_class, p_setter)));
}
ERR_FAIL_COND_MSG(p_getter == String(""), String("Getter method must be specified for '{0}::{1}'.").format(Array::make(p_class, p_pinfo.name)));
MethodBind *getter = get_method(p_class, p_getter);
ERR_FAIL_COND_MSG(!getter, String("Getter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_getter, p_class, p_pinfo.name)));
{
size_t exp_args = 0 + (p_index >= 0 ? 1 : 0);
ERR_FAIL_COND_MSG((int)exp_args != getter->get_argument_count(), String("Getter method '{0}::{1}()' must not take any argument.").format(Array::make(p_class, p_getter)));
}
// register property with plugin
info.property_names.insert(p_pinfo.name);
// register with Godot
GDExtensionPropertyInfo prop_info = {
static_cast<GDExtensionVariantType>(p_pinfo.type), // GDExtensionVariantType type;
p_pinfo.name._native_ptr(), // GDExtensionStringNamePtr name;
p_pinfo.class_name._native_ptr(), // GDExtensionStringNamePtr class_name;
p_pinfo.hint, // NONE //uint32_t hint;
p_pinfo.hint_string._native_ptr(), // GDExtensionStringPtr hint_string;
p_pinfo.usage, // DEFAULT //uint32_t usage;
};
PropertySetGet setget;
setget.setter = p_setter;
setget.getter = p_getter;
setget._setptr = setter;
setget._getptr = getter;
setget.index = p_index;
setget.type = p_pinfo.type;
internal::gde_interface->classdb_register_extension_class_property(internal::library, info.name._native_ptr(), &prop_info, setget.setter._native_ptr(), setget.getter._native_ptr());
}
MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_method) {
ERR_FAIL_COND_V_MSG(classes.find(p_class) == classes.end(), nullptr, String("Class '{0}' not found.").format(Array::make(p_class)));
ClassInfo *type = &classes[p_class];
while (type) {
std::unordered_map<StringName, MethodBind *>::iterator method = type->method_map.find(p_method);
if (method != type->method_map.end()) {
return method->second;
}
type = type->parent_ptr;
continue;
}
return nullptr;
}
MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount) {
StringName instance_type = p_bind->get_instance_class();
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(instance_type);
if (type_it == classes.end()) {
memdelete(p_bind);
ERR_FAIL_V_MSG(nullptr, String("Class '{0}' doesn't exist.").format(Array::make(instance_type)));
}
ClassInfo &type = type_it->second;
if (type.method_map.find(method_name.name) != type.method_map.end()) {
memdelete(p_bind);
ERR_FAIL_V_MSG(nullptr, String("Binding duplicate method: {0}::{1}().").format(Array::make(instance_type, method_name.name)));
}
if (type.virtual_methods.find(method_name.name) != type.virtual_methods.end()) {
memdelete(p_bind);
ERR_FAIL_V_MSG(nullptr, String("Method '{0}::{1}()' already bound as virtual.").format(Array::make(instance_type, method_name.name)));
}
p_bind->set_name(method_name.name);
if ((int)method_name.args.size() > p_bind->get_argument_count()) {
memdelete(p_bind);
ERR_FAIL_V_MSG(nullptr, String("Method '{0}::{1}()' definition has more arguments than the actual method.").format(Array::make(instance_type, method_name.name)));
}
p_bind->set_hint_flags(p_flags);
std::vector<StringName> args;
args.resize(method_name.args.size());
size_t arg_index = 0;
for (StringName arg : method_name.args) {
args[arg_index++] = arg;
}
p_bind->set_argument_names(args);
std::vector<Variant> defvals;
defvals.resize(p_defcount);
for (int i = 0; i < p_defcount; i++) {
defvals[i] = *static_cast<const Variant *>(p_defs[i]);
}
p_bind->set_default_arguments(defvals);
p_bind->set_hint_flags(p_flags);
// register our method bind within our plugin
type.method_map[method_name.name] = p_bind;
// and register with godot
bind_method_godot(type.name, p_bind);
return p_bind;
}
void ClassDB::bind_method_godot(const StringName &p_class_name, MethodBind *p_method) {
std::vector<GDExtensionVariantPtr> def_args;
const std::vector<Variant> &def_args_val = p_method->get_default_arguments();
def_args.resize(def_args_val.size());
for (size_t i = 0; i < def_args_val.size(); i++) {
def_args[i] = (GDExtensionVariantPtr)&def_args_val[i];
}
std::vector<PropertyInfo> return_value_and_arguments_info = p_method->get_arguments_info_list();
std::vector<GDExtensionClassMethodArgumentMetadata> return_value_and_arguments_metadata = p_method->get_arguments_metadata_list();
std::vector<GDExtensionPropertyInfo> return_value_and_arguments_gdextension_info;
return_value_and_arguments_gdextension_info.reserve(return_value_and_arguments_info.size());
for (std::vector<PropertyInfo>::iterator it = return_value_and_arguments_info.begin(); it != return_value_and_arguments_info.end(); it++) {
return_value_and_arguments_gdextension_info.push_back(
GDExtensionPropertyInfo{
static_cast<GDExtensionVariantType>(it->type), // GDExtensionVariantType type;
it->name._native_ptr(), // GDExtensionStringNamePtr name;
it->class_name._native_ptr(), // GDExtensionStringNamePtr class_name;
it->hint, // uint32_t hint;
it->hint_string._native_ptr(), // GDExtensionStringPtr hint_string;
it->usage, // uint32_t usage;
});
}
GDExtensionPropertyInfo *return_value_info = return_value_and_arguments_gdextension_info.data();
GDExtensionClassMethodArgumentMetadata *return_value_metadata = return_value_and_arguments_metadata.data();
GDExtensionPropertyInfo *arguments_info = return_value_and_arguments_gdextension_info.data() + 1;
GDExtensionClassMethodArgumentMetadata *arguments_metadata = return_value_and_arguments_metadata.data() + 1;
StringName name = p_method->get_name();
GDExtensionClassMethodInfo method_info = {
name._native_ptr(), // GDExtensionStringNamePtr;
p_method, // void *method_userdata;
MethodBind::bind_call, // GDExtensionClassMethodCall call_func;
MethodBind::bind_ptrcall, // GDExtensionClassMethodPtrCall ptrcall_func;
p_method->get_hint_flags(), // uint32_t method_flags; /* GDExtensionClassMethodFlags */
(GDExtensionBool)p_method->has_return(), // GDExtensionBool has_return_value;
return_value_info, // GDExtensionPropertyInfo *
*return_value_metadata, // GDExtensionClassMethodArgumentMetadata *
(uint32_t)p_method->get_argument_count(), // uint32_t argument_count;
arguments_info, // GDExtensionPropertyInfo *
arguments_metadata, // GDExtensionClassMethodArgumentMetadata *
(uint32_t)p_method->get_default_argument_count(), // uint32_t default_argument_count;
def_args.data(), // GDExtensionVariantPtr *default_arguments;
};
internal::gde_interface->classdb_register_extension_class_method(internal::library, p_class_name._native_ptr(), &method_info);
}
void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) {
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class);
ERR_FAIL_COND_MSG(type_it == classes.end(), String("Class '{0}' doesn't exist.").format(Array::make(p_class)));
ClassInfo &cl = type_it->second;
// Check if this signal is already register
ClassInfo *check = &cl;
while (check) {
ERR_FAIL_COND_MSG(check->signal_names.find(p_signal.name) != check->signal_names.end(), String("Class '{0}' already has signal '{1}'.").format(Array::make(p_class, p_signal.name)));
check = check->parent_ptr;
}
// register our signal in our plugin
cl.signal_names.insert(p_signal.name);
// register our signal in godot
std::vector<GDExtensionPropertyInfo> parameters;
parameters.reserve(p_signal.arguments.size());
for (const PropertyInfo &par : p_signal.arguments) {
parameters.push_back(GDExtensionPropertyInfo{
static_cast<GDExtensionVariantType>(par.type), // GDExtensionVariantType type;
par.name._native_ptr(), // GDExtensionStringNamePtr name;
par.class_name._native_ptr(), // GDExtensionStringNamePtr class_name;
par.hint, // NONE //uint32_t hint;
par.hint_string._native_ptr(), // GDExtensionStringPtr hint_string;
par.usage, // DEFAULT //uint32_t usage;
});
}
internal::gde_interface->classdb_register_extension_class_signal(internal::library, cl.name._native_ptr(), p_signal.name._native_ptr(), parameters.data(), parameters.size());
}
void ClassDB::bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield) {
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class_name);
ERR_FAIL_COND_MSG(type_it == classes.end(), String("Class '{0}' doesn't exist.").format(Array::make(p_class_name)));
ClassInfo &type = type_it->second;
// check if it already exists
ERR_FAIL_COND_MSG(type.constant_names.find(p_constant_name) != type.constant_names.end(), String("Constant '{0}::{1}' already registered.").format(Array::make(p_class_name, p_constant_name)));
// register it with our plugin (purely to check for duplicates)
type.constant_names.insert(p_constant_name);
// Register it with Godot
internal::gde_interface->classdb_register_extension_class_integer_constant(internal::library, p_class_name._native_ptr(), p_enum_name._native_ptr(), p_constant_name._native_ptr(), p_constant_value, p_is_bitfield);
}
GDExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name) {
// This is called by Godot the first time it calls a virtual function, and it caches the result, per object instance.
// Because of this, it can happen from different threads at once.
// It should be ok not using any mutex as long as we only READ data.
const StringName *class_name = reinterpret_cast<const StringName *>(p_userdata);
const StringName *name = reinterpret_cast<const StringName *>(p_name);
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(*class_name);
ERR_FAIL_COND_V_MSG(type_it == classes.end(), nullptr, String("Class '{0}' doesn't exist.").format(Array::make(*class_name)));
const ClassInfo *type = &type_it->second;
// Find method in current class, or any of its parent classes (Godot classes not included)
while (type != nullptr) {
std::unordered_map<StringName, GDExtensionClassCallVirtual>::const_iterator method_it = type->virtual_methods.find(*name);
if (method_it != type->virtual_methods.end()) {
return method_it->second;
}
type = type->parent_ptr;
}
return nullptr;
}
void ClassDB::bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call) {
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(p_class);
ERR_FAIL_COND_MSG(type_it == classes.end(), String("Class '{0}' doesn't exist.").format(Array::make(p_class)));
ClassInfo &type = type_it->second;
ERR_FAIL_COND_MSG(type.method_map.find(p_method) != type.method_map.end(), String("Method '{0}::{1}()' already registered as non-virtual.").format(Array::make(p_class, p_method)));
ERR_FAIL_COND_MSG(type.virtual_methods.find(p_method) != type.virtual_methods.end(), String("Virtual '{0}::{1}()' method already registered.").format(Array::make(p_class, p_method)));
type.virtual_methods[p_method] = p_call;
}
void ClassDB::initialize_class(const ClassInfo &p_cl) {
}
void ClassDB::initialize(GDExtensionInitializationLevel p_level) {
for (const std::pair<StringName, ClassInfo> pair : classes) {
const ClassInfo &cl = pair.second;
if (cl.level != p_level) {
continue;
}
// Nothing to do here for now...
}
}
void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) {
for (const std::pair<StringName, ClassInfo> pair : classes) {
const ClassInfo &cl = pair.second;
if (cl.level != p_level) {
continue;
}
internal::gde_interface->classdb_unregister_extension_class(internal::library, cl.name._native_ptr());
for (auto method : cl.method_map) {
memdelete(method.second);
}
}
}
} // namespace godot

View File

@@ -0,0 +1,86 @@
/**************************************************************************/
/* error_macros.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/godot.hpp>
#include <godot_cpp/variant/string.hpp>
#include <cstdio>
namespace godot {
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify, bool p_is_warning) {
if (p_is_warning) {
internal::gde_interface->print_warning(p_error, p_function, p_file, p_line, p_editor_notify);
} else {
internal::gde_interface->print_error(p_error, p_function, p_file, p_line, p_editor_notify);
}
}
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify, bool p_is_warning) {
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_editor_notify, p_is_warning);
}
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify, bool p_is_warning) {
if (p_is_warning) {
internal::gde_interface->print_warning_with_message(p_error, p_message, p_function, p_file, p_line, p_editor_notify);
} else {
internal::gde_interface->print_error_with_message(p_error, p_message, p_function, p_file, p_line, p_editor_notify);
}
}
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify, bool p_is_warning) {
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message, p_editor_notify, p_is_warning);
}
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify, bool p_is_warning) {
_err_print_error(p_function, p_file, p_line, p_error, p_message.utf8().get_data(), p_editor_notify, p_is_warning);
}
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify, bool p_is_warning) {
_err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message.utf8().get_data(), p_editor_notify, p_is_warning);
}
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message, bool p_editor_notify, bool p_fatal) {
String fstr(p_fatal ? "FATAL: " : "");
String err(fstr + "Index " + p_index_str + " = " + itos(p_index) + " is out of bounds (" + p_size_str + " = " + itos(p_size) + ").");
_err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message, p_editor_notify, false);
}
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify, bool p_fatal) {
_err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), p_editor_notify, p_fatal);
}
void _err_flush_stdout() {
fflush(stdout);
}
} // namespace godot

View File

@@ -0,0 +1,132 @@
/**************************************************************************/
/* memory.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/godot.hpp>
namespace godot {
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
#ifdef DEBUG_ENABLED
bool prepad = false; // Alredy pre paded in the engine.
#else
bool prepad = p_pad_align;
#endif
void *mem = internal::gde_interface->mem_alloc(p_bytes + (prepad ? PAD_ALIGN : 0));
ERR_FAIL_COND_V(!mem, nullptr);
if (prepad) {
uint8_t *s8 = (uint8_t *)mem;
return s8 + PAD_ALIGN;
} else {
return mem;
}
}
void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
if (p_memory == nullptr) {
return alloc_static(p_bytes, p_pad_align);
} else if (p_bytes == 0) {
free_static(p_memory, p_pad_align);
return nullptr;
}
uint8_t *mem = (uint8_t *)p_memory;
#ifdef DEBUG_ENABLED
bool prepad = false; // Alredy pre paded in the engine.
#else
bool prepad = p_pad_align;
#endif
if (prepad) {
mem -= PAD_ALIGN;
mem = (uint8_t *)internal::gde_interface->mem_realloc(mem, p_bytes + PAD_ALIGN);
ERR_FAIL_COND_V(!mem, nullptr);
return mem + PAD_ALIGN;
} else {
return (uint8_t *)internal::gde_interface->mem_realloc(mem, p_bytes);
}
}
void Memory::free_static(void *p_ptr, bool p_pad_align) {
uint8_t *mem = (uint8_t *)p_ptr;
#ifdef DEBUG_ENABLED
bool prepad = false; // Alredy pre paded in the engine.
#else
bool prepad = p_pad_align;
#endif
if (prepad) {
mem -= PAD_ALIGN;
}
internal::gde_interface->mem_free(mem);
}
_GlobalNil::_GlobalNil() {
left = this;
right = this;
parent = this;
}
_GlobalNil _GlobalNilClass::_nil;
} // namespace godot
void *operator new(size_t p_size, const char *p_description) {
return godot::Memory::alloc_static(p_size);
}
void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)) {
return p_allocfunc(p_size);
}
using namespace godot;
#ifdef _MSC_VER
void operator delete(void *p_mem, const char *p_description) {
ERR_PRINT("Call to placement delete should not happen.");
CRASH_NOW();
}
void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size)) {
ERR_PRINT("Call to placement delete should not happen.");
CRASH_NOW();
}
void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description) {
ERR_PRINT("Call to placement delete should not happen.");
CRASH_NOW();
}
#endif

View File

@@ -0,0 +1,113 @@
/**************************************************************************/
/* method_bind.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/core/method_bind.hpp>
namespace godot {
StringName MethodBind::get_name() const {
return name;
}
void MethodBind::set_name(const StringName &p_name) {
name = p_name;
}
void MethodBind::set_argument_count(int p_count) {
argument_count = p_count;
}
void MethodBind::set_const(bool p_const) {
_is_const = p_const;
}
void MethodBind::set_return(bool p_return) {
_has_return = p_return;
}
void MethodBind::set_static(bool p_static) {
_static = p_static;
}
void MethodBind::set_vararg(bool p_vararg) {
_vararg = p_vararg;
}
void MethodBind::set_argument_names(const std::vector<StringName> &p_names) {
argument_names = p_names;
}
std::vector<StringName> MethodBind::get_argument_names() const {
return argument_names;
}
void MethodBind::generate_argument_types(int p_count) {
set_argument_count(p_count);
if (argument_types != nullptr) {
memdelete_arr(argument_types);
}
argument_types = memnew_arr(GDExtensionVariantType, p_count + 1);
// -1 means return type.
for (int i = -1; i < p_count; i++) {
argument_types[i + 1] = gen_argument_type(i);
}
}
PropertyInfo MethodBind::get_argument_info(int p_argument) const {
PropertyInfo info = gen_argument_type_info(p_argument);
if (p_argument >= 0) {
info.name = p_argument < (int)argument_names.size() ? argument_names[p_argument] : "";
}
return info;
}
void MethodBind::bind_call(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error) {
const MethodBind *bind = reinterpret_cast<const MethodBind *>(p_method_userdata);
Variant ret = bind->call(p_instance, p_args, p_argument_count, *r_error);
// This assumes the return value is an empty Variant, so it doesn't need to call the destructor first.
// Since only GDExtensionMethodBind calls this from the Godot side, it should always be the case.
internal::gde_interface->variant_new_copy(r_return, ret._native_ptr());
}
void MethodBind::bind_ptrcall(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) {
const MethodBind *bind = reinterpret_cast<const MethodBind *>(p_method_userdata);
bind->ptrcall(p_instance, p_args, r_return);
}
MethodBind::~MethodBind() {
if (argument_types) {
memdelete_arr(argument_types);
}
}
} // namespace godot

View File

@@ -0,0 +1,54 @@
/**************************************************************************/
/* object.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/core/object.hpp>
namespace godot {
MethodInfo::MethodInfo() :
flags(GDEXTENSION_METHOD_FLAG_NORMAL) {}
MethodInfo::MethodInfo(StringName p_name) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {}
MethodInfo::MethodInfo(Variant::Type ret) :
flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
return_val.type = ret;
}
MethodInfo::MethodInfo(Variant::Type ret, StringName p_name) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
return_val.type = ret;
}
MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name) :
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {}
} // namespace godot

117
lib/godot-cpp/src/godot.cpp Normal file
View File

@@ -0,0 +1,117 @@
/**************************************************************************/
/* godot.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/godot.hpp>
#include <godot_cpp/classes/wrapped.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/core/error_macros.hpp>
namespace godot {
namespace internal {
const GDExtensionInterface *gde_interface = nullptr;
GDExtensionClassLibraryPtr library = nullptr;
void *token = nullptr;
} // namespace internal
GDExtensionBinding::Callback GDExtensionBinding::init_callback = nullptr;
GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr;
GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
GDExtensionBool GDExtensionBinding::init(const GDExtensionInterface *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
internal::gde_interface = p_interface;
internal::library = p_library;
internal::token = p_library;
r_initialization->initialize = initialize_level;
r_initialization->deinitialize = deinitialize_level;
r_initialization->minimum_initialization_level = minimum_initialization_level;
ERR_FAIL_COND_V_MSG(init_callback == nullptr, false, "Initialization callback must be defined.");
Variant::init_bindings();
return true;
}
void GDExtensionBinding::initialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
ClassDB::current_level = p_level;
if (init_callback) {
init_callback(static_cast<ModuleInitializationLevel>(p_level));
}
ClassDB::initialize(p_level);
}
void GDExtensionBinding::deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
ClassDB::current_level = p_level;
if (terminate_callback) {
terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
}
ClassDB::deinitialize(p_level);
}
void GDExtensionBinding::InitObject::register_initializer(Callback p_init) const {
GDExtensionBinding::init_callback = p_init;
}
void GDExtensionBinding::InitObject::register_terminator(Callback p_terminate) const {
GDExtensionBinding::terminate_callback = p_terminate;
}
void GDExtensionBinding::InitObject::set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const {
GDExtensionBinding::minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
}
GDExtensionBool GDExtensionBinding::InitObject::init() const {
return GDExtensionBinding::init(gde_interface, library, initialization);
}
} // namespace godot
extern "C" {
void GDE_EXPORT initialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
godot::GDExtensionBinding::initialize_level(userdata, p_level);
}
void GDE_EXPORT deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
godot::GDExtensionBinding::deinitialize_level(userdata, p_level);
}
}

View File

@@ -0,0 +1,421 @@
/**************************************************************************/
/* aabb.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/aabb.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
real_t AABB::get_volume() 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) {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
Vector3 beg_1, beg_2;
Vector3 end_1, end_2;
Vector3 min, max;
beg_1 = position;
beg_2 = p_aabb.position;
end_1 = size + beg_1;
end_2 = p_aabb.size + 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 {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
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 {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
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 {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
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 min_size = size.x;
if (size.y < min_size) {
axis = Vector3(0, 1, 0);
min_size = size.y;
}
if (size.z < min_size) {
axis = Vector3(0, 0, 1);
}
return axis;
}
int AABB::get_shortest_axis_index() const {
int axis = 0;
real_t min_size = size.x;
if (size.y < min_size) {
axis = 1;
min_size = size.y;
}
if (size.z < min_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;
}
}
Variant AABB::intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const {
Vector3 inters;
if (intersects_segment(p_from, p_to, &inters)) {
return inters;
}
return Variant();
}
Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
Vector3 inters;
if (intersects_ray(p_from, p_dir, &inters)) {
return inters;
}
return Variant();
}
AABB::operator String() const {
return "[P: " + position.operator String() + ", S: " + size + "]";
}
} // namespace godot

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,472 @@
/**************************************************************************/
/* char_string.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/char_string.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/variant/node_path.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/string_name.hpp>
#include <godot_cpp/godot.hpp>
#include <cmath>
namespace godot {
int CharString::length() const {
return _length;
}
const char *CharString::get_data() const {
return _data;
}
CharString::CharString(CharString &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
void CharString::operator=(CharString &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
CharString::CharString(const char *str, int length) :
_data(str), _length(length) {}
CharString::~CharString() {
if (_data != nullptr) {
memdelete_arr(_data);
}
}
int Char16String::length() const {
return _length;
}
const char16_t *Char16String::get_data() const {
return _data;
}
Char16String::Char16String(Char16String &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
void Char16String::operator=(Char16String &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
Char16String::Char16String(const char16_t *str, int length) :
_data(str), _length(length) {}
Char16String::~Char16String() {
if (_data != nullptr) {
memdelete_arr(_data);
}
}
int Char32String::length() const {
return _length;
}
const char32_t *Char32String::get_data() const {
return _data;
}
Char32String::Char32String(Char32String &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
void Char32String::operator=(Char32String &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
Char32String::Char32String(const char32_t *str, int length) :
_data(str), _length(length) {}
Char32String::~Char32String() {
if (_data != nullptr) {
memdelete_arr(_data);
}
}
int CharWideString::length() const {
return _length;
}
const wchar_t *CharWideString::get_data() const {
return _data;
}
CharWideString::CharWideString(CharWideString &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
void CharWideString::operator=(CharWideString &&p_str) {
SWAP(_length, p_str._length);
SWAP(_data, p_str._data);
}
CharWideString::CharWideString(const wchar_t *str, int length) :
_data(str), _length(length) {}
CharWideString::~CharWideString() {
if (_data != nullptr) {
memdelete_arr(_data);
}
}
// Custom String functions that are not part of bound API.
// It's easier to have them written in C++ directly than in a Python script that generates them.
String::String(const char *from) {
internal::gde_interface->string_new_with_latin1_chars(_native_ptr(), from);
}
String::String(const wchar_t *from) {
internal::gde_interface->string_new_with_wide_chars(_native_ptr(), from);
}
String::String(const char16_t *from) {
internal::gde_interface->string_new_with_utf16_chars(_native_ptr(), from);
}
String::String(const char32_t *from) {
internal::gde_interface->string_new_with_utf32_chars(_native_ptr(), from);
}
String String::utf8(const char *from, int len) {
String ret;
ret.parse_utf8(from, len);
return ret;
}
void String::parse_utf8(const char *from, int len) {
internal::gde_interface->string_new_with_utf8_chars_and_len(_native_ptr(), from, len);
}
String String::utf16(const char16_t *from, int len) {
String ret;
ret.parse_utf16(from, len);
return ret;
}
void String::parse_utf16(const char16_t *from, int len) {
internal::gde_interface->string_new_with_utf16_chars_and_len(_native_ptr(), from, len);
}
String String::num_real(double p_num, bool p_trailing) {
if (p_num == (double)(int64_t)p_num) {
if (p_trailing) {
return num_int64((int64_t)p_num) + ".0";
} else {
return num_int64((int64_t)p_num);
}
}
#ifdef REAL_T_IS_DOUBLE
int decimals = 14;
#else
int decimals = 6;
#endif
// We want to align the digits to the above sane default, so we only
// need to subtract log10 for numbers with a positive power of ten.
if (p_num > 10) {
decimals -= (int)floor(log10(p_num));
}
return num(p_num, decimals);
}
String itos(int64_t p_val) {
return String::num_int64(p_val);
}
String uitos(uint64_t p_val) {
return String::num_uint64(p_val);
}
String rtos(double p_val) {
return String::num(p_val);
}
String rtoss(double p_val) {
return String::num_scientific(p_val);
}
CharString String::utf8() const {
int length = internal::gde_interface->string_to_utf8_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
char *cstr = memnew_arr(char, size);
internal::gde_interface->string_to_utf8_chars(_native_ptr(), cstr, length);
cstr[length] = '\0';
return CharString(cstr, length);
}
CharString String::ascii() const {
int length = internal::gde_interface->string_to_latin1_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
char *cstr = memnew_arr(char, size);
internal::gde_interface->string_to_latin1_chars(_native_ptr(), cstr, length);
cstr[length] = '\0';
return CharString(cstr, length);
}
Char16String String::utf16() const {
int length = internal::gde_interface->string_to_utf16_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
char16_t *cstr = memnew_arr(char16_t, size);
internal::gde_interface->string_to_utf16_chars(_native_ptr(), cstr, length);
cstr[length] = '\0';
return Char16String(cstr, length);
}
Char32String String::utf32() const {
int length = internal::gde_interface->string_to_utf32_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
char32_t *cstr = memnew_arr(char32_t, size);
internal::gde_interface->string_to_utf32_chars(_native_ptr(), cstr, length);
cstr[length] = '\0';
return Char32String(cstr, length);
}
CharWideString String::wide_string() const {
int length = internal::gde_interface->string_to_wide_chars(_native_ptr(), nullptr, 0);
int size = length + 1;
wchar_t *cstr = memnew_arr(wchar_t, size);
internal::gde_interface->string_to_wide_chars(_native_ptr(), cstr, length);
cstr[length] = '\0';
return CharWideString(cstr, length);
}
String &String::operator=(const char *p_str) {
*this = String(p_str);
return *this;
}
String &String::operator=(const wchar_t *p_str) {
*this = String(p_str);
return *this;
}
String &String::operator=(const char16_t *p_str) {
*this = String(p_str);
return *this;
}
String &String::operator=(const char32_t *p_str) {
*this = String(p_str);
return *this;
}
bool String::operator==(const char *p_str) const {
return *this == String(p_str);
}
bool String::operator==(const wchar_t *p_str) const {
return *this == String(p_str);
}
bool String::operator==(const char16_t *p_str) const {
return *this == String(p_str);
}
bool String::operator==(const char32_t *p_str) const {
return *this == String(p_str);
}
bool String::operator!=(const char *p_str) const {
return *this != String(p_str);
}
bool String::operator!=(const wchar_t *p_str) const {
return *this != String(p_str);
}
bool String::operator!=(const char16_t *p_str) const {
return *this != String(p_str);
}
bool String::operator!=(const char32_t *p_str) const {
return *this != String(p_str);
}
String String::operator+(const char *p_str) {
return *this + String(p_str);
}
String String::operator+(const wchar_t *p_str) {
return *this + String(p_str);
}
String String::operator+(const char16_t *p_str) {
return *this + String(p_str);
}
String String::operator+(const char32_t *p_str) {
return *this + String(p_str);
}
String String::operator+(const char32_t p_char) {
return *this + String::chr(p_char);
}
String &String::operator+=(const String &p_str) {
internal::gde_interface->string_operator_plus_eq_string((GDExtensionStringPtr)this, (GDExtensionConstStringPtr)&p_str);
return *this;
}
String &String::operator+=(char32_t p_char) {
internal::gde_interface->string_operator_plus_eq_char((GDExtensionStringPtr)this, p_char);
return *this;
}
String &String::operator+=(const char *p_str) {
internal::gde_interface->string_operator_plus_eq_cstr((GDExtensionStringPtr)this, p_str);
return *this;
}
String &String::operator+=(const wchar_t *p_str) {
internal::gde_interface->string_operator_plus_eq_wcstr((GDExtensionStringPtr)this, p_str);
return *this;
}
String &String::operator+=(const char32_t *p_str) {
internal::gde_interface->string_operator_plus_eq_c32str((GDExtensionStringPtr)this, p_str);
return *this;
}
const char32_t &String::operator[](int p_index) const {
return *internal::gde_interface->string_operator_index_const((GDExtensionStringPtr)this, p_index);
}
char32_t &String::operator[](int p_index) {
return *internal::gde_interface->string_operator_index((GDExtensionStringPtr)this, p_index);
}
const char32_t *String::ptr() const {
return internal::gde_interface->string_operator_index_const((GDExtensionStringPtr)this, 0);
}
char32_t *String::ptrw() {
return internal::gde_interface->string_operator_index((GDExtensionStringPtr)this, 0);
}
bool operator==(const char *p_chr, const String &p_str) {
return p_str == String(p_chr);
}
bool operator==(const wchar_t *p_chr, const String &p_str) {
return p_str == String(p_chr);
}
bool operator==(const char16_t *p_chr, const String &p_str) {
return p_str == String(p_chr);
}
bool operator==(const char32_t *p_chr, const String &p_str) {
return p_str == String(p_chr);
}
bool operator!=(const char *p_chr, const String &p_str) {
return !(p_str == p_chr);
}
bool operator!=(const wchar_t *p_chr, const String &p_str) {
return !(p_str == p_chr);
}
bool operator!=(const char16_t *p_chr, const String &p_str) {
return !(p_str == p_chr);
}
bool operator!=(const char32_t *p_chr, const String &p_str) {
return !(p_str == p_chr);
}
String operator+(const char *p_chr, const String &p_str) {
return String(p_chr) + p_str;
}
String operator+(const wchar_t *p_chr, const String &p_str) {
return String(p_chr) + p_str;
}
String operator+(const char16_t *p_chr, const String &p_str) {
return String(p_chr) + p_str;
}
String operator+(const char32_t *p_chr, const String &p_str) {
return String(p_chr) + p_str;
}
String operator+(char32_t p_char, const String &p_str) {
return String::chr(p_char) + p_str;
}
StringName::StringName(const char *from) :
StringName(String(from)) {}
StringName::StringName(const wchar_t *from) :
StringName(String(from)) {}
StringName::StringName(const char16_t *from) :
StringName(String(from)) {}
StringName::StringName(const char32_t *from) :
StringName(String(from)) {}
NodePath::NodePath(const char *from) :
NodePath(String(from)) {}
NodePath::NodePath(const wchar_t *from) :
NodePath(String(from)) {}
NodePath::NodePath(const char16_t *from) :
NodePath(String(from)) {}
NodePath::NodePath(const char32_t *from) :
NodePath(String(from)) {}
} // namespace godot

View File

@@ -0,0 +1,572 @@
/**************************************************************************/
/* color.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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.0f);
c <<= 8;
c |= (uint8_t)Math::round(r * 255.0f);
c <<= 8;
c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
c |= (uint8_t)Math::round(b * 255.0f);
return c;
}
uint32_t Color::to_abgr32() const {
uint32_t c = (uint8_t)Math::round(a * 255.0f);
c <<= 8;
c |= (uint8_t)Math::round(b * 255.0f);
c <<= 8;
c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
c |= (uint8_t)Math::round(r * 255.0f);
return c;
}
uint32_t Color::to_rgba32() const {
uint32_t c = (uint8_t)Math::round(r * 255.0f);
c <<= 8;
c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
c |= (uint8_t)Math::round(b * 255.0f);
c <<= 8;
c |= (uint8_t)Math::round(a * 255.0f);
return c;
}
uint64_t Color::to_abgr64() const {
uint64_t c = (uint16_t)Math::round(a * 65535.0f);
c <<= 16;
c |= (uint16_t)Math::round(b * 65535.0f);
c <<= 16;
c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
c |= (uint16_t)Math::round(r * 65535.0f);
return c;
}
uint64_t Color::to_argb64() const {
uint64_t c = (uint16_t)Math::round(a * 65535.0f);
c <<= 16;
c |= (uint16_t)Math::round(r * 65535.0f);
c <<= 16;
c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
c |= (uint16_t)Math::round(b * 65535.0f);
return c;
}
uint64_t Color::to_rgba64() const {
uint64_t c = (uint16_t)Math::round(r * 65535.0f);
c <<= 16;
c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
c |= (uint16_t)Math::round(b * 65535.0f);
c <<= 16;
c |= (uint16_t)Math::round(a * 65535.0f);
return c;
}
String _to_hex(float p_val) {
int v = Math::round(p_val * 255.0f);
v = 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(r);
txt = txt + _to_hex(g);
txt = txt + _to_hex(b);
if (p_alpha) {
txt = txt + _to_hex(a);
}
return txt;
}
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.0f) {
return 0.0f;
}
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.0f;
if (h < 0.0f) {
h += 1.0f;
}
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.0f) ? (delta / max) : 0.0f;
}
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.0f) {
// Achromatic (grey)
r = g = b = p_v;
return;
}
p_h *= 6.0f;
p_h = Math::fmod(p_h, 6);
i = Math::floor(p_h);
f = p_h - i;
p = p_v * (1.0f - p_s);
q = p_v * (1.0f - p_s * f);
t = p_v * (1.0f - p_s * (1.0f - 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);
}
Color Color::clamp(const Color &p_min, const Color &p_max) const {
return Color(
CLAMP(r, p_min.r, p_max.r),
CLAMP(g, p_min.g, p_max.g),
CLAMP(b, p_min.b, p_max.b),
CLAMP(a, p_min.a, p_max.a));
}
void Color::invert() {
r = 1.0f - r;
g = 1.0f - g;
b = 1.0f - b;
}
Color Color::hex(uint32_t p_hex) {
float a = (p_hex & 0xFF) / 255.0f;
p_hex >>= 8;
float b = (p_hex & 0xFF) / 255.0f;
p_hex >>= 8;
float g = (p_hex & 0xFF) / 255.0f;
p_hex >>= 8;
float r = (p_hex & 0xFF) / 255.0f;
return Color(r, g, b, a);
}
Color Color::hex64(uint64_t p_hex) {
float a = (p_hex & 0xFFFF) / 65535.0f;
p_hex >>= 16;
float b = (p_hex & 0xFFFF) / 65535.0f;
p_hex >>= 16;
float g = (p_hex & 0xFFFF) / 65535.0f;
p_hex >>= 16;
float r = (p_hex & 0xFFFF) / 65535.0f;
return Color(r, g, b, a);
}
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_MSG(Color(), "Invalid color code: " + p_rgba + ".");
}
float r, g, b, a = 1.0f;
if (is_shorthand) {
r = _parse_col4(color, 0) / 15.0f;
g = _parse_col4(color, 1) / 15.0f;
b = _parse_col4(color, 2) / 15.0f;
if (alpha) {
a = _parse_col4(color, 3) / 15.0f;
}
} else {
r = _parse_col8(color, 0) / 255.0f;
g = _parse_col8(color, 2) / 255.0f;
b = _parse_col8(color, 4) / 255.0f;
if (alpha) {
a = _parse_col8(color, 6) / 255.0f;
}
}
ERR_FAIL_COND_V_MSG(r < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
ERR_FAIL_COND_V_MSG(g < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
ERR_FAIL_COND_V_MSG(b < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
ERR_FAIL_COND_V_MSG(a < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
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_MSG(Color(), "Invalid color name: " + p_name + ".");
return Color();
}
return named_colors[idx].color;
}
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 named_colors[idx].color;
}
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_upper();
int idx = 0;
while (named_colors[idx].name != nullptr) {
if (name == String(named_colors[idx].name).replace("_", "")) {
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) {
ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), "");
return named_colors[p_idx].name;
}
Color Color::get_named_color(int p_idx) {
ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), Color());
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);
}
}
Color Color::from_hsv(float p_h, float p_s, float p_v, float p_alpha) {
Color c;
c.set_hsv(p_h, p_s, p_v, p_alpha);
return c;
}
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.0f, e - 15.0f - 9.0f);
float rd = r * m;
float gd = g * m;
float bd = b * m;
return Color(rd, gd, bd, 1.0f);
}
Color::operator String() const {
return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")";
}
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.0f - r,
1.0f - g,
1.0f - b,
1.0f - a);
}
} // namespace godot

View File

@@ -0,0 +1,230 @@
/**************************************************************************/
/* packed_arrays.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
// extra functions for packed arrays
#include <godot_cpp/godot.hpp>
#include <godot_cpp/variant/array.hpp>
#include <godot_cpp/variant/dictionary.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::gde_interface->packed_byte_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
uint8_t &PackedByteArray::operator[](int p_index) {
return *internal::gde_interface->packed_byte_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
const uint8_t *PackedByteArray::ptr() const {
return internal::gde_interface->packed_byte_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}
uint8_t *PackedByteArray::ptrw() {
return internal::gde_interface->packed_byte_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const Color &PackedColorArray::operator[](int p_index) const {
const Color *color = (const Color *)internal::gde_interface->packed_color_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *color;
}
Color &PackedColorArray::operator[](int p_index) {
Color *color = (Color *)internal::gde_interface->packed_color_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *color;
}
const Color *PackedColorArray::ptr() const {
return (const Color *)internal::gde_interface->packed_color_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}
Color *PackedColorArray::ptrw() {
return (Color *)internal::gde_interface->packed_color_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const float &PackedFloat32Array::operator[](int p_index) const {
return *internal::gde_interface->packed_float32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
float &PackedFloat32Array::operator[](int p_index) {
return *internal::gde_interface->packed_float32_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
const float *PackedFloat32Array::ptr() const {
return internal::gde_interface->packed_float32_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}
float *PackedFloat32Array::ptrw() {
return internal::gde_interface->packed_float32_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const double &PackedFloat64Array::operator[](int p_index) const {
return *internal::gde_interface->packed_float64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
double &PackedFloat64Array::operator[](int p_index) {
return *internal::gde_interface->packed_float64_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
const double *PackedFloat64Array::ptr() const {
return internal::gde_interface->packed_float64_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}
double *PackedFloat64Array::ptrw() {
return internal::gde_interface->packed_float64_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const int32_t &PackedInt32Array::operator[](int p_index) const {
return *internal::gde_interface->packed_int32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
int32_t &PackedInt32Array::operator[](int p_index) {
return *internal::gde_interface->packed_int32_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
const int32_t *PackedInt32Array::ptr() const {
return internal::gde_interface->packed_int32_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}
int32_t *PackedInt32Array::ptrw() {
return internal::gde_interface->packed_int32_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const int64_t &PackedInt64Array::operator[](int p_index) const {
return *internal::gde_interface->packed_int64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
}
int64_t &PackedInt64Array::operator[](int p_index) {
return *internal::gde_interface->packed_int64_array_operator_index((GDExtensionTypePtr *)this, p_index);
}
const int64_t *PackedInt64Array::ptr() const {
return internal::gde_interface->packed_int64_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}
int64_t *PackedInt64Array::ptrw() {
return internal::gde_interface->packed_int64_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const String &PackedStringArray::operator[](int p_index) const {
const String *string = (const String *)internal::gde_interface->packed_string_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *string;
}
String &PackedStringArray::operator[](int p_index) {
String *string = (String *)internal::gde_interface->packed_string_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *string;
}
const String *PackedStringArray::ptr() const {
return (const String *)internal::gde_interface->packed_string_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}
String *PackedStringArray::ptrw() {
return (String *)internal::gde_interface->packed_string_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const Vector2 &PackedVector2Array::operator[](int p_index) const {
const Vector2 *vec = (const Vector2 *)internal::gde_interface->packed_vector2_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *vec;
}
Vector2 &PackedVector2Array::operator[](int p_index) {
Vector2 *vec = (Vector2 *)internal::gde_interface->packed_vector2_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *vec;
}
const Vector2 *PackedVector2Array::ptr() const {
return (const Vector2 *)internal::gde_interface->packed_vector2_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}
Vector2 *PackedVector2Array::ptrw() {
return (Vector2 *)internal::gde_interface->packed_vector2_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const Vector3 &PackedVector3Array::operator[](int p_index) const {
const Vector3 *vec = (const Vector3 *)internal::gde_interface->packed_vector3_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *vec;
}
Vector3 &PackedVector3Array::operator[](int p_index) {
Vector3 *vec = (Vector3 *)internal::gde_interface->packed_vector3_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *vec;
}
const Vector3 *PackedVector3Array::ptr() const {
return (const Vector3 *)internal::gde_interface->packed_vector3_array_operator_index_const((GDExtensionTypePtr *)this, 0);
}
Vector3 *PackedVector3Array::ptrw() {
return (Vector3 *)internal::gde_interface->packed_vector3_array_operator_index((GDExtensionTypePtr *)this, 0);
}
const Variant &Array::operator[](int p_index) const {
const Variant *var = (const Variant *)internal::gde_interface->array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *var;
}
Variant &Array::operator[](int p_index) {
Variant *var = (Variant *)internal::gde_interface->array_operator_index((GDExtensionTypePtr *)this, p_index);
return *var;
}
void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
// p_type is not Variant::Type so that header doesn't depend on <variant.hpp>.
internal::gde_interface->array_set_typed((GDExtensionTypePtr *)this, (GDExtensionVariantType)p_type, (GDExtensionConstStringNamePtr)&p_class_name, (GDExtensionConstVariantPtr)&p_script);
}
void Array::_ref(const Array &p_from) const {
internal::gde_interface->array_ref((GDExtensionTypePtr *)this, (GDExtensionConstTypePtr *)&p_from);
}
const Variant &Dictionary::operator[](const Variant &p_key) const {
const Variant *var = (const Variant *)internal::gde_interface->dictionary_operator_index_const((GDExtensionTypePtr *)this, (GDExtensionVariantPtr)&p_key);
return *var;
}
Variant &Dictionary::operator[](const Variant &p_key) {
Variant *var = (Variant *)internal::gde_interface->dictionary_operator_index((GDExtensionTypePtr *)this, (GDExtensionVariantPtr)&p_key);
return *var;
}
} // namespace godot

View File

@@ -0,0 +1,185 @@
/**************************************************************************/
/* plane.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/plane.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/variant.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.99f) { // 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 > (real_t)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 < (real_t)-CMP_EPSILON || dist > (1.0f + (real_t)CMP_EPSILON)) {
return false;
}
dist = -dist;
*p_intersection = p_begin + segment * dist;
return true;
}
Variant Plane::intersect_3_bind(const Plane &p_plane1, const Plane &p_plane2) const {
Vector3 inters;
if (intersect_3(p_plane1, p_plane2, &inters)) {
return inters;
} else {
return Variant();
}
}
Variant Plane::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
Vector3 inters;
if (intersects_ray(p_from, p_dir, &inters)) {
return inters;
} else {
return Variant();
}
}
Variant Plane::intersects_segment_bind(const Vector3 &p_begin, const Vector3 &p_end) const {
Vector3 inters;
if (intersects_segment(p_begin, p_end, &inters)) {
return inters;
} else {
return Variant();
}
}
/* 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 "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
}
} // namespace godot

View File

@@ -0,0 +1,941 @@
/**************************************************************************/
/* projection.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/projection.hpp>
#include <godot_cpp/variant/aabb.hpp>
#include <godot_cpp/variant/plane.hpp>
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/transform3d.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
float Projection::determinant() const {
return columns[0][3] * columns[1][2] * columns[2][1] * columns[3][0] - columns[0][2] * columns[1][3] * columns[2][1] * columns[3][0] -
columns[0][3] * columns[1][1] * columns[2][2] * columns[3][0] + columns[0][1] * columns[1][3] * columns[2][2] * columns[3][0] +
columns[0][2] * columns[1][1] * columns[2][3] * columns[3][0] - columns[0][1] * columns[1][2] * columns[2][3] * columns[3][0] -
columns[0][3] * columns[1][2] * columns[2][0] * columns[3][1] + columns[0][2] * columns[1][3] * columns[2][0] * columns[3][1] +
columns[0][3] * columns[1][0] * columns[2][2] * columns[3][1] - columns[0][0] * columns[1][3] * columns[2][2] * columns[3][1] -
columns[0][2] * columns[1][0] * columns[2][3] * columns[3][1] + columns[0][0] * columns[1][2] * columns[2][3] * columns[3][1] +
columns[0][3] * columns[1][1] * columns[2][0] * columns[3][2] - columns[0][1] * columns[1][3] * columns[2][0] * columns[3][2] -
columns[0][3] * columns[1][0] * columns[2][1] * columns[3][2] + columns[0][0] * columns[1][3] * columns[2][1] * columns[3][2] +
columns[0][1] * columns[1][0] * columns[2][3] * columns[3][2] - columns[0][0] * columns[1][1] * columns[2][3] * columns[3][2] -
columns[0][2] * columns[1][1] * columns[2][0] * columns[3][3] + columns[0][1] * columns[1][2] * columns[2][0] * columns[3][3] +
columns[0][2] * columns[1][0] * columns[2][1] * columns[3][3] - columns[0][0] * columns[1][2] * columns[2][1] * columns[3][3] -
columns[0][1] * columns[1][0] * columns[2][2] * columns[3][3] + columns[0][0] * columns[1][1] * columns[2][2] * columns[3][3];
}
void Projection::set_identity() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
columns[i][j] = (i == j) ? 1 : 0;
}
}
}
void Projection::set_zero() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
columns[i][j] = 0;
}
}
}
Plane Projection::xform4(const Plane &p_vec4) const {
Plane ret;
ret.normal.x = columns[0][0] * p_vec4.normal.x + columns[1][0] * p_vec4.normal.y + columns[2][0] * p_vec4.normal.z + columns[3][0] * p_vec4.d;
ret.normal.y = columns[0][1] * p_vec4.normal.x + columns[1][1] * p_vec4.normal.y + columns[2][1] * p_vec4.normal.z + columns[3][1] * p_vec4.d;
ret.normal.z = columns[0][2] * p_vec4.normal.x + columns[1][2] * p_vec4.normal.y + columns[2][2] * p_vec4.normal.z + columns[3][2] * p_vec4.d;
ret.d = columns[0][3] * p_vec4.normal.x + columns[1][3] * p_vec4.normal.y + columns[2][3] * p_vec4.normal.z + columns[3][3] * p_vec4.d;
return ret;
}
Vector4 Projection::xform(const Vector4 &p_vec4) const {
return Vector4(
columns[0][0] * p_vec4.x + columns[1][0] * p_vec4.y + columns[2][0] * p_vec4.z + columns[3][0] * p_vec4.w,
columns[0][1] * p_vec4.x + columns[1][1] * p_vec4.y + columns[2][1] * p_vec4.z + columns[3][1] * p_vec4.w,
columns[0][2] * p_vec4.x + columns[1][2] * p_vec4.y + columns[2][2] * p_vec4.z + columns[3][2] * p_vec4.w,
columns[0][3] * p_vec4.x + columns[1][3] * p_vec4.y + columns[2][3] * p_vec4.z + columns[3][3] * p_vec4.w);
}
Vector4 Projection::xform_inv(const Vector4 &p_vec4) const {
return Vector4(
columns[0][0] * p_vec4.x + columns[0][1] * p_vec4.y + columns[0][2] * p_vec4.z + columns[0][3] * p_vec4.w,
columns[1][0] * p_vec4.x + columns[1][1] * p_vec4.y + columns[1][2] * p_vec4.z + columns[1][3] * p_vec4.w,
columns[2][0] * p_vec4.x + columns[2][1] * p_vec4.y + columns[2][2] * p_vec4.z + columns[2][3] * p_vec4.w,
columns[3][0] * p_vec4.x + columns[3][1] * p_vec4.y + columns[3][2] * p_vec4.z + columns[3][3] * p_vec4.w);
}
void Projection::adjust_perspective_znear(real_t p_new_znear) {
real_t zfar = get_z_far();
real_t znear = p_new_znear;
real_t deltaZ = zfar - znear;
columns[2][2] = -(zfar + znear) / deltaZ;
columns[3][2] = -2 * znear * zfar / deltaZ;
}
Projection Projection::create_depth_correction(bool p_flip_y) {
Projection proj;
proj.set_depth_correction(p_flip_y);
return proj;
}
Projection Projection::create_light_atlas_rect(const Rect2 &p_rect) {
Projection proj;
proj.set_light_atlas_rect(p_rect);
return proj;
}
Projection Projection::create_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) {
Projection proj;
proj.set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov);
return proj;
}
Projection Projection::create_perspective_hmd(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) {
Projection proj;
proj.set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov, p_eye, p_intraocular_dist, p_convergence_dist);
return proj;
}
Projection Projection::create_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) {
Projection proj;
proj.set_for_hmd(p_eye, p_aspect, p_intraocular_dist, p_display_width, p_display_to_lens, p_oversample, p_z_near, p_z_far);
return proj;
}
Projection Projection::create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
Projection proj;
proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_zfar, p_zfar);
return proj;
}
Projection Projection::create_orthogonal_aspect(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) {
Projection proj;
proj.set_orthogonal(p_size, p_aspect, p_znear, p_zfar, p_flip_fov);
return proj;
}
Projection Projection::create_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) {
Projection proj;
proj.set_frustum(p_left, p_right, p_bottom, p_top, p_near, p_far);
return proj;
}
Projection Projection::create_frustum_aspect(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) {
Projection proj;
proj.set_frustum(p_size, p_aspect, p_offset, p_near, p_far, p_flip_fov);
return proj;
}
Projection Projection::create_fit_aabb(const AABB &p_aabb) {
Projection proj;
proj.scale_translate_to_fit(p_aabb);
return proj;
}
Projection Projection::perspective_znear_adjusted(real_t p_new_znear) const {
Projection proj = *this;
proj.adjust_perspective_znear(p_new_znear);
return proj;
}
Plane Projection::get_projection_plane(Planes p_plane) const {
const real_t *matrix = (const real_t *)this->columns;
switch (p_plane) {
case PLANE_NEAR: {
Plane new_plane = Plane(matrix[3] + matrix[2],
matrix[7] + matrix[6],
matrix[11] + matrix[10],
matrix[15] + matrix[14]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
}
case PLANE_FAR: {
Plane new_plane = Plane(matrix[3] - matrix[2],
matrix[7] - matrix[6],
matrix[11] - matrix[10],
matrix[15] - matrix[14]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
}
case PLANE_LEFT: {
Plane new_plane = Plane(matrix[3] + matrix[0],
matrix[7] + matrix[4],
matrix[11] + matrix[8],
matrix[15] + matrix[12]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
}
case PLANE_TOP: {
Plane new_plane = Plane(matrix[3] - matrix[1],
matrix[7] - matrix[5],
matrix[11] - matrix[9],
matrix[15] - matrix[13]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
}
case PLANE_RIGHT: {
Plane new_plane = Plane(matrix[3] - matrix[0],
matrix[7] - matrix[4],
matrix[11] - matrix[8],
matrix[15] - matrix[12]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
}
case PLANE_BOTTOM: {
Plane new_plane = Plane(matrix[3] + matrix[1],
matrix[7] + matrix[5],
matrix[11] + matrix[9],
matrix[15] + matrix[13]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane;
}
}
return Plane();
}
Projection Projection::flipped_y() const {
Projection proj = *this;
proj.flip_y();
return proj;
}
Projection Projection ::jitter_offseted(const Vector2 &p_offset) const {
Projection proj = *this;
proj.add_jitter_offset(p_offset);
return proj;
}
void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) {
if (p_flip_fov) {
p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect);
}
real_t sine, cotangent, deltaZ;
real_t radians = Math::deg_to_rad(p_fovy_degrees / 2.0);
deltaZ = p_z_far - p_z_near;
sine = Math::sin(radians);
if ((deltaZ == 0) || (sine == 0) || (p_aspect == 0)) {
return;
}
cotangent = Math::cos(radians) / sine;
set_identity();
columns[0][0] = cotangent / p_aspect;
columns[1][1] = cotangent;
columns[2][2] = -(p_z_far + p_z_near) / deltaZ;
columns[2][3] = -1;
columns[3][2] = -2 * p_z_near * p_z_far / deltaZ;
columns[3][3] = 0;
}
void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) {
if (p_flip_fov) {
p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect);
}
real_t left, right, modeltranslation, ymax, xmax, frustumshift;
ymax = p_z_near * tan(Math::deg_to_rad(p_fovy_degrees / 2.0));
xmax = ymax * p_aspect;
frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist;
switch (p_eye) {
case 1: { // left eye
left = -xmax + frustumshift;
right = xmax + frustumshift;
modeltranslation = p_intraocular_dist / 2.0;
} break;
case 2: { // right eye
left = -xmax - frustumshift;
right = xmax - frustumshift;
modeltranslation = -p_intraocular_dist / 2.0;
} break;
default: { // mono, should give the same result as set_perspective(p_fovy_degrees,p_aspect,p_z_near,p_z_far,p_flip_fov)
left = -xmax;
right = xmax;
modeltranslation = 0.0;
} break;
}
set_frustum(left, right, -ymax, ymax, p_z_near, p_z_far);
// translate matrix by (modeltranslation, 0.0, 0.0)
Projection cm;
cm.set_identity();
cm.columns[3][0] = modeltranslation;
*this = *this * cm;
}
void Projection::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) {
// we first calculate our base frustum on our values without taking our lens magnification into account.
real_t f1 = (p_intraocular_dist * 0.5) / p_display_to_lens;
real_t f2 = ((p_display_width - p_intraocular_dist) * 0.5) / p_display_to_lens;
real_t f3 = (p_display_width / 4.0) / p_display_to_lens;
// now we apply our oversample factor to increase our FOV. how much we oversample is always a balance we strike between performance and how much
// we're willing to sacrifice in FOV.
real_t add = ((f1 + f2) * (p_oversample - 1.0)) / 2.0;
f1 += add;
f2 += add;
f3 *= p_oversample;
// always apply KEEP_WIDTH aspect ratio
f3 /= p_aspect;
switch (p_eye) {
case 1: { // left eye
set_frustum(-f2 * p_z_near, f1 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far);
} break;
case 2: { // right eye
set_frustum(-f1 * p_z_near, f2 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far);
} break;
default: { // mono, does not apply here!
} break;
}
}
void Projection::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
set_identity();
columns[0][0] = 2.0 / (p_right - p_left);
columns[3][0] = -((p_right + p_left) / (p_right - p_left));
columns[1][1] = 2.0 / (p_top - p_bottom);
columns[3][1] = -((p_top + p_bottom) / (p_top - p_bottom));
columns[2][2] = -2.0 / (p_zfar - p_znear);
columns[3][2] = -((p_zfar + p_znear) / (p_zfar - p_znear));
columns[3][3] = 1.0;
}
void Projection::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) {
if (!p_flip_fov) {
p_size *= p_aspect;
}
set_orthogonal(-p_size / 2, +p_size / 2, -p_size / p_aspect / 2, +p_size / p_aspect / 2, p_znear, p_zfar);
}
void Projection::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) {
ERR_FAIL_COND(p_right <= p_left);
ERR_FAIL_COND(p_top <= p_bottom);
ERR_FAIL_COND(p_far <= p_near);
real_t *te = &columns[0][0];
real_t x = 2 * p_near / (p_right - p_left);
real_t y = 2 * p_near / (p_top - p_bottom);
real_t a = (p_right + p_left) / (p_right - p_left);
real_t b = (p_top + p_bottom) / (p_top - p_bottom);
real_t c = -(p_far + p_near) / (p_far - p_near);
real_t d = -2 * p_far * p_near / (p_far - p_near);
te[0] = x;
te[1] = 0;
te[2] = 0;
te[3] = 0;
te[4] = 0;
te[5] = y;
te[6] = 0;
te[7] = 0;
te[8] = a;
te[9] = b;
te[10] = c;
te[11] = -1;
te[12] = 0;
te[13] = 0;
te[14] = d;
te[15] = 0;
}
void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) {
if (!p_flip_fov) {
p_size *= p_aspect;
}
set_frustum(-p_size / 2 + p_offset.x, +p_size / 2 + p_offset.x, -p_size / p_aspect / 2 + p_offset.y, +p_size / p_aspect / 2 + p_offset.y, p_near, p_far);
}
real_t Projection::get_z_far() const {
const real_t *matrix = (const real_t *)this->columns;
Plane new_plane = Plane(matrix[3] - matrix[2],
matrix[7] - matrix[6],
matrix[11] - matrix[10],
matrix[15] - matrix[14]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane.d;
}
real_t Projection::get_z_near() const {
const real_t *matrix = (const real_t *)this->columns;
Plane new_plane = Plane(matrix[3] + matrix[2],
matrix[7] + matrix[6],
matrix[11] + matrix[10],
-matrix[15] - matrix[14]);
new_plane.normalize();
return new_plane.d;
}
Vector2 Projection::get_viewport_half_extents() const {
const real_t *matrix = (const real_t *)this->columns;
///////--- Near Plane ---///////
Plane near_plane = Plane(matrix[3] + matrix[2],
matrix[7] + matrix[6],
matrix[11] + matrix[10],
-matrix[15] - matrix[14]);
near_plane.normalize();
///////--- Right Plane ---///////
Plane right_plane = Plane(matrix[3] - matrix[0],
matrix[7] - matrix[4],
matrix[11] - matrix[8],
-matrix[15] + matrix[12]);
right_plane.normalize();
Plane top_plane = Plane(matrix[3] - matrix[1],
matrix[7] - matrix[5],
matrix[11] - matrix[9],
-matrix[15] + matrix[13]);
top_plane.normalize();
Vector3 res;
near_plane.intersect_3(right_plane, top_plane, &res);
return Vector2(res.x, res.y);
}
Vector2 Projection::get_far_plane_half_extents() const {
const real_t *matrix = (const real_t *)this->columns;
///////--- Far Plane ---///////
Plane far_plane = Plane(matrix[3] - matrix[2],
matrix[7] - matrix[6],
matrix[11] - matrix[10],
-matrix[15] + matrix[14]);
far_plane.normalize();
///////--- Right Plane ---///////
Plane right_plane = Plane(matrix[3] - matrix[0],
matrix[7] - matrix[4],
matrix[11] - matrix[8],
-matrix[15] + matrix[12]);
right_plane.normalize();
Plane top_plane = Plane(matrix[3] - matrix[1],
matrix[7] - matrix[5],
matrix[11] - matrix[9],
-matrix[15] + matrix[13]);
top_plane.normalize();
Vector3 res;
far_plane.intersect_3(right_plane, top_plane, &res);
return Vector2(res.x, res.y);
}
bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const {
Array planes = get_projection_planes(Transform3D());
const Planes intersections[8][3] = {
{ PLANE_FAR, PLANE_LEFT, PLANE_TOP },
{ PLANE_FAR, PLANE_LEFT, PLANE_BOTTOM },
{ PLANE_FAR, PLANE_RIGHT, PLANE_TOP },
{ PLANE_FAR, PLANE_RIGHT, PLANE_BOTTOM },
{ PLANE_NEAR, PLANE_LEFT, PLANE_TOP },
{ PLANE_NEAR, PLANE_LEFT, PLANE_BOTTOM },
{ PLANE_NEAR, PLANE_RIGHT, PLANE_TOP },
{ PLANE_NEAR, PLANE_RIGHT, PLANE_BOTTOM },
};
for (int i = 0; i < 8; i++) {
Vector3 point;
Plane a = planes[intersections[i][0]];
Plane b = planes[intersections[i][1]];
Plane c = planes[intersections[i][2]];
bool res = a.intersect_3(b, c, &point);
ERR_FAIL_COND_V(!res, false);
p_8points[i] = p_transform.xform(point);
}
return true;
}
Array Projection::get_projection_planes(const Transform3D &p_transform) const {
/** Fast Plane Extraction from combined modelview/projection matrices.
* References:
* https://web.archive.org/web/20011221205252/https://www.markmorley.com/opengl/frustumculling.html
* https://web.archive.org/web/20061020020112/https://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf
*/
Array planes;
planes.resize(6);
const real_t *matrix = (const real_t *)this->columns;
Plane new_plane;
///////--- Near Plane ---///////
new_plane = Plane(matrix[3] + matrix[2],
matrix[7] + matrix[6],
matrix[11] + matrix[10],
matrix[15] + matrix[14]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
planes[0] = p_transform.xform(new_plane);
///////--- Far Plane ---///////
new_plane = Plane(matrix[3] - matrix[2],
matrix[7] - matrix[6],
matrix[11] - matrix[10],
matrix[15] - matrix[14]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
planes[1] = p_transform.xform(new_plane);
///////--- Left Plane ---///////
new_plane = Plane(matrix[3] + matrix[0],
matrix[7] + matrix[4],
matrix[11] + matrix[8],
matrix[15] + matrix[12]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
planes[2] = p_transform.xform(new_plane);
///////--- Top Plane ---///////
new_plane = Plane(matrix[3] - matrix[1],
matrix[7] - matrix[5],
matrix[11] - matrix[9],
matrix[15] - matrix[13]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
planes[3] = p_transform.xform(new_plane);
///////--- Right Plane ---///////
new_plane = Plane(matrix[3] - matrix[0],
matrix[7] - matrix[4],
matrix[11] - matrix[8],
matrix[15] - matrix[12]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
planes[4] = p_transform.xform(new_plane);
///////--- Bottom Plane ---///////
new_plane = Plane(matrix[3] + matrix[1],
matrix[7] + matrix[5],
matrix[11] + matrix[9],
matrix[15] + matrix[13]);
new_plane.normal = -new_plane.normal;
new_plane.normalize();
planes[5] = p_transform.xform(new_plane);
return planes;
}
Projection Projection::inverse() const {
Projection cm = *this;
cm.invert();
return cm;
}
void Projection::invert() {
int i, j, k;
int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */
real_t pvt_val; /* Value of current pivot element */
real_t hold; /* Temporary storage */
real_t determinant = 1.0f;
for (k = 0; k < 4; k++) {
/** Locate k'th pivot element **/
pvt_val = columns[k][k]; /** Initialize for search **/
pvt_i[k] = k;
pvt_j[k] = k;
for (i = k; i < 4; i++) {
for (j = k; j < 4; j++) {
if (Math::abs(columns[i][j]) > Math::abs(pvt_val)) {
pvt_i[k] = i;
pvt_j[k] = j;
pvt_val = columns[i][j];
}
}
}
/** Product of pivots, gives determinant when finished **/
determinant *= pvt_val;
if (Math::is_zero_approx(determinant)) {
return; /** Matrix is singular (zero determinant). **/
}
/** "Interchange" rows (with sign change stuff) **/
i = pvt_i[k];
if (i != k) { /** If rows are different **/
for (j = 0; j < 4; j++) {
hold = -columns[k][j];
columns[k][j] = columns[i][j];
columns[i][j] = hold;
}
}
/** "Interchange" columns **/
j = pvt_j[k];
if (j != k) { /** If columns are different **/
for (i = 0; i < 4; i++) {
hold = -columns[i][k];
columns[i][k] = columns[i][j];
columns[i][j] = hold;
}
}
/** Divide column by minus pivot value **/
for (i = 0; i < 4; i++) {
if (i != k) {
columns[i][k] /= (-pvt_val);
}
}
/** Reduce the matrix **/
for (i = 0; i < 4; i++) {
hold = columns[i][k];
for (j = 0; j < 4; j++) {
if (i != k && j != k) {
columns[i][j] += hold * columns[k][j];
}
}
}
/** Divide row by pivot **/
for (j = 0; j < 4; j++) {
if (j != k) {
columns[k][j] /= pvt_val;
}
}
/** Replace pivot by reciprocal (at last we can touch it). **/
columns[k][k] = 1.0 / pvt_val;
}
/* That was most of the work, one final pass of row/column interchange */
/* to finish */
for (k = 4 - 2; k >= 0; k--) { /* Don't need to work with 1 by 1 corner*/
i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */
if (i != k) { /* If rows are different */
for (j = 0; j < 4; j++) {
hold = columns[k][j];
columns[k][j] = -columns[i][j];
columns[i][j] = hold;
}
}
j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */
if (j != k) { /* If columns are different */
for (i = 0; i < 4; i++) {
hold = columns[i][k];
columns[i][k] = -columns[i][j];
columns[i][j] = hold;
}
}
}
}
void Projection::flip_y() {
for (int i = 0; i < 4; i++) {
columns[1][i] = -columns[1][i];
}
}
Projection::Projection() {
set_identity();
}
Projection Projection::operator*(const Projection &p_matrix) const {
Projection new_matrix;
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 4; i++) {
real_t ab = 0;
for (int k = 0; k < 4; k++) {
ab += columns[k][i] * p_matrix.columns[j][k];
}
new_matrix.columns[j][i] = ab;
}
}
return new_matrix;
}
void Projection::set_depth_correction(bool p_flip_y) {
real_t *m = &columns[0][0];
m[0] = 1;
m[1] = 0.0;
m[2] = 0.0;
m[3] = 0.0;
m[4] = 0.0;
m[5] = p_flip_y ? -1 : 1;
m[6] = 0.0;
m[7] = 0.0;
m[8] = 0.0;
m[9] = 0.0;
m[10] = 0.5;
m[11] = 0.0;
m[12] = 0.0;
m[13] = 0.0;
m[14] = 0.5;
m[15] = 1.0;
}
void Projection::set_light_bias() {
real_t *m = &columns[0][0];
m[0] = 0.5;
m[1] = 0.0;
m[2] = 0.0;
m[3] = 0.0;
m[4] = 0.0;
m[5] = 0.5;
m[6] = 0.0;
m[7] = 0.0;
m[8] = 0.0;
m[9] = 0.0;
m[10] = 0.5;
m[11] = 0.0;
m[12] = 0.5;
m[13] = 0.5;
m[14] = 0.5;
m[15] = 1.0;
}
void Projection::set_light_atlas_rect(const Rect2 &p_rect) {
real_t *m = &columns[0][0];
m[0] = p_rect.size.width;
m[1] = 0.0;
m[2] = 0.0;
m[3] = 0.0;
m[4] = 0.0;
m[5] = p_rect.size.height;
m[6] = 0.0;
m[7] = 0.0;
m[8] = 0.0;
m[9] = 0.0;
m[10] = 1.0;
m[11] = 0.0;
m[12] = p_rect.position.x;
m[13] = p_rect.position.y;
m[14] = 0.0;
m[15] = 1.0;
}
Projection::operator String() const {
String str;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
str = str + String((j > 0) ? ", " : "\n") + rtos(columns[i][j]);
}
}
return str;
}
real_t Projection::get_aspect() const {
Vector2 vp_he = get_viewport_half_extents();
return vp_he.x / vp_he.y;
}
int Projection::get_pixels_per_meter(int p_for_pixel_width) const {
Vector3 result = xform(Vector3(1, 0, -1));
return int((result.x * 0.5 + 0.5) * p_for_pixel_width);
}
bool Projection::is_orthogonal() const {
return columns[3][3] == 1.0;
}
real_t Projection::get_fov() const {
const real_t *matrix = (const real_t *)this->columns;
Plane right_plane = Plane(matrix[3] - matrix[0],
matrix[7] - matrix[4],
matrix[11] - matrix[8],
-matrix[15] + matrix[12]);
right_plane.normalize();
if ((matrix[8] == 0) && (matrix[9] == 0)) {
return Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0;
} else {
// our frustum is asymmetrical need to calculate the left planes angle separately..
Plane left_plane = Plane(matrix[3] + matrix[0],
matrix[7] + matrix[4],
matrix[11] + matrix[8],
matrix[15] + matrix[12]);
left_plane.normalize();
return Math::rad_to_deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x)));
}
}
float Projection::get_lod_multiplier() const {
if (is_orthogonal()) {
return get_viewport_half_extents().x;
} else {
float zn = get_z_near();
float width = get_viewport_half_extents().x * 2.0;
return 1.0 / (zn / width);
}
// Usage is lod_size / (lod_distance * multiplier) < threshold
}
void Projection::make_scale(const Vector3 &p_scale) {
set_identity();
columns[0][0] = p_scale.x;
columns[1][1] = p_scale.y;
columns[2][2] = p_scale.z;
}
void Projection::scale_translate_to_fit(const AABB &p_aabb) {
Vector3 min = p_aabb.position;
Vector3 max = p_aabb.position + p_aabb.size;
columns[0][0] = 2 / (max.x - min.x);
columns[1][0] = 0;
columns[2][0] = 0;
columns[3][0] = -(max.x + min.x) / (max.x - min.x);
columns[0][1] = 0;
columns[1][1] = 2 / (max.y - min.y);
columns[2][1] = 0;
columns[3][1] = -(max.y + min.y) / (max.y - min.y);
columns[0][2] = 0;
columns[1][2] = 0;
columns[2][2] = 2 / (max.z - min.z);
columns[3][2] = -(max.z + min.z) / (max.z - min.z);
columns[0][3] = 0;
columns[1][3] = 0;
columns[2][3] = 0;
columns[3][3] = 1;
}
void Projection::add_jitter_offset(const Vector2 &p_offset) {
columns[3][0] += p_offset.x;
columns[3][1] += p_offset.y;
}
Projection::operator Transform3D() const {
Transform3D tr;
const real_t *m = &columns[0][0];
tr.basis.rows[0][0] = m[0];
tr.basis.rows[1][0] = m[1];
tr.basis.rows[2][0] = m[2];
tr.basis.rows[0][1] = m[4];
tr.basis.rows[1][1] = m[5];
tr.basis.rows[2][1] = m[6];
tr.basis.rows[0][2] = m[8];
tr.basis.rows[1][2] = m[9];
tr.basis.rows[2][2] = m[10];
tr.origin.x = m[12];
tr.origin.y = m[13];
tr.origin.z = m[14];
return tr;
}
Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) {
columns[0] = p_x;
columns[1] = p_y;
columns[2] = p_z;
columns[3] = p_w;
}
Projection::Projection(const Transform3D &p_transform) {
const Transform3D &tr = p_transform;
real_t *m = &columns[0][0];
m[0] = tr.basis.rows[0][0];
m[1] = tr.basis.rows[1][0];
m[2] = tr.basis.rows[2][0];
m[3] = 0.0;
m[4] = tr.basis.rows[0][1];
m[5] = tr.basis.rows[1][1];
m[6] = tr.basis.rows[2][1];
m[7] = 0.0;
m[8] = tr.basis.rows[0][2];
m[9] = tr.basis.rows[1][2];
m[10] = tr.basis.rows[2][2];
m[11] = 0.0;
m[12] = tr.origin.x;
m[13] = tr.origin.y;
m[14] = tr.origin.z;
m[15] = 1.0;
}
Projection::~Projection() {
}
} // namespace godot

View File

@@ -0,0 +1,353 @@
/**************************************************************************/
/* quaternion.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/quaternion.hpp>
#include <godot_cpp/variant/basis.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
real_t Quaternion::angle_to(const Quaternion &p_to) const {
real_t d = dot(p_to);
return Math::acos(CLAMP(d * d * 2 - 1, -1, 1));
}
// 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(EULER_ORDER_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_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized.");
#endif
Basis m(*this);
return m.get_euler(EULER_ORDER_YXZ);
}
void Quaternion::operator*=(const Quaternion &p_q) {
real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y;
real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z;
real_t zz = 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;
x = xx;
y = yy;
z = zz;
}
Quaternion Quaternion::operator*(const Quaternion &p_q) const {
Quaternion r = *this;
r *= p_q;
return r;
}
bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const {
return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.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, (real_t)UNIT_EPSILON); //use less epsilon
}
Quaternion Quaternion::inverse() const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion must be normalized.");
#endif
return Quaternion(-x, -y, -z, w);
}
Quaternion Quaternion::log() const {
Quaternion src = *this;
Vector3 src_v = src.get_axis() * src.get_angle();
return Quaternion(src_v.x, src_v.y, src_v.z, 0);
}
Quaternion Quaternion::exp() const {
Quaternion src = *this;
Vector3 src_v = Vector3(src.x, src.y, src.z);
real_t theta = src_v.length();
src_v = src_v.normalized();
if (theta < CMP_EPSILON || !src_v.is_normalized()) {
return Quaternion(0, 0, 0, 1);
}
return Quaternion(src_v, theta);
}
Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
#endif
Quaternion to1;
real_t omega, cosom, sinom, scale0, scale1;
// calc cosine
cosom = dot(p_to);
// adjust signs (if necessary)
if (cosom < 0.0f) {
cosom = -cosom;
to1 = -p_to;
} else {
to1 = p_to;
}
// calculate coefficients
if ((1.0f - cosom) > (real_t)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.0f - 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_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
#endif
const Quaternion &from = *this;
real_t dot = from.dot(p_to);
if (Math::absf(dot) > 0.9999f) {
return from;
}
real_t theta = Math::acos(dot),
sinT = 1.0f / Math::sin(theta),
newFactor = Math::sin(p_weight * theta) * sinT,
invFactor = Math::sin((1.0f - 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::spherical_cubic_interpolate(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_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
#endif
Quaternion from_q = *this;
Quaternion pre_q = p_pre_a;
Quaternion to_q = p_b;
Quaternion post_q = p_post_b;
// Align flip phases.
from_q = Basis(from_q).get_rotation_quaternion();
pre_q = Basis(pre_q).get_rotation_quaternion();
to_q = Basis(to_q).get_rotation_quaternion();
post_q = Basis(post_q).get_rotation_quaternion();
// Flip quaternions to shortest path if necessary.
bool flip1 = Math::sign(from_q.dot(pre_q));
pre_q = flip1 ? -pre_q : pre_q;
bool flip2 = Math::sign(from_q.dot(to_q));
to_q = flip2 ? -to_q : to_q;
bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : Math::sign(to_q.dot(post_q));
post_q = flip3 ? -post_q : post_q;
// Calc by Expmap in from_q space.
Quaternion ln_from = Quaternion(0, 0, 0, 0);
Quaternion ln_to = (from_q.inverse() * to_q).log();
Quaternion ln_pre = (from_q.inverse() * pre_q).log();
Quaternion ln_post = (from_q.inverse() * post_q).log();
Quaternion ln = Quaternion(0, 0, 0, 0);
ln.x = Math::cubic_interpolate(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight);
ln.y = Math::cubic_interpolate(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight);
ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight);
Quaternion q1 = from_q * ln.exp();
// Calc by Expmap in to_q space.
ln_from = (to_q.inverse() * from_q).log();
ln_to = Quaternion(0, 0, 0, 0);
ln_pre = (to_q.inverse() * pre_q).log();
ln_post = (to_q.inverse() * post_q).log();
ln = Quaternion(0, 0, 0, 0);
ln.x = Math::cubic_interpolate(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight);
ln.y = Math::cubic_interpolate(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight);
ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight);
Quaternion q2 = to_q * ln.exp();
// To cancel error made by Expmap ambiguity, do blends.
return q1.slerp(q2, p_weight);
}
Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight,
const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
#endif
Quaternion from_q = *this;
Quaternion pre_q = p_pre_a;
Quaternion to_q = p_b;
Quaternion post_q = p_post_b;
// Align flip phases.
from_q = Basis(from_q).get_rotation_quaternion();
pre_q = Basis(pre_q).get_rotation_quaternion();
to_q = Basis(to_q).get_rotation_quaternion();
post_q = Basis(post_q).get_rotation_quaternion();
// Flip quaternions to shortest path if necessary.
bool flip1 = Math::sign(from_q.dot(pre_q));
pre_q = flip1 ? -pre_q : pre_q;
bool flip2 = Math::sign(from_q.dot(to_q));
to_q = flip2 ? -to_q : to_q;
bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : Math::sign(to_q.dot(post_q));
post_q = flip3 ? -post_q : post_q;
// Calc by Expmap in from_q space.
Quaternion ln_from = Quaternion(0, 0, 0, 0);
Quaternion ln_to = (from_q.inverse() * to_q).log();
Quaternion ln_pre = (from_q.inverse() * pre_q).log();
Quaternion ln_post = (from_q.inverse() * post_q).log();
Quaternion ln = Quaternion(0, 0, 0, 0);
ln.x = Math::cubic_interpolate_in_time(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
ln.y = Math::cubic_interpolate_in_time(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
Quaternion q1 = from_q * ln.exp();
// Calc by Expmap in to_q space.
ln_from = (to_q.inverse() * from_q).log();
ln_to = Quaternion(0, 0, 0, 0);
ln_pre = (to_q.inverse() * pre_q).log();
ln_post = (to_q.inverse() * post_q).log();
ln = Quaternion(0, 0, 0, 0);
ln.x = Math::cubic_interpolate_in_time(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
ln.y = Math::cubic_interpolate_in_time(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
Quaternion q2 = to_q * ln.exp();
// To cancel error made by Expmap ambiguity, do blends.
return q1.slerp(q2, p_weight);
}
Quaternion::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
}
Vector3 Quaternion::get_axis() const {
if (Math::abs(w) > 1 - CMP_EPSILON) {
return Vector3(x, y, z);
}
real_t r = ((real_t)1) / Math::sqrt(1 - w * w);
return Vector3(x * r, y * r, z * r);
}
real_t Quaternion::get_angle() const {
return 2 * Math::acos(w);
}
Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
#ifdef MATH_CHECKS
ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be 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.5f);
real_t cos_angle = Math::cos(p_angle * 0.5f);
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.5f;
real_t half_a2 = p_euler.x * 0.5f;
real_t half_a3 = p_euler.z * 0.5f;
// 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

View File

@@ -0,0 +1,291 @@
/**************************************************************************/
/* rect2.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/rect2i.hpp>
#include <godot_cpp/variant/string.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 {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
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 {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
//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.columns[0].dot(xf_points2[0]);
real_t mina = maxa;
real_t dp = p_xform.columns[0].dot(xf_points2[1]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
dp = p_xform.columns[0].dot(xf_points2[2]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
dp = p_xform.columns[0].dot(xf_points2[3]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
real_t maxb = p_xform.columns[0].dot(xf_points[0]);
real_t minb = maxb;
dp = p_xform.columns[0].dot(xf_points[1]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
dp = p_xform.columns[0].dot(xf_points[2]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
dp = p_xform.columns[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.columns[1].dot(xf_points2[0]);
mina = maxa;
dp = p_xform.columns[1].dot(xf_points2[1]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
dp = p_xform.columns[1].dot(xf_points2[2]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
dp = p_xform.columns[1].dot(xf_points2[3]);
maxa = Math::max(dp, maxa);
mina = Math::min(dp, mina);
maxb = p_xform.columns[1].dot(xf_points[0]);
minb = maxb;
dp = p_xform.columns[1].dot(xf_points[1]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
dp = p_xform.columns[1].dot(xf_points[2]);
maxb = Math::max(dp, maxb);
minb = Math::min(dp, minb);
dp = p_xform.columns[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;
}
Rect2::operator String() const {
return "[P: " + position.operator String() + ", S: " + size + "]";
}
Rect2::operator Rect2i() const {
return Rect2i(position, size);
}
} // namespace godot

View File

@@ -0,0 +1,46 @@
/**************************************************************************/
/* rect2i.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/rect2i.hpp>
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/string.hpp>
namespace godot {
Rect2i::operator String() const {
return "[P: " + position.operator String() + ", S: " + size + "]";
}
Rect2i::operator Rect2() const {
return Rect2(position, size);
}
} // namespace godot

View File

@@ -0,0 +1,323 @@
/**************************************************************************/
/* transform2d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/transform2d.hpp>
#include <godot_cpp/variant/string.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(columns[0][1], columns[1][0]);
columns[2] = basis_xform(-columns[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.0f / det;
SWAP(columns[0][0], columns[1][1]);
columns[0] *= Vector2(idet, -idet);
columns[1] *= Vector2(-idet, idet);
columns[2] = basis_xform(-columns[2]);
}
Transform2D Transform2D::affine_inverse() const {
Transform2D inv = *this;
inv.affine_invert();
return inv;
}
void Transform2D::rotate(const real_t p_angle) {
*this = Transform2D(p_angle, Vector2()) * (*this);
}
real_t Transform2D::get_skew() const {
real_t det = basis_determinant();
return Math::acos(columns[0].normalized().dot(SIGN(det) * columns[1].normalized())) - (real_t)Math_PI * 0.5f;
}
void Transform2D::set_skew(const real_t p_angle) {
real_t det = basis_determinant();
columns[1] = SIGN(det) * columns[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * columns[1].length();
}
real_t Transform2D::get_rotation() const {
return Math::atan2(columns[0].y, columns[0].x);
}
void Transform2D::set_rotation(const real_t p_rot) {
Size2 scale = get_scale();
real_t cr = Math::cos(p_rot);
real_t sr = Math::sin(p_rot);
columns[0][0] = cr;
columns[0][1] = sr;
columns[1][0] = -sr;
columns[1][1] = cr;
set_scale(scale);
}
Transform2D::Transform2D(const real_t p_rot, const Vector2 &p_pos) {
real_t cr = Math::cos(p_rot);
real_t sr = Math::sin(p_rot);
columns[0][0] = cr;
columns[0][1] = sr;
columns[1][0] = -sr;
columns[1][1] = cr;
columns[2] = p_pos;
}
Transform2D::Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos) {
columns[0][0] = Math::cos(p_rot) * p_scale.x;
columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
columns[0][1] = Math::sin(p_rot) * p_scale.x;
columns[2] = p_pos;
}
Size2 Transform2D::get_scale() const {
real_t det_sign = Math::sign(basis_determinant());
return Size2(columns[0].length(), det_sign * columns[1].length());
}
void Transform2D::set_scale(const Size2 &p_scale) {
columns[0].normalize();
columns[1].normalize();
columns[0] *= p_scale.x;
columns[1] *= p_scale.y;
}
void Transform2D::scale(const Size2 &p_scale) {
scale_basis(p_scale);
columns[2] *= p_scale;
}
void Transform2D::scale_basis(const Size2 &p_scale) {
columns[0][0] *= p_scale.x;
columns[0][1] *= p_scale.y;
columns[1][0] *= p_scale.x;
columns[1][1] *= p_scale.y;
}
void Transform2D::translate_local(const real_t p_tx, const real_t p_ty) {
translate_local(Vector2(p_tx, p_ty));
}
void Transform2D::translate_local(const Vector2 &p_translation) {
columns[2] += basis_xform(p_translation);
}
void Transform2D::orthonormalize() {
// Gram-Schmidt Process
Vector2 x = columns[0];
Vector2 y = columns[1];
x.normalize();
y = (y - x * (x.dot(y)));
y.normalize();
columns[0] = x;
columns[1] = y;
}
Transform2D Transform2D::orthonormalized() const {
Transform2D on = *this;
on.orthonormalize();
return on;
}
bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]);
}
Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
Transform2D return_trans = Transform2D(get_rotation(), get_origin());
Vector2 target_position = affine_inverse().xform(p_target);
return_trans.set_rotation(return_trans.get_rotation() + (target_position * get_scale()).angle());
return return_trans;
}
bool Transform2D::operator==(const Transform2D &p_transform) const {
for (int i = 0; i < 3; i++) {
if (columns[i] != p_transform.columns[i]) {
return false;
}
}
return true;
}
bool Transform2D::operator!=(const Transform2D &p_transform) const {
for (int i = 0; i < 3; i++) {
if (columns[i] != p_transform.columns[i]) {
return true;
}
}
return false;
}
void Transform2D::operator*=(const Transform2D &p_transform) {
columns[2] = xform(p_transform.columns[2]);
real_t x0, x1, y0, y1;
x0 = tdotx(p_transform.columns[0]);
x1 = tdoty(p_transform.columns[0]);
y0 = tdotx(p_transform.columns[1]);
y1 = tdoty(p_transform.columns[1]);
columns[0][0] = x0;
columns[0][1] = x1;
columns[1][0] = y0;
columns[1][1] = y1;
}
Transform2D Transform2D::operator*(const Transform2D &p_transform) const {
Transform2D t = *this;
t *= p_transform;
return t;
}
Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
Transform2D copy = *this;
copy.scale_basis(p_scale);
return copy;
}
Transform2D Transform2D::scaled(const Size2 &p_scale) const {
// Equivalent to left multiplication
Transform2D copy = *this;
copy.scale(p_scale);
return copy;
}
Transform2D Transform2D::scaled_local(const Size2 &p_scale) const {
// Equivalent to right multiplication
return Transform2D(columns[0] * p_scale.x, columns[1] * p_scale.y, columns[2]);
}
Transform2D Transform2D::untranslated() const {
Transform2D copy = *this;
copy.columns[2] = Vector2();
return copy;
}
Transform2D Transform2D::translated(const Vector2 &p_offset) const {
// Equivalent to left multiplication
return Transform2D(columns[0], columns[1], columns[2] + p_offset);
}
Transform2D Transform2D::translated_local(const Vector2 &p_offset) const {
// Equivalent to right multiplication
return Transform2D(columns[0], columns[1], columns[2] + basis_xform(p_offset));
}
Transform2D Transform2D::rotated(const real_t p_angle) const {
// Equivalent to left multiplication
return Transform2D(p_angle, Vector2()) * (*this);
}
Transform2D Transform2D::rotated_local(const real_t p_angle) const {
// Equivalent to right multiplication
return (*this) * Transform2D(p_angle, Vector2()); // Could be optimized, because origin transform can be skipped.
}
real_t Transform2D::basis_determinant() const {
return columns[0].x * columns[1].y - columns[0].y * columns[1].x;
}
Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const 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.9995f) {
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(v.angle(), p1.lerp(p2, p_c));
res.scale_basis(s1.lerp(s2, p_c));
return res;
}
void Transform2D::operator*=(const real_t p_val) {
columns[0] *= p_val;
columns[1] *= p_val;
columns[2] *= p_val;
}
Transform2D Transform2D::operator*(const real_t p_val) const {
Transform2D ret(*this);
ret *= p_val;
return ret;
}
Transform2D::operator String() const {
return "[X: " + columns[0].operator String() +
", Y: " + columns[1].operator String() +
", O: " + columns[2].operator String() + "]";
}
} // namespace godot

View File

@@ -0,0 +1,232 @@
/**************************************************************************/
/* transform3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#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_angle) {
*this = rotated(p_axis, p_angle);
}
Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_angle) const {
// Equivalent to left multiplication
Basis p_basis(p_axis, p_angle);
return Transform3D(p_basis * basis, p_basis.xform(origin));
}
Transform3D Transform3D::rotated_local(const Vector3 &p_axis, real_t p_angle) const {
// Equivalent to right multiplication
Basis p_basis(p_axis, p_angle);
return Transform3D(basis * p_basis, origin);
}
void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) {
basis.rotate(p_axis, p_angle);
}
Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(origin.is_equal_approx(p_target), Transform3D(), "The transform's origin and target can't be equal.");
#endif
Transform3D t = *this;
t.basis = Basis::looking_at(p_target - origin, 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_MSG(p_eye.is_equal_approx(p_target), "The eye and target vectors can't be equal.");
#endif
basis = Basis::looking_at(p_target - p_eye, p_up);
origin = p_eye;
}
Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const {
Transform3D interp;
Vector3 src_scale = basis.get_scale();
Quaternion src_rot = basis.get_rotation_quaternion();
Vector3 src_loc = origin;
Vector3 dst_scale = p_transform.basis.get_scale();
Quaternion dst_rot = p_transform.basis.get_rotation_quaternion();
Vector3 dst_loc = p_transform.origin;
interp.basis.set_quaternion_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 {
// Equivalent to left multiplication
return Transform3D(basis.scaled(p_scale), origin * p_scale);
}
Transform3D Transform3D::scaled_local(const Vector3 &p_scale) const {
// Equivalent to right multiplication
return Transform3D(basis.scaled_local(p_scale), origin);
}
void Transform3D::scale_basis(const Vector3 &p_scale) {
basis.scale(p_scale);
}
void Transform3D::translate_local(real_t p_tx, real_t p_ty, real_t p_tz) {
translate_local(Vector3(p_tx, p_ty, p_tz));
}
void Transform3D::translate_local(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 {
// Equivalent to left multiplication
return Transform3D(basis, origin + p_translation);
}
Transform3D Transform3D::translated_local(const Vector3 &p_translation) const {
// Equivalent to right multiplication
return Transform3D(basis, origin + basis.xform(p_translation));
}
void Transform3D::orthonormalize() {
basis.orthonormalize();
}
Transform3D Transform3D::orthonormalized() const {
Transform3D _copy = *this;
_copy.orthonormalize();
return _copy;
}
void Transform3D::orthogonalize() {
basis.orthogonalize();
}
Transform3D Transform3D::orthogonalized() const {
Transform3D _copy = *this;
_copy.orthogonalize();
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;
}
void Transform3D::operator*=(const real_t p_val) {
origin *= p_val;
basis *= p_val;
}
Transform3D Transform3D::operator*(const real_t p_val) const {
Transform3D ret(*this);
ret *= p_val;
return ret;
}
Transform3D::operator String() const {
return "[X: " + basis.get_column(0).operator String() +
", Y: " + basis.get_column(1).operator String() +
", Z: " + basis.get_column(2).operator String() +
", O: " + 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_column(0, p_x);
basis.set_column(1, p_y);
basis.set_column(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

@@ -0,0 +1,783 @@
/**************************************************************************/
/* variant.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/godot.hpp>
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/defs.hpp>
#include <utility>
namespace godot {
GDExtensionVariantFromTypeConstructorFunc Variant::from_type_constructor[Variant::VARIANT_MAX]{};
GDExtensionTypeFromVariantConstructorFunc Variant::to_type_constructor[Variant::VARIANT_MAX]{};
void Variant::init_bindings() {
// Start from 1 to skip NIL.
for (int i = 1; i < VARIANT_MAX; i++) {
from_type_constructor[i] = internal::gde_interface->get_variant_from_type_constructor((GDExtensionVariantType)i);
to_type_constructor[i] = internal::gde_interface->get_variant_to_type_constructor((GDExtensionVariantType)i);
}
StringName::init_bindings();
String::init_bindings();
NodePath::init_bindings();
RID::init_bindings();
Callable::init_bindings();
Signal::init_bindings();
Dictionary::init_bindings();
Array::init_bindings();
PackedByteArray::init_bindings();
PackedInt32Array::init_bindings();
PackedInt64Array::init_bindings();
PackedFloat32Array::init_bindings();
PackedFloat64Array::init_bindings();
PackedStringArray::init_bindings();
PackedVector2Array::init_bindings();
PackedVector3Array::init_bindings();
PackedColorArray::init_bindings();
}
Variant::Variant() {
internal::gde_interface->variant_new_nil(_native_ptr());
}
Variant::Variant(GDExtensionConstVariantPtr native_ptr) {
internal::gde_interface->variant_new_copy(_native_ptr(), native_ptr);
}
Variant::Variant(const Variant &other) {
internal::gde_interface->variant_new_copy(_native_ptr(), other._native_ptr());
}
Variant::Variant(Variant &&other) {
std::swap(opaque, other.opaque);
}
Variant::Variant(bool v) {
GDExtensionBool encoded;
PtrToArg<bool>::encode(v, &encoded);
from_type_constructor[BOOL](_native_ptr(), &encoded);
}
Variant::Variant(int64_t v) {
GDExtensionInt encoded;
PtrToArg<int64_t>::encode(v, &encoded);
from_type_constructor[INT](_native_ptr(), &encoded);
}
Variant::Variant(double v) {
double encoded;
PtrToArg<double>::encode(v, &encoded);
from_type_constructor[FLOAT](_native_ptr(), &encoded);
}
Variant::Variant(const String &v) {
from_type_constructor[STRING](_native_ptr(), v._native_ptr());
}
Variant::Variant(const Vector2 &v) {
from_type_constructor[VECTOR2](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Vector2i &v) {
from_type_constructor[VECTOR2I](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Rect2 &v) {
from_type_constructor[RECT2](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Rect2i &v) {
from_type_constructor[RECT2I](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Vector3 &v) {
from_type_constructor[VECTOR3](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Vector3i &v) {
from_type_constructor[VECTOR3I](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Transform2D &v) {
from_type_constructor[TRANSFORM2D](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Vector4 &v) {
from_type_constructor[VECTOR4](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Vector4i &v) {
from_type_constructor[VECTOR4I](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Plane &v) {
from_type_constructor[PLANE](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Quaternion &v) {
from_type_constructor[QUATERNION](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const godot::AABB &v) {
from_type_constructor[AABB](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Basis &v) {
from_type_constructor[BASIS](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Transform3D &v) {
from_type_constructor[TRANSFORM3D](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Projection &v) {
from_type_constructor[PROJECTION](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const Color &v) {
from_type_constructor[COLOR](_native_ptr(), (GDExtensionTypePtr)&v);
}
Variant::Variant(const StringName &v) {
from_type_constructor[STRING_NAME](_native_ptr(), v._native_ptr());
}
Variant::Variant(const NodePath &v) {
from_type_constructor[NODE_PATH](_native_ptr(), v._native_ptr());
}
Variant::Variant(const godot::RID &v) {
from_type_constructor[RID](_native_ptr(), v._native_ptr());
}
Variant::Variant(const Object *v) {
if (v) {
from_type_constructor[OBJECT](_native_ptr(), const_cast<GodotObject **>(&v->_owner));
} else {
GodotObject *nullobject = nullptr;
from_type_constructor[OBJECT](_native_ptr(), &nullobject);
}
}
Variant::Variant(const ObjectID &p_id) :
Variant(p_id.operator uint64_t()) {
}
Variant::Variant(const Callable &v) {
from_type_constructor[CALLABLE](_native_ptr(), v._native_ptr());
}
Variant::Variant(const Signal &v) {
from_type_constructor[SIGNAL](_native_ptr(), v._native_ptr());
}
Variant::Variant(const Dictionary &v) {
from_type_constructor[DICTIONARY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const Array &v) {
from_type_constructor[ARRAY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const PackedByteArray &v) {
from_type_constructor[PACKED_BYTE_ARRAY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const PackedInt32Array &v) {
from_type_constructor[PACKED_INT32_ARRAY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const PackedInt64Array &v) {
from_type_constructor[PACKED_INT64_ARRAY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const PackedFloat32Array &v) {
from_type_constructor[PACKED_FLOAT32_ARRAY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const PackedFloat64Array &v) {
from_type_constructor[PACKED_FLOAT64_ARRAY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const PackedStringArray &v) {
from_type_constructor[PACKED_STRING_ARRAY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const PackedVector2Array &v) {
from_type_constructor[PACKED_VECTOR2_ARRAY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const PackedVector3Array &v) {
from_type_constructor[PACKED_VECTOR3_ARRAY](_native_ptr(), v._native_ptr());
}
Variant::Variant(const PackedColorArray &v) {
from_type_constructor[PACKED_COLOR_ARRAY](_native_ptr(), v._native_ptr());
}
Variant::~Variant() {
internal::gde_interface->variant_destroy(_native_ptr());
}
Variant::operator bool() const {
GDExtensionBool result;
to_type_constructor[BOOL](&result, _native_ptr());
return PtrToArg<bool>::convert(&result);
}
Variant::operator int64_t() const {
GDExtensionInt result;
to_type_constructor[INT](&result, _native_ptr());
return PtrToArg<int64_t>::convert(&result);
}
Variant::operator int32_t() const {
return static_cast<int32_t>(operator int64_t());
}
Variant::operator uint64_t() const {
return static_cast<uint64_t>(operator int64_t());
}
Variant::operator uint32_t() const {
return static_cast<uint32_t>(operator int64_t());
}
Variant::operator double() const {
double result;
to_type_constructor[FLOAT](&result, _native_ptr());
return PtrToArg<double>::convert(&result);
}
Variant::operator float() const {
return static_cast<float>(operator double());
}
Variant::operator String() const {
String result;
to_type_constructor[STRING](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator Vector2() const {
Vector2 result;
to_type_constructor[VECTOR2]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Vector2i() const {
Vector2i result;
to_type_constructor[VECTOR2I]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Rect2() const {
Rect2 result;
to_type_constructor[RECT2]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Rect2i() const {
Rect2i result;
to_type_constructor[RECT2I]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Vector3() const {
Vector3 result;
to_type_constructor[VECTOR3]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Vector3i() const {
Vector3i result;
to_type_constructor[VECTOR3I]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Transform2D() const {
Transform2D result;
to_type_constructor[TRANSFORM2D]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Vector4() const {
Vector4 result;
to_type_constructor[VECTOR4]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Vector4i() const {
Vector4i result;
to_type_constructor[VECTOR4I]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Plane() const {
Plane result;
to_type_constructor[PLANE]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Quaternion() const {
Quaternion result;
to_type_constructor[QUATERNION]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator godot::AABB() const {
godot::AABB result;
to_type_constructor[AABB]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Basis() const {
Basis result;
to_type_constructor[BASIS]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Transform3D() const {
Transform3D result;
to_type_constructor[TRANSFORM3D]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Projection() const {
Projection result;
to_type_constructor[PROJECTION]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator Color() const {
Color result;
to_type_constructor[COLOR]((GDExtensionTypePtr)&result, _native_ptr());
return result;
}
Variant::operator StringName() const {
StringName result;
to_type_constructor[STRING_NAME](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator NodePath() const {
NodePath result;
to_type_constructor[NODE_PATH](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator godot::RID() const {
godot::RID result;
to_type_constructor[RID](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator Object *() const {
GodotObject *obj;
to_type_constructor[OBJECT](&obj, _native_ptr());
if (obj == nullptr) {
return nullptr;
}
return reinterpret_cast<Object *>(internal::gde_interface->object_get_instance_binding(obj, internal::token, &Object::___binding_callbacks));
}
Variant::operator ObjectID() const {
if (get_type() == Type::INT) {
return ObjectID(operator uint64_t());
} else if (get_type() == Type::OBJECT) {
Object *obj = operator Object *();
if (obj != nullptr) {
return ObjectID(obj->get_instance_id());
} else {
return ObjectID();
}
} else {
return ObjectID();
}
}
Variant::operator Callable() const {
Callable result;
to_type_constructor[CALLABLE](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator Signal() const {
Signal result;
to_type_constructor[SIGNAL](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator Dictionary() const {
Dictionary result;
to_type_constructor[DICTIONARY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator Array() const {
Array result;
to_type_constructor[ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator PackedByteArray() const {
PackedByteArray result;
to_type_constructor[PACKED_BYTE_ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator PackedInt32Array() const {
PackedInt32Array result;
to_type_constructor[PACKED_INT32_ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator PackedInt64Array() const {
PackedInt64Array result;
to_type_constructor[PACKED_INT64_ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator PackedFloat32Array() const {
PackedFloat32Array result;
to_type_constructor[PACKED_FLOAT32_ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator PackedFloat64Array() const {
PackedFloat64Array result;
to_type_constructor[PACKED_FLOAT64_ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator PackedStringArray() const {
PackedStringArray result;
to_type_constructor[PACKED_STRING_ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator PackedVector2Array() const {
PackedVector2Array result;
to_type_constructor[PACKED_VECTOR2_ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator PackedVector3Array() const {
PackedVector3Array result;
to_type_constructor[PACKED_VECTOR3_ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant::operator PackedColorArray() const {
PackedColorArray result;
to_type_constructor[PACKED_COLOR_ARRAY](result._native_ptr(), _native_ptr());
return result;
}
Variant &Variant::operator=(const Variant &other) {
clear();
internal::gde_interface->variant_new_copy(_native_ptr(), other._native_ptr());
return *this;
}
Variant &Variant::operator=(Variant &&other) {
std::swap(opaque, other.opaque);
return *this;
}
bool Variant::operator==(const Variant &other) const {
if (get_type() != other.get_type()) {
return false;
}
bool valid = false;
Variant result;
evaluate(OP_EQUAL, *this, other, result, valid);
return result.operator bool();
}
bool Variant::operator!=(const Variant &other) const {
if (get_type() != other.get_type()) {
return true;
}
bool valid = false;
Variant result;
evaluate(OP_NOT_EQUAL, *this, other, result, valid);
return result.operator bool();
}
bool Variant::operator<(const Variant &other) const {
if (get_type() != other.get_type()) {
return get_type() < other.get_type();
}
bool valid = false;
Variant result;
evaluate(OP_LESS, *this, other, result, valid);
return result.operator bool();
}
void Variant::call(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error) {
internal::gde_interface->variant_call(_native_ptr(), method._native_ptr(), reinterpret_cast<GDExtensionConstVariantPtr *>(args), argcount, r_ret._native_ptr(), &r_error);
}
void Variant::call_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error) {
internal::gde_interface->variant_call_static(static_cast<GDExtensionVariantType>(type), method._native_ptr(), reinterpret_cast<GDExtensionConstVariantPtr *>(args), argcount, r_ret._native_ptr(), &r_error);
}
void Variant::evaluate(const Operator &op, const Variant &a, const Variant &b, Variant &r_ret, bool &r_valid) {
GDExtensionBool valid;
internal::gde_interface->variant_evaluate(static_cast<GDExtensionVariantOperator>(op), a._native_ptr(), b._native_ptr(), r_ret._native_ptr(), &valid);
r_valid = PtrToArg<bool>::convert(&valid);
}
void Variant::set(const Variant &key, const Variant &value, bool *r_valid) {
GDExtensionBool valid;
internal::gde_interface->variant_set(_native_ptr(), key._native_ptr(), value._native_ptr(), &valid);
if (r_valid) {
*r_valid = PtrToArg<bool>::convert(&valid);
}
}
void Variant::set_named(const StringName &name, const Variant &value, bool &r_valid) {
GDExtensionBool valid;
internal::gde_interface->variant_set_named(_native_ptr(), name._native_ptr(), value._native_ptr(), &valid);
r_valid = PtrToArg<bool>::convert(&valid);
}
void Variant::set_indexed(int64_t index, const Variant &value, bool &r_valid, bool &r_oob) {
GDExtensionBool valid, oob;
internal::gde_interface->variant_set_indexed(_native_ptr(), index, value._native_ptr(), &valid, &oob);
r_valid = PtrToArg<bool>::convert(&valid);
r_oob = PtrToArg<bool>::convert(&oob);
}
void Variant::set_keyed(const Variant &key, const Variant &value, bool &r_valid) {
GDExtensionBool valid;
internal::gde_interface->variant_set_keyed(_native_ptr(), key._native_ptr(), value._native_ptr(), &valid);
r_valid = PtrToArg<bool>::convert(&valid);
}
Variant Variant::get(const Variant &key, bool *r_valid) const {
Variant result;
GDExtensionBool valid;
internal::gde_interface->variant_get(_native_ptr(), key._native_ptr(), result._native_ptr(), &valid);
if (r_valid) {
*r_valid = PtrToArg<bool>::convert(&valid);
}
return result;
}
Variant Variant::get_named(const StringName &name, bool &r_valid) const {
Variant result;
GDExtensionBool valid;
internal::gde_interface->variant_get_named(_native_ptr(), name._native_ptr(), result._native_ptr(), &valid);
r_valid = PtrToArg<bool>::convert(&valid);
return result;
}
Variant Variant::get_indexed(int64_t index, bool &r_valid, bool &r_oob) const {
Variant result;
GDExtensionBool valid;
GDExtensionBool oob;
internal::gde_interface->variant_get_indexed(_native_ptr(), index, result._native_ptr(), &valid, &oob);
r_valid = PtrToArg<bool>::convert(&valid);
r_oob = PtrToArg<bool>::convert(&oob);
return result;
}
Variant Variant::get_keyed(const Variant &key, bool &r_valid) const {
Variant result;
GDExtensionBool valid;
internal::gde_interface->variant_get_keyed(_native_ptr(), key._native_ptr(), result._native_ptr(), &valid);
r_valid = PtrToArg<bool>::convert(&valid);
return result;
}
bool Variant::in(const Variant &index, bool *r_valid) const {
Variant result;
bool valid;
evaluate(OP_IN, *this, index, result, valid);
if (r_valid) {
*r_valid = valid;
}
return result.operator bool();
}
bool Variant::iter_init(Variant &r_iter, bool &r_valid) const {
GDExtensionBool valid;
internal::gde_interface->variant_iter_init(_native_ptr(), r_iter._native_ptr(), &valid);
return PtrToArg<bool>::convert(&valid);
}
bool Variant::iter_next(Variant &r_iter, bool &r_valid) const {
GDExtensionBool valid;
internal::gde_interface->variant_iter_next(_native_ptr(), r_iter._native_ptr(), &valid);
return PtrToArg<bool>::convert(&valid);
}
Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
Variant result;
GDExtensionBool valid;
internal::gde_interface->variant_iter_get(_native_ptr(), r_iter._native_ptr(), result._native_ptr(), &valid);
r_valid = PtrToArg<bool>::convert(&valid);
return result;
}
Variant::Type Variant::get_type() const {
return static_cast<Variant::Type>(internal::gde_interface->variant_get_type(_native_ptr()));
}
bool Variant::has_method(const StringName &method) const {
GDExtensionBool has = internal::gde_interface->variant_has_method(_native_ptr(), method._native_ptr());
return PtrToArg<bool>::convert(&has);
}
bool Variant::has_key(const Variant &key, bool *r_valid) const {
GDExtensionBool valid;
GDExtensionBool has = internal::gde_interface->variant_has_key(_native_ptr(), key._native_ptr(), &valid);
if (r_valid) {
*r_valid = PtrToArg<bool>::convert(&valid);
}
return PtrToArg<bool>::convert(&has);
}
bool Variant::has_member(Variant::Type type, const StringName &member) {
GDExtensionBool has = internal::gde_interface->variant_has_member(static_cast<GDExtensionVariantType>(type), member._native_ptr());
return PtrToArg<bool>::convert(&has);
}
uint32_t Variant::hash() const {
GDExtensionInt hash = internal::gde_interface->variant_hash(_native_ptr());
return PtrToArg<uint32_t>::convert(&hash);
}
uint32_t Variant::recursive_hash(int recursion_count) const {
GDExtensionInt hash = internal::gde_interface->variant_recursive_hash(_native_ptr(), recursion_count);
return PtrToArg<uint32_t>::convert(&hash);
}
bool Variant::hash_compare(const Variant &variant) const {
GDExtensionBool compare = internal::gde_interface->variant_hash_compare(_native_ptr(), variant._native_ptr());
return PtrToArg<bool>::convert(&compare);
}
bool Variant::booleanize() const {
GDExtensionBool booleanized = internal::gde_interface->variant_booleanize(_native_ptr());
return PtrToArg<bool>::convert(&booleanized);
}
String Variant::stringify() const {
String result;
internal::gde_interface->variant_stringify(_native_ptr(), result._native_ptr());
return result;
}
Variant Variant::duplicate(bool deep) const {
Variant result;
GDExtensionBool _deep;
PtrToArg<bool>::encode(deep, &_deep);
internal::gde_interface->variant_duplicate(_native_ptr(), result._native_ptr(), _deep);
return result;
}
String Variant::get_type_name(Variant::Type type) {
String result;
internal::gde_interface->variant_get_type_name(static_cast<GDExtensionVariantType>(type), result._native_ptr());
return result;
}
bool Variant::can_convert(Variant::Type from, Variant::Type to) {
GDExtensionBool can = internal::gde_interface->variant_can_convert(static_cast<GDExtensionVariantType>(from), static_cast<GDExtensionVariantType>(to));
return PtrToArg<bool>::convert(&can);
}
bool Variant::can_convert_strict(Variant::Type from, Variant::Type to) {
GDExtensionBool can = internal::gde_interface->variant_can_convert_strict(static_cast<GDExtensionVariantType>(from), static_cast<GDExtensionVariantType>(to));
return PtrToArg<bool>::convert(&can);
}
void Variant::clear() {
static const bool needs_deinit[Variant::VARIANT_MAX] = {
false, // NIL,
false, // BOOL,
false, // INT,
false, // FLOAT,
true, // STRING,
false, // VECTOR2,
false, // VECTOR2I,
false, // RECT2,
false, // RECT2I,
false, // VECTOR3,
false, // VECTOR3I,
true, // TRANSFORM2D,
false, // VECTOR4,
false, // VECTOR4I,
false, // PLANE,
false, // QUATERNION,
true, // AABB,
true, // BASIS,
true, // TRANSFORM3D,
true, // PROJECTION,
// misc types
false, // COLOR,
true, // STRING_NAME,
true, // NODE_PATH,
false, // RID,
true, // OBJECT,
true, // CALLABLE,
true, // SIGNAL,
true, // DICTIONARY,
true, // ARRAY,
// typed arrays
true, // PACKED_BYTE_ARRAY,
true, // PACKED_INT32_ARRAY,
true, // PACKED_INT64_ARRAY,
true, // PACKED_FLOAT32_ARRAY,
true, // PACKED_FLOAT64_ARRAY,
true, // PACKED_STRING_ARRAY,
true, // PACKED_VECTOR2_ARRAY,
true, // PACKED_VECTOR3_ARRAY,
true, // PACKED_COLOR_ARRAY,
};
if (unlikely(needs_deinit[get_type()])) { // Make it fast for types that don't need deinit.
internal::gde_interface->variant_destroy(_native_ptr());
}
internal::gde_interface->variant_new_nil(_native_ptr());
}
} // namespace godot

View File

@@ -0,0 +1,199 @@
/**************************************************************************/
/* vector2.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/vector2i.hpp>
namespace godot {
real_t Vector2::angle() const {
return Math::atan2(y, x);
}
Vector2 Vector2::from_angle(const real_t p_angle) {
return Vector2(Math::cos(p_angle), Math::sin(p_angle));
}
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, (real_t)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 (p_vector2 - *this).angle();
}
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(SIGN(x), 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(const 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::clamp(const Vector2 &p_min, const Vector2 &p_max) const {
return Vector2(
CLAMP(x, p_min.x, p_max.x),
CLAMP(y, p_min.y, p_max.y));
}
Vector2 Vector2::snapped(const Vector2 &p_step) const {
return Vector2(
Math::snapped(x, p_step.x),
Math::snapped(y, p_step.y));
}
Vector2 Vector2::limit_length(const real_t p_len) const {
const real_t l = length();
Vector2 v = *this;
if (l > 0 && p_len < l) {
v /= l;
v *= p_len;
}
return v;
}
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 < (real_t)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_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 must be normalized.");
#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_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 must be normalized.");
#endif
return 2.0f * 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);
}
bool Vector2::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y);
}
Vector2::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
}
Vector2::operator Vector2i() const {
return Vector2i(x, y);
}
} // namespace godot

View File

@@ -0,0 +1,129 @@
/**************************************************************************/
/* vector2i.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/vector2i.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/vector2.hpp>
namespace godot {
Vector2i Vector2i::clamp(const Vector2i &p_min, const Vector2i &p_max) const {
return Vector2i(
CLAMP(x, p_min.x, p_max.x),
CLAMP(y, p_min.y, p_max.y));
}
int64_t Vector2i::length_squared() const {
return x * (int64_t)x + y * (int64_t)y;
}
double Vector2i::length() const {
return Math::sqrt((double)length_squared());
}
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;
}
Vector2i::operator String() const {
return "(" + itos(x) + ", " + itos(y) + ")";
}
Vector2i::operator Vector2() const {
return Vector2((int32_t)x, (int32_t)y);
}
} // namespace godot

View File

@@ -0,0 +1,152 @@
/**************************************************************************/
/* vector3.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/vector3.hpp>
#include <godot_cpp/variant/basis.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/vector3i.hpp>
namespace godot {
void Vector3::rotate(const Vector3 &p_axis, const real_t p_angle) {
*this = Basis(p_axis, p_angle).xform(*this);
}
Vector3 Vector3::rotated(const Vector3 &p_axis, const real_t p_angle) const {
Vector3 r = *this;
r.rotate(p_axis, p_angle);
return r;
}
Vector3 Vector3::clamp(const Vector3 &p_min, const Vector3 &p_max) const {
return Vector3(
CLAMP(x, p_min.x, p_max.x),
CLAMP(y, p_min.y, p_max.y),
CLAMP(z, p_min.z, p_max.z));
}
void Vector3::snap(const 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(const Vector3 p_step) const {
Vector3 v = *this;
v.snap(p_step);
return v;
}
Vector3 Vector3::limit_length(const real_t p_len) const {
const real_t l = length();
Vector3 v = *this;
if (l > 0 && p_len < l) {
v /= l;
v *= p_len;
}
return v;
}
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 < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
Vector2 Vector3::octahedron_encode() const {
Vector3 n = *this;
n /= Math::abs(n.x) + Math::abs(n.y) + Math::abs(n.z);
Vector2 o;
if (n.z >= 0.0f) {
o.x = n.x;
o.y = n.y;
} else {
o.x = (1.0f - Math::abs(n.y)) * (n.x >= 0.0f ? 1.0f : -1.0f);
o.y = (1.0f - Math::abs(n.x)) * (n.y >= 0.0f ? 1.0f : -1.0f);
}
o.x = o.x * 0.5f + 0.5f;
o.y = o.y * 0.5f + 0.5f;
return o;
}
Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) {
Vector2 f(p_oct.x * 2.0f - 1.0f, p_oct.y * 2.0f - 1.0f);
Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y));
float t = CLAMP(-n.z, 0.0f, 1.0f);
n.x += n.x >= 0 ? -t : t;
n.y += n.y >= 0 ? -t : t;
return n.normalized();
}
Vector2 Vector3::octahedron_tangent_encode(const float sign) const {
Vector2 res = this->octahedron_encode();
res.y = res.y * 0.5f + 0.5f;
res.y = sign >= 0.0f ? res.y : 1 - res.y;
return res;
}
Vector3 Vector3::octahedron_tangent_decode(const Vector2 &p_oct, float *sign) {
Vector2 oct_compressed = p_oct;
oct_compressed.y = oct_compressed.y * 2 - 1;
*sign = oct_compressed.y >= 0.0f ? 1.0f : -1.0f;
oct_compressed.y = Math::abs(oct_compressed.y);
Vector3 res = Vector3::octahedron_decode(oct_compressed);
return res;
}
Basis Vector3::outer(const Vector3 &p_with) const {
Basis basis;
basis.rows[0] = Vector3(x * p_with.x, x * p_with.y, x * p_with.z);
basis.rows[1] = Vector3(y * p_with.x, y * p_with.y, y * p_with.z);
basis.rows[2] = Vector3(z * p_with.x, z * p_with.y, z * p_with.z);
return basis;
}
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);
}
bool Vector3::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z);
}
Vector3::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
}
Vector3::operator Vector3i() const {
return Vector3i(x, y, z);
}
} // namespace godot

View File

@@ -0,0 +1,61 @@
/**************************************************************************/
/* vector3i.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/vector3i.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/vector3.hpp>
namespace godot {
Vector3i::Axis Vector3i::min_axis_index() const {
return x < y ? (x < z ? Vector3i::AXIS_X : Vector3i::AXIS_Z) : (y < z ? Vector3i::AXIS_Y : Vector3i::AXIS_Z);
}
Vector3i::Axis Vector3i::max_axis_index() const {
return x < y ? (y < z ? Vector3i::AXIS_Z : Vector3i::AXIS_Y) : (x < z ? Vector3i::AXIS_Z : Vector3i::AXIS_X);
}
Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const {
return Vector3i(
CLAMP(x, p_min.x, p_max.x),
CLAMP(y, p_min.y, p_max.y),
CLAMP(z, p_min.z, p_max.z));
}
Vector3i::operator String() const {
return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")";
}
Vector3i::operator Vector3() const {
return Vector3(x, y, z);
}
} // namespace godot

View File

@@ -0,0 +1,196 @@
/**************************************************************************/
/* vector4.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/vector4.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/vector4i.hpp>
namespace godot {
Vector4::Axis Vector4::min_axis_index() const {
uint32_t min_index = 0;
real_t min_value = x;
for (uint32_t i = 1; i < 4; i++) {
if (operator[](i) <= min_value) {
min_index = i;
min_value = operator[](i);
}
}
return Vector4::Axis(min_index);
}
Vector4::Axis Vector4::max_axis_index() const {
uint32_t max_index = 0;
real_t max_value = x;
for (uint32_t i = 1; i < 4; i++) {
if (operator[](i) > max_value) {
max_index = i;
max_value = operator[](i);
}
}
return Vector4::Axis(max_index);
}
bool Vector4::is_equal_approx(const Vector4 &p_vec4) const {
return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w);
}
bool Vector4::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w);
}
real_t Vector4::length() const {
return Math::sqrt(length_squared());
}
void Vector4::normalize() {
real_t lengthsq = length_squared();
if (lengthsq == 0) {
x = y = z = w = 0;
} else {
real_t length = Math::sqrt(lengthsq);
x /= length;
y /= length;
z /= length;
w /= length;
}
}
Vector4 Vector4::normalized() const {
Vector4 v = *this;
v.normalize();
return v;
}
bool Vector4::is_normalized() const {
return Math::is_equal_approx(length_squared(), (real_t)1, (real_t)UNIT_EPSILON);
}
real_t Vector4::distance_to(const Vector4 &p_to) const {
return (p_to - *this).length();
}
real_t Vector4::distance_squared_to(const Vector4 &p_to) const {
return (p_to - *this).length_squared();
}
Vector4 Vector4::direction_to(const Vector4 &p_to) const {
Vector4 ret(p_to.x - x, p_to.y - y, p_to.z - z, p_to.w - w);
ret.normalize();
return ret;
}
Vector4 Vector4::abs() const {
return Vector4(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w));
}
Vector4 Vector4::sign() const {
return Vector4(Math::sign(x), Math::sign(y), Math::sign(z), Math::sign(w));
}
Vector4 Vector4::floor() const {
return Vector4(Math::floor(x), Math::floor(y), Math::floor(z), Math::floor(w));
}
Vector4 Vector4::ceil() const {
return Vector4(Math::ceil(x), Math::ceil(y), Math::ceil(z), Math::ceil(w));
}
Vector4 Vector4::round() const {
return Vector4(Math::round(x), Math::round(y), Math::round(z), Math::round(w));
}
Vector4 Vector4::lerp(const Vector4 &p_to, const real_t p_weight) const {
return Vector4(
x + (p_weight * (p_to.x - x)),
y + (p_weight * (p_to.y - y)),
z + (p_weight * (p_to.z - z)),
w + (p_weight * (p_to.w - w)));
}
Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const {
Vector4 res = *this;
res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight);
res.w = Math::cubic_interpolate(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight);
return res;
}
Vector4 Vector4::cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
Vector4 res = *this;
res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
res.z = Math::cubic_interpolate_in_time(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
res.w = Math::cubic_interpolate_in_time(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
return res;
}
Vector4 Vector4::posmod(const real_t p_mod) const {
return Vector4(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod), Math::fposmod(w, p_mod));
}
Vector4 Vector4::posmodv(const Vector4 &p_modv) const {
return Vector4(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z), Math::fposmod(w, p_modv.w));
}
void Vector4::snap(const Vector4 &p_step) {
x = Math::snapped(x, p_step.x);
y = Math::snapped(y, p_step.y);
z = Math::snapped(z, p_step.z);
w = Math::snapped(w, p_step.w);
}
Vector4 Vector4::snapped(const Vector4 &p_step) const {
Vector4 v = *this;
v.snap(p_step);
return v;
}
Vector4 Vector4::inverse() const {
return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w);
}
Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const {
return Vector4(
CLAMP(x, p_min.x, p_max.x),
CLAMP(y, p_min.y, p_max.y),
CLAMP(z, p_min.z, p_max.z),
CLAMP(w, p_min.w, p_max.w));
}
Vector4::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
}
static_assert(sizeof(Vector4) == 4 * sizeof(real_t));
} // namespace godot

View File

@@ -0,0 +1,87 @@
/**************************************************************************/
/* vector4i.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include <godot_cpp/variant/vector4i.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/vector4.hpp>
namespace godot {
Vector4i::Axis Vector4i::min_axis_index() const {
uint32_t min_index = 0;
int32_t min_value = x;
for (uint32_t i = 1; i < 4; i++) {
if (operator[](i) <= min_value) {
min_index = i;
min_value = operator[](i);
}
}
return Vector4i::Axis(min_index);
}
Vector4i::Axis Vector4i::max_axis_index() const {
uint32_t max_index = 0;
int32_t max_value = x;
for (uint32_t i = 1; i < 4; i++) {
if (operator[](i) > max_value) {
max_index = i;
max_value = operator[](i);
}
}
return Vector4i::Axis(max_index);
}
Vector4i Vector4i::clamp(const Vector4i &p_min, const Vector4i &p_max) const {
return Vector4i(
CLAMP(x, p_min.x, p_max.x),
CLAMP(y, p_min.y, p_max.y),
CLAMP(z, p_min.z, p_max.z),
CLAMP(w, p_min.w, p_max.w));
}
Vector4i::operator String() const {
return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ", " + itos(w) + ")";
}
Vector4i::operator Vector4() const {
return Vector4(x, y, z, w);
}
Vector4i::Vector4i(const Vector4 &p_vec4) {
x = (int32_t)p_vec4.x;
y = (int32_t)p_vec4.y;
z = (int32_t)p_vec4.z;
w = (int32_t)p_vec4.w;
}
static_assert(sizeof(Vector4i) == 4 * sizeof(int32_t));
} // namespace godot