diff options
147 files changed, 6146 insertions, 2185 deletions
diff --git a/.editorconfig b/.editorconfig index b7ef43c340..ead5e14ca9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,6 +8,10 @@ indent_style = tab [*.{cpp,hpp,c,h,mm}] trim_trailing_whitespace = true +[*.py] +indent_style = space +indent_size = 4 + [.travis.yml] indent_style = space indent_size = 2 diff --git a/.travis.yml b/.travis.yml index c11a21aeef..0dfeaf16e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,14 +48,14 @@ addons: - pkg-config - libx11-dev - libxcursor-dev - - libasound2-dev - - libfreetype6-dev + - libxi-dev + - libxinerama-dev + - libxrandr-dev - libgl1-mesa-dev - libglu1-mesa-dev + - libasound2-dev + - libfreetype6-dev - libssl-dev - - libxinerama-dev - - libxrandr-dev - - libxi-dev # For cross-compiling to Windows. #- binutils-mingw-w64-i686 @@ -90,5 +90,5 @@ script: - if [ "$STATIC_CHECKS" = "yes" ]; then sh ./misc/travis/clang-format.sh; else - scons -j2 CC=$CC CXX=$CXX platform=$GODOT_TARGET TOOLS=$TOOLS verbose=yes progress=no; + scons -j2 CC=$CC CXX=$CXX platform=$GODOT_TARGET TOOLS=$TOOLS verbose=yes progress=no openmp=no; fi diff --git a/SConstruct b/SConstruct index b3e0672c94..af1ffb544e 100644 --- a/SConstruct +++ b/SConstruct @@ -168,6 +168,8 @@ opts.Add(BoolVariable('vsproj', "Generate Visual Studio Project.", False)) opts.Add(EnumVariable('warnings', "Set the level of warnings emitted during compilation", 'no', ('extra', 'all', 'moderate', 'no'))) opts.Add(BoolVariable('progress', "Show a progress indicator during build", True)) opts.Add(BoolVariable('dev', "If yes, alias for verbose=yes warnings=all", False)) +opts.Add(BoolVariable('openmp', "If yes, enable OpenMP", True)) +opts.Add(EnumVariable('macports_clang', "Build using clang from MacPorts", 'no', ('no', '5.0', 'devel'))) # Thirdparty libraries opts.Add(BoolVariable('builtin_enet', "Use the builtin enet library", True)) diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 9d89baafb1..e457a4ac1e 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -30,27 +30,53 @@ #include "http_client.h" #include "io/stream_peer_ssl.h" +const char *HTTPClient::_methods[METHOD_MAX] = { + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "OPTIONS", + "TRACE", + "CONNECT", + "PATCH" +}; + #ifndef JAVASCRIPT_ENABLED Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) { close(); + conn_port = p_port; conn_host = p_host; - if (conn_host.begins_with("http://")) { + ssl = p_ssl; + ssl_verify_host = p_verify_host; + + String host_lower = conn_host.to_lower(); + if (host_lower.begins_with("http://")) { - conn_host = conn_host.replace_first("http://", ""); - } else if (conn_host.begins_with("https://")) { - //use https - conn_host = conn_host.replace_first("https://", ""); + conn_host = conn_host.substr(7, conn_host.length() - 7); + } else if (host_lower.begins_with("https://")) { + + ssl = true; + conn_host = conn_host.substr(8, conn_host.length() - 8); + } + + ERR_FAIL_COND_V(conn_host.length() < HOST_MIN_LEN, ERR_INVALID_PARAMETER); + + if (conn_port < 0) { + if (ssl) { + conn_port = PORT_HTTPS; + } else { + conn_port = PORT_HTTP; + } } - ssl = p_ssl; - ssl_verify_host = p_verify_host; connection = tcp_connection; if (conn_host.is_valid_ip_address()) { - //is ip + // Host contains valid IP Error err = tcp_connection->connect_to_host(IP_Address(conn_host), p_port); if (err) { status = STATUS_CANT_CONNECT; @@ -59,7 +85,7 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, status = STATUS_CONNECTING; } else { - //is hostname + // Host contains hostname and needs to be resolved to IP resolving = IP::get_singleton()->resolve_hostname_queue_item(conn_host); status = STATUS_RESOLVING; } @@ -82,24 +108,13 @@ Ref<StreamPeer> HTTPClient::get_connection() const { Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const PoolVector<uint8_t> &p_body) { ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA); - static const char *_methods[METHOD_MAX] = { - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "OPTIONS", - "TRACE", - "CONNECT", - "PATCH" - }; - String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; - if ((ssl && conn_port == 443) || (!ssl && conn_port == 80)) { - // don't append the standard ports + if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) { + // Don't append the standard ports request += "Host: " + conn_host + "\r\n"; } else { request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; @@ -113,17 +128,20 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector } if (add_clen) { request += "Content-Length: " + itos(p_body.size()) + "\r\n"; - //should it add utf8 encoding? not sure + // Should it add utf8 encoding? } request += "\r\n"; CharString cs = request.utf8(); PoolVector<uint8_t> data; - - //Maybe this goes faster somehow? - for (int i = 0; i < cs.length(); i++) { - data.append(cs[i]); + data.resize(cs.length()); + { + PoolVector<uint8_t>::Write data_write = data.write(); + for (int i = 0; i < cs.length(); i++) { + data_write[i] = cs[i]; + } } + data.append_array(p_body); PoolVector<uint8_t>::Read r = data.read(); @@ -143,24 +161,13 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) { ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA); - static const char *_methods[METHOD_MAX] = { - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "OPTIONS", - "TRACE", - "CONNECT", - "PATCH" - }; - String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; - if ((ssl && conn_port == 443) || (!ssl && conn_port == 80)) { - // don't append the standard ports + if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) { + // Don't append the standard ports request += "Host: " + conn_host + "\r\n"; } else { request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; @@ -174,7 +181,7 @@ Error HTTPClient::request(Method p_method, const String &p_url, const Vector<Str } if (add_clen) { request += "Content-Length: " + itos(p_body.utf8().length()) + "\r\n"; - //should it add utf8 encoding? not sure + // Should it add utf8 encoding? } request += "\r\n"; request += p_body; @@ -253,7 +260,7 @@ Error HTTPClient::poll() { IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving); switch (rstatus) { case IP::RESOLVER_STATUS_WAITING: - return OK; //still resolving + return OK; // Still resolving case IP::RESOLVER_STATUS_DONE: { @@ -285,7 +292,7 @@ Error HTTPClient::poll() { switch (s) { case StreamPeerTCP::STATUS_CONNECTING: { - return OK; //do none + return OK; } break; case StreamPeerTCP::STATUS_CONNECTED: { if (ssl) { @@ -296,7 +303,6 @@ Error HTTPClient::poll() { status = STATUS_SSL_HANDSHAKE_ERROR; return ERR_CANT_CONNECT; } - //print_line("SSL! TURNED ON!"); connection = ssl; } status = STATUS_CONNECTED; @@ -312,7 +318,7 @@ Error HTTPClient::poll() { } } break; case STATUS_CONNECTED: { - //request something please + // Connection established, requests can now be made return OK; } break; case STATUS_REQUESTING: { @@ -328,7 +334,7 @@ Error HTTPClient::poll() { } if (rec == 0) - return OK; //keep trying! + return OK; // Still requesting, keep trying! response_str.push_back(byte); int rs = response_str.size(); @@ -336,11 +342,10 @@ Error HTTPClient::poll() { (rs >= 2 && response_str[rs - 2] == '\n' && response_str[rs - 1] == '\n') || (rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) { - //end of response, parse. + // End of response, parse. response_str.push_back(0); String response; response.parse_utf8((const char *)response_str.ptr()); - //print_line("END OF RESPONSE? :\n"+response+"\n------"); Vector<String> responses = response.split("\n"); body_size = 0; chunked = false; @@ -363,7 +368,6 @@ Error HTTPClient::poll() { if (s.begins_with("transfer-encoding:")) { String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges(); - //print_line("TRANSFER ENCODING: "+encoding); if (encoding == "chunked") { chunked = true; } @@ -381,14 +385,14 @@ Error HTTPClient::poll() { if (body_size == 0 && !chunked) { - status = STATUS_CONNECTED; //ask for something again? + status = STATUS_CONNECTED; // Ready for new requests } else { status = STATUS_BODY; } return OK; } } - //wait for response + // Wait for response return OK; } break; case STATUS_DISCONNECTED: { @@ -424,7 +428,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() { while (true) { if (chunk_left == 0) { - //reading len + // Reading length uint8_t b; int rec = 0; err = _get_http_data(&b, 1, rec); @@ -467,7 +471,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() { } if (len == 0) { - //end! + // End reached! status = STATUS_CONNECTED; chunk.clear(); return PoolByteArray(); @@ -525,7 +529,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() { to_read -= rec; _offset += rec; } else { - if (to_read > 0) //ended up reading less + if (to_read > 0) // Ended up reading less ret.resize(_offset); break; } @@ -540,7 +544,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() { close(); if (err == ERR_FILE_EOF) { - status = STATUS_DISCONNECTED; //server disconnected + status = STATUS_DISCONNECTED; // Server disconnected } else { status = STATUS_CONNECTION_ERROR; @@ -593,7 +597,7 @@ HTTPClient::HTTPClient() { tcp_connection = StreamPeerTCP::create_ref(); resolving = IP::RESOLVER_INVALID_ID; status = STATUS_DISCONNECTED; - conn_port = 80; + conn_port = -1; body_size = 0; chunked = false; body_left = 0; @@ -653,7 +657,7 @@ PoolStringArray HTTPClient::_get_response_headers() { void HTTPClient::_bind_methods() { - ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port", "use_ssl", "verify_host"), &HTTPClient::connect_to_host, DEFVAL(false), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port", "use_ssl", "verify_host"), &HTTPClient::connect_to_host, DEFVAL(-1), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("set_connection", "connection"), &HTTPClient::set_connection); ClassDB::bind_method(D_METHOD("get_connection"), &HTTPClient::get_connection); ClassDB::bind_method(D_METHOD("request_raw", "method", "url", "headers", "body"), &HTTPClient::request_raw); @@ -689,13 +693,13 @@ void HTTPClient::_bind_methods() { BIND_ENUM_CONSTANT(METHOD_MAX); BIND_ENUM_CONSTANT(STATUS_DISCONNECTED); - BIND_ENUM_CONSTANT(STATUS_RESOLVING); //resolving hostname (if passed a hostname) + BIND_ENUM_CONSTANT(STATUS_RESOLVING); // Resolving hostname (if hostname was passed in) BIND_ENUM_CONSTANT(STATUS_CANT_RESOLVE); - BIND_ENUM_CONSTANT(STATUS_CONNECTING); //connecting to ip + BIND_ENUM_CONSTANT(STATUS_CONNECTING); // Connecting to IP BIND_ENUM_CONSTANT(STATUS_CANT_CONNECT); - BIND_ENUM_CONSTANT(STATUS_CONNECTED); //connected ); requests only accepted here - BIND_ENUM_CONSTANT(STATUS_REQUESTING); // request in progress - BIND_ENUM_CONSTANT(STATUS_BODY); // request resulted in body ); which must be read + BIND_ENUM_CONSTANT(STATUS_CONNECTED); // Connected, now accepting requests + BIND_ENUM_CONSTANT(STATUS_REQUESTING); // Request in progress + BIND_ENUM_CONSTANT(STATUS_BODY); // Request resulted in body which must be read BIND_ENUM_CONSTANT(STATUS_CONNECTION_ERROR); BIND_ENUM_CONSTANT(STATUS_SSL_HANDSHAKE_ERROR); diff --git a/core/io/http_client.h b/core/io/http_client.h index 2e0a345f1c..3d8953c156 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -133,19 +133,29 @@ public: enum Status { STATUS_DISCONNECTED, - STATUS_RESOLVING, //resolving hostname (if passed a hostname) + STATUS_RESOLVING, // Resolving hostname (if passed a hostname) STATUS_CANT_RESOLVE, - STATUS_CONNECTING, //connecting to ip + STATUS_CONNECTING, // Connecting to IP STATUS_CANT_CONNECT, - STATUS_CONNECTED, //connected, requests only accepted here - STATUS_REQUESTING, // request in progress - STATUS_BODY, // request resulted in body, which must be read + STATUS_CONNECTED, // Connected, requests can be made + STATUS_REQUESTING, // Request in progress + STATUS_BODY, // Request resulted in body, which must be read STATUS_CONNECTION_ERROR, STATUS_SSL_HANDSHAKE_ERROR, }; private: + static const char *_methods[METHOD_MAX]; + static const int HOST_MIN_LEN = 4; + + enum Port { + + PORT_HTTP = 80, + PORT_HTTPS = 443, + + }; + #ifndef JAVASCRIPT_ENABLED Status status; IP::ResolverID resolving; @@ -182,8 +192,7 @@ private: static void _bind_methods(); public: - //Error connect_and_get(const String& p_url,bool p_verify_host=true); //connects to a full url and perform request - Error connect_to_host(const String &p_host, int p_port, bool p_ssl = false, bool p_verify_host = true); + Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true); void set_connection(const Ref<StreamPeer> &p_connection); Ref<StreamPeer> get_connection() const; @@ -201,9 +210,9 @@ public: Error get_response_headers(List<String> *r_response); int get_response_body_length() const; - PoolByteArray read_response_body_chunk(); // can't get body as partial text because of most encodings UTF8, gzip, etc. + PoolByteArray read_response_body_chunk(); // Can't get body as partial text because of most encodings UTF8, gzip, etc. - void set_blocking_mode(bool p_enable); //useful mostly if running in a thread + void set_blocking_mode(bool p_enable); // Useful mostly if running in a thread bool is_blocking_mode_enabled() const; void set_read_chunk_size(int p_size); diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 16c73c26e7..c6b12f73ae 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -49,7 +49,7 @@ bool PacketPeer::is_object_decoding_allowed() const { return allow_object_decoding; } -Error PacketPeer::get_packet_buffer(PoolVector<uint8_t> &r_buffer) const { +Error PacketPeer::get_packet_buffer(PoolVector<uint8_t> &r_buffer) { const uint8_t *buffer; int buffer_size; @@ -78,7 +78,7 @@ Error PacketPeer::put_packet_buffer(const PoolVector<uint8_t> &p_buffer) { return put_packet(&r[0], len); } -Error PacketPeer::get_var(Variant &r_variant) const { +Error PacketPeer::get_var(Variant &r_variant) { const uint8_t *buffer; int buffer_size; @@ -107,7 +107,7 @@ Error PacketPeer::put_var(const Variant &p_packet) { return put_packet(buf, len); } -Variant PacketPeer::_bnd_get_var() const { +Variant PacketPeer::_bnd_get_var() { Variant var; get_var(var); @@ -117,7 +117,7 @@ Variant PacketPeer::_bnd_get_var() const { Error PacketPeer::_put_packet(const PoolVector<uint8_t> &p_buffer) { return put_packet_buffer(p_buffer); } -PoolVector<uint8_t> PacketPeer::_get_packet() const { +PoolVector<uint8_t> PacketPeer::_get_packet() { PoolVector<uint8_t> raw; last_get_error = get_packet_buffer(raw); @@ -202,7 +202,7 @@ int PacketPeerStream::get_available_packet_count() const { return count; } -Error PacketPeerStream::get_packet(const uint8_t **r_buffer, int &r_buffer_size) const { +Error PacketPeerStream::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { ERR_FAIL_COND_V(peer.is_null(), ERR_UNCONFIGURED); _poll_buffer(); diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index b08d44ad8a..a6d363ec12 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -37,13 +37,13 @@ class PacketPeer : public Reference { GDCLASS(PacketPeer, Reference); - Variant _bnd_get_var() const; + Variant _bnd_get_var(); void _bnd_put_var(const Variant &p_var); static void _bind_methods(); Error _put_packet(const PoolVector<uint8_t> &p_buffer); - PoolVector<uint8_t> _get_packet() const; + PoolVector<uint8_t> _get_packet(); Error _get_packet_error() const; mutable Error last_get_error; @@ -52,17 +52,17 @@ class PacketPeer : public Reference { public: virtual int get_available_packet_count() const = 0; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) const = 0; ///< buffer is GONE after next get_packet + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) = 0; ///< buffer is GONE after next get_packet virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) = 0; virtual int get_max_packet_size() const = 0; /* helpers / binders */ - virtual Error get_packet_buffer(PoolVector<uint8_t> &r_buffer) const; + virtual Error get_packet_buffer(PoolVector<uint8_t> &r_buffer); virtual Error put_packet_buffer(const PoolVector<uint8_t> &p_buffer); - virtual Error get_var(Variant &r_variant) const; + virtual Error get_var(Variant &r_variant); virtual Error put_var(const Variant &p_packet); void set_allow_object_decoding(bool p_enable); @@ -91,7 +91,7 @@ protected: public: virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) const; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); virtual int get_max_packet_size() const; diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index df0d41ea9d..92fdbc1581 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -104,7 +104,7 @@ StringName ResourceInteractiveLoaderBinary::_get_string() { uint32_t id = f->get_32(); if (id & 0x80000000) { - int len = id & 0x7FFFFFFF; + uint32_t len = id & 0x7FFFFFFF; if (len > str_buf.size()) { str_buf.resize(len); } @@ -734,6 +734,7 @@ Error ResourceInteractiveLoaderBinary::poll() { for (int i = 0; i < pc; i++) { StringName name = _get_string(); + if (name == StringName()) { error = ERR_FILE_CORRUPT; ERR_FAIL_V(ERR_FILE_CORRUPT); @@ -902,7 +903,9 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { ExtResource er; er.type = get_unicode_string(); + er.path = get_unicode_string(); + external_resources.push_back(er); } @@ -1271,7 +1274,7 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// -void ResourceFormatSaverBinaryInstance::_pad_buffer(int p_bytes) { +void ResourceFormatSaverBinaryInstance::_pad_buffer(FileAccess *f, int p_bytes) { int extra = 4 - (p_bytes % 4); if (extra < 4) { @@ -1280,7 +1283,12 @@ void ResourceFormatSaverBinaryInstance::_pad_buffer(int p_bytes) { } } -void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property, const PropertyInfo &p_hint) { +void ResourceFormatSaverBinaryInstance::_write_variant(const Variant &p_property, const PropertyInfo &p_hint) { + + write_variant(f, p_property, resource_set, external_resources, string_map, p_hint); +} + +void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Variant &p_property, Set<RES> &resource_set, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint) { switch (p_property.get_type()) { @@ -1327,7 +1335,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property, f->store_32(VARIANT_STRING); String val = p_property; - save_unicode_string(val); + save_unicode_string(f, val); } break; case Variant::VECTOR2: { @@ -1453,10 +1461,20 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property, if (np.is_absolute()) snc |= 0x8000; f->store_16(snc); - for (int i = 0; i < np.get_name_count(); i++) - f->store_32(get_string_index(np.get_name(i))); - for (int i = 0; i < np.get_subname_count(); i++) - f->store_32(get_string_index(np.get_subname(i))); + for (int i = 0; i < np.get_name_count(); i++) { + if (string_map.has(np.get_name(i))) { + f->store_32(string_map[np.get_name(i)]); + } else { + save_unicode_string(f, np.get_name(i), true); + } + } + for (int i = 0; i < np.get_subname_count(); i++) { + if (string_map.has(np.get_subname(i))) { + f->store_32(string_map[np.get_subname(i)]); + } else { + save_unicode_string(f, np.get_subname(i), true); + } + } } break; case Variant::_RID: { @@ -1508,8 +1526,8 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property, continue; */ - write_variant(E->get()); - write_variant(d[E->get()]); + write_variant(f, E->get(), resource_set, external_resources, string_map); + write_variant(f, d[E->get()], resource_set, external_resources, string_map); } } break; @@ -1520,7 +1538,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property, f->store_32(uint32_t(a.size())); for (int i = 0; i < a.size(); i++) { - write_variant(a[i]); + write_variant(f, a[i], resource_set, external_resources, string_map); } } break; @@ -1532,7 +1550,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property, f->store_32(len); PoolVector<uint8_t>::Read r = arr.read(); f->store_buffer(r.ptr(), len); - _pad_buffer(len); + _pad_buffer(f, len); } break; case Variant::POOL_INT_ARRAY: { @@ -1566,7 +1584,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property, f->store_32(len); PoolVector<String>::Read r = arr.read(); for (int i = 0; i < len; i++) { - save_unicode_string(r[i]); + save_unicode_string(f, r[i]); } } break; @@ -1693,10 +1711,14 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant } } -void ResourceFormatSaverBinaryInstance::save_unicode_string(const String &p_string) { +void ResourceFormatSaverBinaryInstance::save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len) { CharString utf8 = p_string.utf8(); - f->store_32(utf8.length() + 1); + if (p_bit_on_len) { + f->store_32(utf8.length() + 1 | 0x80000000); + } else { + f->store_32(utf8.length() + 1); + } f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); } @@ -1763,7 +1785,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p return ERR_CANT_CREATE; } - save_unicode_string(p_resource->get_class()); + save_unicode_string(f, p_resource->get_class()); f->store_64(0); //offset to import metadata for (int i = 0; i < 14; i++) f->store_32(0); // reserved @@ -1800,7 +1822,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p f->store_32(strings.size()); //string table size for (int i = 0; i < strings.size(); i++) { - save_unicode_string(strings[i]); + save_unicode_string(f, strings[i]); } // save external resource table @@ -1814,10 +1836,10 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p for (int i = 0; i < save_order.size(); i++) { - save_unicode_string(save_order[i]->get_save_class()); + save_unicode_string(f, save_order[i]->get_save_class()); String path = save_order[i]->get_path(); path = relative_paths ? local_path.path_to_file(path) : path; - save_unicode_string(path); + save_unicode_string(f, path); } // save internal resource table f->store_32(saved_resources.size()); //amount of internal resources @@ -1853,7 +1875,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p used_indices.insert(new_subindex); } - save_unicode_string("local://" + itos(r->get_subindex())); + save_unicode_string(f, "local://" + itos(r->get_subindex())); if (takeover_paths) { r->set_path(p_path + "::" + itos(r->get_subindex()), true); } @@ -1861,7 +1883,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p r->set_edited(false); #endif } else { - save_unicode_string(r->get_path()); //actual external + save_unicode_string(f, r->get_path()); //actual external } ofs_pos.push_back(f->get_position()); f->store_64(0); //offset in 64 bits @@ -1875,14 +1897,14 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p ResourceData &rd = E->get(); ofs_table.push_back(f->get_position()); - save_unicode_string(rd.type); + save_unicode_string(f, rd.type); f->store_32(rd.properties.size()); for (List<Property>::Element *F = rd.properties.front(); F; F = F->next()) { Property &p = F->get(); f->store_32(p.name_idx); - write_variant(p.value, F->get().pi); + _write_variant(p.value, F->get().pi); } } diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 687da0a9b4..176b8350cf 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -140,14 +140,15 @@ class ResourceFormatSaverBinaryInstance { List<Property> properties; }; - void _pad_buffer(int p_bytes); - void write_variant(const Variant &p_property, const PropertyInfo &p_hint = PropertyInfo()); + static void _pad_buffer(FileAccess *f, int p_bytes); + void _write_variant(const Variant &p_property, const PropertyInfo &p_hint = PropertyInfo()); void _find_resources(const Variant &p_variant, bool p_main = false); - void save_unicode_string(const String &p_string); + static void save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false); int get_string_index(const String &p_string); public: Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + static void write_variant(FileAccess *f, const Variant &p_property, Set<RES> &resource_set, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint = PropertyInfo()); }; class ResourceFormatSaverBinary : public ResourceFormatSaver { diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index ed0d491679..d2aad1d63a 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -196,19 +196,19 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p else local_path = ProjectSettings::get_singleton()->localize_path(p_path); - bool xl_remapped = false; - String path = _path_remap(local_path, &xl_remapped); - - ERR_FAIL_COND_V(path == "", RES()); - - if (!p_no_cache && ResourceCache::has(path)) { + if (!p_no_cache && ResourceCache::has(local_path)) { if (OS::get_singleton()->is_stdout_verbose()) - print_line("load resource: " + path + " (cached)"); + print_line("load resource: " + local_path + " (cached)"); - return RES(ResourceCache::get(path)); + return RES(ResourceCache::get(local_path)); } + bool xl_remapped = false; + String path = _path_remap(local_path, &xl_remapped); + + ERR_FAIL_COND_V(path == "", RES()); + if (OS::get_singleton()->is_stdout_verbose()) print_line("load resource: " + path); @@ -247,23 +247,23 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ else local_path = ProjectSettings::get_singleton()->localize_path(p_path); - bool xl_remapped = false; - String path = _path_remap(local_path, &xl_remapped); - - ERR_FAIL_COND_V(path == "", Ref<ResourceInteractiveLoader>()); - - if (!p_no_cache && ResourceCache::has(path)) { + if (!p_no_cache && ResourceCache::has(local_path)) { if (OS::get_singleton()->is_stdout_verbose()) - print_line("load resource: " + path + " (cached)"); + print_line("load resource: " + local_path + " (cached)"); - Ref<Resource> res_cached = ResourceCache::get(path); + Ref<Resource> res_cached = ResourceCache::get(local_path); Ref<ResourceInteractiveLoaderDefault> ril = Ref<ResourceInteractiveLoaderDefault>(memnew(ResourceInteractiveLoaderDefault)); ril->resource = res_cached; return ril; } + bool xl_remapped = false; + String path = _path_remap(local_path, &xl_remapped); + + ERR_FAIL_COND_V(path == "", Ref<ResourceInteractiveLoader>()); + if (OS::get_singleton()->is_stdout_verbose()) print_line("load resource: "); @@ -426,9 +426,11 @@ String ResourceLoader::get_resource_type(const String &p_path) { String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_remapped) { - if (translation_remaps.has(p_path)) { + String new_path = p_path; - Vector<String> &v = *translation_remaps.getptr(p_path); + if (translation_remaps.has(new_path)) { + + Vector<String> &v = *translation_remaps.getptr(new_path); String locale = TranslationServer::get_singleton()->get_locale(); if (r_translation_remapped) { *r_translation_remapped = true; @@ -443,12 +445,16 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem continue; if (l.begins_with(locale)) { - return v[i].left(split); + new_path = v[i].left(split); + break; } } } - return p_path; + if (path_remaps.has(new_path)) { + new_path = path_remaps[new_path]; + } + return new_path; } String ResourceLoader::import_remap(const String &p_path) { @@ -515,6 +521,27 @@ void ResourceLoader::clear_translation_remaps() { translation_remaps.clear(); } +void ResourceLoader::load_path_remaps() { + + if (!ProjectSettings::get_singleton()->has_setting("path_remap/remapped_paths")) + return; + + PoolVector<String> remaps = ProjectSettings::get_singleton()->get("path_remap/remapped_paths"); + int rc = remaps.size(); + ERR_FAIL_COND(rc & 1); //must be even + PoolVector<String>::Read r = remaps.read(); + + for (int i = 0; i < rc; i += 2) { + + path_remaps[r[i]] = r[i + 1]; + } +} + +void ResourceLoader::clear_path_remaps() { + + path_remaps.clear(); +} + ResourceLoadErrorNotify ResourceLoader::err_notify = NULL; void *ResourceLoader::err_notify_ud = NULL; @@ -526,3 +553,4 @@ bool ResourceLoader::timestamp_on_load = false; SelfList<Resource>::List ResourceLoader::remapped_list; HashMap<String, Vector<String> > ResourceLoader::translation_remaps; +HashMap<String, String> ResourceLoader::path_remaps; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 5deffbca1a..05f01d8d31 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -91,6 +91,7 @@ class ResourceLoader { static DependencyErrorNotify dep_err_notify; static bool abort_on_missing_resource; static HashMap<String, Vector<String> > translation_remaps; + static HashMap<String, String> path_remaps; static String _path_remap(const String &p_path, bool *r_translation_remapped = NULL); friend class Resource; @@ -137,6 +138,9 @@ public: static String path_remap(const String &p_path); static String import_remap(const String &p_path); + static void load_path_remaps(); + static void clear_path_remaps(); + static void reload_translation_remaps(); static void load_translation_remaps(); static void clear_translation_remaps(); diff --git a/core/os/os.h b/core/os/os.h index 979ad7e92a..41500acd93 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -191,7 +191,7 @@ public: virtual bool is_window_maximized() const { return true; } virtual void request_attention() {} - virtual void set_borderless_window(int p_borderless) {} + virtual void set_borderless_window(bool p_borderless) {} virtual bool get_borderless_window() { return 0; } virtual void set_ime_position(const Point2 &p_pos) {} @@ -442,6 +442,7 @@ public: virtual int get_power_seconds_left(); virtual int get_power_percent_left(); + virtual void force_process_input(){}; bool has_feature(const String &p_feature); /** diff --git a/core/ustring.cpp b/core/ustring.cpp index 3a0708851e..1bf7d000c3 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -734,7 +734,7 @@ Vector<String> String::split_spaces() const { return ret; } -Vector<String> String::split(const String &p_splitter, bool p_allow_empty) const { +Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p_maxsplit) const { Vector<String> ret; int from = 0; @@ -745,8 +745,21 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty) const int end = find(p_splitter, from); if (end < 0) end = len; - if (p_allow_empty || (end > from)) - ret.push_back(substr(from, end - from)); + if (p_allow_empty || (end > from)) { + if (p_maxsplit <= 0) + ret.push_back(substr(from, end - from)); + else if (p_maxsplit > 0) { + + // Put rest of the string and leave cycle. + if (p_maxsplit == ret.size()) { + ret.push_back(substr(from, len)); + break; + } + + // Otherwise, push items until positive limit is reached. + ret.push_back(substr(from, end - from)); + } + } if (end == len) break; diff --git a/core/ustring.h b/core/ustring.h index 9c24133b55..6541642bd1 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -162,7 +162,7 @@ public: String get_slice(String p_splitter, int p_slice) const; String get_slicec(CharType p_splitter, int p_slice) const; - Vector<String> split(const String &p_splitter, bool p_allow_empty = true) const; + Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const; Vector<String> split_spaces() const; Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const; Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index f66cce85c9..2b99a60ba5 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -254,7 +254,7 @@ struct _VariantCall { VCALL_LOCALMEM2R(String, replacen); VCALL_LOCALMEM2R(String, insert); VCALL_LOCALMEM0R(String, capitalize); - VCALL_LOCALMEM2R(String, split); + VCALL_LOCALMEM3R(String, split); VCALL_LOCALMEM2R(String, split_floats); VCALL_LOCALMEM0R(String, to_upper); VCALL_LOCALMEM0R(String, to_lower); @@ -1446,7 +1446,7 @@ void register_variant_methods() { ADDFUNC2R(STRING, STRING, String, replacen, STRING, "what", STRING, "forwhat", varray()); ADDFUNC2R(STRING, STRING, String, insert, INT, "position", STRING, "what", varray()); ADDFUNC0R(STRING, STRING, String, capitalize, varray()); - ADDFUNC2R(STRING, POOL_STRING_ARRAY, String, split, STRING, "divisor", BOOL, "allow_empty", varray(true)); + ADDFUNC3R(STRING, POOL_STRING_ARRAY, String, split, STRING, "divisor", BOOL, "allow_empty", INT, "maxsplit", varray(true, 0)); ADDFUNC2R(STRING, POOL_REAL_ARRAY, String, split_floats, STRING, "divisor", BOOL, "allow_empty", varray(true)); ADDFUNC0R(STRING, STRING, String, to_upper, varray()); diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index 93b01a466b..dd248d18f7 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -38,6 +38,7 @@ <argument index="1" name="to_animation" type="Animation"> </argument> <description> + Adds a new track that is a copy of the given track from [code]to_animation[/code]. </description> </method> <method name="find_track" qualifiers="const"> @@ -260,6 +261,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns [code]true[/code] if the track at index [code]idx[/code] is enabled. </description> </method> <method name="track_is_imported" qualifiers="const"> @@ -319,6 +321,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + Enables/disables the given track. Tracks are enabled by default. </description> </method> <method name="track_set_imported"> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index cf0b482b07..bd20cfcf5d 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -36,7 +36,7 @@ <argument index="4" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> </argument> <description> - Draw a string character using a custom font. Returns the advance, depending on the char width and kerning with an optional next char. + Draws a string character using a custom font. Returns the advance, depending on the char width and kerning with an optional next char. </description> </method> <method name="draw_circle"> @@ -49,7 +49,7 @@ <argument index="2" name="color" type="Color"> </argument> <description> - Draw a colored circle. + Draws a colored circle. </description> </method> <method name="draw_colored_polygon"> @@ -68,7 +68,7 @@ <argument index="5" name="antialiased" type="bool" default="false"> </argument> <description> - Draw a colored polygon of any amount of points, convex or concave. + Draws a colored polygon of any amount of points, convex or concave. </description> </method> <method name="draw_line"> @@ -85,7 +85,7 @@ <argument index="4" name="antialiased" type="bool" default="false"> </argument> <description> - Draw a line from a 2D point to another, with a given color and width. It can be optionally antialiased. + Draws a line from a 2D point to another, with a given color and width. It can be optionally antialiased. </description> </method> <method name="draw_multiline"> @@ -100,6 +100,7 @@ <argument index="3" name="antialiased" type="bool" default="false"> </argument> <description> + Draws multiple, parallel lines with a uniform [code]color[/code] and [code]width[/code] and optional antialiasing. </description> </method> <method name="draw_multiline_colors"> @@ -114,6 +115,7 @@ <argument index="3" name="antialiased" type="bool" default="false"> </argument> <description> + Draws multiple, parallel lines with a uniform [code]width[/code], segment-by-segment coloring, and optional antialiasing. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. </description> </method> <method name="draw_polygon"> @@ -132,7 +134,7 @@ <argument index="5" name="antialiased" type="bool" default="false"> </argument> <description> - Draw a polygon of any amount of points, convex or concave. + Draws a polygon of any amount of points, convex or concave. </description> </method> <method name="draw_polyline"> @@ -147,7 +149,7 @@ <argument index="3" name="antialiased" type="bool" default="false"> </argument> <description> - Draw a polyline with a uniform [code]color[/code] and [code]width[/code] and optional antialiasing. + Draws interconnected line segments with a uniform [code]color[/code] and [code]width[/code] and optional antialiasing. </description> </method> <method name="draw_polyline_colors"> @@ -162,7 +164,7 @@ <argument index="3" name="antialiased" type="bool" default="false"> </argument> <description> - Draw a polyline with a uniform [code]width[/code], segment-by-segment coloring, and optional antialiasing. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. + Draws interconnected line segments with a uniform [code]width[/code], segment-by-segment coloring, and optional antialiasing. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. </description> </method> <method name="draw_primitive"> @@ -181,7 +183,7 @@ <argument index="5" name="normal_map" type="Texture" default="null"> </argument> <description> - Draw a custom primitive, 1 point for a point, 2 points for a line, 3 points for a triangle and 4 points for a quad. + Draws a custom primitive, 1 point for a point, 2 points for a line, 3 points for a triangle and 4 points for a quad. </description> </method> <method name="draw_rect"> @@ -194,7 +196,7 @@ <argument index="2" name="filled" type="bool" default="true"> </argument> <description> - Draw a colored rectangle. + Draws a colored rectangle. </description> </method> <method name="draw_set_transform"> @@ -233,7 +235,7 @@ <argument index="4" name="clip_w" type="int" default="-1"> </argument> <description> - Draw a string using a custom font. + Draws a string using a custom font. </description> </method> <method name="draw_style_box"> @@ -244,7 +246,7 @@ <argument index="1" name="rect" type="Rect2"> </argument> <description> - Draw a styled rectangle. + Draws a styled rectangle. </description> </method> <method name="draw_texture"> @@ -259,7 +261,7 @@ <argument index="3" name="normal_map" type="Texture" default="null"> </argument> <description> - Draw a texture at a given position. + Draws a texture at a given position. </description> </method> <method name="draw_texture_rect"> @@ -278,7 +280,7 @@ <argument index="5" name="normal_map" type="Texture" default="null"> </argument> <description> - Draw a textured rectangle at a given position, optionally modulated by a color. Transpose swaps the x and y coordinates when reading the texture. + Draws a textured rectangle at a given position, optionally modulated by a color. Transpose swaps the x and y coordinates when reading the texture. </description> </method> <method name="draw_texture_rect_region"> @@ -299,7 +301,7 @@ <argument index="6" name="clip_uv" type="bool" default="true"> </argument> <description> - Draw a textured rectangle region at a given position, optionally modulated by a color. Transpose swaps the x and y coordinates when reading the texture. + Draws a textured rectangle region at a given position, optionally modulated by a color. Transpose swaps the x and y coordinates when reading the texture. </description> </method> <method name="get_canvas" qualifiers="const"> diff --git a/doc/classes/Curve.xml b/doc/classes/Curve.xml index 3e1158ca3b..f7ef9a182c 100644 --- a/doc/classes/Curve.xml +++ b/doc/classes/Curve.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Curve" inherits="Resource" category="Core" version="3.0-beta"> <brief_description> + A mathematic curve. </brief_description> <description> + A curve that can be saved and re-used for other objects. By default it ranges between [code]0[/code] and [code]1[/code] on the y-axis and positions points relative to the [code]0.5[/code] y-position. </description> <tutorials> </tutorials> @@ -23,24 +25,28 @@ <argument index="4" name="right_mode" type="int" enum="Curve.TangentMode" default="0"> </argument> <description> + Adds a point to the curve. For each side, if the [code]*_mode[/code] is [code]TANGENT_LINEAR[/code], the [code]*_tangent[/code] angle (in degrees) uses the slope of the curve halfway to the adjacent point. Allows custom assignments to the [code]*_tangent[/code] angle if [code]*_mode[/code] is set to [code]TANGENT_FREE[/code]. </description> </method> <method name="bake"> <return type="void"> </return> <description> + Recomputes the baked cache of points for the curve. </description> </method> <method name="clean_dupes"> <return type="void"> </return> <description> + Removes points that are closer than [code]CMP_EPSILON[/code] (0.00001) units to their neighbor on the curve. </description> </method> <method name="clear_points"> <return type="void"> </return> <description> + Removes all points from the curve. </description> </method> <method name="get_point_left_mode" qualifiers="const"> @@ -49,6 +55,7 @@ <argument index="0" name="index" type="int"> </argument> <description> + Returns the left [code]TangentMode[/code] for the point at [code]index[/code]. </description> </method> <method name="get_point_left_tangent" qualifiers="const"> @@ -57,6 +64,7 @@ <argument index="0" name="index" type="int"> </argument> <description> + Returns the left tangent angle (in degrees) for the point at [code]index[/code]. </description> </method> <method name="get_point_position" qualifiers="const"> @@ -65,6 +73,7 @@ <argument index="0" name="index" type="int"> </argument> <description> + Returns the curve coordinates for the point at [code]index[/code]. </description> </method> <method name="get_point_right_mode" qualifiers="const"> @@ -73,6 +82,7 @@ <argument index="0" name="index" type="int"> </argument> <description> + Returns the right [code]TangentMode[/code] for the point at [code]index[/code]. </description> </method> <method name="get_point_right_tangent" qualifiers="const"> @@ -81,6 +91,7 @@ <argument index="0" name="index" type="int"> </argument> <description> + Returns the right tangent angle (in degrees) for the point at [code]index[/code]. </description> </method> <method name="interpolate" qualifiers="const"> @@ -89,12 +100,14 @@ <argument index="0" name="offset" type="float"> </argument> <description> + Returns the y value for the point that would exist at x-position [code]offset[/code] along the curve. </description> </method> <method name="interpolate_baked"> <return type="float"> </return> <argument index="0" name="offset" type="float"> + Returns the y value for the point that would exist at x-position [code]offset[/code] along the curve using the baked cache. Bakes the curve's points if not already baked. </argument> <description> </description> @@ -105,6 +118,7 @@ <argument index="0" name="index" type="int"> </argument> <description> + Removes the point at [code]index[/code] from the curve. </description> </method> <method name="set_point_left_mode"> @@ -115,6 +129,7 @@ <argument index="1" name="mode" type="int" enum="Curve.TangentMode"> </argument> <description> + Sets the left [code]TangentMode[/code] for the point at [code]index[/code] to [code]mode[/code]. </description> </method> <method name="set_point_left_tangent"> @@ -125,6 +140,7 @@ <argument index="1" name="tangent" type="float"> </argument> <description> + Sets the left tangent angle for the point at [code]index[/code] to [code]tangent[/code]. </description> </method> <method name="set_point_offset"> @@ -135,6 +151,7 @@ <argument index="1" name="offset" type="float"> </argument> <description> + Sets the offset from [code]0.5[/code] </description> </method> <method name="set_point_right_mode"> @@ -145,6 +162,7 @@ <argument index="1" name="mode" type="int" enum="Curve.TangentMode"> </argument> <description> + Sets the right [code]TangentMode[/code] for the point at [code]index[/code] to [code]mode[/code]. </description> </method> <method name="set_point_right_tangent"> @@ -155,6 +173,7 @@ <argument index="1" name="tangent" type="float"> </argument> <description> + Sets the right tangent angle for the point at [code]index[/code] to [code]tangent[/code]. </description> </method> <method name="set_point_value"> @@ -165,29 +184,37 @@ <argument index="1" name="y" type="float"> </argument> <description> + Assigns the vertical position [code]y[/code] to the point at [code]index[/code]. </description> </method> </methods> <members> <member name="bake_resolution" type="int" setter="set_bake_resolution" getter="get_bake_resolution"> + The number of points to include in the baked (i.e. cached) curve data. </member> <member name="max_value" type="float" setter="set_max_value" getter="get_max_value"> + The maximum value the curve can reach. Default value: [code]1[/code]. </member> <member name="min_value" type="float" setter="set_min_value" getter="get_min_value"> + The minimum value the curve can reach. Default value: [code]0[/code]. </member> </members> <signals> <signal name="range_changed"> <description> + Emitted when [member max_value] or [member min_value] is changed. </description> </signal> </signals> <constants> <constant name="TANGENT_FREE" value="0" enum="TangentMode"> + The tangent on this side of the point is user-defined. </constant> <constant name="TANGENT_LINEAR" value="1" enum="TangentMode"> + The curve calculates the tangent on this side of the point as the slope halfway towards the adjacent point. </constant> <constant name="TANGENT_MODE_COUNT" value="2" enum="TangentMode"> + The total number of available tangent modes. </constant> </constants> </class> diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml index e30ae85617..91d7a9bed8 100644 --- a/doc/classes/Curve3D.xml +++ b/doc/classes/Curve3D.xml @@ -32,6 +32,7 @@ <return type="void"> </return> <description> + Removes all points from the curve. </description> </method> <method name="get_baked_length" qualifiers="const"> @@ -203,6 +204,7 @@ </methods> <members> <member name="bake_interval" type="float" setter="set_bake_interval" getter="get_bake_interval"> + The distance in meters between two adjacent cached points. Changing it forces the cache to be recomputed the next time the [method get_baked_points] or [method get_baked_length] function is called. The smaller the distance, the more points in the cache and the more memory it will consume, so use with care. </member> </members> <constants> diff --git a/doc/classes/Navigation.xml b/doc/classes/Navigation.xml index 4bfe964a4d..8fe520f853 100644 --- a/doc/classes/Navigation.xml +++ b/doc/classes/Navigation.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Navigation" inherits="Spatial" category="Core" version="3.0-beta"> <brief_description> + A collection of [code]NavigationMesh[/code] resources and methods used for pathfinding. </brief_description> <description> + The Navigation node is used for basic or advanced navigation. By default it will automatically collect all child [code]NavigationMesh[/code] resources, but they can also be added on the fly through scripting. It can be used for generating a simple path between two points or it can be used to ensure that a navigation agent is angled perfectly to the terrain it is navigating. </description> <tutorials> </tutorials> @@ -15,6 +17,7 @@ <argument index="0" name="to_point" type="Vector3"> </argument> <description> + Returns the closest navigation point to the point passed. </description> </method> <method name="get_closest_point_normal"> @@ -23,6 +26,7 @@ <argument index="0" name="to_point" type="Vector3"> </argument> <description> + Returns the surface normal of the navigation mesh at the point passed. For instance, if the point passed was at a 45 degree slope it would return something like (0.5,0.5,0). This is useful for rotating a navigation agent in accordance with the [code]NavigationMesh[/code]. </description> </method> <method name="get_closest_point_owner"> @@ -31,6 +35,7 @@ <argument index="0" name="to_point" type="Vector3"> </argument> <description> + Returns the nearest [code]NavigationMeshInstance[/code] to the point passed. </description> </method> <method name="get_closest_point_to_segment"> @@ -43,6 +48,7 @@ <argument index="2" name="use_collision" type="bool" default="false"> </argument> <description> + Returns the nearest point to the line segment passed. The third optional parameter takes collisions into account. </description> </method> <method name="get_simple_path"> @@ -55,9 +61,10 @@ <argument index="2" name="optimize" type="bool" default="true"> </argument> <description> + Returns a path of points as a [code]PoolVector3Array[/code]. If [code]optimize[/code] is false the [code]NavigationMesh[/code] agent properties will be taken into account, otherwise it will return the nearest path and ignore agent radius, height, etc. </description> </method> - <method name="navmesh_create"> + <method name="navmesh_add"> <return type="int"> </return> <argument index="0" name="mesh" type="NavigationMesh"> @@ -67,6 +74,7 @@ <argument index="2" name="owner" type="Object" default="null"> </argument> <description> + Adds a [code]NavigationMesh[/code] to the list of NavigationMesh's in this node. Returns an id. Its position, rotation and scale are associated with the [code]Transform[/code] passed. The [code]Node[/code] (or [code]Object[/code]) that owns this node is an optional parameter. </description> </method> <method name="navmesh_remove"> @@ -75,6 +83,7 @@ <argument index="0" name="id" type="int"> </argument> <description> + Removes a [code]NavigationMesh[/code] from the list of NavigationMesh's in this node. </description> </method> <method name="navmesh_set_transform"> @@ -85,11 +94,13 @@ <argument index="1" name="xform" type="Transform"> </argument> <description> + Associates a [code]NavigationMesh[/code]'s id with a [code]Transform[/code]. Its position, rotation and scale are based on the [code]Transform[/code] passed. </description> </method> </methods> <members> <member name="up_vector" type="Vector3" setter="set_up_vector" getter="get_up_vector"> + Defines which direction is up. The default defines 0,1,0 as up which is the world up direction. To make this a ceiling use 0,-1,0 to define down as up. </member> </members> <constants> diff --git a/doc/classes/Navigation2D.xml b/doc/classes/Navigation2D.xml index 8868348cf9..18c15a616a 100644 --- a/doc/classes/Navigation2D.xml +++ b/doc/classes/Navigation2D.xml @@ -37,7 +37,7 @@ <description> </description> </method> - <method name="navpoly_create"> + <method name="navpoly_add"> <return type="int"> </return> <argument index="0" name="mesh" type="NavigationPolygon"> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 78e9f3cd3f..8bbd52b417 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -662,8 +662,11 @@ </argument> <argument index="1" name="allow_empty" type="bool" default="True"> </argument> + <argument index="2" name="maxsplit" type="int" default="0"> + </argument> <description> Splits the string by a divisor string and returns an array of the substrings. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". + If [code]maxsplit[/code] is given, at most maxsplit number of splits occur, and the remainder of the string is returned as the final element of the list (thus, the list will have at most maxsplit+1 elements) </description> </method> <method name="split_floats"> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index d38ec2a1f9..13fbb5c293 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1849,6 +1849,20 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, false); } + } else if (!e->instance->lightmap_capture_data.empty()) { + + glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES3::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr()); + state.scene_shader.set_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURE_SKY, false); + + } else if (e->instance->lightmap.is_valid()) { + RasterizerStorageGLES3::Texture *lightmap = storage->texture_owner.getornull(e->instance->lightmap); + RasterizerStorageGLES3::LightmapCapture *capture = storage->lightmap_capture_data_owner.getornull(e->instance->lightmap_capture->base); + + if (lightmap && capture) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 9); + glBindTexture(GL_TEXTURE_2D, lightmap->tex_id); + state.scene_shader.set_uniform(SceneShaderGLES3::LIGHTMAP_ENERGY, capture->energy); + } } } @@ -1971,6 +1985,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP_CAPTURE, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false); @@ -1978,6 +1994,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ } else { state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, e->instance->gi_probe_instances.size() > 0); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP, e->instance->lightmap.is_valid() && e->instance->gi_probe_instances.size() == 0); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP_CAPTURE, !e->instance->lightmap_capture_data.empty() && !e->instance->lightmap.is_valid() && e->instance->gi_probe_instances.size() == 0); state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, false); @@ -2148,6 +2166,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP_CAPTURE, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_OPAQUE_PREPASS, false); @@ -2274,6 +2294,14 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G e->sort_key |= SORT_KEY_GI_PROBES_FLAG; } + if (e->instance->lightmap.is_valid()) { + e->sort_key |= SORT_KEY_LIGHTMAP_FLAG; + } + + if (!e->instance->lightmap_capture_data.empty()) { + e->sort_key |= SORT_KEY_LIGHTMAP_CAPTURE_FLAG; + } + e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT; } else { e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT; diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index ffbe10fb60..6df223c961 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -662,19 +662,21 @@ public: SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT = 52, SORT_KEY_OPAQUE_DEPTH_LAYER_MASK = 0xF, //64 bits unsupported in MSVC -#define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 51) -#define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 50) -#define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 49) -#define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 48) - SORT_KEY_SHADING_SHIFT = 48, - SORT_KEY_SHADING_MASK = 15, - //48-32 material index - SORT_KEY_MATERIAL_INDEX_SHIFT = 32, - //32-12 geometry index - SORT_KEY_GEOMETRY_INDEX_SHIFT = 12, - //bits 12-8 geometry type - SORT_KEY_GEOMETRY_TYPE_SHIFT = 8, - //bits 0-7 for flags +#define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 49) +#define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 48) +#define SORT_KEY_LIGHTMAP_CAPTURE_FLAG (uint64_t(1) << 47) +#define SORT_KEY_LIGHTMAP_FLAG (uint64_t(1) << 46) +#define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 45) +#define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 44) + SORT_KEY_SHADING_SHIFT = 44, + SORT_KEY_SHADING_MASK = 63, + //44-28 material index + SORT_KEY_MATERIAL_INDEX_SHIFT = 28, + //28-8 geometry index + SORT_KEY_GEOMETRY_INDEX_SHIFT = 8, + //bits 5-7 geometry type + SORT_KEY_GEOMETRY_TYPE_SHIFT = 5, + //bits 0-5 for flags SORT_KEY_OPAQUE_PRE_PASS = 8, SORT_KEY_CULL_DISABLED_FLAG = 4, SORT_KEY_SKELETON_FLAG = 2, diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index cba9f08537..ee6c738a05 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -5216,6 +5216,104 @@ void RasterizerStorageGLES3::gi_probe_dynamic_data_update(RID p_gi_probe_data, i //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,p_data); //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr()); } +///////////////////////////// + +RID RasterizerStorageGLES3::lightmap_capture_create() { + + LightmapCapture *capture = memnew(LightmapCapture); + return lightmap_capture_data_owner.make_rid(capture); +} + +void RasterizerStorageGLES3::lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) { + + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->bounds = p_bounds; + capture->instance_change_notify(); +} +AABB RasterizerStorageGLES3::lightmap_capture_get_bounds(RID p_capture) const { + + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, AABB()); + return capture->bounds; +} +void RasterizerStorageGLES3::lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) { + + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + + ERR_FAIL_COND(p_octree.size() == 0 || (p_octree.size() % sizeof(LightmapCaptureOctree)) != 0); + + capture->octree.resize(p_octree.size() / sizeof(LightmapCaptureOctree)); + if (p_octree.size()) { + PoolVector<LightmapCaptureOctree>::Write w = capture->octree.write(); + PoolVector<uint8_t>::Read r = p_octree.read(); + copymem(w.ptr(), r.ptr(), p_octree.size()); + } + capture->instance_change_notify(); +} +PoolVector<uint8_t> RasterizerStorageGLES3::lightmap_capture_get_octree(RID p_capture) const { + + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, PoolVector<uint8_t>()); + + if (capture->octree.size() == 0) + return PoolVector<uint8_t>(); + + PoolVector<uint8_t> ret; + ret.resize(capture->octree.size() * sizeof(LightmapCaptureOctree)); + { + PoolVector<LightmapCaptureOctree>::Read r = capture->octree.read(); + PoolVector<uint8_t>::Write w = ret.write(); + copymem(w.ptr(), r.ptr(), ret.size()); + } + + return ret; +} + +void RasterizerStorageGLES3::lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) { + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->cell_xform = p_xform; +} + +Transform RasterizerStorageGLES3::lightmap_capture_get_octree_cell_transform(RID p_capture) const { + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, Transform()); + return capture->cell_xform; +} + +void RasterizerStorageGLES3::lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) { + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->cell_subdiv = p_subdiv; +} + +int RasterizerStorageGLES3::lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, 0); + return capture->cell_subdiv; +} + +void RasterizerStorageGLES3::lightmap_capture_set_energy(RID p_capture, float p_energy) { + + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->energy = p_energy; +} + +float RasterizerStorageGLES3::lightmap_capture_get_energy(RID p_capture) const { + + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, 0); + return capture->energy; +} + +const PoolVector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES3::lightmap_capture_get_octree_ptr(RID p_capture) const { + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, NULL); + return &capture->octree; +} /////// @@ -5817,6 +5915,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base, RasterizerScene inst = gi_probe_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_LIGHTMAP_CAPTURE: { + inst = lightmap_capture_data_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; default: { if (!inst) { ERR_FAIL(); @@ -5860,6 +5962,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base, RasterizerSc inst = gi_probe_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_LIGHTMAP_CAPTURE: { + inst = lightmap_capture_data_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; default: { if (!inst) { @@ -6609,6 +6715,10 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { return VS::INSTANCE_GI_PROBE; } + if (lightmap_capture_data_owner.owns(p_rid)) { + return VS::INSTANCE_LIGHTMAP_CAPTURE; + } + return VS::INSTANCE_NONE; } @@ -6795,6 +6905,13 @@ bool RasterizerStorageGLES3::free(RID p_rid) { glDeleteTextures(1, &gi_probe_data->tex_id); gi_probe_owner.free(p_rid); memdelete(gi_probe_data); + } else if (lightmap_capture_data_owner.owns(p_rid)) { + + // delete the texture + LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get(p_rid); + + gi_probe_owner.free(p_rid); + memdelete(lightmap_capture); } else if (canvas_occluder_owner.owns(p_rid)) { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 25327af0a5..6647372688 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -1069,6 +1069,38 @@ public: virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression); virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data); + /* LIGHTMAP CAPTURE */ + + virtual RID lightmap_capture_create(); + virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds); + virtual AABB lightmap_capture_get_bounds(RID p_capture) const; + virtual void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree); + virtual PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const; + virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform); + virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const; + virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv); + virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const; + + virtual void lightmap_capture_set_energy(RID p_capture, float p_energy); + virtual float lightmap_capture_get_energy(RID p_capture) const; + + virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const; + + struct LightmapCapture : public Instantiable { + + PoolVector<LightmapCaptureOctree> octree; + AABB bounds; + Transform cell_xform; + int cell_subdiv; + float energy; + LightmapCapture() { + energy = 1.0; + cell_subdiv = 1; + } + }; + + mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner; + /* PARTICLES */ struct Particles : public GeometryOwner { diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 21102e8c25..101978548d 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -812,6 +812,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { //for light actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view"; actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color"; + actions[VS::SHADER_SPATIAL].renames["LIGHT"] = "light"; actions[VS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation"; actions[VS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light"; actions[VS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light"; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index fb0f06de01..9bc2bc079d 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -35,7 +35,7 @@ layout(location=3) in vec4 color_attrib; layout(location=4) in vec2 uv_attrib; #endif -#if defined(ENABLE_UV2_INTERP) +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) layout(location=5) in vec2 uv2_attrib; #endif @@ -223,7 +223,7 @@ out vec4 color_interp; out vec2 uv_interp; #endif -#if defined(ENABLE_UV2_INTERP) +#if defined(ENABLE_UV2_INTERP) || defined (USE_LIGHTMAP) out vec2 uv2_interp; #endif @@ -234,9 +234,6 @@ out vec3 binormal_interp; #endif - - - #if defined(USE_MATERIAL) layout(std140) uniform UniformData { //ubo:1 @@ -356,7 +353,7 @@ void main() { uv_interp = uv_attrib; #endif -#if defined(ENABLE_UV2_INTERP) +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) uv2_interp = uv2_attrib; #endif @@ -549,7 +546,7 @@ in vec4 color_interp; in vec2 uv_interp; #endif -#if defined(ENABLE_UV2_INTERP) +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) in vec2 uv2_interp; #endif @@ -1357,7 +1354,7 @@ void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 ta reflection_accum+=reflection; } - +#ifndef USE_LIGHTMAP if (reflections[idx].ambient.a>0.0) { //compute ambient using skybox @@ -1403,8 +1400,20 @@ void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 ta ambient_accum+=ambient_out; } +#endif } +#ifdef USE_LIGHTMAP +uniform mediump sampler2D lightmap; //texunit:-9 +uniform mediump float lightmap_energy; +#endif + +#ifdef USE_LIGHTMAP_CAPTURE +uniform mediump vec4[12] lightmap_captures; +uniform bool lightmap_capture_sky; + +#endif + #ifdef USE_GI_PROBES uniform mediump sampler3D gi_probe1; //texunit:-9 @@ -1632,7 +1641,7 @@ void main() { vec2 uv = uv_interp; #endif -#if defined(ENABLE_UV2_INTERP) +#if defined(ENABLE_UV2_INTERP) || defined (USE_LIGHTMAP) vec2 uv2 = uv2_interp; #endif @@ -1745,7 +1754,7 @@ FRAGMENT_SHADER_CODE //vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); } - +#ifndef USE_LIGHTMAP { vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); @@ -1754,6 +1763,7 @@ FRAGMENT_SHADER_CODE ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution); //ambient_light=vec3(0.0,0.0,0.0); } +#endif } #else @@ -1938,6 +1948,48 @@ FRAGMENT_SHADER_CODE #endif +#ifdef USE_LIGHTMAP + ambient_light = texture(lightmap,uv2).rgb * lightmap_energy; +#endif + +#ifdef USE_LIGHTMAP_CAPTURE + { + vec3 cone_dirs[12] = vec3[] ( + vec3(0, 0, 1), + vec3(0.866025, 0, 0.5), + vec3(0.267617, 0.823639, 0.5), + vec3(-0.700629, 0.509037, 0.5), + vec3(-0.700629, -0.509037, 0.5), + vec3(0.267617, -0.823639, 0.5), + vec3(0, 0, -1), + vec3(0.866025, 0, -0.5), + vec3(0.267617, 0.823639, -0.5), + vec3(-0.700629, 0.509037, -0.5), + vec3(-0.700629, -0.509037, -0.5), + vec3(0.267617, -0.823639, -0.5) + ); + + + vec3 local_normal = normalize(camera_matrix * vec4(normal,0.0)).xyz; + vec4 captured = vec4(0.0); + float sum = 0.0; + for(int i=0;i<12;i++) { + float amount = max(0.0,dot(local_normal,cone_dirs[i])); //not correct, but creates a nice wrap around effect + captured += lightmap_captures[i]*amount; + sum+=amount; + } + + captured/=sum; + + if (lightmap_capture_sky) { + ambient_light = mix( ambient_light, captured.rgb, captured.a); + } else { + ambient_light = captured.rgb; + } + + } +#endif + #ifdef USE_FORWARD_LIGHTING @@ -1952,11 +2004,11 @@ FRAGMENT_SHADER_CODE } else { specular_light+=env_reflection_light; } - +#ifndef USE_LIGHTMAP if (ambient_accum.a>0.0) { ambient_light+=ambient_accum.rgb/ambient_accum.a; } - +#endif #ifdef USE_VERTEX_LIGHTING diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp index 61d2737555..f6742d8114 100644 --- a/drivers/unix/packet_peer_udp_posix.cpp +++ b/drivers/unix/packet_peer_udp_posix.cpp @@ -65,7 +65,7 @@ int PacketPeerUDPPosix::get_available_packet_count() const { return queue_count; } -Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer, int &r_buffer_size) const { +Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { Error err = const_cast<PacketPeerUDPPosix *>(this)->_poll(false); if (err != OK) diff --git a/drivers/unix/packet_peer_udp_posix.h b/drivers/unix/packet_peer_udp_posix.h index e580d336b2..ad7be5bbe0 100644 --- a/drivers/unix/packet_peer_udp_posix.h +++ b/drivers/unix/packet_peer_udp_posix.h @@ -41,12 +41,12 @@ class PacketPeerUDPPosix : public PacketPeerUDP { PACKET_BUFFER_SIZE = 65536 }; - mutable RingBuffer<uint8_t> rb; + RingBuffer<uint8_t> rb; uint8_t recv_buffer[PACKET_BUFFER_SIZE]; - mutable uint8_t packet_buffer[PACKET_BUFFER_SIZE]; - mutable IP_Address packet_ip; - mutable int packet_port; - mutable int queue_count; + uint8_t packet_buffer[PACKET_BUFFER_SIZE]; + IP_Address packet_ip; + int packet_port; + int queue_count; int sockfd; bool sock_blocking; IP::Type sock_type; @@ -62,7 +62,7 @@ class PacketPeerUDPPosix : public PacketPeerUDP { public: virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) const; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); virtual int get_max_packet_size() const; diff --git a/platform/windows/packet_peer_udp_winsock.cpp b/drivers/windows/packet_peer_udp_winsock.cpp index d414ec891e..119ee68bd2 100644 --- a/platform/windows/packet_peer_udp_winsock.cpp +++ b/drivers/windows/packet_peer_udp_winsock.cpp @@ -27,6 +27,8 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifdef WINDOWS_ENABLED + #include "packet_peer_udp_winsock.h" #include <winsock2.h> @@ -43,7 +45,7 @@ int PacketPeerUDPWinsock::get_available_packet_count() const { return queue_count; } -Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer, int &r_buffer_size) const { +Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { Error err = const_cast<PacketPeerUDPWinsock *>(this)->_poll(false); if (err != OK) @@ -291,3 +293,5 @@ PacketPeerUDPWinsock::~PacketPeerUDPWinsock() { close(); } + +#endif diff --git a/platform/windows/packet_peer_udp_winsock.h b/drivers/windows/packet_peer_udp_winsock.h index 8a6951fd6e..8ce2cff741 100644 --- a/platform/windows/packet_peer_udp_winsock.h +++ b/drivers/windows/packet_peer_udp_winsock.h @@ -27,6 +27,8 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifdef WINDOWS_ENABLED + #ifndef PACKET_PEER_UDP_WINSOCK_H #define PACKET_PEER_UDP_WINSOCK_H @@ -39,12 +41,12 @@ class PacketPeerUDPWinsock : public PacketPeerUDP { PACKET_BUFFER_SIZE = 65536 }; - mutable RingBuffer<uint8_t> rb; + RingBuffer<uint8_t> rb; uint8_t recv_buffer[PACKET_BUFFER_SIZE]; - mutable uint8_t packet_buffer[PACKET_BUFFER_SIZE]; - mutable IP_Address packet_ip; - mutable int packet_port; - mutable int queue_count; + uint8_t packet_buffer[PACKET_BUFFER_SIZE]; + IP_Address packet_ip; + int packet_port; + int queue_count; int sockfd; bool sock_blocking; IP::Type sock_type; @@ -62,7 +64,7 @@ class PacketPeerUDPWinsock : public PacketPeerUDP { public: virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) const; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); virtual int get_max_packet_size() const; @@ -82,3 +84,5 @@ public: ~PacketPeerUDPWinsock(); }; #endif // PACKET_PEER_UDP_WINSOCK_H + +#endif diff --git a/platform/windows/stream_peer_winsock.cpp b/drivers/windows/stream_peer_tcp_winsock.cpp index 8b83215325..f4cd38079d 100644 --- a/platform/windows/stream_peer_winsock.cpp +++ b/drivers/windows/stream_peer_tcp_winsock.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* stream_peer_winsock.cpp */ +/* stream_peer_tcp_winsock.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -29,7 +29,7 @@ /*************************************************************************/ #ifdef WINDOWS_ENABLED -#include "stream_peer_winsock.h" +#include "stream_peer_tcp_winsock.h" #include <winsock2.h> #include <ws2tcpip.h> @@ -38,14 +38,14 @@ int winsock_refcount = 0; -StreamPeerTCP *StreamPeerWinsock::_create() { +StreamPeerTCP *StreamPeerTCPWinsock::_create() { - return memnew(StreamPeerWinsock); + return memnew(StreamPeerTCPWinsock); }; -void StreamPeerWinsock::make_default() { +void StreamPeerTCPWinsock::make_default() { - StreamPeerTCP::_create = StreamPeerWinsock::_create; + StreamPeerTCP::_create = StreamPeerTCPWinsock::_create; if (winsock_refcount == 0) { WSADATA data; @@ -54,7 +54,7 @@ void StreamPeerWinsock::make_default() { ++winsock_refcount; }; -void StreamPeerWinsock::cleanup() { +void StreamPeerTCPWinsock::cleanup() { --winsock_refcount; if (winsock_refcount == 0) { @@ -63,7 +63,7 @@ void StreamPeerWinsock::cleanup() { }; }; -Error StreamPeerWinsock::_block(int p_sockfd, bool p_read, bool p_write) const { +Error StreamPeerTCPWinsock::_block(int p_sockfd, bool p_read, bool p_write) const { fd_set read, write; FD_ZERO(&read); @@ -78,7 +78,7 @@ Error StreamPeerWinsock::_block(int p_sockfd, bool p_read, bool p_write) const { return ret < 0 ? FAILED : OK; }; -Error StreamPeerWinsock::_poll_connection() const { +Error StreamPeerTCPWinsock::_poll_connection() const { ERR_FAIL_COND_V(status != STATUS_CONNECTING || sockfd == INVALID_SOCKET, FAILED); @@ -108,7 +108,7 @@ Error StreamPeerWinsock::_poll_connection() const { return OK; }; -Error StreamPeerWinsock::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block) { +Error StreamPeerTCPWinsock::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block) { if (status == STATUS_NONE || status == STATUS_ERROR) { @@ -166,7 +166,7 @@ Error StreamPeerWinsock::write(const uint8_t *p_data, int p_bytes, int &r_sent, return OK; }; -Error StreamPeerWinsock::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block) { +Error StreamPeerTCPWinsock::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block) { if (!is_connected_to_host()) { @@ -224,29 +224,29 @@ Error StreamPeerWinsock::read(uint8_t *p_buffer, int p_bytes, int &r_received, b return OK; }; -Error StreamPeerWinsock::put_data(const uint8_t *p_data, int p_bytes) { +Error StreamPeerTCPWinsock::put_data(const uint8_t *p_data, int p_bytes) { int total; return write(p_data, p_bytes, total, true); }; -Error StreamPeerWinsock::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { +Error StreamPeerTCPWinsock::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { return write(p_data, p_bytes, r_sent, false); }; -Error StreamPeerWinsock::get_data(uint8_t *p_buffer, int p_bytes) { +Error StreamPeerTCPWinsock::get_data(uint8_t *p_buffer, int p_bytes) { int total; return read(p_buffer, p_bytes, total, true); }; -Error StreamPeerWinsock::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { +Error StreamPeerTCPWinsock::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { return read(p_buffer, p_bytes, r_received, false); }; -StreamPeerTCP::Status StreamPeerWinsock::get_status() const { +StreamPeerTCP::Status StreamPeerTCPWinsock::get_status() const { if (status == STATUS_CONNECTING) { _poll_connection(); @@ -255,7 +255,7 @@ StreamPeerTCP::Status StreamPeerWinsock::get_status() const { return status; }; -bool StreamPeerWinsock::is_connected_to_host() const { +bool StreamPeerTCPWinsock::is_connected_to_host() const { if (status == STATUS_NONE || status == STATUS_ERROR) { @@ -268,7 +268,7 @@ bool StreamPeerWinsock::is_connected_to_host() const { return (sockfd != INVALID_SOCKET); }; -void StreamPeerWinsock::disconnect_from_host() { +void StreamPeerTCPWinsock::disconnect_from_host() { if (sockfd != INVALID_SOCKET) closesocket(sockfd); @@ -281,7 +281,7 @@ void StreamPeerWinsock::disconnect_from_host() { peer_port = 0; }; -void StreamPeerWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type) { +void StreamPeerTCPWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type) { sockfd = p_sockfd; sock_type = p_sock_type; @@ -290,7 +290,7 @@ void StreamPeerWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port, peer_port = p_port; }; -Error StreamPeerWinsock::connect_to_host(const IP_Address &p_host, uint16_t p_port) { +Error StreamPeerTCPWinsock::connect_to_host(const IP_Address &p_host, uint16_t p_port) { ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER); @@ -331,13 +331,13 @@ Error StreamPeerWinsock::connect_to_host(const IP_Address &p_host, uint16_t p_po return OK; }; -void StreamPeerWinsock::set_nodelay(bool p_enabled) { +void StreamPeerTCPWinsock::set_nodelay(bool p_enabled) { ERR_FAIL_COND(!is_connected_to_host()); int flag = p_enabled ? 1 : 0; setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)); } -int StreamPeerWinsock::get_available_bytes() const { +int StreamPeerTCPWinsock::get_available_bytes() const { unsigned long len; int ret = ioctlsocket(sockfd, FIONREAD, &len); @@ -345,17 +345,17 @@ int StreamPeerWinsock::get_available_bytes() const { return len; } -IP_Address StreamPeerWinsock::get_connected_host() const { +IP_Address StreamPeerTCPWinsock::get_connected_host() const { return peer_host; }; -uint16_t StreamPeerWinsock::get_connected_port() const { +uint16_t StreamPeerTCPWinsock::get_connected_port() const { return peer_port; }; -StreamPeerWinsock::StreamPeerWinsock() { +StreamPeerTCPWinsock::StreamPeerTCPWinsock() { sock_type = IP::TYPE_NONE; sockfd = INVALID_SOCKET; @@ -363,7 +363,7 @@ StreamPeerWinsock::StreamPeerWinsock() { peer_port = 0; }; -StreamPeerWinsock::~StreamPeerWinsock() { +StreamPeerTCPWinsock::~StreamPeerTCPWinsock() { disconnect_from_host(); }; diff --git a/platform/windows/stream_peer_winsock.h b/drivers/windows/stream_peer_tcp_winsock.h index 26e2a3e4c9..fef457c43f 100644 --- a/platform/windows/stream_peer_winsock.h +++ b/drivers/windows/stream_peer_tcp_winsock.h @@ -29,15 +29,15 @@ /*************************************************************************/ #ifdef WINDOWS_ENABLED -#ifndef STREAM_PEER_WINSOCK_H -#define STREAM_PEER_WINSOCK_H +#ifndef STREAM_PEER_TCP_WINSOCK_H +#define STREAM_PEER_TCP_WINSOCK_H #include "error_list.h" #include "core/io/ip_address.h" #include "core/io/stream_peer_tcp.h" -class StreamPeerWinsock : public StreamPeerTCP { +class StreamPeerTCPWinsock : public StreamPeerTCP { protected: mutable Status status; @@ -82,10 +82,10 @@ public: virtual void set_nodelay(bool p_enabled); - StreamPeerWinsock(); - ~StreamPeerWinsock(); + StreamPeerTCPWinsock(); + ~StreamPeerTCPWinsock(); }; -#endif // TCP_SOCKET_POSIX_H +#endif // STREAM_PEER_TCP_WINSOCK_H #endif diff --git a/platform/windows/tcp_server_winsock.cpp b/drivers/windows/tcp_server_winsock.cpp index de300befa7..49de279793 100644 --- a/platform/windows/tcp_server_winsock.cpp +++ b/drivers/windows/tcp_server_winsock.cpp @@ -27,9 +27,11 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifdef WINDOWS_ENABLED + #include "tcp_server_winsock.h" -#include "stream_peer_winsock.h" +#include "stream_peer_tcp_winsock.h" #include <winsock2.h> #include <ws2tcpip.h> @@ -151,7 +153,7 @@ Ref<StreamPeerTCP> TCPServerWinsock::take_connection() { int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &sin_size); ERR_FAIL_COND_V(fd == INVALID_SOCKET, NULL); - Ref<StreamPeerWinsock> conn = memnew(StreamPeerWinsock); + Ref<StreamPeerTCPWinsock> conn = memnew(StreamPeerTCPWinsock); IP_Address ip; int port; _set_ip_addr_port(ip, port, &their_addr); @@ -181,3 +183,5 @@ TCPServerWinsock::~TCPServerWinsock() { stop(); }; + +#endif diff --git a/platform/windows/tcp_server_winsock.h b/drivers/windows/tcp_server_winsock.h index a3e01098ed..fd16480167 100644 --- a/platform/windows/tcp_server_winsock.h +++ b/drivers/windows/tcp_server_winsock.h @@ -27,6 +27,8 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifdef WINDOWS_ENABLED + #ifndef TCP_SERVER_WINSOCK_H #define TCP_SERVER_WINSOCK_H @@ -54,3 +56,5 @@ public: }; #endif + +#endif diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index ec0ca3add5..f357f1e51f 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -678,7 +678,7 @@ bool OrphanResourcesDialog::_fill_owners(EditorFileSystemDirectory *efsd, HashMa int ds = efsd->get_file_deps(i).size(); ti->set_text(1, itos(ds)); if (ds) { - ti->add_button(1, get_icon("Visible", "EditorIcons")); + ti->add_button(1, get_icon("GuiVisibilityVisible", "EditorIcons")); } ti->set_metadata(0, path); has_childs = true; diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 3f618c3199..b330f5d177 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -39,10 +39,10 @@ #include "io/zip_io.h" #include "os/file_access.h" #include "project_settings.h" +#include "scene/resources/scene_format_text.h" #include "script_language.h" -#include "version.h" - #include "thirdparty/misc/md5.h" +#include "version.h" static int _get_pad(int p_alignment, int p_n) { @@ -1399,3 +1399,30 @@ EditorExportPlatformPC::EditorExportPlatformPC() { chmod_flags = -1; } + +/////////////////////// + +void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, const String &p_type, const Set<String> &p_features) { + + String extension = p_path.get_extension().to_lower(); + if (extension != "tres" && extension != "tscn") { + return; + } + + print_line("exporting " + p_path); + + bool convert = GLOBAL_GET("editor/convert_text_resources_to_binary_on_export"); + if (!convert) + return; + String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("file.res"); + Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path); + ERR_FAIL_COND(err != OK); + Vector<uint8_t> data = FileAccess::get_file_as_array(tmp_path); + ERR_FAIL_COND(data.size() == 0); + add_file(p_path + ".converted.res", data, true); +} + +EditorExportTextSceneToBinaryPlugin::EditorExportTextSceneToBinaryPlugin() { + + GLOBAL_DEF("editor/convert_text_resources_to_binary_on_export", false); +} diff --git a/editor/editor_export.h b/editor/editor_export.h index 215a770a12..8b1cf4bcff 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -408,4 +408,13 @@ public: EditorExportPlatformPC(); }; +class EditorExportTextSceneToBinaryPlugin : public EditorExportPlugin { + + GDCLASS(EditorExportTextSceneToBinaryPlugin, EditorExportPlugin) + +public: + virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features); + EditorExportTextSceneToBinaryPlugin(); +}; + #endif // EDITOR_IMPORT_EXPORT_H diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 27ed53bb42..cb8407386d 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -67,6 +67,7 @@ #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/animation_tree_editor_plugin.h" #include "editor/plugins/asset_library_editor_plugin.h" +#include "editor/plugins/baked_lightmap_editor_plugin.h" #include "editor/plugins/camera_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/collision_polygon_2d_editor_plugin.h" @@ -3384,14 +3385,14 @@ void EditorNode::stop_child_process() { _menu_option_confirm(RUN_STOP, false); } -void EditorNode::progress_add_task(const String &p_task, const String &p_label, int p_steps) { +void EditorNode::progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) { - singleton->progress_dialog->add_task(p_task, p_label, p_steps); + singleton->progress_dialog->add_task(p_task, p_label, p_steps, p_can_cancel); } -void EditorNode::progress_task_step(const String &p_task, const String &p_state, int p_step, bool p_force_refresh) { +bool EditorNode::progress_task_step(const String &p_task, const String &p_state, int p_step, bool p_force_refresh) { - singleton->progress_dialog->task_step(p_task, p_state, p_step, p_force_refresh); + return singleton->progress_dialog->task_step(p_task, p_state, p_step, p_force_refresh); } void EditorNode::progress_end_task(const String &p_task) { @@ -4707,6 +4708,7 @@ EditorNode::EditorNode() { EditorHelp::generate_doc(); //before any editor classes are crated SceneState::set_disable_placeholders(true); ResourceLoader::clear_translation_remaps(); //no remaps using during editor + ResourceLoader::clear_path_remaps(); editor_initialize_certificates(); //for asset sharing InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton()); @@ -5659,6 +5661,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(TextureRegionEditorPlugin(this))); add_editor_plugin(memnew(Particles2DEditorPlugin(this))); add_editor_plugin(memnew(GIProbeEditorPlugin(this))); + add_editor_plugin(memnew(BakedLightmapEditorPlugin(this))); add_editor_plugin(memnew(Path2DEditorPlugin(this))); add_editor_plugin(memnew(PathEditorPlugin(this))); add_editor_plugin(memnew(Line2DEditorPlugin(this))); @@ -5715,6 +5718,11 @@ EditorNode::EditorNode() { editor_plugins_force_over = memnew(EditorPluginList); editor_plugins_force_input_forwarding = memnew(EditorPluginList); + Ref<EditorExportTextSceneToBinaryPlugin> export_text_to_binary_plugin; + export_text_to_binary_plugin.instance(); + + EditorExport::get_singleton()->add_export_plugin(export_text_to_binary_plugin); + _edit_current(); current = NULL; diff --git a/editor/editor_node.h b/editor/editor_node.h index 658d5dc0ae..e7ef9eefb5 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -745,8 +745,8 @@ public: static void add_io_error(const String &p_error); - static void progress_add_task(const String &p_task, const String &p_label, int p_steps); - static void progress_task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_refresh = true); + static void progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel = false); + static bool progress_task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_refresh = true); static void progress_end_task(const String &p_task); static void progress_add_task_bg(const String &p_task, const String &p_label, int p_steps); @@ -807,9 +807,9 @@ public: struct EditorProgress { String task; - void step(const String &p_state, int p_step = -1, bool p_force_refresh = true) { EditorNode::progress_task_step(task, p_state, p_step, p_force_refresh); } - EditorProgress(const String &p_task, const String &p_label, int p_amount) { - EditorNode::progress_add_task(p_task, p_label, p_amount); + bool step(const String &p_state, int p_step = -1, bool p_force_refresh = true) { return EditorNode::progress_task_step(task, p_state, p_step, p_force_refresh); } + EditorProgress(const String &p_task, const String &p_label, int p_amount, bool p_can_cancel = false) { + EditorNode::progress_add_task(p_task, p_label, p_amount, p_can_cancel); task = p_task; } ~EditorProgress() { EditorNode::progress_end_task(task); } diff --git a/editor/icons/icon_GUI_visibility_hidden.svg b/editor/icons/icon_GUI_visibility_hidden.svg index 2add2e9eb8..61131c77c8 100644 --- a/editor/icons/icon_GUI_visibility_hidden.svg +++ b/editor/icons/icon_GUI_visibility_hidden.svg @@ -1,55 +1,3 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="16" - height="16" - version="1.1" - viewBox="0 0 16 16" - id="svg2" - inkscape:version="0.91 r13725" - sodipodi:docname="icon_GUI_visibility_hidden.svg"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1027" - id="namedview8" - showgrid="false" - inkscape:zoom="14.75" - inkscape:cx="18.882384" - inkscape:cy="7.2939487" - inkscape:window-x="-8" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg2" /> - <path - style="color:#000000;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-opacity:1;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" - d="M 8.3320312 2.1328125 C 8.1166713 2.129146 7.900423 2.1368613 7.6855469 2.1542969 C 4.8418629 2.3850399 2.1034153 4.4237115 1.0449219 7.5722656 C 0.98765482 7.7577705 0.9856205 7.9559357 1.0390625 8.1425781 C 1.2458895 8.8664725 1.5352035 9.5092453 1.8730469 10.089844 L 12.501953 3.7890625 C 11.256805 2.6845102 9.797893 2.1577685 8.3320312 2.1328125 z M 14.554688 3.3046875 L 0.7421875 11.507812 L 1.4453125 12.695312 L 15.257812 4.4921875 L 14.554688 3.3046875 z M 14.169922 5.8847656 L 3.6171875 12.140625 C 4.9944165 13.294116 6.6188565 13.867188 8 13.867188 C 10.5 13.867188 13.836536 12.077978 14.960938 8.1425781 C 15.012856 7.9619931 15.012856 7.7704285 14.960938 7.5898438 C 14.731965 6.9583712 14.46336 6.3981967 14.169922 5.8847656 z " - id="path6" /> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m7.9998 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -0.00586 0.5703c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0 -0.5527c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4 -4 4 4 0 0 1 4 -4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2z" color="#000000" color-rendering="auto" fill="#e0e0e0" fill-opacity=".39216" fill-rule="evenodd" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/> </svg> diff --git a/editor/icons/icon_GUI_visibility_visible.svg b/editor/icons/icon_GUI_visibility_visible.svg index 11ae563779..e3aff37058 100644 --- a/editor/icons/icon_GUI_visibility_visible.svg +++ b/editor/icons/icon_GUI_visibility_visible.svg @@ -1,63 +1,3 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="16" - height="16" - version="1.1" - viewBox="0 0 16 16" - id="svg2" - inkscape:version="0.91 r13725" - sodipodi:docname="icon_visibility_visible.svg"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1027" - id="namedview8" - showgrid="false" - inkscape:zoom="14.75" - inkscape:cx="15.823281" - inkscape:cy="12.108563" - inkscape:window-x="-8" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg2" /> - <g - transform="translate(0 -1036.4)" - id="g4" - style="fill:#e0e0e0;fill-opacity:1"> - <path - transform="translate(0,1036.4)" - d="M 8,2 C 5.4433,2 2.2093,3.9477 1.0449,7.7051 c -0.0572671,0.1855049 -0.059303,0.3836676 -0.00586,0.57031 1.1244,3.9354 4.4609,5.7246 6.9609,5.7246 2.5000004,0 5.8365004,-1.7892 6.9609004,-5.7246 0.05192,-0.180585 0.05192,-0.372145 0,-0.55273 -1.1003,-3.7876 -4.4066,-5.7227 -6.9609004,-5.7227 z m 0,2 c 2.209139,0 4,1.790861 4,4 0,2.209139 -1.790861,4 -4,4 C 5.790861,12 4,10.209139 4,8 4,5.790861 5.790861,4 8,4 Z M 8,6 C 6.8954305,6 6,6.8954305 6,8 6,9.1045695 6.8954305,10 8,10 9.1045695,10 10,9.1045695 10,8 10,6.8954305 9.1045695,6 8,6 Z" - style="color:#000000;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-opacity:1;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" - id="path6" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccsccccssssssssss" /> - </g> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m8 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -0.00586 0.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0 -0.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4 -4 4 4 0 0 1 4 -4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2z" color="#000000" color-rendering="auto" fill="#e0e0e0" fill-opacity=".99608" fill-rule="evenodd" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/> </svg> diff --git a/editor/icons/icon_GUI_visibility_xray.svg b/editor/icons/icon_GUI_visibility_xray.svg index 1fd9fcf1b5..b78709821f 100644 --- a/editor/icons/icon_GUI_visibility_xray.svg +++ b/editor/icons/icon_GUI_visibility_xray.svg @@ -1,61 +1,6 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="16" - height="16" - version="1.1" - viewBox="0 0 16 16" - id="svg2" - inkscape:version="0.91 r13725" - sodipodi:docname="icon_GUI_visibility_xray.svg"> - <metadata - id="metadata12"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs10" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1027" - id="namedview8" - showgrid="false" - inkscape:zoom="7.375" - inkscape:cx="43.019438" - inkscape:cy="-8.9853027" - inkscape:window-x="-8" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg2" /> - <g - transform="translate(0.20338214,-1036.671)" - id="g4" - style="fill:#e0e0e0;fill-opacity:1" /> - <path - id="path4154" - style="opacity:1;fill:#e0e0e0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42799997;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - d="m 5.0107427,7.1191578 c -0.084872,0.2859445 -0.1282828,0.5825859 -0.128907,0.8808593 8.579e-4,0.263009 0.034983,0.5248532 0.101563,0.7792969 l 6.0312493,0 C 11.081887,8.5249547 11.116668,8.2631092 11.118164,8.0000171 11.11754,7.7017437 11.074129,7.4051023 10.989257,7.1191578 Z M 7.9999096,2.000005 c -2.5567,0 -5.7907,1.9477 -6.9551,5.7051 -0.057267,0.1855049 -0.059303,0.3836676 -0.00586,0.57031 1.1244,3.9354 4.4609,5.7246 6.9609,5.7246 2.4999994,0 5.8364994,-1.7892 6.9608994,-5.7246 0.05192,-0.180585 0.05192,-0.372145 0,-0.55273 -1.1003,-3.7876 -4.4066,-5.7227 -6.9608994,-5.7227 z m 0,2 c 2.2091384,0 3.9999994,1.790861 3.9999994,4 0,2.209139 -1.790861,4 -3.9999994,4 -2.209139,0 -4,-1.790861 -4,-4 0,-2.209139 1.790861,-4 4,-4 z" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccccccccsccccsssss" /> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<g fill="#e0e0e0" fill-rule="evenodd" shape-rendering="auto"> +<path d="m7.9998 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -0.00586 0.5703c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0 -0.5527c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4 -4 4 4 0 0 1 4 -4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2z" color="#000000" color-rendering="auto" fill-opacity=".39216" image-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/> +<path d="m8 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -0.00586 0.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246v-2a4 4 0 0 1 -4 -4 4 4 0 0 1 4 -4zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2z" color="#000000" color-rendering="auto" fill-opacity=".99608" image-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/> +</g> </svg> diff --git a/editor/icons/icon_bake.svg b/editor/icons/icon_bake.svg index 4a9ccfed12..ca5245da10 100644 --- a/editor/icons/icon_bake.svg +++ b/editor/icons/icon_bake.svg @@ -1,5 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m2 1v2h12v-2h-12zm-1 3v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-9h-14zm2 1h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm-9 2h10v6h-10v-6zm3 1v1h4v-1h-4z" fill="#e0e0e0"/> -</g> +<path d="m2 1v2h12v-2h-12zm-1 3v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-9h-14zm2 1h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm-9 2h10v6h-10v-6zm3 1v1h4v-1h-4z" fill="#e0e0e0"/> </svg> diff --git a/editor/icons/icon_baked_light.svg b/editor/icons/icon_baked_light.svg deleted file mode 100644 index f5bf07a444..0000000000 --- a/editor/icons/icon_baked_light.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m2 1v2h12v-2h-12zm-1 3v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-9h-14zm2 1h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm-9 2h10v6h-10v-6zm3 1v1h4v-1h-4z" fill="#fc9c9c"/> -</g> -</svg> diff --git a/editor/icons/icon_baked_light_instance.svg b/editor/icons/icon_baked_light_instance.svg deleted file mode 100644 index f5bf07a444..0000000000 --- a/editor/icons/icon_baked_light_instance.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m2 1v2h12v-2h-12zm-1 3v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-9h-14zm2 1h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm-9 2h10v6h-10v-6zm3 1v1h4v-1h-4z" fill="#fc9c9c"/> -</g> -</svg> diff --git a/editor/icons/icon_baked_light_sampler.svg b/editor/icons/icon_baked_light_sampler.svg deleted file mode 100644 index 0bf630039d..0000000000 --- a/editor/icons/icon_baked_light_sampler.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m2 1v2h12v-2h-12zm-1 3v9a2 2 0 0 0 2 2h4v-2h-4v-6h4 6 2v-3h-14zm2 1h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm-6 3v1h1v-1h-1zm4 1a1 1 0 0 0 -1 1v4a1 1 0 0 0 1 1h4a1 1 0 0 0 1 -1v-4a1 1 0 0 0 -1 -1h-4zm3 1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm-2 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#fc9c9c"/> -</g> -</svg> diff --git a/editor/icons/icon_baked_lightmap.svg b/editor/icons/icon_baked_lightmap.svg new file mode 100644 index 0000000000..6c6586244e --- /dev/null +++ b/editor/icons/icon_baked_lightmap.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m2 1v2h12v-2h-12zm-1 3v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-9h-14zm2 1h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm3 0h1v1h-1v-1zm-9 2h10v6h-10v-6zm3 1v1h4v-1h-4z" fill="#fc9c9c"/> +</svg> diff --git a/editor/icons/icon_baked_lightmap_data.svg b/editor/icons/icon_baked_lightmap_data.svg new file mode 100644 index 0000000000..b5ddd24680 --- /dev/null +++ b/editor/icons/icon_baked_lightmap_data.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m1 1v2h2v-2h-2zm3 0v2h2v-2h-2zm4 0v2h6v-2h-6zm-7 3v2h2v-2h-2zm3 0v2h2v-2h-2zm4 0v3h5v6h-5v2h5a2 2 0 0 0 2 -2v-9h-7zm1 1h1v1h-1v-1zm3 0h1v1h-1v-1zm-11 2v2h2v-2h-2zm3 0v2h2v-2h-2zm4 1v1h2v-1h-2zm-7 2v2h2v-2h-2zm3 0v2h2v-2h-2zm-3 3v2h2v-2h-2zm3 0v2h2v-2h-2z" fill="#e0e0e0"/> +</svg> diff --git a/editor/icons/icon_editor_handle.svg b/editor/icons/icon_editor_handle.svg index 05f3e2f2cc..f215820ddc 100644 --- a/editor/icons/icon_editor_handle.svg +++ b/editor/icons/icon_editor_handle.svg @@ -1,7 +1,5 @@ <svg width="10" height="10" version="1.1" viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1042.4)"> -<ellipse cx="5" cy="1047.4" rx="5" ry="5" fill-opacity=".29412"/> -<ellipse cx="5" cy="1047.4" rx="4" ry="4" fill="#fff"/> -<ellipse cx="5" cy="1047.4" rx="3" ry="3" fill="#ff8484"/> -</g> +<circle cx="5" cy="5" r="5" fill-opacity=".29412"/> +<circle cx="5" cy="5" r="4" fill="#fff"/> +<circle cx="5" cy="5" r="3" fill="#ff8484"/> </svg> diff --git a/editor/icons/icon_editor_handle_add.svg b/editor/icons/icon_editor_handle_add.svg index be61cd53f9..a8bc1fdc9b 100644 --- a/editor/icons/icon_editor_handle_add.svg +++ b/editor/icons/icon_editor_handle_add.svg @@ -1,5 +1,5 @@ <svg width="10" height="10" version="1.1" viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"> - <circle cx="5" cy="5" r="5" fill-opacity=".29412"/> - <circle cx="5" cy="5" r="4" fill="#474747"/> - <path d="m4 2v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#84ffb1"/> +<circle cx="5" cy="5" r="5" fill-opacity=".29412"/> +<circle cx="5" cy="5" r="4" fill="#474747"/> +<path d="m4 2v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#84ffb1"/> </svg> diff --git a/editor/icons/icon_editor_plugin.svg b/editor/icons/icon_editor_plugin.svg index 528a583a04..e68d787bd3 100644 --- a/editor/icons/icon_editor_plugin.svg +++ b/editor/icons/icon_editor_plugin.svg @@ -1,9 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)" fill="#e0e0e0" fill-opacity=".99608"> -<path d="m2 1038.4v8h8v-8z" fill-rule="evenodd" stroke="#e0e0e0" stroke-linejoin="round" stroke-opacity=".99608" stroke-width="2"/> -<circle cx="13" cy="1042.4" r="2"/> -<circle cx="6" cy="1049.4" r="2"/> -<rect x="5" y="1046.4" width="2" height="2"/> -<rect x="10" y="1041.4" width="2" height="2"/> -</g> +<path d="m2 1c-0.55226 1e-4 -0.99994 0.4477-1 1v8c5.52e-5 0.5523 0.44774 0.9999 1 1h3v0.27148a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -1 -1.7305v-0.26953h3c0.55226-1e-4 0.99994-0.4477 1-1v-3h0.27148a2 2 0 0 0 1.7285 1 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2 2 2 0 0 0 -1.7305 1h-0.26953v-3c-5.5e-5 -0.5523-0.44774-0.9999-1-1h-8z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#e0e0e0" fill-opacity=".99608" fill-rule="evenodd" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> </svg> diff --git a/editor/icons/icon_gizmo_baked_lightmap.svg b/editor/icons/icon_gizmo_baked_lightmap.svg new file mode 100644 index 0000000000..cc21b7c1c5 --- /dev/null +++ b/editor/icons/icon_gizmo_baked_lightmap.svg @@ -0,0 +1,4 @@ +<svg width="128" height="128" version="1.1" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"> +<path d="m18 8c-2.209 2.2e-4 -3.9998 1.791-4 4l0.01563 20h-6.0156c-2.209 2.2e-4 -3.9998 1.791-4 4v71.076c0 9.3065 7.6174 16.924 16.924 16.924h61.076c2.209-2e-4 3.9998-1.791 4-4v-12c-2.21e-4 -2.209-1.791-3.9998-4-4h-58v-40h20v12c2.21e-4 2.209 1.791 3.9998 4 4h32c2.209-2e-4 3.9998-1.791 4-4v-12h20v4c2e-3 0.72576 0.20093 1.4374 0.57617 2.0586-0.19584-6e-3 -0.37901-0.058594-0.57617-0.058594-10.998 0-20 9.0016-20 20-4e-6 0-4e-6 0.0098 0 0.0098 0.0088 6.2734 3.0833 12.01 8 15.756v2.2383c0 2.8834 1.66 5.3456 4 6.75v5.2461c2.21e-4 2.209 1.791 3.9998 4 4h8c2.209-2e-4 3.9998-1.791 4-4v-5.248c2.3405-1.4043 4-3.8682 4-6.752v-2.2344c4.9179-3.7475 7.9931-9.4866 8-15.762 0-7.935-4.7186-14.774-11.459-18h7.459c2.209-2.2e-4 3.9998-1.791 4-4v-32c-2.2e-4 -2.209-1.791-3.9998-4-4l-6-0.003906v-19.996c-2.2e-4 -2.209-1.791-3.9998-4-4zm8 38c1.1519 0 2 0.84806 2 2 3e-6 1.1519-0.84806 2-2 2s-2-0.84806-2-2c-3e-6 -1.1519 0.84806-2 2-2zm25 0c1.1519 0 2 0.84806 2 2 3e-6 1.1519-0.84806 2-2 2s-2-0.84806-2-2c-3e-6 -1.1519 0.84806-2 2-2zm26 0c1.1519 0 2 0.84806 2 2 3e-6 1.1519-0.84806 2-2 2s-2-0.84806-2-2c-3e-6 -1.1519 0.84806-2 2-2zm25 0c1.1519 0 2 0.84806 2 2s-0.84806 2-2 2-2-0.84806-2-2c-3e-6 -1.1519 0.84806-2 2-2zm2 38c3.3611 0 6 2.6388 6 6 0 3.361-2.639 6-6 6-3.361 0-6-2.639-6-6 0-3.3612 2.6389-6 6-6z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill-opacity=".29412" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> +<path d="m18 12v16h92v-16zm-10 24v71.076c0 7.1594 5.7644 12.924 12.924 12.924h61.076v-12h-62v-48h88v8h12v-32zm18 6c3.3137-1e-5 6 2.6863 6 6 9e-6 3.3137-2.6863 6-6 6-3.3137 1e-5 -6-2.6863-6-6-9e-6 -3.3137 2.6863-6 6-6zm25 0c3.3137-1e-5 6 2.6863 6 6 9e-6 3.3137-2.6863 6-6 6-3.3137 1e-5 -6-2.6863-6-6-9e-6 -3.3137 2.6863-6 6-6zm26 0c3.3137-1e-5 6 2.6863 6 6 9e-6 3.3137-2.6863 6-6 6-3.3137 1e-5 -6-2.6863-6-6-9e-6 -3.3137 2.6863-6 6-6zm25 0c3.3137-1e-5 6 2.6863 6 6 1e-5 3.3137-2.6863 6-6 6-3.3137 1e-5 -6-2.6863-6-6-9e-6 -3.3137 2.6863-6 6-6zm-54 26v8h32v-8zm56 6c-8.8365 0-16 7.1634-16 16 8e-3 5.7082 3.0565 10.98 8 13.834v4.166c0 2.216 1.784 4 4 4h8c2.216 0 4-1.784 4-4v-4.1602c4.945-2.855 7.9937-8.1299 8-13.84 0-8.8366-7.1635-16-16-16zm0 6c5.5228 0 10 4.4771 10 10 0 5.5228-4.4772 10-10 10-5.5228 0-10-4.4772-10-10 0-5.5229 4.4772-10 10-10zm-4 36v4h8v-4z" fill="#f7f5cf"/> +</svg> diff --git a/editor/icons/icon_hidden.svg b/editor/icons/icon_hidden.svg deleted file mode 100644 index 8328156e76..0000000000 --- a/editor/icons/icon_hidden.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m2.9609 7.7266l-1.9219 0.54883c0.31999 1.12 0.8236 2.0593 1.4316 2.8398l-0.83398 0.83398 1.4141 1.4141 0.84375-0.84375c0.98585 0.74762 2.0766 1.2067 3.1055 1.3867v1.0938h2v-1.0938c1.0288-0.17998 2.1196-0.6391 3.1055-1.3867l0.84375 0.84375 1.4141-1.4141-0.83398-0.83398c0.60804-0.78055 1.1117-1.7199 1.4316-2.8398l-1.9219-0.54883c-0.8756 3.0646-3.5391 4.2734-5.0391 4.2734s-4.1635-1.2088-5.0391-4.2734z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#e0e0e0" fill-opacity=".99608" fill-rule="evenodd" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="filter-blend-mode:normal;filter-gaussianBlur-deviation:0;font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> -</g> -</svg> diff --git a/editor/icons/icon_kinematic_body_2d.svg b/editor/icons/icon_kinematic_body_2d.svg index 51026e5f28..0441e499c0 100644 --- a/editor/icons/icon_kinematic_body_2d.svg +++ b/editor/icons/icon_kinematic_body_2d.svg @@ -1,7 +1,7 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <g transform="translate(0 -1036.4)"> -<g transform="translate(.49212 -.0044019)" fill="#a5b7f5" fill-opacity=".98824"> -<path transform="translate(0 1036.4)" d="m6 1c-0.55401 0-1 0.44599-1 1v3c0 0.55401 0.44599 1 1 1h1v0.99023a1.0001 1.0001 0 0 0 -0.31641 0.0625l-2.0508 0.68359-0.68359-2.0508a1.0001 1.0001 0 0 0 -0.99023 -0.69727 1.0001 1.0001 0 0 0 -0.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656 0.63281l1.6836-0.56055v0.61133c0 0.04088 0.018715 0.07566 0.023437 0.11523l-4.5781 3.0527a1.0001 1.0001 0 1 0 1.1094 1.6641l5.0566-3.3711 1.4941 2.9863a1.0001 1.0001 0 0 0 1.2109 0.50195l3-1a1.0001 1.0001 0 1 0 -0.63281 -1.8965l-2.1777 0.72461-0.97461-1.9512c0.2759-0.17764 0.46875-0.47227 0.46875-0.82617v-1h1.3828l0.72266 1.4473a1.0001 1.0001 0 1 0 1.7891 -0.89453l-1-2a1.0001 1.0001 0 0 0 -0.89453 -0.55273h-3v-1h1c0.55401 0 1-0.44599 1-1v-3c0-0.55401-0.44599-1-1-1zm0 2h1v2h-1z" fill="#a5b7f5" fill-opacity=".98824"/> +<g transform="translate(.49212 -.0044019)" fill="#a5b7f3"> +<path transform="translate(0 1036.4)" d="m6 1c-0.55401 0-1 0.44599-1 1v3c0 0.55401 0.44599 1 1 1h1v0.99023a1.0001 1.0001 0 0 0 -0.31641 0.0625l-2.0508 0.68359-0.68359-2.0508a1.0001 1.0001 0 0 0 -0.99023 -0.69727 1.0001 1.0001 0 0 0 -0.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656 0.63281l1.6836-0.56055v0.61133c0 0.04088 0.018715 0.07566 0.023437 0.11523l-4.5781 3.0527a1.0001 1.0001 0 1 0 1.1094 1.6641l5.0566-3.3711 1.4941 2.9863a1.0001 1.0001 0 0 0 1.2109 0.50195l3-1a1.0001 1.0001 0 1 0 -0.63281 -1.8965l-2.1777 0.72461-0.97461-1.9512c0.2759-0.17764 0.46875-0.47227 0.46875-0.82617v-1h1.3828l0.72266 1.4473a1.0001 1.0001 0 1 0 1.7891 -0.89453l-1-2a1.0001 1.0001 0 0 0 -0.89453 -0.55273h-3v-1h1c0.55401 0 1-0.44599 1-1v-3c0-0.55401-0.44599-1-1-1zm0 2h1v2h-1z" fill="#a5b7f3"/> </g> </g> </svg> diff --git a/editor/icons/icon_plugin_script.svg b/editor/icons/icon_plugin_script.svg new file mode 100644 index 0000000000..763cca3a92 --- /dev/null +++ b/editor/icons/icon_plugin_script.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m7 1l-0.56445 2.2578c-0.23643 0.075851-0.46689 0.16921-0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941c-0.11191 0.22113-0.20723 0.45028-0.28516 0.68555l-2.2539 0.5625v2l2.2578 0.56445c0.048141 0.14946 0.11579 0.29137 0.17773 0.43555h0.58789c0.51595-0.6841 1.1988-1.2456 2.0195-1.5957-0.028019-0.13296-0.042416-0.26842-0.042969-0.4043 9.6e-6 -1.1046 0.89543-2 2-2 1.1046 9.6e-6 2 0.89543 2 2-1.737e-4 0.1345-0.013915 0.26865-0.041016 0.40039 0.82295 0.35108 1.509 0.91301 2.0254 1.5996h0.58008c0.063668-0.14463 0.13192-0.2874 0.18164-0.4375l2.2539-0.5625v-2l-2.2578-0.56445c-0.075942-0.23577-0.1693-0.46557-0.2793-0.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953c-0.22113-0.11191-0.45028-0.20723-0.68555-0.28516l-0.5625-2.2539h-2zm1 6a1 1 0 0 0 -0.99805 0.92969 1 1 0 0 0 -0.0019531 0.070312v2.1738a3 3 0 0 0 -2 2.8262h1v2h1v-2h2v2h1v-2h1a3 3 0 0 0 -0.015625 -0.29883 3 3 0 0 0 -1.9844 -2.5254v-2.1758a1 1 0 0 0 -1 -1z" fill="#e0e0e0"/> +</svg> diff --git a/editor/icons/icon_proxy_texture.svg b/editor/icons/icon_proxy_texture.svg new file mode 100644 index 0000000000..15ed5e7f2b --- /dev/null +++ b/editor/icons/icon_proxy_texture.svg @@ -0,0 +1,5 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<g transform="translate(0 -1036.4)"> +<path transform="translate(0 1036.4)" d="m1 1v4h4v-4h-4zm6 0v2h6v8h-6v4h7a1 1 0 0 0 1 -1v-12a1 1 0 0 0 -1 -1h-7zm2 4v1h-1v1h-1v3h1 2 2v-2h-1v-2h-1v-1h-1zm-8 1v4h4v-4h-4zm0 5v4h4v-4h-4z" fill="#e0e0e0" fill-opacity=".99608"/> +</g> +</svg> diff --git a/editor/icons/icon_sprite.svg b/editor/icons/icon_sprite.svg index 09fc2f0979..11ad42ec98 100644 --- a/editor/icons/icon_sprite.svg +++ b/editor/icons/icon_sprite.svg @@ -1,3 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<path d="m5 1c-2.216 0-4 1.784-4 4v6c0 2.216 1.784 4 4 4h6c2.216 0 4-1.784 4-4v-6c0-2.216-1.784-4-4-4h-6zm-1 5c0.554 0 1 0.446 1 1v2c0 0.554-0.446 1-1 1s-1-0.446-1-1v-2c0-0.554 0.446-1 1-1zm8 0c0.554 0 1 0.446 1 1v2c0 0.554-0.446 1-1 1s-1-0.446-1-1v-2c0-0.554 0.446-1 1-1zm-1.8887 5.1074a1.0001 1.0001 0 0 1 0.7168 1.7207c-0.74987 0.74987-1.7676 1.1719-2.8281 1.1719s-2.0783-0.422-2.8281-1.1719a1.0001 1.0001 0 0 1 0.69727 -1.7168 1.0001 1.0001 0 0 1 0.7168 0.30273c0.37534 0.37535 0.88325 0.58594 1.4141 0.58594s1.0387-0.21059 1.4141-0.58594a1.0001 1.0001 0 0 1 0.69727 -0.30664z" fill="#a5b7f6" fill-opacity=".98824"/> +<path d="m5 1c-2.216 0-4 1.784-4 4v6c0 2.216 1.784 4 4 4h6c2.216 0 4-1.784 4-4v-6c0-2.216-1.784-4-4-4h-6zm-1 5c0.554 0 1 0.446 1 1v2c0 0.554-0.446 1-1 1s-1-0.446-1-1v-2c0-0.554 0.446-1 1-1zm8 0c0.554 0 1 0.446 1 1v2c0 0.554-0.446 1-1 1s-1-0.446-1-1v-2c0-0.554 0.446-1 1-1zm-1.8887 5.1074a1.0001 1.0001 0 0 1 0.7168 1.7207c-0.74987 0.74987-1.7676 1.1719-2.8281 1.1719s-2.0783-0.422-2.8281-1.1719a1.0001 1.0001 0 0 1 0.69727 -1.7168 1.0001 1.0001 0 0 1 0.7168 0.30273c0.37534 0.37535 0.88325 0.58594 1.4141 0.58594s1.0387-0.21059 1.4141-0.58594a1.0001 1.0001 0 0 1 0.69727 -0.30664z" fill="#a5b7f3"/> </svg> diff --git a/editor/icons/icon_visible.svg b/editor/icons/icon_visible.svg deleted file mode 100644 index 7d157d7b7f..0000000000 --- a/editor/icons/icon_visible.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m8 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -0.0058594 0.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0 -0.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4 -4 4 4 0 0 1 4 -4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2z" color="#000000" color-rendering="auto" fill="#e0e0e0" fill-opacity=".99608" fill-rule="evenodd" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="block-progression:tb;isolation:auto;mix-blend-mode:normal;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/> -</g> -</svg> diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 08d2897250..ed7c6dba79 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1165,8 +1165,8 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), meshes_out ? 1 : 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps"), 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.05)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15)); diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/baked_lightmap_editor_plugin.cpp new file mode 100644 index 0000000000..08f4d06ef7 --- /dev/null +++ b/editor/plugins/baked_lightmap_editor_plugin.cpp @@ -0,0 +1,95 @@ +#include "baked_lightmap_editor_plugin.h" + +void BakedLightmapEditorPlugin::_bake() { + + if (lightmap) { + BakedLightmap::BakeError err; + if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) { + err = lightmap->bake(lightmap); + } else { + err = lightmap->bake(lightmap->get_parent()); + } + + switch (err) { + case BakedLightmap::BAKE_ERROR_NO_SAVE_PATH: + EditorNode::get_singleton()->show_warning(TTR("Can't determine a save path for lightmap images.\nSave your scene (for images to be saved in the same dir), or pick a save path from the BakedLightmap properties.")); + break; + case BakedLightmap::BAKE_ERROR_NO_MESHES: + EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on.")); + break; + case BakedLightmap::BAKE_ERROR_CANT_CREATE_IMAGE: + EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable.")); + break; + defaut : {} + } + } +} + +void BakedLightmapEditorPlugin::edit(Object *p_object) { + + BakedLightmap *s = Object::cast_to<BakedLightmap>(p_object); + if (!s) + return; + + lightmap = s; +} + +bool BakedLightmapEditorPlugin::handles(Object *p_object) const { + + return p_object->is_class("BakedLightmap"); +} + +void BakedLightmapEditorPlugin::make_visible(bool p_visible) { + + if (p_visible) { + bake->show(); + } else { + + bake->hide(); + } +} + +EditorProgress *BakedLightmapEditorPlugin::tmp_progress = NULL; + +void BakedLightmapEditorPlugin::bake_func_begin(int p_steps) { + + ERR_FAIL_COND(tmp_progress != NULL); + + tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), p_steps, true)); +} + +bool BakedLightmapEditorPlugin::bake_func_step(int p_step, const String &p_description) { + + ERR_FAIL_COND_V(tmp_progress == NULL, false); + return tmp_progress->step(p_description, p_step); +} + +void BakedLightmapEditorPlugin::bake_func_end() { + ERR_FAIL_COND(tmp_progress == NULL); + memdelete(tmp_progress); + tmp_progress = NULL; +} + +void BakedLightmapEditorPlugin::_bind_methods() { + + ClassDB::bind_method("_bake", &BakedLightmapEditorPlugin::_bake); +} + +BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) { + + editor = p_node; + bake = memnew(Button); + bake->set_icon(editor->get_gui_base()->get_icon("Bake", "EditorIcons")); + bake->set_text(TTR("Bake Lightmaps")); + bake->hide(); + bake->connect("pressed", this, "_bake"); + add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake); + lightmap = NULL; + + BakedLightmap::bake_begin_function = bake_func_begin; + BakedLightmap::bake_step_function = bake_func_step; + BakedLightmap::bake_end_function = bake_func_end; +} + +BakedLightmapEditorPlugin::~BakedLightmapEditorPlugin() { +} diff --git a/editor/plugins/baked_lightmap_editor_plugin.h b/editor/plugins/baked_lightmap_editor_plugin.h new file mode 100644 index 0000000000..d64c33884a --- /dev/null +++ b/editor/plugins/baked_lightmap_editor_plugin.h @@ -0,0 +1,39 @@ +#ifndef BAKED_LIGHTMAP_EDITOR_PLUGIN_H +#define BAKED_LIGHTMAP_EDITOR_PLUGIN_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "scene/3d/baked_lightmap.h" +#include "scene/resources/material.h" + +class BakedLightmapEditorPlugin : public EditorPlugin { + + GDCLASS(BakedLightmapEditorPlugin, EditorPlugin); + + BakedLightmap *lightmap; + + Button *bake; + EditorNode *editor; + + static EditorProgress *tmp_progress; + static void bake_func_begin(int p_steps); + static bool bake_func_step(int p_step, const String &p_description); + static void bake_func_end(); + + void _bake(); + +protected: + static void _bind_methods(); + +public: + virtual String get_name() const { return "BakedLightmap"; } + bool has_main_screen() const { return false; } + virtual void edit(Object *p_object); + virtual bool handles(Object *p_object) const; + virtual void make_visible(bool p_visible); + + BakedLightmapEditorPlugin(EditorNode *p_node); + ~BakedLightmapEditorPlugin(); +}; + +#endif // BAKED_LIGHTMAP_EDITOR_PLUGIN_H diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/gi_probe_editor_plugin.cpp index 443cd2e41f..416b0edb20 100644 --- a/editor/plugins/gi_probe_editor_plugin.cpp +++ b/editor/plugins/gi_probe_editor_plugin.cpp @@ -90,7 +90,7 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) { editor = p_node; bake = memnew(Button); - bake->set_icon(editor->get_gui_base()->get_icon("BakedLight", "EditorIcons")); + bake->set_icon(editor->get_gui_base()->get_icon("Bake", "EditorIcons")); bake->set_text(TTR("Bake GI Probe")); bake->hide(); bake->connect("pressed", this, "_bake"); diff --git a/editor/plugins/mesh_instance_editor_plugin.h b/editor/plugins/mesh_instance_editor_plugin.h index 68c149f98a..32c779509a 100644 --- a/editor/plugins/mesh_instance_editor_plugin.h +++ b/editor/plugins/mesh_instance_editor_plugin.h @@ -35,9 +35,9 @@ #include "scene/3d/mesh_instance.h" #include "scene/gui/spin_box.h" -class MeshInstanceEditor : public Node { +class MeshInstanceEditor : public Control { - GDCLASS(MeshInstanceEditor, Node); + GDCLASS(MeshInstanceEditor, Control); enum Menu { diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 95f2739927..17b0e986e7 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -924,26 +924,7 @@ void ScriptTextEditor::_edit_option(int p_op) { if (scr.is_null()) return; - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - tx->indent_selection_left(); - } else { - int begin = tx->cursor_get_line(); - String line_text = tx->get_line(begin); - // begins with tab - if (line_text.begins_with("\t")) { - line_text = line_text.substr(1, line_text.length()); - tx->set_line(begin, line_text); - } - // begins with 4 spaces - else if (line_text.begins_with(" ")) { - line_text = line_text.substr(4, line_text.length()); - tx->set_line(begin, line_text); - } - } - tx->end_complex_operation(); - tx->update(); - //tx->deselect(); + tx->indent_left(); } break; case EDIT_INDENT_RIGHT: { @@ -951,18 +932,7 @@ void ScriptTextEditor::_edit_option(int p_op) { if (scr.is_null()) return; - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - tx->indent_selection_right(); - } else { - int begin = tx->cursor_get_line(); - String line_text = tx->get_line(begin); - line_text = '\t' + line_text; - tx->set_line(begin, line_text); - } - tx->end_complex_operation(); - tx->update(); - //tx->deselect(); + tx->indent_right(); } break; case EDIT_DELETE_LINE: { @@ -1503,14 +1473,15 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); if (p_selection) { context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); } if (p_can_fold || p_is_folded) context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index b390070b4a..3e00776dfd 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -161,7 +161,7 @@ void ShaderTextEditor::_load_theme_settings() { for (const Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())).front(); E; E = E->next()) { - for (const Map<StringName, ShaderLanguage::DataType>::Element *F = E->get().built_ins.front(); F; F = F->next()) { + for (const Map<StringName, ShaderLanguage::BuiltInInfo>::Element *F = E->get().built_ins.front(); F; F = F->next()) { keywords.push_back(F->key()); } } @@ -379,26 +379,7 @@ void ShaderEditor::_menu_option(int p_option) { if (shader.is_null()) return; - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - tx->indent_selection_left(); - } else { - int begin = tx->cursor_get_line(); - String line_text = tx->get_line(begin); - // begins with tab - if (line_text.begins_with("\t")) { - line_text = line_text.substr(1, line_text.length()); - tx->set_line(begin, line_text); - } - // begins with 4 spaces - else if (line_text.begins_with(" ")) { - line_text = line_text.substr(4, line_text.length()); - tx->set_line(begin, line_text); - } - } - tx->end_complex_operation(); - tx->update(); - //tx->deselect(); + tx->indent_left(); } break; case EDIT_INDENT_RIGHT: { @@ -407,18 +388,7 @@ void ShaderEditor::_menu_option(int p_option) { if (shader.is_null()) return; - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - tx->indent_selection_right(); - } else { - int begin = tx->cursor_get_line(); - String line_text = tx->get_line(begin); - line_text = '\t' + line_text; - tx->set_line(begin, line_text); - } - tx->end_complex_operation(); - tx->update(); - //tx->deselect(); + tx->indent_right(); } break; case EDIT_DELETE_LINE: { diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp index 09f5375bb4..2c2e5a7c9b 100644 --- a/editor/progress_dialog.cpp +++ b/editor/progress_dialog.cpp @@ -163,7 +163,7 @@ void ProgressDialog::_popup() { popup_centered(ms); } -void ProgressDialog::add_task(const String &p_task, const String &p_label, int p_steps) { +void ProgressDialog::add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) { ERR_FAIL_COND(tasks.has(p_task)); Task t; @@ -180,17 +180,24 @@ void ProgressDialog::add_task(const String &p_task, const String &p_label, int p main->add_child(t.vb); tasks[p_task] = t; + if (p_can_cancel) { + cancel_hb->show(); + } else { + cancel_hb->hide(); + } + cancel_hb->raise(); + cancelled = false; _popup(); } -void ProgressDialog::task_step(const String &p_task, const String &p_state, int p_step, bool p_force_redraw) { +bool ProgressDialog::task_step(const String &p_task, const String &p_state, int p_step, bool p_force_redraw) { - ERR_FAIL_COND(!tasks.has(p_task)); + ERR_FAIL_COND_V(!tasks.has(p_task), cancelled); if (!p_force_redraw) { uint64_t tus = OS::get_singleton()->get_ticks_usec(); if (tus - last_progress_tick < 50000) //50ms - return; + return cancelled; } Task &t = tasks[p_task]; @@ -201,7 +208,11 @@ void ProgressDialog::task_step(const String &p_task, const String &p_state, int t.state->set_text(p_state); last_progress_tick = OS::get_singleton()->get_ticks_usec(); + if (cancel_hb->is_visible()) { + OS::get_singleton()->force_process_input(); + } Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor + return cancelled; } void ProgressDialog::end_task(const String &p_task) { @@ -218,6 +229,14 @@ void ProgressDialog::end_task(const String &p_task) { _popup(); } +void ProgressDialog::_cancel_pressed() { + cancelled = true; +} + +void ProgressDialog::_bind_methods() { + ClassDB::bind_method("_cancel_pressed", &ProgressDialog::_cancel_pressed); +} + ProgressDialog::ProgressDialog() { main = memnew(VBoxContainer); @@ -226,4 +245,13 @@ ProgressDialog::ProgressDialog() { set_exclusive(true); last_progress_tick = 0; singleton = this; + cancel_hb = memnew(HBoxContainer); + main->add_child(cancel_hb); + cancel_hb->hide(); + cancel = memnew(Button); + cancel_hb->add_spacer(); + cancel_hb->add_child(cancel); + cancel->set_text(TTR("Cancel")); + cancel_hb->add_spacer(); + cancel->connect("pressed", this, "_cancel_pressed"); } diff --git a/editor/progress_dialog.h b/editor/progress_dialog.h index 8ac0907145..b13ea606bc 100644 --- a/editor/progress_dialog.h +++ b/editor/progress_dialog.h @@ -31,6 +31,7 @@ #define PROGRESS_DIALOG_H #include "scene/gui/box_container.h" +#include "scene/gui/button.h" #include "scene/gui/label.h" #include "scene/gui/popup.h" #include "scene/gui/progress_bar.h" @@ -76,6 +77,8 @@ class ProgressDialog : public Popup { ProgressBar *progress; Label *state; }; + HBoxContainer *cancel_hb; + Button *cancel; Map<String, Task> tasks; VBoxContainer *main; @@ -84,13 +87,17 @@ class ProgressDialog : public Popup { static ProgressDialog *singleton; void _popup(); + void _cancel_pressed(); + bool cancelled; + protected: void _notification(int p_what); + static void _bind_methods(); public: static ProgressDialog *get_singleton() { return singleton; } - void add_task(const String &p_task, const String &p_label, int p_steps); - void task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_redraw = true); + void add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel = false); + bool task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_redraw = true); void end_task(const String &p_task); ProgressDialog(); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 25924212fd..827e8d9ee4 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -256,9 +256,9 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { bool v = p_node->call("is_visible"); if (v) - item->add_button(0, get_icon("Visible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility")); + item->add_button(0, get_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility")); else - item->add_button(0, get_icon("Hidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility")); + item->add_button(0, get_icon("GuiVisibilityHidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility")); if (!p_node->is_connected("visibility_changed", this, "_node_visibility_changed")) p_node->connect("visibility_changed", this, "_node_visibility_changed", varray(p_node)); @@ -272,9 +272,9 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { bool v = p_node->call("is_visible"); if (v) - item->add_button(0, get_icon("Visible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility")); + item->add_button(0, get_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility")); else - item->add_button(0, get_icon("Hidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility")); + item->add_button(0, get_icon("GuiVisibilityHidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility")); if (!p_node->is_connected("visibility_changed", this, "_node_visibility_changed")) p_node->connect("visibility_changed", this, "_node_visibility_changed", varray(p_node)); @@ -337,9 +337,9 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) { } if (visible) - item->set_button(0, idx, get_icon("Visible", "EditorIcons")); + item->set_button(0, idx, get_icon("GuiVisibilityVisible", "EditorIcons")); else - item->set_button(0, idx, get_icon("Hidden", "EditorIcons")); + item->set_button(0, idx, get_icon("GuiVisibilityHidden", "EditorIcons")); _update_visibility_color(p_node, item); } @@ -774,9 +774,11 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from Node *n = get_node(np); if (n) { - - selected.push_back(n); - icons.push_back(next->get_icon(0)); + // Only allow selection if not part of an instanced scene. + if (!n->get_owner() || n->get_owner() == get_scene_node() || n->get_owner()->get_filename() == String()) { + selected.push_back(n); + icons.push_back(next->get_icon(0)); + } } next = tree->get_next_selected(next); } diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 3cab14b0c4..25e63319d0 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -331,6 +331,12 @@ void ScriptCreateDialog::_file_selected(const String &p_file) { } else { file_path->set_text(p); _path_changed(p); + + String filename = p.get_file().get_basename(); + int select_start = p.find_last(filename); + file_path->select(select_start, select_start + filename.length()); + file_path->set_cursor_position(select_start + filename.length()); + file_path->grab_focus(); } } @@ -459,7 +465,7 @@ void ScriptCreateDialog::_update_dialog() { script_ok = false; } } - if (has_named_classes && (!is_class_name_valid)) { + if (has_named_classes && (is_new_script_created && !is_class_name_valid)) { _msg_script_valid(false, TTR("Invalid class name")); script_ok = false; } diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index f785b3e198..f0e8d438fa 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -2753,7 +2753,122 @@ GIProbeGizmo::GIProbeGizmo(GIProbe *p_probe) { } //////// +//////// + +/// + +String BakedIndirectLightGizmo::get_handle_name(int p_idx) const { + + switch (p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + } + + return ""; +} +Variant BakedIndirectLightGizmo::get_handle_value(int p_idx) const { + + return baker->get_extents(); +} +void BakedIndirectLightGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { + + Transform gt = baker->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + Vector3 extents = baker->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_idx] = 1.0; + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_idx]; + if (d < 0.001) + d = 0.001; + + extents[p_idx] = d; + baker->set_extents(extents); +} + +void BakedIndirectLightGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { + + Vector3 restore = p_restore; + + if (p_cancel) { + baker->set_extents(restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(baker, "set_extents", baker->get_extents()); + ur->add_undo_method(baker, "set_extents", restore); + ur->commit_action(); +} +void BakedIndirectLightGizmo::redraw() { + + Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/baked_indirect_light"); + Ref<Material> material = create_material("baked_indirect_light_material", gizmo_color); + Ref<Material> icon = create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_icon("GizmoBakedLightmap", "EditorIcons")); + Color gizmo_color_internal = gizmo_color; + gizmo_color_internal.a = 0.1; + Ref<Material> material_internal = create_material("baked_indirect_light_internal_material", gizmo_color_internal); + + clear(); + + Vector<Vector3> lines; + Vector3 extents = baker->get_extents(); + + static const int subdivs[BakedLightmap::SUBDIV_MAX] = { 64, 128, 256, 512 }; + + AABB aabb = AABB(-extents, extents * 2); + int subdiv = subdivs[baker->get_bake_subdiv()]; + float cell_size = aabb.get_longest_axis_size() / subdiv; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + add_lines(lines, material); + add_collision_segments(lines); + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + if (is_selected()) { + + gizmo_color.a = 0.1; + Ref<Material> solid_material = create_material("baked_indirect_light_solid_material", gizmo_color); + add_solid_box(solid_material, aabb.get_size()); + } + + add_unscaled_billboard(icon, 0.05); + add_handles(handles); +} +BakedIndirectLightGizmo::BakedIndirectLightGizmo(BakedLightmap *p_baker) { + + baker = p_baker; + set_spatial_node(p_baker); +} + +//////// void NavigationMeshSpatialGizmo::redraw() { Ref<Material> edge_material = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_edge")); @@ -3409,6 +3524,11 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { Ref<GIProbeGizmo> misg = memnew(GIProbeGizmo(Object::cast_to<GIProbe>(p_spatial))); return misg; } + if (Object::cast_to<BakedLightmap>(p_spatial)) { + + Ref<BakedIndirectLightGizmo> misg = memnew(BakedIndirectLightGizmo(Object::cast_to<BakedLightmap>(p_spatial))); + return misg; + } if (Object::cast_to<VehicleWheel>(p_spatial)) { @@ -3495,6 +3615,7 @@ SpatialEditorGizmos::SpatialEditorGizmos() { EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6)); + EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1)); diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index 751bad2b13..ea8a33d2c6 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -32,6 +32,7 @@ #include "editor/plugins/spatial_editor_plugin.h" #include "scene/3d/audio_stream_player_3d.h" +#include "scene/3d/baked_lightmap.h" #include "scene/3d/camera.h" #include "scene/3d/collision_polygon.h" #include "scene/3d/collision_shape.h" @@ -288,6 +289,22 @@ public: GIProbeGizmo(GIProbe *p_probe = NULL); }; +class BakedIndirectLightGizmo : public EditorSpatialGizmo { + + GDCLASS(BakedIndirectLightGizmo, EditorSpatialGizmo); + + BakedLightmap *baker; + +public: + virtual String get_handle_name(int p_idx) const; + virtual Variant get_handle_value(int p_idx) const; + virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); + virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + + void redraw(); + BakedIndirectLightGizmo(BakedLightmap *p_baker = NULL); +}; + class CollisionShapeSpatialGizmo : public EditorSpatialGizmo { GDCLASS(CollisionShapeSpatialGizmo, EditorSpatialGizmo); diff --git a/main/input_default.cpp b/main/input_default.cpp index 8c91a1a5de..f637e77d56 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -635,7 +635,7 @@ static const char *s_ControllerMappings[] = { "d81d0b00000000000000504944564944,BUFFALO BSGP1601 Series ,x:b4,a:b5,b:b3,y:b2,back:b12,start:b13,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b6,rightshoulder:b9,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "d81d0f00000000000000504944564944,iBUFFALO BSGP1204 Series,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "d81d1000000000000000504944564944,iBUFFALO BSGP1204P Series,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", - "ff113133000000000000504944564944,Gembird JPD-DualForce,a:b2,b:b3,x:b0,y:b1,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,leftstick:b10,rightstick:b11,", + "ff113133000000000000504944564944,SVEN X-PAD,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,", "ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", "__XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,", #endif @@ -684,7 +684,7 @@ static const char *s_ControllerMappings[] = { "0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", "030000000d0f00000d00000000010000,hori,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5,", "030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7", - "030000000d0f00002200000011010000,HORI CO.,LTD. REAL ARCADE Pro.V3,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,", + "030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,", "030000000d0f00004d00000011010000,HORI Gem Pad 3,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,", "030000001008000001e5000010010000,NEXT Classic USB Game Controller,a:b0,b:b1,back:b8,start:b9,rightx:a2,righty:a3,leftx:a0,lefty:a1,", @@ -698,8 +698,8 @@ static const char *s_ControllerMappings[] = { "03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,", "030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,", "030000004c050000a00b000011010000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,", - "030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,", - "030000004c050000c405000011810000,Sony Computer Entertainment Wireless Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:h0.1,rightshoulder:b5,rightx:a3,start:b9,righty:a4,dpleft:h0.8,lefttrigger:a2,x:b3,dpup:h0.1,back:b8,leftstick:b11,leftshoulder:b4,y:b2,a:b0,dpright:h0.2,righttrigger:a5,b:b1,", + "030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,", + "030000004c050000c405000011810000,Sony DualShock 4,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,", "030000004c050000cc09000011010000,Sony DualShock 4 V2,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,", "030000004c050000cc09000011810000,Sony DualShock 4 (CUH-ZCT2U) (USB),a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", "030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,", @@ -718,7 +718,7 @@ static const char *s_ControllerMappings[] = { "030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000005e0400008e02000062230000,Microsoft X-Box 360 pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", - "030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,", "030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000005e040000d102000001010000,Microsoft X-Box One pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", @@ -734,7 +734,7 @@ static const char *s_ControllerMappings[] = { "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "030000006f0e00000103000000020000,Logic3 Controller,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", - "030000006f0e00001304000000010000,Generic X-Box pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", + "030000006f0e00001304000000010000,Generic X-Box pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", "030000006f0e00001f01000000010000,Generic X-Box pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000006f0e00002801000011010000,PDP Rock Candy Wireless Controller for PS3,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b0,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b1,dpright:h0.2,righttrigger:b7,b:b2,", @@ -742,13 +742,13 @@ static const char *s_ControllerMappings[] = { "030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4,", "03000000780000000600000010010000,Microntek USB Joystick,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftx:a0,lefty:a1,", - "03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", - "03000000790000001100000010010000,Retrolink Classic Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,", + "03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,", + "03000000790000001100000010010000,RetroLink Saturn Classic Controller,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", "03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,", "030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,", "030000008916000001fd000024010000,Razer Onza Classic Edition,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,", - "030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", - "030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", + "030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", + "030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,", "030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,x:b1,a:b0,b:b4,y:b5,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,", "03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,", "03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,", @@ -761,7 +761,7 @@ static const char *s_ControllerMappings[] = { "03000000bd12000015d0000010010000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,", "03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,x:b13,y:b11,back:b4,start:b5,leftstick:b14,rightstick:b15,leftshoulder:b9,rightshoulder:b8,dpup:b0,dpdown:b2,dpleft:b3,dpright:b1,leftx:a1,lefty:a0,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,", "03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,y:b0,x:b1,b:b3,a:b4,leftshoulder:b2,rightshoulder:b5,back:b6,start:b7,guide:b9,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftx:a0,lefty:a1,", - "03000000c9110000f055000011010000,HJC Game GAMEPAD,x:b2,a:b0,b:b1,y:b3,back:b4,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,", + "03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,", "03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,", "03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1,", "03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", @@ -778,7 +778,7 @@ static const char *s_ControllerMappings[] = { "05000000380700006652000025010000,Mad Catz C.T.R.L.R ,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", "050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,", - "050000004c050000c405000000010000,PS4 Controller (Bluetooth),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", + "050000004c050000c405000000010000,Sony DualShock 4 BT,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "050000004c050000cc09000000010000,Sony DualShock 4 V2 BT,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b13,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,", "050000004c050000cc09000000810000,Sony DualShock 4 (CUH-ZCT2U) (Bluetooth),a:b0,b:b1,y:b2,x:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,guide:b10,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,", "05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,", diff --git a/main/main.cpp b/main/main.cpp index 1328807121..c6e20f6d3b 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1136,6 +1136,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) { translation_server->load_translations(); ResourceLoader::load_translation_remaps(); //load remaps for resources + ResourceLoader::load_path_remaps(); + audio_server->load_default_bus_layout(); if (use_debug_profiler && script_debugger) { @@ -1816,6 +1818,9 @@ void Main::cleanup() { OS::get_singleton()->_execpath = ""; OS::get_singleton()->_local_clipboard = ""; + ResourceLoader::clear_translation_remaps(); + ResourceLoader::clear_path_remaps(); + ScriptServer::finish_languages(); #ifdef TOOLS_ENABLED diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index ce485956b4..396bebf0ea 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -386,7 +386,7 @@ int NetworkedMultiplayerENet::get_available_packet_count() const { return incoming_packets.size(); } -Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer, int &r_buffer_size) const { +Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { ERR_FAIL_COND_V(incoming_packets.size() == 0, ERR_UNAVAILABLE); @@ -480,7 +480,7 @@ int NetworkedMultiplayerENet::get_max_packet_size() const { return 1 << 24; //anything is good } -void NetworkedMultiplayerENet::_pop_current_packet() const { +void NetworkedMultiplayerENet::_pop_current_packet() { if (current_packet.packet) { enet_packet_destroy(current_packet.packet); diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/networked_multiplayer_enet.h index 81d517147d..d7bc5c7849 100644 --- a/modules/enet/networked_multiplayer_enet.h +++ b/modules/enet/networked_multiplayer_enet.h @@ -86,12 +86,12 @@ private: CompressionMode compression_mode; - mutable List<Packet> incoming_packets; + List<Packet> incoming_packets; - mutable Packet current_packet; + Packet current_packet; uint32_t _gen_unique_id() const; - void _pop_current_packet() const; + void _pop_current_packet(); Vector<uint8_t> src_compressor_mem; Vector<uint8_t> dst_compressor_mem; @@ -123,7 +123,7 @@ public: virtual bool is_server() const; virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) const; ///< buffer is GONE after next get_packet + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); virtual int get_max_packet_size() const; diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 31f3b0b77b..b7b2553435 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -5533,6 +5533,12 @@ ] }, { + "name": "godot_get_stack_bottom", + "return_type": "void *", + "arguments": [ + ] + }, + { "name": "godot_method_bind_get_method", "return_type": "godot_method_bind *", "arguments": [ @@ -5569,6 +5575,12 @@ ] }, { + "name": "godot_get_global_constants", + "return_type": "godot_dictionary", + "arguments": [ + ] + }, + { "name": "godot_register_native_call_type", "return_type": "void", "arguments": [ diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 1e007ddb0f..e707032ed8 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -30,6 +30,7 @@ #include "register_types.h" #include "gdscript.h" +#include "gdscript_tokenizer.h" #include "io/file_access_encrypted.h" #include "io/resource_loader.h" #include "os/file_access.h" @@ -38,6 +39,45 @@ GDScriptLanguage *script_language_gd = NULL; ResourceFormatLoaderGDScript *resource_loader_gd = NULL; ResourceFormatSaverGDScript *resource_saver_gd = NULL; +#ifdef TOOLS_ENABLED + +#include "editor/editor_export.h" +#include "editor/editor_node.h" +#include "editor/editor_settings.h" + +class EditorExportGDScript : public EditorExportPlugin { + + GDCLASS(EditorExportGDScript, EditorExportPlugin); + +public: + virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features) { + + if (!p_path.ends_with(".gd")) + return; + + Vector<uint8_t> file = FileAccess::get_file_as_array(p_path); + if (file.empty()) + return; + String txt; + txt.parse_utf8((const char *)file.ptr(), file.size()); + file = GDScriptTokenizerBuffer::parse_code_string(txt); + + if (file.empty()) + return; + + add_file(p_path.get_basename() + ".gdc", file, true); + } +}; + +static void _editor_init() { + + Ref<EditorExportGDScript> gd_export; + gd_export.instance(); + EditorExport::get_singleton()->add_export_plugin(gd_export); +} + +#endif + void register_gdscript_types() { ClassDB::register_class<GDScript>(); @@ -49,6 +89,10 @@ void register_gdscript_types() { ResourceLoader::add_resource_format_loader(resource_loader_gd); resource_saver_gd = memnew(ResourceFormatSaverGDScript); ResourceSaver::add_resource_format_saver(resource_saver_gd); + +#ifdef TOOLS_ENABLED + EditorNode::add_init_callback(_editor_init); +#endif } void unregister_gdscript_types() { diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index b3a1947647..bebf8bcf8f 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -469,7 +469,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { nm.xform = xform; if (navigation) { - nm.id = navigation->navmesh_create(navmesh, xform, this); + nm.id = navigation->navmesh_add(navmesh, xform, this); } else { nm.id = -1; } @@ -556,7 +556,7 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) { if (cell_map.has(F->key()) && F->get().id < 0) { Ref<NavigationMesh> nm = theme->get_item_navmesh(cell_map[F->key()].item); if (nm.is_valid()) { - F->get().id = navigation->navmesh_create(nm, F->get().xform, this); + F->get().id = navigation->navmesh_add(nm, F->get().xform, this); } } } diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 5bfdf1dac3..ab66bf123e 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -186,6 +186,11 @@ class GridMap : public Spatial { Vector3 _get_offset() const; + struct BakedMesh { + Ref<Mesh> mesh; + Transform transform; + }; + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; diff --git a/modules/thekla_unwrap/SCsub b/modules/thekla_unwrap/SCsub index b489fcc9e7..c57bf326ea 100644 --- a/modules/thekla_unwrap/SCsub +++ b/modules/thekla_unwrap/SCsub @@ -67,7 +67,7 @@ if env['builtin_thekla_atlas']: if env.msvc: env_thekla_unwrap.Append(CCFLAGS=["-DNV_OS_WIN32", "-DNV_CC_MSVC", "-DPOSH_COMPILER_MSVC" ]) else: - env_thekla_unwrap.Append(CCFLAGS=["-DNV_OS_MINGW", "-DNV_CC_GNUC", "-DPOSH_COMPILER_GCC"]) + env_thekla_unwrap.Append(CCFLAGS=["-DNV_OS_MINGW", "-DNV_CC_GNUC", "-DPOSH_COMPILER_GCC", "-U__STRICT_ANSI__"]) env.Append(LIBS=["dbghelp"]) # Godot source files diff --git a/modules/thekla_unwrap/register_types.cpp b/modules/thekla_unwrap/register_types.cpp index 01b834f8cb..ab3203068f 100644 --- a/modules/thekla_unwrap/register_types.cpp +++ b/modules/thekla_unwrap/register_types.cpp @@ -42,7 +42,7 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver input_mesh.face_array[i].vertex_index[0] = p_indices[i * 3 + 0]; input_mesh.face_array[i].vertex_index[1] = p_indices[i * 3 + 1]; input_mesh.face_array[i].vertex_index[2] = p_indices[i * 3 + 2]; - printf("face %i - %i, %i, %i - mat %i\n", i, input_mesh.face_array[i].vertex_index[0], input_mesh.face_array[i].vertex_index[1], input_mesh.face_array[i].vertex_index[2], p_face_materials[i]); + //printf("face %i - %i, %i, %i - mat %i\n", i, input_mesh.face_array[i].vertex_index[0], input_mesh.face_array[i].vertex_index[1], input_mesh.face_array[i].vertex_index[2], p_face_materials[i]); input_mesh.face_array[i].material_index = p_face_materials[i]; } input_mesh.vertex_array = new Thekla::Atlas_Input_Vertex[p_vertex_count]; @@ -54,8 +54,8 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver } input_mesh.vertex_array[i].uv[0] = 0; input_mesh.vertex_array[i].uv[1] = 0; - printf("vertex %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].position[0], input_mesh.vertex_array[i].position[1], input_mesh.vertex_array[i].position[2]); - printf("normal %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].normal[0], input_mesh.vertex_array[i].normal[1], input_mesh.vertex_array[i].normal[2]); + //printf("vertex %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].position[0], input_mesh.vertex_array[i].position[1], input_mesh.vertex_array[i].position[2]); + //printf("normal %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].normal[0], input_mesh.vertex_array[i].normal[1], input_mesh.vertex_array[i].normal[2]); } input_mesh.face_count = p_index_count / 3; input_mesh.vertex_count = p_vertex_count; @@ -65,6 +65,7 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver Thekla::atlas_set_default_options(&options); options.packer_options.witness.packing_quality = 1; options.packer_options.witness.texel_area = 1.0 / p_texel_size; + options.packer_options.witness.conservative = true; //generate Thekla::Atlas_Error err; diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp index 0b105dcb40..b170ba6f35 100644 --- a/platform/javascript/http_client_javascript.cpp +++ b/platform/javascript/http_client_javascript.cpp @@ -37,16 +37,31 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, WARN_PRINT("Disabling HTTPClient's host verification is not supported for the HTML5 platform, host will be verified"); } + port = p_port; + use_tls = p_ssl; + host = p_host; - if (host.begins_with("http://")) { - host.replace_first("http://", ""); - } else if (host.begins_with("https://")) { - host.replace_first("https://", ""); + + String host_lower = host.to_lower(); + if (host_lower.begins_with("http://")) { + host = host.substr(7, host.length() - 7); + } else if (host_lower.begins_with("https://")) { + use_tls = true; + host = host.substr(8, host.length() - 8); + } + + ERR_FAIL_COND_V(host.length() < HOST_MIN_LEN, ERR_INVALID_PARAMETER); + + if (port < 0) { + if (use_tls) { + port = PORT_HTTPS; + } else { + port = PORT_HTTP; + } } status = host.is_valid_ip_address() ? STATUS_CONNECTING : STATUS_RESOLVING; - port = p_port; - use_tls = p_ssl; + return OK; } @@ -68,17 +83,7 @@ Error HTTPClient::prepare_request(Method p_method, const String &p_url, const Ve ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(host.empty(), ERR_UNCONFIGURED); ERR_FAIL_COND_V(port < 0, ERR_UNCONFIGURED); - - static const char *_methods[HTTPClient::METHOD_MAX] = { - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "OPTIONS", - "TRACE", - "CONNECT" - }; + ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER); String url = (use_tls ? "https://" : "http://") + host + ":" + itos(port) + "/" + p_url; godot_xhr_reset(xhr_id); diff --git a/platform/osx/SCsub b/platform/osx/SCsub index cb88bc470a..029e3d808c 100644 --- a/platform/osx/SCsub +++ b/platform/osx/SCsub @@ -4,7 +4,12 @@ import os Import('env') def make_debug(target, source, env): - os.system('dsymutil %s -o %s.dSYM' % (target[0], target[0])) + if (env["macports_clang"] != 'no'): + mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local") + mpclangver = env["macports_clang"] + os.system(mpprefix + '/libexec/llvm-' + mpclangver + '/bin/llvm-dsymutil %s -o %s.dSYM' % (target[0], target[0])) + else: + os.system('dsymutil %s -o %s.dSYM' % (target[0], target[0])) files = [ 'crash_handler_osx.mm', diff --git a/platform/osx/detect.py b/platform/osx/detect.py index ff7cf2ad2f..e8a8319431 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -72,6 +72,19 @@ def configure(env): else: # 64-bit, default env.Append(CCFLAGS=['-arch', 'x86_64']) env.Append(LINKFLAGS=['-arch', 'x86_64']) + if (env["macports_clang"] != 'no'): + mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local") + mpclangver = env["macports_clang"] + env["CC"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/clang" + env["LD"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/clang++" + env["CXX"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/clang++" + env['AR'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ar" + env['RANLIB'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib" + env['AS'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as" + env.Append(CCFLAGS=['-D__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define + if (env["openmp"]): + env.Append(CPPFLAGS=['-fopenmp']) + env.Append(LINKFLAGS=['-fopenmp']) else: # osxcross build root = os.environ.get("OSXCROSS_ROOT", 0) diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 6543ca7dd2..ede50a05ba 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -204,7 +204,7 @@ public: virtual void request_attention(); virtual String get_joy_guid(int p_device) const; - virtual void set_borderless_window(int p_borderless); + virtual void set_borderless_window(bool p_borderless); virtual bool get_borderless_window(); virtual void set_ime_position(const Point2 &p_pos); virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp); @@ -228,6 +228,8 @@ public: virtual Error move_to_trash(const String &p_path); + void force_process_input(); + OS_OSX(); private: diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 75d0bd1648..f3809e6eed 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1818,7 +1818,7 @@ void OS_OSX::request_attention() { [NSApp requestUserAttention:NSCriticalRequest]; } -void OS_OSX::set_borderless_window(int p_borderless) { +void OS_OSX::set_borderless_window(bool p_borderless) { // OrderOut prevents a lose focus bug with the window [window_object orderOut:nil]; @@ -1971,6 +1971,12 @@ void OS_OSX::push_input(const Ref<InputEvent> &p_event) { input->parse_input_event(ev); } +void OS_OSX::force_process_input() { + + process_events(); // get rid of pending events + joypad_osx->process_joypads(); +} + void OS_OSX::run() { force_quit = false; diff --git a/platform/uwp/SCsub b/platform/uwp/SCsub index f0d69fef33..fb0c4a92ae 100644 --- a/platform/uwp/SCsub +++ b/platform/uwp/SCsub @@ -4,9 +4,6 @@ Import('env') files = [ 'thread_uwp.cpp', - '#platform/windows/tcp_server_winsock.cpp', - '#platform/windows/packet_peer_udp_winsock.cpp', - '#platform/windows/stream_peer_winsock.cpp', '#platform/windows/key_mapping_win.cpp', '#platform/windows/windows_terminal_logger.cpp', 'joypad_uwp.cpp', diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 659f162724..3018ac0bef 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -34,13 +34,13 @@ #include "drivers/windows/dir_access_windows.h" #include "drivers/windows/file_access_windows.h" #include "drivers/windows/mutex_windows.h" +#include "drivers/windows/packet_peer_udp_winsock.h" #include "drivers/windows/rw_lock_windows.h" #include "drivers/windows/semaphore_windows.h" +#include "drivers/windows/stream_peer_tcp_winsock.h" +#include "drivers/windows/tcp_server_winsock.h" #include "io/marshalls.h" #include "main/main.h" -#include "platform/windows/packet_peer_udp_winsock.h" -#include "platform/windows/stream_peer_winsock.h" -#include "platform/windows/tcp_server_winsock.h" #include "platform/windows/windows_terminal_logger.h" #include "project_settings.h" #include "servers/audio_server.h" @@ -163,7 +163,7 @@ void OSUWP::initialize_core() { DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM); TCPServerWinsock::make_default(); - StreamPeerWinsock::make_default(); + StreamPeerTCPWinsock::make_default(); PacketPeerUDPWinsock::make_default(); // We need to know how often the clock is updated diff --git a/platform/windows/SCsub b/platform/windows/SCsub index 135ccd902a..5030f4b3e0 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -19,9 +19,6 @@ common_win = [ "os_windows.cpp", "ctxgl_procaddr.cpp", "key_mapping_win.cpp", - "tcp_server_winsock.cpp", - "packet_peer_udp_winsock.cpp", - "stream_peer_winsock.cpp", "joypad.cpp", "power_windows.cpp", "windows_terminal_logger.cpp" diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp index 81aa18dd23..ccb0a41d13 100644 --- a/platform/windows/context_gl_win.cpp +++ b/platform/windows/context_gl_win.cpp @@ -181,8 +181,6 @@ Error ContextGL_Win::initialize() { MessageBox(NULL, "Can't Activate The GL 3.3 Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return ERR_CANT_CREATE; // Return FALSE } - - printf("Activated GL 3.3 context"); } wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index d85e1b061c..01eb50e69c 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -188,6 +188,9 @@ def configure(env): else: VC_PATH = "" + if (env["openmp"]): + env.Append(CPPFLAGS=['/openmp']) + env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")]) env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) @@ -264,6 +267,10 @@ def configure(env): env.Append(CCFLAGS=['-flto']) env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))]) + if (env["openmp"]): + env.Append(CPPFLAGS=['-fopenmp']) + env.Append(LINKFLAGS=['-fopenmp']) + ## Compile flags env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows']) diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 41730d33af..6cab683e83 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -34,19 +34,19 @@ #include "drivers/windows/dir_access_windows.h" #include "drivers/windows/file_access_windows.h" #include "drivers/windows/mutex_windows.h" +#include "drivers/windows/packet_peer_udp_winsock.h" #include "drivers/windows/rw_lock_windows.h" #include "drivers/windows/semaphore_windows.h" +#include "drivers/windows/stream_peer_tcp_winsock.h" +#include "drivers/windows/tcp_server_winsock.h" #include "drivers/windows/thread_windows.h" #include "io/marshalls.h" #include "joypad.h" #include "lang_table.h" #include "main/main.h" -#include "packet_peer_udp_winsock.h" #include "servers/audio_server.h" #include "servers/visual/visual_server_raster.h" #include "servers/visual/visual_server_wrap_mt.h" -#include "stream_peer_winsock.h" -#include "tcp_server_winsock.h" #include "version_generated.gen.h" #include "windows_terminal_logger.h" @@ -196,7 +196,7 @@ void OS_Windows::initialize_core() { DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM); TCPServerWinsock::make_default(); - StreamPeerWinsock::make_default(); + StreamPeerTCPWinsock::make_default(); PacketPeerUDPWinsock::make_default(); // We need to know how often the clock is updated @@ -1253,7 +1253,7 @@ void OS_Windows::finalize_core() { memdelete(process_map); TCPServerWinsock::cleanup(); - StreamPeerWinsock::cleanup(); + StreamPeerTCPWinsock::cleanup(); } void OS_Windows::alert(const String &p_alert, const String &p_title) { @@ -1598,7 +1598,7 @@ bool OS_Windows::is_window_maximized() const { return maximized; } -void OS_Windows::set_borderless_window(int p_borderless) { +void OS_Windows::set_borderless_window(bool p_borderless) { if (video_mode.borderless_window == p_borderless) return; @@ -2156,6 +2156,10 @@ void OS_Windows::swap_buffers() { gl_context->swap_buffers(); } +void OS_Windows::force_process_input() { + process_events(); // get rid of pending events +} + void OS_Windows::run() { if (!main_loop) diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index af1ccd4446..f2226a53a9 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -210,7 +210,7 @@ public: virtual bool is_window_maximized() const; virtual void request_attention(); - virtual void set_borderless_window(int p_borderless); + virtual void set_borderless_window(bool p_borderless); virtual bool get_borderless_window(); virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); @@ -287,6 +287,8 @@ public: void disable_crash_handler(); bool is_disable_crash_handler() const; + void force_process_input(); + virtual Error move_to_trash(const String &p_path); OS_Windows(HINSTANCE _hInstance); diff --git a/platform/x11/detect.py b/platform/x11/detect.py index d7dbe71da4..09bf57c5f1 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -158,6 +158,7 @@ def configure(env): if not env['builtin_libwebp']: env.ParseConfig('pkg-config libwebp --cflags --libs') + # freetype depends on libpng and zlib, so bundling one of them while keeping others # as shared libraries leads to weird issues if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']: @@ -263,5 +264,10 @@ def configure(env): env.Append(CPPFLAGS=['-m64']) env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu']) + + if env["openmp"]: + env.Append(CPPFLAGS=['-fopenmp']) + env.Append(LINKFLAGS=['-fopenmp']) + if env['use_static_cpp']: env.Append(LINKFLAGS=['-static-libstdc++']) diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index b59fab7088..0c0bc1a8a3 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -1098,7 +1098,7 @@ bool OS_X11::is_window_maximized() const { return false; } -void OS_X11::set_borderless_window(int p_borderless) { +void OS_X11::set_borderless_window(bool p_borderless) { if (current_videomode.borderless_window == p_borderless) return; @@ -2264,6 +2264,13 @@ void OS_X11::set_icon(const Ref<Image> &p_icon) { XFlush(x11_display); } +void OS_X11::force_process_input() { + process_xevents(); // get rid of pending events +#ifdef JOYDEV_ENABLED + joypad->process_joypads(); +#endif +} + void OS_X11::run() { force_quit = false; diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 244c69ee2b..c8cea1e30c 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -258,7 +258,7 @@ public: virtual bool is_window_maximized() const; virtual void request_attention(); - virtual void set_borderless_window(int p_borderless); + virtual void set_borderless_window(bool p_borderless); virtual bool get_borderless_window(); virtual void set_ime_position(const Point2 &p_pos); @@ -279,6 +279,7 @@ public: virtual bool _check_internal_feature_support(const String &p_feature); + virtual void force_process_input(); void run(); void disable_crash_handler(); diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp index 9eff107827..40013814f8 100644 --- a/scene/2d/navigation2d.cpp +++ b/scene/2d/navigation2d.cpp @@ -205,7 +205,7 @@ void Navigation2D::_navpoly_unlink(int p_id) { nm.linked = false; } -int Navigation2D::navpoly_create(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner) { +int Navigation2D::navpoly_add(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner) { int id = last_id++; NavMesh nm; @@ -708,7 +708,7 @@ Object *Navigation2D::get_closest_point_owner(const Vector2 &p_point) { void Navigation2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("navpoly_create", "mesh", "xform", "owner"), &Navigation2D::navpoly_create, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("navpoly_add", "mesh", "xform", "owner"), &Navigation2D::navpoly_add, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("navpoly_set_transform", "id", "xform"), &Navigation2D::navpoly_set_transform); ClassDB::bind_method(D_METHOD("navpoly_remove", "id"), &Navigation2D::navpoly_remove); diff --git a/scene/2d/navigation2d.h b/scene/2d/navigation2d.h index bb97e1a9a9..02dbcb0f96 100644 --- a/scene/2d/navigation2d.h +++ b/scene/2d/navigation2d.h @@ -159,7 +159,7 @@ protected: public: //API should be as dynamic as possible - int navpoly_create(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL); + int navpoly_add(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL); void navpoly_set_transform(int p_id, const Transform2D &p_xform); void navpoly_remove(int p_id); diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index c53241e985..5a6a5128e6 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -293,7 +293,7 @@ void NavigationPolygonInstance::set_enabled(bool p_enabled) { if (navpoly.is_valid()) { - nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this); + nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this); } } } @@ -324,7 +324,7 @@ void NavigationPolygonInstance::_notification(int p_what) { if (enabled && navpoly.is_valid()) { - nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this); + nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this); } break; } @@ -419,7 +419,7 @@ void NavigationPolygonInstance::set_navigation_polygon(const Ref<NavigationPolyg } if (navigation && navpoly.is_valid() && enabled) { - nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this); + nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this); } //update_gizmo(); _change_notify("navpoly"); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 1e34372d1e..bcdad177c5 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -486,7 +486,7 @@ void TileMap::_update_dirty_quadrants() { xform.set_origin(offset.floor() + q.pos); _fix_cell_transform(xform, c, npoly_ofs + center_ofs, s); - int pid = navigation->navpoly_create(navpoly, nav_rel * xform); + int pid = navigation->navpoly_add(navpoly, nav_rel * xform); Quadrant::NavPoly np; np.id = pid; diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp new file mode 100644 index 0000000000..3d9bb73181 --- /dev/null +++ b/scene/3d/baked_lightmap.cpp @@ -0,0 +1,718 @@ +#include "baked_lightmap.h" +#include "io/resource_saver.h" +#include "os/dir_access.h" +#include "os/os.h" +#include "voxel_light_baker.h" + +void BakedLightmapData::set_bounds(const AABB &p_bounds) { + + bounds = p_bounds; + VS::get_singleton()->lightmap_capture_set_bounds(baked_light, p_bounds); +} + +AABB BakedLightmapData::get_bounds() const { + + return bounds; +} + +void BakedLightmapData::set_octree(const PoolVector<uint8_t> &p_octree) { + + VS::get_singleton()->lightmap_capture_set_octree(baked_light, p_octree); +} + +PoolVector<uint8_t> BakedLightmapData::get_octree() const { + + return VS::get_singleton()->lightmap_capture_get_octree(baked_light); +} + +void BakedLightmapData::set_cell_space_transform(const Transform &p_xform) { + + cell_space_xform = p_xform; + VS::get_singleton()->lightmap_capture_set_octree_cell_transform(baked_light, p_xform); +} + +Transform BakedLightmapData::get_cell_space_transform() const { + return cell_space_xform; +} + +void BakedLightmapData::set_cell_subdiv(int p_cell_subdiv) { + cell_subdiv = p_cell_subdiv; + VS::get_singleton()->lightmap_capture_set_octree_cell_subdiv(baked_light, p_cell_subdiv); +} + +int BakedLightmapData::get_cell_subdiv() const { + return cell_subdiv; +} + +void BakedLightmapData::set_energy(float p_energy) { + + energy = p_energy; + VS::get_singleton()->lightmap_capture_set_energy(baked_light, energy); +} + +float BakedLightmapData::get_energy() const { + + return energy; +} + +void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap) { + + ERR_FAIL_COND(p_lightmap.is_null()); + User user; + user.path = p_path; + user.lightmap = p_lightmap; + users.push_back(user); +} + +int BakedLightmapData::get_user_count() const { + + return users.size(); +} +NodePath BakedLightmapData::get_user_path(int p_user) const { + + ERR_FAIL_INDEX_V(p_user, users.size(), NodePath()); + return users[p_user].path; +} +Ref<Texture> BakedLightmapData::get_user_lightmap(int p_user) const { + + ERR_FAIL_INDEX_V(p_user, users.size(), Ref<Texture>()); + return users[p_user].lightmap; +} + +void BakedLightmapData::clear_users() { + users.clear(); +} + +void BakedLightmapData::_set_user_data(const Array &p_data) { + + ERR_FAIL_COND(p_data.size() & 1); + + for (int i = 0; i < p_data.size(); i += 2) { + add_user(p_data[i], p_data[i + 1]); + } +} + +Array BakedLightmapData::_get_user_data() const { + + Array ret; + for (int i = 0; i < users.size(); i++) { + ret.push_back(users[i].path); + ret.push_back(users[i].lightmap); + } + return ret; +} + +RID BakedLightmapData::get_rid() const { + return baked_light; +} +void BakedLightmapData::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &BakedLightmapData::_set_user_data); + ClassDB::bind_method(D_METHOD("_get_user_data"), &BakedLightmapData::_get_user_data); + + ClassDB::bind_method(D_METHOD("set_bounds", "bounds"), &BakedLightmapData::set_bounds); + ClassDB::bind_method(D_METHOD("get_bounds"), &BakedLightmapData::get_bounds); + + ClassDB::bind_method(D_METHOD("set_cell_space_transform", "xform"), &BakedLightmapData::set_cell_space_transform); + ClassDB::bind_method(D_METHOD("get_cell_space_transform"), &BakedLightmapData::get_cell_space_transform); + + ClassDB::bind_method(D_METHOD("set_cell_subdiv", "cell_subdiv"), &BakedLightmapData::set_cell_subdiv); + ClassDB::bind_method(D_METHOD("get_cell_subdiv"), &BakedLightmapData::get_cell_subdiv); + + ClassDB::bind_method(D_METHOD("set_octree", "octree"), &BakedLightmapData::set_octree); + ClassDB::bind_method(D_METHOD("get_octree"), &BakedLightmapData::get_octree); + + ClassDB::bind_method(D_METHOD("set_energy", "energy"), &BakedLightmapData::set_energy); + ClassDB::bind_method(D_METHOD("get_energy"), &BakedLightmapData::get_energy); + + ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap"), &BakedLightmapData::add_user); + ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count); + ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path); + ClassDB::bind_method(D_METHOD("get_user_lightmap", "user_idx"), &BakedLightmapData::get_user_lightmap); + ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users); + + ADD_PROPERTY(PropertyInfo(Variant::AABB, "bounds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bounds", "get_bounds"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "cell_space_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_space_transform", "get_cell_space_transform"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_subdiv", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_subdiv", "get_cell_subdiv"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_user_data", "_get_user_data"); +} + +BakedLightmapData::BakedLightmapData() { + + baked_light = VS::get_singleton()->lightmap_capture_create(); + energy = 1; + cell_subdiv = 1; +} + +BakedLightmapData::~BakedLightmapData() { + + VS::get_singleton()->free(baked_light); +} + +/////////////////////////// + +BakedLightmap::BakeBeginFunc BakedLightmap::bake_begin_function = NULL; +BakedLightmap::BakeStepFunc BakedLightmap::bake_step_function = NULL; +BakedLightmap::BakeEndFunc BakedLightmap::bake_end_function = NULL; + +void BakedLightmap::set_bake_subdiv(Subdiv p_subdiv) { + bake_subdiv = p_subdiv; +} + +BakedLightmap::Subdiv BakedLightmap::get_bake_subdiv() const { + return bake_subdiv; +} + +void BakedLightmap::set_capture_subdiv(Subdiv p_subdiv) { + capture_subdiv = p_subdiv; +} + +BakedLightmap::Subdiv BakedLightmap::get_capture_subdiv() const { + return capture_subdiv; +} + +void BakedLightmap::set_extents(const Vector3 &p_extents) { + extents = p_extents; + update_gizmo(); +} + +Vector3 BakedLightmap::get_extents() const { + return extents; +} + +void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plot_meshes, List<PlotLight> &plot_lights) { + + MeshInstance *mi = Object::cast_to<MeshInstance>(p_at_node); + if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT) && mi->is_visible_in_tree()) { + Ref<Mesh> mesh = mi->get_mesh(); + if (mesh.is_valid()) { + + bool all_have_uv2 = true; + for (int i = 0; i < mesh->get_surface_count(); i++) { + if (!(mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_TEX_UV2)) { + all_have_uv2 = false; + break; + } + } + + if (all_have_uv2 && mesh->get_lightmap_size_hint() != Size2()) { + //READY TO BAKE! size hint could be computed if not found, actually.. + + AABB aabb = mesh->get_aabb(); + + Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform(); + + if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) { + PlotMesh pm; + pm.local_xform = xf; + pm.mesh = mesh; + pm.path = get_path_to(mi); + for (int i = 0; i < mesh->get_surface_count(); i++) { + pm.instance_materials.push_back(mi->get_surface_material(i)); + } + pm.override_material = mi->get_material_override(); + plot_meshes.push_back(pm); + } + } + } + } + + Light *light = Object::cast_to<Light>(p_at_node); + + if (light && light->get_bake_mode() != Light::BAKE_DISABLED) { + PlotLight pl; + Transform xf = get_global_transform().affine_inverse() * light->get_global_transform(); + + pl.local_xform = xf; + pl.light = light; + plot_lights.push_back(pl); + } + for (int i = 0; i < p_at_node->get_child_count(); i++) { + + Node *child = p_at_node->get_child(i); + if (!child->get_owner()) + continue; //maybe a helper + + _find_meshes_and_lights(child, plot_meshes, plot_lights); + } +} + +void BakedLightmap::set_hdr(bool p_enable) { + hdr = p_enable; +} + +bool BakedLightmap::is_hdr() const { + return hdr; +} + +bool BakedLightmap::_bake_time(void *ud, float p_secs, float p_progress) { + + uint64_t time = OS::get_singleton()->get_ticks_usec(); + BakeTimeData *btd = (BakeTimeData *)ud; + + if (time - btd->last_step > 1000000) { + + int mins_left = p_secs / 60; + int secs_left = Math::fmod(p_secs, 60.0f); + int percent = p_progress * 100; + bool abort = bake_step_function(btd->pass + percent, btd->text + " " + itos(percent) + "% (Time Left: " + itos(mins_left) + ":" + itos(secs_left) + "s)"); + btd->last_step = time; + if (abort) + return true; + } + + return false; +} + +BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_visual_debug) { + + String save_path; + + if (image_path.begins_with("res://")) { + save_path = image_path; + } else { + if (get_filename() != "") { + save_path = get_filename().get_base_dir(); + } else if (get_owner() && get_owner()->get_filename() != "") { + save_path = get_owner()->get_filename().get_base_dir(); + } + + if (save_path == "") { + return BAKE_ERROR_NO_SAVE_PATH; + } + if (image_path != "") { + save_path.plus_file(image_path); + } + } + { + //check for valid save path + DirAccessRef d = DirAccess::open(save_path); + if (!d) { + ERR_PRINTS("Invalid Save Path: " + save_path); + return BAKE_ERROR_NO_SAVE_PATH; + } + } + + Ref<BakedLightmapData> new_light_data; + new_light_data.instance(); + + static const int subdiv_value[SUBDIV_MAX] = { 8, 9, 10, 11, 12, 13 }; + + VoxelLightBaker baker; + + baker.begin_bake(subdiv_value[bake_subdiv], AABB(-extents, extents * 2.0)); + + List<PlotMesh> mesh_list; + List<PlotLight> light_list; + + _find_meshes_and_lights(p_from_node ? p_from_node : get_parent(), mesh_list, light_list); + + if (bake_begin_function) { + bake_begin_function(mesh_list.size() + light_list.size() + 1 + mesh_list.size() * 100); + } + + int step = 0; + + int pmc = 0; + + for (List<PlotMesh>::Element *E = mesh_list.front(); E; E = E->next()) { + + if (bake_step_function) { + bake_step_function(step++, RTR("Plotting Meshes: ") + " (" + itos(pmc + 1) + "/" + itos(mesh_list.size()) + ")"); + } + + pmc++; + baker.plot_mesh(E->get().local_xform, E->get().mesh, E->get().instance_materials, E->get().override_material); + } + + pmc = 0; + baker.begin_bake_light(VoxelLightBaker::BakeQuality(bake_quality), VoxelLightBaker::BakeMode(bake_mode), propagation, energy); + + for (List<PlotLight>::Element *E = light_list.front(); E; E = E->next()) { + + if (bake_step_function) { + bake_step_function(step++, RTR("Plotting Lights:") + " (" + itos(pmc + 1) + "/" + itos(light_list.size()) + ")"); + } + + pmc++; + PlotLight pl = E->get(); + switch (pl.light->get_light_type()) { + case VS::LIGHT_DIRECTIONAL: { + baker.plot_light_directional(-pl.local_xform.basis.get_axis(2), pl.light->get_color(), pl.light->get_param(Light::PARAM_ENERGY), pl.light->get_param(Light::PARAM_INDIRECT_ENERGY), pl.light->get_bake_mode() == Light::BAKE_ALL); + } break; + case VS::LIGHT_OMNI: { + baker.plot_light_omni(pl.local_xform.origin, pl.light->get_color(), pl.light->get_param(Light::PARAM_ENERGY), pl.light->get_param(Light::PARAM_INDIRECT_ENERGY), pl.light->get_param(Light::PARAM_RANGE), pl.light->get_param(Light::PARAM_ATTENUATION), pl.light->get_bake_mode() == Light::BAKE_ALL); + } break; + case VS::LIGHT_SPOT: { + baker.plot_light_spot(pl.local_xform.origin, pl.local_xform.basis.get_axis(2), pl.light->get_color(), pl.light->get_param(Light::PARAM_ENERGY), pl.light->get_param(Light::PARAM_INDIRECT_ENERGY), pl.light->get_param(Light::PARAM_RANGE), pl.light->get_param(Light::PARAM_ATTENUATION), pl.light->get_param(Light::PARAM_SPOT_ANGLE), pl.light->get_param(Light::PARAM_SPOT_ATTENUATION), pl.light->get_bake_mode() == Light::BAKE_ALL); + + } break; + } + } + /*if (bake_step_function) { + bake_step_function(pmc++, RTR("Finishing Plot")); + }*/ + + baker.end_bake(); + + Set<String> used_mesh_names; + + pmc = 0; + for (List<PlotMesh>::Element *E = mesh_list.front(); E; E = E->next()) { + + String mesh_name = E->get().mesh->get_name(); + if (mesh_name == "" || mesh_name.find(":") != -1 || mesh_name.find("/") != -1) { + mesh_name = "LightMap"; + } + + if (used_mesh_names.has(mesh_name)) { + int idx = 2; + String base = mesh_name; + while (true) { + mesh_name = base + itos(idx); + if (!used_mesh_names.has(mesh_name)) + break; + idx++; + } + } + used_mesh_names.insert(mesh_name); + + pmc++; + VoxelLightBaker::LightMapData lm; + + Error err; + if (bake_step_function) { + BakeTimeData btd; + btd.text = RTR("Lighting Meshes: ") + mesh_name + " (" + itos(pmc) + "/" + itos(mesh_list.size()) + ")"; + btd.pass = step; + btd.last_step = 0; + err = baker.make_lightmap(E->get().local_xform, E->get().mesh, lm, _bake_time, &btd); + if (err != OK) { + bake_end_function(); + if (err == ERR_SKIP) + return BAKE_ERROR_USER_ABORTED; + return BAKE_ERROR_CANT_CREATE_IMAGE; + } + step += 100; + } else { + + err = baker.make_lightmap(E->get().local_xform, E->get().mesh, lm); + } + + if (err == OK) { + + Ref<Image> image; + image.instance(); + + uint32_t tex_flags = Texture::FLAGS_DEFAULT; + if (hdr) { + + //just save a regular image + PoolVector<uint8_t> data; + int s = lm.light.size(); + data.resize(lm.light.size() * 2); + { + + PoolVector<uint8_t>::Write w = data.write(); + PoolVector<float>::Read r = lm.light.read(); + uint16_t *hfw = (uint16_t *)w.ptr(); + for (int i = 0; i < s; i++) { + hfw[i] = Math::make_half_float(r[i]); + } + } + + image->create(lm.width, lm.height, false, Image::FORMAT_RGBH, data); + + } else { + + //just save a regular image + PoolVector<uint8_t> data; + int s = lm.light.size(); + data.resize(lm.light.size()); + { + + PoolVector<uint8_t>::Write w = data.write(); + PoolVector<float>::Read r = lm.light.read(); + for (int i = 0; i < s; i += 3) { + Color c(r[i + 0], r[i + 1], r[i + 2]); + c = c.to_srgb(); + w[i + 0] = CLAMP(c.r * 255, 0, 255); + w[i + 1] = CLAMP(c.g * 255, 0, 255); + w[i + 2] = CLAMP(c.b * 255, 0, 255); + } + } + + image->create(lm.width, lm.height, false, Image::FORMAT_RGB8, data); + + //This texture is saved to SRGB for two reasons: + // 1) first is so it looks better when doing the LINEAR->SRGB conversion (more accurate) + // 2) So it can be used in the GLES2 backend, which does not support linkear workflow + tex_flags |= Texture::FLAG_CONVERT_TO_LINEAR; + } + + Ref<ImageTexture> tex; + String image_path = save_path.plus_file(mesh_name + ".tex"); + bool set_path = true; + if (ResourceCache::has(image_path)) { + tex = Ref<Resource>((Resource *)ResourceCache::get(image_path)); + set_path = false; + } + + if (!tex.is_valid()) { + tex.instance(); + } + + tex->create_from_image(image, tex_flags); + + err = ResourceSaver::save(image_path, tex, ResourceSaver::FLAG_CHANGE_PATH); + if (err != OK) { + if (bake_end_function) { + bake_end_function(); + } + ERR_FAIL_COND_V(err != OK, BAKE_ERROR_CANT_CREATE_IMAGE); + } + + if (set_path) { + tex->set_path(image_path); + } + new_light_data->add_user(E->get().path, tex); + } + } + + int csubdiv = subdiv_value[capture_subdiv]; + AABB bounds = AABB(-extents, extents * 2); + new_light_data->set_cell_subdiv(csubdiv); + new_light_data->set_bounds(bounds); + new_light_data->set_octree(baker.create_capture_octree(csubdiv)); + { + + Transform to_bounds; + to_bounds.basis.scale(Vector3(bounds.get_longest_axis_size(), bounds.get_longest_axis_size(), bounds.get_longest_axis_size())); + to_bounds.origin = bounds.position; + + Transform to_grid; + to_grid.basis.scale(Vector3(1 << (csubdiv - 1), 1 << (csubdiv - 1), 1 << (csubdiv - 1))); + + Transform to_cell_space = to_grid * to_bounds.affine_inverse(); + new_light_data->set_cell_space_transform(to_cell_space); + } + + if (bake_end_function) { + bake_end_function(); + } + + //create the data for visual server + + if (p_create_visual_debug) { + MultiMeshInstance *mmi = memnew(MultiMeshInstance); + mmi->set_multimesh(baker.create_debug_multimesh(VoxelLightBaker::DEBUG_LIGHT)); + add_child(mmi); +#ifdef TOOLS_ENABLED + if (get_tree()->get_edited_scene_root() == this) { + mmi->set_owner(this); + } else { + mmi->set_owner(get_owner()); + } +#else + mmi->set_owner(get_owner()); +#endif + } + + set_light_data(new_light_data); + + return BAKE_ERROR_OK; +} + +void BakedLightmap::_notification(int p_what) { + if (p_what == NOTIFICATION_READY) { + + if (light_data.is_valid()) { + _assign_lightmaps(); + } + request_ready(); //will need ready again if re-enters tree + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + + if (light_data.is_valid()) { + _clear_lightmaps(); + } + } +} + +void BakedLightmap::_assign_lightmaps() { + + ERR_FAIL_COND(!light_data.is_valid()); + + for (int i = 0; i < light_data->get_user_count(); i++) { + Node *node = get_node(light_data->get_user_path(i)); + VisualInstance *vi = Object::cast_to<VisualInstance>(node); + ERR_CONTINUE(!vi); + Ref<Texture> lightmap = light_data->get_user_lightmap(i); + ERR_CONTINUE(!lightmap.is_valid()); + VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid()); + } +} + +void BakedLightmap::_clear_lightmaps() { + ERR_FAIL_COND(!light_data.is_valid()); + for (int i = 0; i < light_data->get_user_count(); i++) { + Node *node = get_node(light_data->get_user_path(i)); + VisualInstance *vi = Object::cast_to<VisualInstance>(node); + ERR_CONTINUE(!vi); + VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), RID(), RID()); + } +} + +void BakedLightmap::set_light_data(const Ref<BakedLightmapData> &p_data) { + + if (light_data.is_valid()) { + if (is_inside_tree()) { + _clear_lightmaps(); + } + set_base(RID()); + } + light_data = p_data; + + if (light_data.is_valid()) { + set_base(light_data->get_rid()); + if (is_inside_tree()) { + _assign_lightmaps(); + } + } +} + +Ref<BakedLightmapData> BakedLightmap::get_light_data() const { + + return light_data; +} + +void BakedLightmap::_debug_bake() { + bake(get_parent(), true); +} + +void BakedLightmap::set_propagation(float p_propagation) { + propagation = p_propagation; +} + +float BakedLightmap::get_propagation() const { + + return propagation; +} + +void BakedLightmap::set_energy(float p_energy) { + energy = p_energy; +} + +float BakedLightmap::get_energy() const { + + return energy; +} + +void BakedLightmap::set_bake_quality(BakeQuality p_quality) { + bake_quality = p_quality; +} + +BakedLightmap::BakeQuality BakedLightmap::get_bake_quality() const { + return bake_quality; +} + +void BakedLightmap::set_bake_mode(BakeMode p_mode) { + bake_mode = p_mode; +} + +BakedLightmap::BakeMode BakedLightmap::get_bake_mode() const { + return bake_mode; +} + +void BakedLightmap::set_image_path(const String &p_path) { + image_path = p_path; +} + +String BakedLightmap::get_image_path() const { + return image_path; +} + +AABB BakedLightmap::get_aabb() const { + return AABB(-extents, extents * 2); +} +PoolVector<Face3> BakedLightmap::get_faces(uint32_t p_usage_flags) const { + return PoolVector<Face3>(); +} + +void BakedLightmap::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_light_data", "data"), &BakedLightmap::set_light_data); + ClassDB::bind_method(D_METHOD("get_light_data"), &BakedLightmap::get_light_data); + + ClassDB::bind_method(D_METHOD("set_bake_subdiv", "bake_subdiv"), &BakedLightmap::set_bake_subdiv); + ClassDB::bind_method(D_METHOD("get_bake_subdiv"), &BakedLightmap::get_bake_subdiv); + + ClassDB::bind_method(D_METHOD("set_capture_subdiv", "capture_subdiv"), &BakedLightmap::set_capture_subdiv); + ClassDB::bind_method(D_METHOD("get_capture_subdiv"), &BakedLightmap::get_capture_subdiv); + + ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &BakedLightmap::set_bake_quality); + ClassDB::bind_method(D_METHOD("get_bake_quality"), &BakedLightmap::get_bake_quality); + + ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &BakedLightmap::set_bake_mode); + ClassDB::bind_method(D_METHOD("get_bake_mode"), &BakedLightmap::get_bake_mode); + + ClassDB::bind_method(D_METHOD("set_extents", "extents"), &BakedLightmap::set_extents); + ClassDB::bind_method(D_METHOD("get_extents"), &BakedLightmap::get_extents); + + ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &BakedLightmap::set_propagation); + ClassDB::bind_method(D_METHOD("get_propagation"), &BakedLightmap::get_propagation); + + ClassDB::bind_method(D_METHOD("set_energy", "energy"), &BakedLightmap::set_energy); + ClassDB::bind_method(D_METHOD("get_energy"), &BakedLightmap::get_energy); + + ClassDB::bind_method(D_METHOD("set_hdr", "hdr"), &BakedLightmap::set_hdr); + ClassDB::bind_method(D_METHOD("is_hdr"), &BakedLightmap::is_hdr); + + ClassDB::bind_method(D_METHOD("set_image_path", "image_path"), &BakedLightmap::set_image_path); + ClassDB::bind_method(D_METHOD("get_image_path"), &BakedLightmap::get_image_path); + + ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &BakedLightmap::bake, DEFVAL(Variant()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("debug_bake"), &BakedLightmap::_debug_bake); + ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_subdiv", PROPERTY_HINT_ENUM, "128,256,512,1024,2048,4096"), "set_bake_subdiv", "get_bake_subdiv"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "capture_subdiv", PROPERTY_HINT_ENUM, "128,256,512"), "set_capture_subdiv", "get_capture_subdiv"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_bake_quality", "get_bake_quality"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mode", PROPERTY_HINT_ENUM, "ConeTrace,RayTrace"), "set_bake_mode", "get_bake_mode"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "is_hdr"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_path", PROPERTY_HINT_DIR), "set_image_path", "get_image_path"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedIndirectLightData"), "set_light_data", "get_light_data"); + + BIND_ENUM_CONSTANT(SUBDIV_128); + BIND_ENUM_CONSTANT(SUBDIV_256); + BIND_ENUM_CONSTANT(SUBDIV_512); + BIND_ENUM_CONSTANT(SUBDIV_1024); + BIND_ENUM_CONSTANT(SUBDIV_2048); + BIND_ENUM_CONSTANT(SUBDIV_4096); + BIND_ENUM_CONSTANT(SUBDIV_MAX); + + BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW); + BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM); + BIND_ENUM_CONSTANT(BAKE_QUALITY_HIGH); + BIND_ENUM_CONSTANT(BAKE_MODE_CONE_TRACE); + BIND_ENUM_CONSTANT(BAKE_MODE_RAY_TRACE); +} + +BakedLightmap::BakedLightmap() { + + extents = Vector3(10, 10, 10); + bake_subdiv = SUBDIV_256; + capture_subdiv = SUBDIV_128; + bake_quality = BAKE_QUALITY_MEDIUM; + bake_mode = BAKE_MODE_CONE_TRACE; + energy = 1; + propagation = 1; + hdr = false; + image_path = "."; +} diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h new file mode 100644 index 0000000000..5595ec1e61 --- /dev/null +++ b/scene/3d/baked_lightmap.h @@ -0,0 +1,189 @@ +#ifndef BAKED_INDIRECT_LIGHT_H +#define BAKED_INDIRECT_LIGHT_H + +#include "multimesh_instance.h" +#include "scene/3d/light.h" +#include "scene/3d/visual_instance.h" + +class BakedLightmapData : public Resource { + GDCLASS(BakedLightmapData, Resource); + + RID baked_light; + AABB bounds; + float energy; + int cell_subdiv; + Transform cell_space_xform; + + struct User { + + NodePath path; + Ref<Texture> lightmap; + }; + + Vector<User> users; + + void _set_user_data(const Array &p_data); + Array _get_user_data() const; + +protected: + static void _bind_methods(); + +public: + void set_bounds(const AABB &p_bounds); + AABB get_bounds() const; + + void set_octree(const PoolVector<uint8_t> &p_octree); + PoolVector<uint8_t> get_octree() const; + + void set_cell_space_transform(const Transform &p_xform); + Transform get_cell_space_transform() const; + + void set_cell_subdiv(int p_cell_subdiv); + int get_cell_subdiv() const; + + void set_energy(float p_energy); + float get_energy() const; + + void add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap); + int get_user_count() const; + NodePath get_user_path(int p_user) const; + Ref<Texture> get_user_lightmap(int p_user) const; + void clear_users(); + + virtual RID get_rid() const; + BakedLightmapData(); + ~BakedLightmapData(); +}; + +class BakedLightmap : public VisualInstance { + GDCLASS(BakedLightmap, VisualInstance); + +public: + enum Subdiv { + SUBDIV_128, + SUBDIV_256, + SUBDIV_512, + SUBDIV_1024, + SUBDIV_2048, + SUBDIV_4096, + SUBDIV_MAX + + }; + + enum BakeQuality { + BAKE_QUALITY_LOW, + BAKE_QUALITY_MEDIUM, + BAKE_QUALITY_HIGH + }; + + enum BakeMode { + BAKE_MODE_CONE_TRACE, + BAKE_MODE_RAY_TRACE, + }; + + enum BakeError { + BAKE_ERROR_OK, + BAKE_ERROR_NO_SAVE_PATH, + BAKE_ERROR_NO_MESHES, + BAKE_ERROR_CANT_CREATE_IMAGE, + BAKE_ERROR_USER_ABORTED + + }; + + typedef void (*BakeBeginFunc)(int); + typedef bool (*BakeStepFunc)(int, const String &); + typedef void (*BakeEndFunc)(); + +private: + Subdiv bake_subdiv; + Subdiv capture_subdiv; + Vector3 extents; + float propagation; + float energy; + BakeQuality bake_quality; + BakeMode bake_mode; + bool hdr; + String image_path; + + Ref<BakedLightmapData> light_data; + + struct PlotMesh { + Ref<Material> override_material; + Vector<Ref<Material> > instance_materials; + Ref<Mesh> mesh; + Transform local_xform; + NodePath path; + }; + + struct PlotLight { + Light *light; + Transform local_xform; + }; + + void _find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plot_meshes, List<PlotLight> &plot_lights); + + void _debug_bake(); + + void _assign_lightmaps(); + void _clear_lightmaps(); + + static bool _bake_time(void *ud, float p_secs, float p_progress); + + struct BakeTimeData { + String text; + int pass; + uint64_t last_step; + }; + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + static BakeBeginFunc bake_begin_function; + static BakeStepFunc bake_step_function; + static BakeEndFunc bake_end_function; + + void set_light_data(const Ref<BakedLightmapData> &p_data); + Ref<BakedLightmapData> get_light_data() const; + + void set_bake_subdiv(Subdiv p_subdiv); + Subdiv get_bake_subdiv() const; + + void set_capture_subdiv(Subdiv p_subdiv); + Subdiv get_capture_subdiv() const; + + void set_extents(const Vector3 &p_extents); + Vector3 get_extents() const; + + void set_propagation(float p_propagation); + float get_propagation() const; + + void set_energy(float p_energy); + float get_energy() const; + + void set_bake_quality(BakeQuality p_quality); + BakeQuality get_bake_quality() const; + + void set_bake_mode(BakeMode p_mode); + BakeMode get_bake_mode() const; + + void set_hdr(bool p_enable); + bool is_hdr() const; + + void set_image_path(const String &p_path); + String get_image_path() const; + + AABB get_aabb() const; + PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + + BakeError bake(Node *p_from_node, bool p_create_visual_debug = false); + BakedLightmap(); +}; + +VARIANT_ENUM_CAST(BakedLightmap::Subdiv); +VARIANT_ENUM_CAST(BakedLightmap::BakeQuality); +VARIANT_ENUM_CAST(BakedLightmap::BakeMode); +VARIANT_ENUM_CAST(BakedLightmap::BakeError); + +#endif // BAKED_INDIRECT_LIGHT_H diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 1f2b43165e..9c811a74bf 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -30,6 +30,7 @@ #include "gi_probe.h" #include "mesh_instance.h" +#include "voxel_light_baker.h" void GIProbeData::set_bounds(const AABB &p_bounds) { @@ -329,754 +330,7 @@ bool GIProbe::is_compressed() const { return compress; } -#include "math.h" - -#define FINDMINMAX(x0, x1, x2, min, max) \ - min = max = x0; \ - if (x1 < min) min = x1; \ - if (x1 > max) max = x1; \ - if (x2 < min) min = x2; \ - if (x2 > max) max = x2; - -static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) { - int q; - Vector3 vmin, vmax; - for (q = 0; q <= 2; q++) { - if (normal[q] > 0.0f) { - vmin[q] = -maxbox[q]; - vmax[q] = maxbox[q]; - } else { - vmin[q] = maxbox[q]; - vmax[q] = -maxbox[q]; - } - } - if (normal.dot(vmin) + d > 0.0f) return false; - if (normal.dot(vmax) + d >= 0.0f) return true; - - return false; -} - -/*======================== X-tests ========================*/ -#define AXISTEST_X01(a, b, fa, fb) \ - p0 = a * v0.y - b * v0.z; \ - p2 = a * v2.y - b * v2.z; \ - if (p0 < p2) { \ - min = p0; \ - max = p2; \ - } else { \ - min = p2; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \ - if (min > rad || max < -rad) return false; - -#define AXISTEST_X2(a, b, fa, fb) \ - p0 = a * v0.y - b * v0.z; \ - p1 = a * v1.y - b * v1.z; \ - if (p0 < p1) { \ - min = p0; \ - max = p1; \ - } else { \ - min = p1; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \ - if (min > rad || max < -rad) return false; - -/*======================== Y-tests ========================*/ -#define AXISTEST_Y02(a, b, fa, fb) \ - p0 = -a * v0.x + b * v0.z; \ - p2 = -a * v2.x + b * v2.z; \ - if (p0 < p2) { \ - min = p0; \ - max = p2; \ - } else { \ - min = p2; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \ - if (min > rad || max < -rad) return false; - -#define AXISTEST_Y1(a, b, fa, fb) \ - p0 = -a * v0.x + b * v0.z; \ - p1 = -a * v1.x + b * v1.z; \ - if (p0 < p1) { \ - min = p0; \ - max = p1; \ - } else { \ - min = p1; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \ - if (min > rad || max < -rad) return false; - - /*======================== Z-tests ========================*/ - -#define AXISTEST_Z12(a, b, fa, fb) \ - p1 = a * v1.x - b * v1.y; \ - p2 = a * v2.x - b * v2.y; \ - if (p2 < p1) { \ - min = p2; \ - max = p1; \ - } else { \ - min = p1; \ - max = p2; \ - } \ - rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \ - if (min > rad || max < -rad) return false; - -#define AXISTEST_Z0(a, b, fa, fb) \ - p0 = a * v0.x - b * v0.y; \ - p1 = a * v1.x - b * v1.y; \ - if (p0 < p1) { \ - min = p0; \ - max = p1; \ - } else { \ - min = p1; \ - max = p0; \ - } \ - rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \ - if (min > rad || max < -rad) return false; - -static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalfsize, const Vector3 *triverts) { - - /* use separating axis theorem to test overlap between triangle and box */ - /* need to test for overlap in these directions: */ - /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ - /* we do not even need to test these) */ - /* 2) normal of the triangle */ - /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ - /* this gives 3x3=9 more tests */ - Vector3 v0, v1, v2; - float min, max, d, p0, p1, p2, rad, fex, fey, fez; - Vector3 normal, e0, e1, e2; - - /* This is the fastest branch on Sun */ - /* move everything so that the boxcenter is in (0,0,0) */ - - v0 = triverts[0] - boxcenter; - v1 = triverts[1] - boxcenter; - v2 = triverts[2] - boxcenter; - - /* compute triangle edges */ - e0 = v1 - v0; /* tri edge 0 */ - e1 = v2 - v1; /* tri edge 1 */ - e2 = v0 - v2; /* tri edge 2 */ - - /* Bullet 3: */ - /* test the 9 tests first (this was faster) */ - fex = Math::abs(e0.x); - fey = Math::abs(e0.y); - fez = Math::abs(e0.z); - AXISTEST_X01(e0.z, e0.y, fez, fey); - AXISTEST_Y02(e0.z, e0.x, fez, fex); - AXISTEST_Z12(e0.y, e0.x, fey, fex); - - fex = Math::abs(e1.x); - fey = Math::abs(e1.y); - fez = Math::abs(e1.z); - AXISTEST_X01(e1.z, e1.y, fez, fey); - AXISTEST_Y02(e1.z, e1.x, fez, fex); - AXISTEST_Z0(e1.y, e1.x, fey, fex); - - fex = Math::abs(e2.x); - fey = Math::abs(e2.y); - fez = Math::abs(e2.z); - AXISTEST_X2(e2.z, e2.y, fez, fey); - AXISTEST_Y1(e2.z, e2.x, fez, fex); - AXISTEST_Z12(e2.y, e2.x, fey, fex); - - /* Bullet 1: */ - /* first test overlap in the {x,y,z}-directions */ - /* find min, max of the triangle each direction, and test for overlap in */ - /* that direction -- this is equivalent to testing a minimal AABB around */ - /* the triangle against the AABB */ - - /* test in X-direction */ - FINDMINMAX(v0.x, v1.x, v2.x, min, max); - if (min > boxhalfsize.x || max < -boxhalfsize.x) return false; - - /* test in Y-direction */ - FINDMINMAX(v0.y, v1.y, v2.y, min, max); - if (min > boxhalfsize.y || max < -boxhalfsize.y) return false; - - /* test in Z-direction */ - FINDMINMAX(v0.z, v1.z, v2.z, min, max); - if (min > boxhalfsize.z || max < -boxhalfsize.z) return false; - - /* Bullet 2: */ - /* test if the box intersects the plane of the triangle */ - /* compute plane equation of triangle: normal*x+d=0 */ - normal = e0.cross(e1); - d = -normal.dot(v0); /* plane eq: normal.x+d=0 */ - if (!planeBoxOverlap(normal, d, boxhalfsize)) return false; - - return true; /* box and triangle overlaps */ -} - -static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv) { - - if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) - return p_uv[0]; - if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) - return p_uv[1]; - if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) - return p_uv[2]; - - Vector3 v0 = p_vtx[1] - p_vtx[0]; - Vector3 v1 = p_vtx[2] - p_vtx[0]; - Vector3 v2 = p_pos - p_vtx[0]; - - float d00 = v0.dot(v0); - float d01 = v0.dot(v1); - float d11 = v1.dot(v1); - float d20 = v2.dot(v0); - float d21 = v2.dot(v1); - float denom = (d00 * d11 - d01 * d01); - if (denom == 0) - return p_uv[0]; - float v = (d11 * d20 - d01 * d21) / denom; - float w = (d00 * d21 - d01 * d20) / denom; - float u = 1.0f - v - w; - - return p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; -} - -void GIProbe::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const Baker::MaterialCache &p_material, const AABB &p_aabb, Baker *p_baker) { - - if (p_level == p_baker->cell_subdiv - 1) { - //plot the face by guessing it's albedo and emission value - - //find best axis to map to, for scanning values - int closest_axis = 0; - float closest_dot = 0; - - Plane plane = Plane(p_vtx[0], p_vtx[1], p_vtx[2]); - Vector3 normal = plane.normal; - - for (int i = 0; i < 3; i++) { - - Vector3 axis; - axis[i] = 1.0; - float dot = ABS(normal.dot(axis)); - if (i == 0 || dot > closest_dot) { - closest_axis = i; - closest_dot = dot; - } - } - - Vector3 axis; - axis[closest_axis] = 1.0; - Vector3 t1; - t1[(closest_axis + 1) % 3] = 1.0; - Vector3 t2; - t2[(closest_axis + 2) % 3] = 1.0; - - t1 *= p_aabb.size[(closest_axis + 1) % 3] / float(color_scan_cell_width); - t2 *= p_aabb.size[(closest_axis + 2) % 3] / float(color_scan_cell_width); - - Color albedo_accum; - Color emission_accum; - Vector3 normal_accum; - - float alpha = 0.0; - - //map to a grid average in the best axis for this face - for (int i = 0; i < color_scan_cell_width; i++) { - - Vector3 ofs_i = float(i) * t1; - - for (int j = 0; j < color_scan_cell_width; j++) { - - Vector3 ofs_j = float(j) * t2; - - Vector3 from = p_aabb.position + ofs_i + ofs_j; - Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis]; - Vector3 half = (to - from) * 0.5; - - //is in this cell? - if (!fast_tri_box_overlap(from + half, half, p_vtx)) { - continue; //face does not span this cell - } - - //go from -size to +size*2 to avoid skipping collisions - Vector3 ray_from = from + (t1 + t2) * 0.5 - axis * p_aabb.size[closest_axis]; - Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis] * 2; - - if (normal.dot(ray_from - ray_to) < 0) { - SWAP(ray_from, ray_to); - } - - Vector3 intersection; - - if (!plane.intersects_segment(ray_from, ray_to, &intersection)) { - if (ABS(plane.distance_to(ray_from)) < ABS(plane.distance_to(ray_to))) { - intersection = plane.project(ray_from); - } else { - - intersection = plane.project(ray_to); - } - } - - intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection); - - Vector2 uv = get_uv(intersection, p_vtx, p_uv); - - int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); - int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); - - int ofs = uv_y * bake_texture_size + uv_x; - albedo_accum.r += p_material.albedo[ofs].r; - albedo_accum.g += p_material.albedo[ofs].g; - albedo_accum.b += p_material.albedo[ofs].b; - albedo_accum.a += p_material.albedo[ofs].a; - - emission_accum.r += p_material.emission[ofs].r; - emission_accum.g += p_material.emission[ofs].g; - emission_accum.b += p_material.emission[ofs].b; - - normal_accum += normal; - - alpha += 1.0; - } - } - - if (alpha == 0) { - //could not in any way get texture information.. so use closest point to center - - Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]); - Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5); - - Vector2 uv = get_uv(inters, p_vtx, p_uv); - - int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); - int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); - - int ofs = uv_y * bake_texture_size + uv_x; - - alpha = 1.0 / (color_scan_cell_width * color_scan_cell_width); - - albedo_accum.r = p_material.albedo[ofs].r * alpha; - albedo_accum.g = p_material.albedo[ofs].g * alpha; - albedo_accum.b = p_material.albedo[ofs].b * alpha; - albedo_accum.a = p_material.albedo[ofs].a * alpha; - - emission_accum.r = p_material.emission[ofs].r * alpha; - emission_accum.g = p_material.emission[ofs].g * alpha; - emission_accum.b = p_material.emission[ofs].b * alpha; - - normal_accum *= alpha; - - } else { - - float accdiv = 1.0 / (color_scan_cell_width * color_scan_cell_width); - alpha *= accdiv; - - albedo_accum.r *= accdiv; - albedo_accum.g *= accdiv; - albedo_accum.b *= accdiv; - albedo_accum.a *= accdiv; - - emission_accum.r *= accdiv; - emission_accum.g *= accdiv; - emission_accum.b *= accdiv; - - normal_accum *= accdiv; - } - - //put this temporarily here, corrected in a later step - p_baker->bake_cells[p_idx].albedo[0] += albedo_accum.r; - p_baker->bake_cells[p_idx].albedo[1] += albedo_accum.g; - p_baker->bake_cells[p_idx].albedo[2] += albedo_accum.b; - p_baker->bake_cells[p_idx].emission[0] += emission_accum.r; - p_baker->bake_cells[p_idx].emission[1] += emission_accum.g; - p_baker->bake_cells[p_idx].emission[2] += emission_accum.b; - p_baker->bake_cells[p_idx].normal[0] += normal_accum.x; - p_baker->bake_cells[p_idx].normal[1] += normal_accum.y; - p_baker->bake_cells[p_idx].normal[2] += normal_accum.z; - p_baker->bake_cells[p_idx].alpha += alpha; - - } else { - //go down - - int half = (1 << (p_baker->cell_subdiv - 1)) >> (p_level + 1); - for (int i = 0; i < 8; i++) { - - AABB aabb = p_aabb; - aabb.size *= 0.5; - - int nx = p_x; - int ny = p_y; - int nz = p_z; - - if (i & 1) { - aabb.position.x += aabb.size.x; - nx += half; - } - if (i & 2) { - aabb.position.y += aabb.size.y; - ny += half; - } - if (i & 4) { - aabb.position.z += aabb.size.z; - nz += half; - } - //make sure to not plot beyond limits - if (nx < 0 || nx >= p_baker->axis_cell_size[0] || ny < 0 || ny >= p_baker->axis_cell_size[1] || nz < 0 || nz >= p_baker->axis_cell_size[2]) - continue; - - { - AABB test_aabb = aabb; - //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time - Vector3 qsize = test_aabb.size * 0.5; //quarter size, for fast aabb test - - if (!fast_tri_box_overlap(test_aabb.position + qsize, qsize, p_vtx)) { - //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) { - //does not fit in child, go on - continue; - } - } - - if (p_baker->bake_cells[p_idx].childs[i] == Baker::CHILD_EMPTY) { - //sub cell must be created - - uint32_t child_idx = p_baker->bake_cells.size(); - p_baker->bake_cells[p_idx].childs[i] = child_idx; - p_baker->bake_cells.resize(p_baker->bake_cells.size() + 1); - p_baker->bake_cells[child_idx].level = p_level + 1; - } - - _plot_face(p_baker->bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_uv, p_material, aabb, p_baker); - } - } -} - -void GIProbe::_fixup_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, Baker *p_baker) { - - if (p_level == p_baker->cell_subdiv - 1) { - - p_baker->leaf_voxel_count++; - float alpha = p_baker->bake_cells[p_idx].alpha; - - p_baker->bake_cells[p_idx].albedo[0] /= alpha; - p_baker->bake_cells[p_idx].albedo[1] /= alpha; - p_baker->bake_cells[p_idx].albedo[2] /= alpha; - - //transfer emission to light - p_baker->bake_cells[p_idx].emission[0] /= alpha; - p_baker->bake_cells[p_idx].emission[1] /= alpha; - p_baker->bake_cells[p_idx].emission[2] /= alpha; - - p_baker->bake_cells[p_idx].normal[0] /= alpha; - p_baker->bake_cells[p_idx].normal[1] /= alpha; - p_baker->bake_cells[p_idx].normal[2] /= alpha; - - Vector3 n(p_baker->bake_cells[p_idx].normal[0], p_baker->bake_cells[p_idx].normal[1], p_baker->bake_cells[p_idx].normal[2]); - if (n.length() < 0.01) { - //too much fight over normal, zero it - p_baker->bake_cells[p_idx].normal[0] = 0; - p_baker->bake_cells[p_idx].normal[1] = 0; - p_baker->bake_cells[p_idx].normal[2] = 0; - } else { - n.normalize(); - p_baker->bake_cells[p_idx].normal[0] = n.x; - p_baker->bake_cells[p_idx].normal[1] = n.y; - p_baker->bake_cells[p_idx].normal[2] = n.z; - } - - p_baker->bake_cells[p_idx].alpha = 1.0; - - /* - //remove neighbours from used sides - - for(int n=0;n<6;n++) { - - int ofs[3]={0,0,0}; - - ofs[n/2]=(n&1)?1:-1; - - //convert to x,y,z on this level - int x=p_x; - int y=p_y; - int z=p_z; - - x+=ofs[0]; - y+=ofs[1]; - z+=ofs[2]; - - int ofs_x=0; - int ofs_y=0; - int ofs_z=0; - int size = 1<<p_level; - int half=size/2; - - - if (x<0 || x>=size || y<0 || y>=size || z<0 || z>=size) { - //neighbour is out, can't use it - p_baker->bake_cells[p_idx].used_sides&=~(1<<uint32_t(n)); - continue; - } - - uint32_t neighbour=0; - - for(int i=0;i<p_baker->cell_subdiv-1;i++) { - - Baker::Cell *bc = &p_baker->bake_cells[neighbour]; - - int child = 0; - if (x >= ofs_x + half) { - child|=1; - ofs_x+=half; - } - if (y >= ofs_y + half) { - child|=2; - ofs_y+=half; - } - if (z >= ofs_z + half) { - child|=4; - ofs_z+=half; - } - - neighbour = bc->childs[child]; - if (neighbour==Baker::CHILD_EMPTY) { - break; - } - - half>>=1; - } - - if (neighbour!=Baker::CHILD_EMPTY) { - p_baker->bake_cells[p_idx].used_sides&=~(1<<uint32_t(n)); - } - } - */ - } else { - - //go down - - float alpha_average = 0; - int half = (1 << (p_baker->cell_subdiv - 1)) >> (p_level + 1); - for (int i = 0; i < 8; i++) { - - uint32_t child = p_baker->bake_cells[p_idx].childs[i]; - - if (child == Baker::CHILD_EMPTY) - continue; - - int nx = p_x; - int ny = p_y; - int nz = p_z; - - if (i & 1) - nx += half; - if (i & 2) - ny += half; - if (i & 4) - nz += half; - - _fixup_plot(child, p_level + 1, nx, ny, nz, p_baker); - alpha_average += p_baker->bake_cells[child].alpha; - } - - p_baker->bake_cells[p_idx].alpha = alpha_average / 8.0; - p_baker->bake_cells[p_idx].emission[0] = 0; - p_baker->bake_cells[p_idx].emission[1] = 0; - p_baker->bake_cells[p_idx].emission[2] = 0; - p_baker->bake_cells[p_idx].normal[0] = 0; - p_baker->bake_cells[p_idx].normal[1] = 0; - p_baker->bake_cells[p_idx].normal[2] = 0; - p_baker->bake_cells[p_idx].albedo[0] = 0; - p_baker->bake_cells[p_idx].albedo[1] = 0; - p_baker->bake_cells[p_idx].albedo[2] = 0; - } -} - -Vector<Color> GIProbe::_get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add) { - - Vector<Color> ret; - - if (p_image.is_null() || p_image->empty()) { - - ret.resize(bake_texture_size * bake_texture_size); - for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { - ret[i] = p_color_add; - } - - return ret; - } - p_image = p_image->duplicate(); - - if (p_image->is_compressed()) { - print_line("DECOMPRESSING!!!!"); - - p_image->decompress(); - } - p_image->convert(Image::FORMAT_RGBA8); - p_image->resize(bake_texture_size, bake_texture_size, Image::INTERPOLATE_CUBIC); - - PoolVector<uint8_t>::Read r = p_image->get_data().read(); - ret.resize(bake_texture_size * bake_texture_size); - - for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { - Color c; - c.r = (r[i * 4 + 0] / 255.0) * p_color_mul.r + p_color_add.r; - c.g = (r[i * 4 + 1] / 255.0) * p_color_mul.g + p_color_add.g; - c.b = (r[i * 4 + 2] / 255.0) * p_color_mul.b + p_color_add.b; - - c.a = r[i * 4 + 3] / 255.0; - - ret[i] = c; - } - - return ret; -} - -GIProbe::Baker::MaterialCache GIProbe::_get_material_cache(Ref<Material> p_material, Baker *p_baker) { - - //this way of obtaining materials is inaccurate and also does not support some compressed formats very well - Ref<SpatialMaterial> mat = p_material; - - Ref<Material> material = mat; //hack for now - - if (p_baker->material_cache.has(material)) { - return p_baker->material_cache[material]; - } - - Baker::MaterialCache mc; - - if (mat.is_valid()) { - - Ref<Texture> albedo_tex = mat->get_texture(SpatialMaterial::TEXTURE_ALBEDO); - - Ref<Image> img_albedo; - if (albedo_tex.is_valid()) { - - img_albedo = albedo_tex->get_data(); - mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative - } else { - mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive - } - - Ref<Texture> emission_tex = mat->get_texture(SpatialMaterial::TEXTURE_EMISSION); - - Color emission_col = mat->get_emission(); - float emission_energy = mat->get_emission_energy(); - - Ref<Image> img_emission; - - if (emission_tex.is_valid()) { - - img_emission = emission_tex->get_data(); - } - - if (mat->get_emission_operator() == SpatialMaterial::EMISSION_OP_ADD) { - mc.emission = _get_bake_texture(img_emission, Color(1, 1, 1) * emission_energy, emission_col * emission_energy); - } else { - mc.emission = _get_bake_texture(img_emission, emission_col * emission_energy, Color(0, 0, 0)); - } - - } else { - Ref<Image> empty; - - mc.albedo = _get_bake_texture(empty, Color(0, 0, 0), Color(1, 1, 1)); - mc.emission = _get_bake_texture(empty, Color(0, 0, 0), Color(0, 0, 0)); - } - - p_baker->material_cache[p_material] = mc; - return mc; -} - -void GIProbe::_plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, Baker *p_baker, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) { - - for (int i = 0; i < p_mesh->get_surface_count(); i++) { - - if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) - continue; //only triangles - - Ref<Material> src_material; - - if (p_override_material.is_valid()) { - src_material = p_override_material; - } else if (i < p_materials.size() && p_materials[i].is_valid()) { - src_material = p_materials[i]; - } else { - src_material = p_mesh->surface_get_material(i); - } - Baker::MaterialCache material = _get_material_cache(src_material, p_baker); - - Array a = p_mesh->surface_get_arrays(i); - - PoolVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX]; - PoolVector<Vector3>::Read vr = vertices.read(); - PoolVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV]; - PoolVector<Vector2>::Read uvr; - PoolVector<int> index = a[Mesh::ARRAY_INDEX]; - - bool read_uv = false; - - if (uv.size()) { - - uvr = uv.read(); - read_uv = true; - } - - if (index.size()) { - - int facecount = index.size() / 3; - PoolVector<int>::Read ir = index.read(); - - for (int j = 0; j < facecount; j++) { - - Vector3 vtxs[3]; - Vector2 uvs[3]; - - for (int k = 0; k < 3; k++) { - vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]); - } - - if (read_uv) { - for (int k = 0; k < 3; k++) { - uvs[k] = uvr[ir[j * 3 + k]]; - } - } - - //test against original bounds - if (!fast_tri_box_overlap(-extents, extents * 2, vtxs)) - continue; - //plot - _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, p_baker->po2_bounds, p_baker); - } - - } else { - - int facecount = vertices.size() / 3; - - for (int j = 0; j < facecount; j++) { - - Vector3 vtxs[3]; - Vector2 uvs[3]; - - for (int k = 0; k < 3; k++) { - vtxs[k] = p_xform.xform(vr[j * 3 + k]); - } - - if (read_uv) { - for (int k = 0; k < 3; k++) { - uvs[k] = uvr[j * 3 + k]; - } - } - - //test against original bounds - if (!fast_tri_box_overlap(-extents, extents * 2, vtxs)) - continue; - //plot face - _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, p_baker->po2_bounds, p_baker); - } - } - } -} - -void GIProbe::_find_meshes(Node *p_at_node, Baker *p_baker) { +void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { MeshInstance *mi = Object::cast_to<MeshInstance>(p_at_node); if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT) && mi->is_visible_in_tree()) { @@ -1088,14 +342,14 @@ void GIProbe::_find_meshes(Node *p_at_node, Baker *p_baker) { Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform(); if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) { - Baker::PlotMesh pm; + PlotMesh pm; pm.local_xform = xf; pm.mesh = mesh; for (int i = 0; i < mesh->get_surface_count(); i++) { pm.instance_materials.push_back(mi->get_surface_material(i)); } pm.override_material = mi->get_material_override(); - p_baker->mesh_list.push_back(pm); + plot_meshes.push_back(pm); } } } @@ -1118,10 +372,10 @@ void GIProbe::_find_meshes(Node *p_at_node, Baker *p_baker) { Transform xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf); if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) { - Baker::PlotMesh pm; + PlotMesh pm; pm.local_xform = xf; pm.mesh = mesh; - p_baker->mesh_list.push_back(pm); + plot_meshes.push_back(pm); } } } @@ -1133,7 +387,7 @@ void GIProbe::_find_meshes(Node *p_at_node, Baker *p_baker) { if (!child->get_owner()) continue; //maybe a helper - _find_meshes(child, p_baker); + _find_meshes(child, plot_meshes); } } @@ -1143,145 +397,56 @@ GIProbe::BakeEndFunc GIProbe::bake_end_function = NULL; void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { - Baker baker; - static const int subdiv_value[SUBDIV_MAX] = { 7, 8, 9, 10 }; - baker.cell_subdiv = subdiv_value[subdiv]; - baker.bake_cells.resize(1); - - //find out the actual real bounds, power of 2, which gets the highest subdivision - baker.po2_bounds = AABB(-extents, extents * 2.0); - int longest_axis = baker.po2_bounds.get_longest_axis_index(); - baker.axis_cell_size[longest_axis] = (1 << (baker.cell_subdiv - 1)); - baker.leaf_voxel_count = 0; - - for (int i = 0; i < 3; i++) { - - if (i == longest_axis) - continue; + VoxelLightBaker baker; - baker.axis_cell_size[i] = baker.axis_cell_size[longest_axis]; - float axis_size = baker.po2_bounds.size[longest_axis]; + baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0)); - //shrink until fit subdiv - while (axis_size / 2.0 >= baker.po2_bounds.size[i]) { - axis_size /= 2.0; - baker.axis_cell_size[i] >>= 1; - } - - baker.po2_bounds.size[i] = baker.po2_bounds.size[longest_axis]; - } - - Transform to_bounds; - to_bounds.basis.scale(Vector3(baker.po2_bounds.size[longest_axis], baker.po2_bounds.size[longest_axis], baker.po2_bounds.size[longest_axis])); - to_bounds.origin = baker.po2_bounds.position; - - Transform to_grid; - to_grid.basis.scale(Vector3(baker.axis_cell_size[longest_axis], baker.axis_cell_size[longest_axis], baker.axis_cell_size[longest_axis])); + List<PlotMesh> mesh_list; - baker.to_cell_space = to_grid * to_bounds.affine_inverse(); - - _find_meshes(p_from_node ? p_from_node : get_parent(), &baker); + _find_meshes(p_from_node ? p_from_node : get_parent(), mesh_list); if (bake_begin_function) { - bake_begin_function(baker.mesh_list.size() + 1); + bake_begin_function(mesh_list.size() + 1); } int pmc = 0; - for (List<Baker::PlotMesh>::Element *E = baker.mesh_list.front(); E; E = E->next()) { + for (List<PlotMesh>::Element *E = mesh_list.front(); E; E = E->next()) { if (bake_step_function) { - bake_step_function(pmc, RTR("Plotting Meshes") + " " + itos(pmc) + "/" + itos(baker.mesh_list.size())); + bake_step_function(pmc, RTR("Plotting Meshes") + " " + itos(pmc) + "/" + itos(mesh_list.size())); } pmc++; - _plot_mesh(E->get().local_xform, E->get().mesh, &baker, E->get().instance_materials, E->get().override_material); + baker.plot_mesh(E->get().local_xform, E->get().mesh, E->get().instance_materials, E->get().override_material); } if (bake_step_function) { bake_step_function(pmc++, RTR("Finishing Plot")); } - _fixup_plot(0, 0, 0, 0, 0, &baker); + baker.end_bake(); //create the data for visual server - PoolVector<int> data; - - data.resize(16 + (8 + 1 + 1 + 1 + 1) * baker.bake_cells.size()); //4 for header, rest for rest. - - { - PoolVector<int>::Write w = data.write(); - - uint32_t *w32 = (uint32_t *)w.ptr(); + PoolVector<int> data = baker.create_gi_probe_data(); - w32[0] = 0; //version - w32[1] = baker.cell_subdiv; //subdiv - w32[2] = baker.axis_cell_size[0]; - w32[3] = baker.axis_cell_size[1]; - w32[4] = baker.axis_cell_size[2]; - w32[5] = baker.bake_cells.size(); - w32[6] = baker.leaf_voxel_count; - - int ofs = 16; - - for (int i = 0; i < baker.bake_cells.size(); i++) { - - for (int j = 0; j < 8; j++) { - w32[ofs++] = baker.bake_cells[i].childs[j]; - } - - { //albedo - uint32_t rgba = uint32_t(CLAMP(baker.bake_cells[i].albedo[0] * 255.0, 0, 255)) << 16; - rgba |= uint32_t(CLAMP(baker.bake_cells[i].albedo[1] * 255.0, 0, 255)) << 8; - rgba |= uint32_t(CLAMP(baker.bake_cells[i].albedo[2] * 255.0, 0, 255)) << 0; - - w32[ofs++] = rgba; - } - { //emission - - Vector3 e(baker.bake_cells[i].emission[0], baker.bake_cells[i].emission[1], baker.bake_cells[i].emission[2]); - float l = e.length(); - if (l > 0) { - e.normalize(); - l = CLAMP(l / 8.0, 0, 1.0); - } - - uint32_t em = uint32_t(CLAMP(e[0] * 255, 0, 255)) << 24; - em |= uint32_t(CLAMP(e[1] * 255, 0, 255)) << 16; - em |= uint32_t(CLAMP(e[2] * 255, 0, 255)) << 8; - em |= uint32_t(CLAMP(l * 255, 0, 255)); - - w32[ofs++] = em; - } - - //w32[ofs++]=baker.bake_cells[i].used_sides; - { //normal - - Vector3 n(baker.bake_cells[i].normal[0], baker.bake_cells[i].normal[1], baker.bake_cells[i].normal[2]); - n = n * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - uint32_t norm = 0; - - norm |= uint32_t(CLAMP(n.x * 255.0, 0, 255)) << 16; - norm |= uint32_t(CLAMP(n.y * 255.0, 0, 255)) << 8; - norm |= uint32_t(CLAMP(n.z * 255.0, 0, 255)) << 0; - - w32[ofs++] = norm; - } - - { - uint16_t alpha = CLAMP(uint32_t(baker.bake_cells[i].alpha * 65535.0), 0, 65535); - uint16_t level = baker.bake_cells[i].level; - - w32[ofs++] = (uint32_t(level) << 16) | uint32_t(alpha); - } + if (p_create_visual_debug) { + MultiMeshInstance *mmi = memnew(MultiMeshInstance); + mmi->set_multimesh(baker.create_debug_multimesh()); + add_child(mmi); +#ifdef TOOLS_ENABLED + if (get_tree()->get_edited_scene_root() == this) { + mmi->set_owner(this); + } else { + mmi->set_owner(get_owner()); } - } +#else + mmi->set_owner(get_owner()); +#endif - if (p_create_visual_debug) { - _create_debug_mesh(&baker); } else { Ref<GIProbeData> probe_data = get_probe_data(); @@ -1290,7 +455,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { probe_data.instance(); probe_data->set_bounds(AABB(-extents, extents * 2.0)); - probe_data->set_cell_size(baker.po2_bounds.size[longest_axis] / baker.axis_cell_size[longest_axis]); + probe_data->set_cell_size(baker.get_cell_size()); probe_data->set_dynamic_data(data); probe_data->set_dynamic_range(dynamic_range); probe_data->set_energy(energy); @@ -1299,7 +464,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { probe_data->set_propagation(propagation); probe_data->set_interior(interior); probe_data->set_compress(compress); - probe_data->set_to_cell_xform(baker.to_cell_space); + probe_data->set_to_cell_xform(baker.get_to_cell_space_xform()); set_probe_data(probe_data); } @@ -1309,135 +474,6 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { } } -void GIProbe::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, Baker *p_baker) { - - if (p_level == p_baker->cell_subdiv - 1) { - - Vector3 center = p_aabb.position + p_aabb.size * 0.5; - Transform xform; - xform.origin = center; - xform.basis.scale(p_aabb.size * 0.5); - p_multimesh->set_instance_transform(idx, xform); - Color col = Color(p_baker->bake_cells[p_idx].albedo[0], p_baker->bake_cells[p_idx].albedo[1], p_baker->bake_cells[p_idx].albedo[2]); - //Color col = Color(p_baker->bake_cells[p_idx].emission[0], p_baker->bake_cells[p_idx].emission[1], p_baker->bake_cells[p_idx].emission[2]); - p_multimesh->set_instance_color(idx, col); - - idx++; - - } else { - - for (int i = 0; i < 8; i++) { - - if (p_baker->bake_cells[p_idx].childs[i] == Baker::CHILD_EMPTY) - continue; - - AABB aabb = p_aabb; - aabb.size *= 0.5; - - if (i & 1) - aabb.position.x += aabb.size.x; - if (i & 2) - aabb.position.y += aabb.size.y; - if (i & 4) - aabb.position.z += aabb.size.z; - - _debug_mesh(p_baker->bake_cells[p_idx].childs[i], p_level + 1, aabb, p_multimesh, idx, p_baker); - } - } -} - -void GIProbe::_create_debug_mesh(Baker *p_baker) { - - Ref<MultiMesh> mm; - mm.instance(); - - mm->set_transform_format(MultiMesh::TRANSFORM_3D); - mm->set_color_format(MultiMesh::COLOR_8BIT); - print_line("leaf voxels: " + itos(p_baker->leaf_voxel_count)); - mm->set_instance_count(p_baker->leaf_voxel_count); - - Ref<ArrayMesh> mesh; - mesh.instance(); - - { - Array arr; - arr.resize(Mesh::ARRAY_MAX); - - PoolVector<Vector3> vertices; - PoolVector<Color> colors; - - int vtx_idx = 0; -#define ADD_VTX(m_idx) \ - ; \ - vertices.push_back(face_points[m_idx]); \ - colors.push_back(Color(1, 1, 1, 1)); \ - vtx_idx++; - - for (int i = 0; i < 6; i++) { - - Vector3 face_points[4]; - - for (int j = 0; j < 4; j++) { - - float v[3]; - v[0] = 1.0; - v[1] = 1 - 2 * ((j >> 1) & 1); - v[2] = v[1] * (1 - 2 * (j & 1)); - - for (int k = 0; k < 3; k++) { - - if (i < 3) - face_points[j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1); - else - face_points[3 - j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1); - } - } - - //tri 1 - ADD_VTX(0); - ADD_VTX(1); - ADD_VTX(2); - //tri 2 - ADD_VTX(2); - ADD_VTX(3); - ADD_VTX(0); - } - - arr[Mesh::ARRAY_VERTEX] = vertices; - arr[Mesh::ARRAY_COLOR] = colors; - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr); - } - - { - Ref<SpatialMaterial> fsm; - fsm.instance(); - fsm->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - fsm->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - fsm->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - fsm->set_albedo(Color(1, 1, 1, 1)); - - mesh->surface_set_material(0, fsm); - } - - mm->set_mesh(mesh); - - int idx = 0; - _debug_mesh(0, 0, p_baker->po2_bounds, mm, idx, p_baker); - - MultiMeshInstance *mmi = memnew(MultiMeshInstance); - mmi->set_multimesh(mm); - add_child(mmi); -#ifdef TOOLS_ENABLED - if (get_tree()->get_edited_scene_root() == this) { - mmi->set_owner(this); - } else { - mmi->set_owner(get_owner()); - } -#else - mmi->set_owner(get_owner()); -#endif -} - void GIProbe::_debug_bake() { bake(NULL, true); @@ -1516,8 +552,6 @@ GIProbe::GIProbe() { normal_bias = 0.0; propagation = 0.7; extents = Vector3(10, 10, 10); - color_scan_cell_width = 4; - bake_texture_size = 128; interior = false; compress = false; diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index 324ff8e917..0858af0001 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -100,67 +100,6 @@ public: typedef void (*BakeEndFunc)(); private: - //stuff used for bake - struct Baker { - - enum { - CHILD_EMPTY = 0xFFFFFFFF - }; - struct Cell { - - uint32_t childs[8]; - float albedo[3]; //albedo in RGB24 - float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) - float normal[3]; - uint32_t used_sides; - float alpha; //used for upsampling - int level; - - Cell() { - for (int i = 0; i < 8; i++) { - childs[i] = CHILD_EMPTY; - } - - for (int i = 0; i < 3; i++) { - emission[i] = 0; - albedo[i] = 0; - normal[i] = 0; - } - alpha = 0; - used_sides = 0; - level = 0; - } - }; - - Vector<Cell> bake_cells; - int cell_subdiv; - - struct MaterialCache { - //128x128 textures - Vector<Color> albedo; - Vector<Color> emission; - }; - - Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color); - Map<Ref<Material>, MaterialCache> material_cache; - MaterialCache _get_material_cache(Ref<Material> p_material); - int leaf_voxel_count; - - AABB po2_bounds; - int axis_cell_size[3]; - - struct PlotMesh { - Ref<Material> override_material; - Vector<Ref<Material> > instance_materials; - Ref<Mesh> mesh; - Transform local_xform; - }; - - Transform to_cell_space; - - List<PlotMesh> mesh_list; - }; - Ref<GIProbeData> probe_data; RID gi_probe; @@ -175,19 +114,14 @@ private: bool interior; bool compress; - int color_scan_cell_width; - int bake_texture_size; - - Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add); - Baker::MaterialCache _get_material_cache(Ref<Material> p_material, Baker *p_baker); - void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const Baker::MaterialCache &p_material, const AABB &p_aabb, Baker *p_baker); - void _plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, Baker *p_baker, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material); - void _find_meshes(Node *p_at_node, Baker *p_baker); - void _fixup_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, Baker *p_baker); - - void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, Baker *p_baker); - void _create_debug_mesh(Baker *p_baker); + struct PlotMesh { + Ref<Material> override_material; + Vector<Ref<Material> > instance_materials; + Ref<Mesh> mesh; + Transform local_xform; + }; + void _find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes); void _debug_bake(); protected: diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 1fc4e932e8..6eb2028d8e 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -142,6 +142,14 @@ PoolVector<Face3> Light::get_faces(uint32_t p_usage_flags) const { return PoolVector<Face3>(); } +void Light::set_bake_mode(BakeMode p_mode) { + bake_mode = p_mode; +} + +Light::BakeMode Light::get_bake_mode() const { + return bake_mode; +} + void Light::_update_visibility() { if (!is_inside_tree()) @@ -219,12 +227,16 @@ void Light::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_color", "shadow_color"), &Light::set_shadow_color); ClassDB::bind_method(D_METHOD("get_shadow_color"), &Light::get_shadow_color); + ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light::set_bake_mode); + ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light::get_bake_mode); + ADD_GROUP("Light", "light_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_ENERGY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR); + ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disable,Indirect,All"), "set_bake_mode", "get_bake_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); ADD_GROUP("Shadow", "shadow_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow"); @@ -252,6 +264,10 @@ void Light::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS); BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS_SPLIT_SCALE); BIND_ENUM_CONSTANT(PARAM_MAX); + + BIND_ENUM_CONSTANT(BAKE_DISABLED); + BIND_ENUM_CONSTANT(BAKE_INDIRECT); + BIND_ENUM_CONSTANT(BAKE_ALL); } Light::Light(VisualServer::LightType p_type) { @@ -267,6 +283,7 @@ Light::Light(VisualServer::LightType p_type) { VS::get_singleton()->instance_set_base(get_instance(), light); reverse_cull = false; + bake_mode = BAKE_INDIRECT; editor_only = false; set_color(Color(1, 1, 1, 1)); diff --git a/scene/3d/light.h b/scene/3d/light.h index 33e62214b1..7ba25731d9 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -63,6 +63,12 @@ public: PARAM_MAX = VS::LIGHT_PARAM_MAX }; + enum BakeMode { + BAKE_DISABLED, + BAKE_INDIRECT, + BAKE_ALL + }; + private: Color color; float param[PARAM_MAX]; @@ -74,6 +80,7 @@ private: VS::LightType type; bool editor_only; void _update_visibility(); + BakeMode bake_mode; // bind helpers @@ -114,6 +121,9 @@ public: void set_shadow_reverse_cull_face(bool p_enable); bool get_shadow_reverse_cull_face() const; + void set_bake_mode(BakeMode p_mode); + BakeMode get_bake_mode() const; + virtual AABB get_aabb() const; virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; @@ -122,6 +132,7 @@ public: }; VARIANT_ENUM_CAST(Light::Param); +VARIANT_ENUM_CAST(Light::BakeMode); class DirectionalLight : public Light { diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index b6507aedb3..78cf75e3b3 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -202,7 +202,7 @@ void Navigation::_navmesh_unlink(int p_id) { nm.linked = false; } -int Navigation::navmesh_create(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) { +int Navigation::navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) { int id = last_id++; NavMesh nm; @@ -686,7 +686,7 @@ Vector3 Navigation::get_up_vector() const { void Navigation::_bind_methods() { - ClassDB::bind_method(D_METHOD("navmesh_create", "mesh", "xform", "owner"), &Navigation::navmesh_create, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("navmesh_add", "mesh", "xform", "owner"), &Navigation::navmesh_add, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("navmesh_set_transform", "id", "xform"), &Navigation::navmesh_set_transform); ClassDB::bind_method(D_METHOD("navmesh_remove", "id"), &Navigation::navmesh_remove); diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h index d9a38f7b00..134afa2278 100644 --- a/scene/3d/navigation.h +++ b/scene/3d/navigation.h @@ -166,7 +166,7 @@ public: Vector3 get_up_vector() const; //API should be as dynamic as possible - int navmesh_create(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner = NULL); + int navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner = NULL); void navmesh_set_transform(int p_id, const Transform &p_xform); void navmesh_remove(int p_id); diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 40750cdfe8..4fb12b8fac 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -471,7 +471,7 @@ void NavigationMeshInstance::set_enabled(bool p_enabled) { if (navmesh.is_valid()) { - nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this); + nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); } } } @@ -508,7 +508,7 @@ void NavigationMeshInstance::_notification(int p_what) { if (enabled && navmesh.is_valid()) { - nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this); + nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); } break; } @@ -568,7 +568,7 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh> &p_na navmesh = p_navmesh; if (navigation && navmesh.is_valid() && enabled) { - nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this); + nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); } if (debug_view && navmesh.is_valid()) { diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp new file mode 100644 index 0000000000..98dc1590d8 --- /dev/null +++ b/scene/3d/voxel_light_baker.cpp @@ -0,0 +1,2373 @@ +#include "voxel_light_baker.h" +#include "os/os.h" +#define FINDMINMAX(x0, x1, x2, min, max) \ + min = max = x0; \ + if (x1 < min) min = x1; \ + if (x1 > max) max = x1; \ + if (x2 < min) min = x2; \ + if (x2 > max) max = x2; + +static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) { + int q; + Vector3 vmin, vmax; + for (q = 0; q <= 2; q++) { + if (normal[q] > 0.0f) { + vmin[q] = -maxbox[q]; + vmax[q] = maxbox[q]; + } else { + vmin[q] = maxbox[q]; + vmax[q] = -maxbox[q]; + } + } + if (normal.dot(vmin) + d > 0.0f) return false; + if (normal.dot(vmax) + d >= 0.0f) return true; + + return false; +} + +/*======================== X-tests ========================*/ +#define AXISTEST_X01(a, b, fa, fb) \ + p0 = a * v0.y - b * v0.z; \ + p2 = a * v2.y - b * v2.z; \ + if (p0 < p2) { \ + min = p0; \ + max = p2; \ + } else { \ + min = p2; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \ + if (min > rad || max < -rad) return false; + +#define AXISTEST_X2(a, b, fa, fb) \ + p0 = a * v0.y - b * v0.z; \ + p1 = a * v1.y - b * v1.z; \ + if (p0 < p1) { \ + min = p0; \ + max = p1; \ + } else { \ + min = p1; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \ + if (min > rad || max < -rad) return false; + +/*======================== Y-tests ========================*/ +#define AXISTEST_Y02(a, b, fa, fb) \ + p0 = -a * v0.x + b * v0.z; \ + p2 = -a * v2.x + b * v2.z; \ + if (p0 < p2) { \ + min = p0; \ + max = p2; \ + } else { \ + min = p2; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \ + if (min > rad || max < -rad) return false; + +#define AXISTEST_Y1(a, b, fa, fb) \ + p0 = -a * v0.x + b * v0.z; \ + p1 = -a * v1.x + b * v1.z; \ + if (p0 < p1) { \ + min = p0; \ + max = p1; \ + } else { \ + min = p1; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \ + if (min > rad || max < -rad) return false; + + /*======================== Z-tests ========================*/ + +#define AXISTEST_Z12(a, b, fa, fb) \ + p1 = a * v1.x - b * v1.y; \ + p2 = a * v2.x - b * v2.y; \ + if (p2 < p1) { \ + min = p2; \ + max = p1; \ + } else { \ + min = p1; \ + max = p2; \ + } \ + rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \ + if (min > rad || max < -rad) return false; + +#define AXISTEST_Z0(a, b, fa, fb) \ + p0 = a * v0.x - b * v0.y; \ + p1 = a * v1.x - b * v1.y; \ + if (p0 < p1) { \ + min = p0; \ + max = p1; \ + } else { \ + min = p1; \ + max = p0; \ + } \ + rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \ + if (min > rad || max < -rad) return false; + +static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalfsize, const Vector3 *triverts) { + + /* use separating axis theorem to test overlap between triangle and box */ + /* need to test for overlap in these directions: */ + /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ + /* we do not even need to test these) */ + /* 2) normal of the triangle */ + /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ + /* this gives 3x3=9 more tests */ + Vector3 v0, v1, v2; + float min, max, d, p0, p1, p2, rad, fex, fey, fez; + Vector3 normal, e0, e1, e2; + + /* This is the fastest branch on Sun */ + /* move everything so that the boxcenter is in (0,0,0) */ + + v0 = triverts[0] - boxcenter; + v1 = triverts[1] - boxcenter; + v2 = triverts[2] - boxcenter; + + /* compute triangle edges */ + e0 = v1 - v0; /* tri edge 0 */ + e1 = v2 - v1; /* tri edge 1 */ + e2 = v0 - v2; /* tri edge 2 */ + + /* Bullet 3: */ + /* test the 9 tests first (this was faster) */ + fex = Math::abs(e0.x); + fey = Math::abs(e0.y); + fez = Math::abs(e0.z); + AXISTEST_X01(e0.z, e0.y, fez, fey); + AXISTEST_Y02(e0.z, e0.x, fez, fex); + AXISTEST_Z12(e0.y, e0.x, fey, fex); + + fex = Math::abs(e1.x); + fey = Math::abs(e1.y); + fez = Math::abs(e1.z); + AXISTEST_X01(e1.z, e1.y, fez, fey); + AXISTEST_Y02(e1.z, e1.x, fez, fex); + AXISTEST_Z0(e1.y, e1.x, fey, fex); + + fex = Math::abs(e2.x); + fey = Math::abs(e2.y); + fez = Math::abs(e2.z); + AXISTEST_X2(e2.z, e2.y, fez, fey); + AXISTEST_Y1(e2.z, e2.x, fez, fex); + AXISTEST_Z12(e2.y, e2.x, fey, fex); + + /* Bullet 1: */ + /* first test overlap in the {x,y,z}-directions */ + /* find min, max of the triangle each direction, and test for overlap in */ + /* that direction -- this is equivalent to testing a minimal AABB around */ + /* the triangle against the AABB */ + + /* test in X-direction */ + FINDMINMAX(v0.x, v1.x, v2.x, min, max); + if (min > boxhalfsize.x || max < -boxhalfsize.x) return false; + + /* test in Y-direction */ + FINDMINMAX(v0.y, v1.y, v2.y, min, max); + if (min > boxhalfsize.y || max < -boxhalfsize.y) return false; + + /* test in Z-direction */ + FINDMINMAX(v0.z, v1.z, v2.z, min, max); + if (min > boxhalfsize.z || max < -boxhalfsize.z) return false; + + /* Bullet 2: */ + /* test if the box intersects the plane of the triangle */ + /* compute plane equation of triangle: normal*x+d=0 */ + normal = e0.cross(e1); + d = -normal.dot(v0); /* plane eq: normal.x+d=0 */ + if (!planeBoxOverlap(normal, d, boxhalfsize)) return false; + + return true; /* box and triangle overlaps */ +} + +static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv) { + + if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) + return p_uv[0]; + if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) + return p_uv[1]; + if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) + return p_uv[2]; + + Vector3 v0 = p_vtx[1] - p_vtx[0]; + Vector3 v1 = p_vtx[2] - p_vtx[0]; + Vector3 v2 = p_pos - p_vtx[0]; + + float d00 = v0.dot(v0); + float d01 = v0.dot(v1); + float d11 = v1.dot(v1); + float d20 = v2.dot(v0); + float d21 = v2.dot(v1); + float denom = (d00 * d11 - d01 * d01); + if (denom == 0) + return p_uv[0]; + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + + return p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; +} + +void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) { + + if (p_level == cell_subdiv - 1) { + //plot the face by guessing it's albedo and emission value + + //find best axis to map to, for scanning values + int closest_axis = 0; + float closest_dot = 0; + + Plane plane = Plane(p_vtx[0], p_vtx[1], p_vtx[2]); + Vector3 normal = plane.normal; + + for (int i = 0; i < 3; i++) { + + Vector3 axis; + axis[i] = 1.0; + float dot = ABS(normal.dot(axis)); + if (i == 0 || dot > closest_dot) { + closest_axis = i; + closest_dot = dot; + } + } + + Vector3 axis; + axis[closest_axis] = 1.0; + Vector3 t1; + t1[(closest_axis + 1) % 3] = 1.0; + Vector3 t2; + t2[(closest_axis + 2) % 3] = 1.0; + + t1 *= p_aabb.size[(closest_axis + 1) % 3] / float(color_scan_cell_width); + t2 *= p_aabb.size[(closest_axis + 2) % 3] / float(color_scan_cell_width); + + Color albedo_accum; + Color emission_accum; + Vector3 normal_accum; + + float alpha = 0.0; + + //map to a grid average in the best axis for this face + for (int i = 0; i < color_scan_cell_width; i++) { + + Vector3 ofs_i = float(i) * t1; + + for (int j = 0; j < color_scan_cell_width; j++) { + + Vector3 ofs_j = float(j) * t2; + + Vector3 from = p_aabb.position + ofs_i + ofs_j; + Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis]; + Vector3 half = (to - from) * 0.5; + + //is in this cell? + if (!fast_tri_box_overlap(from + half, half, p_vtx)) { + continue; //face does not span this cell + } + + //go from -size to +size*2 to avoid skipping collisions + Vector3 ray_from = from + (t1 + t2) * 0.5 - axis * p_aabb.size[closest_axis]; + Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis] * 2; + + if (normal.dot(ray_from - ray_to) < 0) { + SWAP(ray_from, ray_to); + } + + Vector3 intersection; + + if (!plane.intersects_segment(ray_from, ray_to, &intersection)) { + if (ABS(plane.distance_to(ray_from)) < ABS(plane.distance_to(ray_to))) { + intersection = plane.project(ray_from); + } else { + + intersection = plane.project(ray_to); + } + } + + intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection); + + Vector2 uv = get_uv(intersection, p_vtx, p_uv); + + int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); + int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); + + int ofs = uv_y * bake_texture_size + uv_x; + albedo_accum.r += p_material.albedo[ofs].r; + albedo_accum.g += p_material.albedo[ofs].g; + albedo_accum.b += p_material.albedo[ofs].b; + albedo_accum.a += p_material.albedo[ofs].a; + + emission_accum.r += p_material.emission[ofs].r; + emission_accum.g += p_material.emission[ofs].g; + emission_accum.b += p_material.emission[ofs].b; + + normal_accum += normal; + + alpha += 1.0; + } + } + + if (alpha == 0) { + //could not in any way get texture information.. so use closest point to center + + Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]); + Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5); + + Vector2 uv = get_uv(inters, p_vtx, p_uv); + + int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); + int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); + + int ofs = uv_y * bake_texture_size + uv_x; + + alpha = 1.0 / (color_scan_cell_width * color_scan_cell_width); + + albedo_accum.r = p_material.albedo[ofs].r * alpha; + albedo_accum.g = p_material.albedo[ofs].g * alpha; + albedo_accum.b = p_material.albedo[ofs].b * alpha; + albedo_accum.a = p_material.albedo[ofs].a * alpha; + + emission_accum.r = p_material.emission[ofs].r * alpha; + emission_accum.g = p_material.emission[ofs].g * alpha; + emission_accum.b = p_material.emission[ofs].b * alpha; + + normal_accum *= alpha; + + } else { + + float accdiv = 1.0 / (color_scan_cell_width * color_scan_cell_width); + alpha *= accdiv; + + albedo_accum.r *= accdiv; + albedo_accum.g *= accdiv; + albedo_accum.b *= accdiv; + albedo_accum.a *= accdiv; + + emission_accum.r *= accdiv; + emission_accum.g *= accdiv; + emission_accum.b *= accdiv; + + normal_accum *= accdiv; + } + + //put this temporarily here, corrected in a later step + bake_cells[p_idx].albedo[0] += albedo_accum.r; + bake_cells[p_idx].albedo[1] += albedo_accum.g; + bake_cells[p_idx].albedo[2] += albedo_accum.b; + bake_cells[p_idx].emission[0] += emission_accum.r; + bake_cells[p_idx].emission[1] += emission_accum.g; + bake_cells[p_idx].emission[2] += emission_accum.b; + bake_cells[p_idx].normal[0] += normal_accum.x; + bake_cells[p_idx].normal[1] += normal_accum.y; + bake_cells[p_idx].normal[2] += normal_accum.z; + bake_cells[p_idx].alpha += alpha; + + } else { + //go down + + int half = (1 << (cell_subdiv - 1)) >> (p_level + 1); + for (int i = 0; i < 8; i++) { + + AABB aabb = p_aabb; + aabb.size *= 0.5; + + int nx = p_x; + int ny = p_y; + int nz = p_z; + + if (i & 1) { + aabb.position.x += aabb.size.x; + nx += half; + } + if (i & 2) { + aabb.position.y += aabb.size.y; + ny += half; + } + if (i & 4) { + aabb.position.z += aabb.size.z; + nz += half; + } + //make sure to not plot beyond limits + if (nx < 0 || nx >= axis_cell_size[0] || ny < 0 || ny >= axis_cell_size[1] || nz < 0 || nz >= axis_cell_size[2]) + continue; + + { + AABB test_aabb = aabb; + //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time + Vector3 qsize = test_aabb.size * 0.5; //quarter size, for fast aabb test + + if (!fast_tri_box_overlap(test_aabb.position + qsize, qsize, p_vtx)) { + //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) { + //does not fit in child, go on + continue; + } + } + + if (bake_cells[p_idx].childs[i] == CHILD_EMPTY) { + //sub cell must be created + + uint32_t child_idx = bake_cells.size(); + bake_cells[p_idx].childs[i] = child_idx; + bake_cells.resize(bake_cells.size() + 1); + bake_cells[child_idx].level = p_level + 1; + } + + _plot_face(bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_uv, p_material, aabb); + } + } +} + +Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add) { + + Vector<Color> ret; + + if (p_image.is_null() || p_image->empty()) { + + ret.resize(bake_texture_size * bake_texture_size); + for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { + ret[i] = p_color_add; + } + + return ret; + } + p_image = p_image->duplicate(); + + if (p_image->is_compressed()) { + print_line("DECOMPRESSING!!!!"); + + p_image->decompress(); + } + p_image->convert(Image::FORMAT_RGBA8); + p_image->resize(bake_texture_size, bake_texture_size, Image::INTERPOLATE_CUBIC); + + PoolVector<uint8_t>::Read r = p_image->get_data().read(); + ret.resize(bake_texture_size * bake_texture_size); + + for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { + Color c; + c.r = (r[i * 4 + 0] / 255.0) * p_color_mul.r + p_color_add.r; + c.g = (r[i * 4 + 1] / 255.0) * p_color_mul.g + p_color_add.g; + c.b = (r[i * 4 + 2] / 255.0) * p_color_mul.b + p_color_add.b; + + c.a = r[i * 4 + 3] / 255.0; + + ret[i] = c; + } + + return ret; +} + +VoxelLightBaker::MaterialCache VoxelLightBaker::_get_material_cache(Ref<Material> p_material) { + + //this way of obtaining materials is inaccurate and also does not support some compressed formats very well + Ref<SpatialMaterial> mat = p_material; + + Ref<Material> material = mat; //hack for now + + if (material_cache.has(material)) { + return material_cache[material]; + } + + MaterialCache mc; + + if (mat.is_valid()) { + + Ref<Texture> albedo_tex = mat->get_texture(SpatialMaterial::TEXTURE_ALBEDO); + + Ref<Image> img_albedo; + if (albedo_tex.is_valid()) { + + img_albedo = albedo_tex->get_data(); + mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative + } else { + mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive + } + + Ref<Texture> emission_tex = mat->get_texture(SpatialMaterial::TEXTURE_EMISSION); + + Color emission_col = mat->get_emission(); + float emission_energy = mat->get_emission_energy(); + + Ref<Image> img_emission; + + if (emission_tex.is_valid()) { + + img_emission = emission_tex->get_data(); + } + + if (mat->get_emission_operator() == SpatialMaterial::EMISSION_OP_ADD) { + mc.emission = _get_bake_texture(img_emission, Color(1, 1, 1) * emission_energy, emission_col * emission_energy); + } else { + mc.emission = _get_bake_texture(img_emission, emission_col * emission_energy, Color(0, 0, 0)); + } + + } else { + Ref<Image> empty; + + mc.albedo = _get_bake_texture(empty, Color(0, 0, 0), Color(1, 1, 1)); + mc.emission = _get_bake_texture(empty, Color(0, 0, 0), Color(0, 0, 0)); + } + + material_cache[p_material] = mc; + return mc; +} + +void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) { + + for (int i = 0; i < p_mesh->get_surface_count(); i++) { + + if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) + continue; //only triangles + + Ref<Material> src_material; + + if (p_override_material.is_valid()) { + src_material = p_override_material; + } else if (i < p_materials.size() && p_materials[i].is_valid()) { + src_material = p_materials[i]; + } else { + src_material = p_mesh->surface_get_material(i); + } + MaterialCache material = _get_material_cache(src_material); + + Array a = p_mesh->surface_get_arrays(i); + + PoolVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX]; + PoolVector<Vector3>::Read vr = vertices.read(); + PoolVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV]; + PoolVector<Vector2>::Read uvr; + PoolVector<int> index = a[Mesh::ARRAY_INDEX]; + + bool read_uv = false; + + if (uv.size()) { + + uvr = uv.read(); + read_uv = true; + } + + if (index.size()) { + + int facecount = index.size() / 3; + PoolVector<int>::Read ir = index.read(); + + for (int j = 0; j < facecount; j++) { + + Vector3 vtxs[3]; + Vector2 uvs[3]; + + for (int k = 0; k < 3; k++) { + vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]); + } + + if (read_uv) { + for (int k = 0; k < 3; k++) { + uvs[k] = uvr[ir[j * 3 + k]]; + } + } + + //test against original bounds + if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) + continue; + //plot + _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds); + } + + } else { + + int facecount = vertices.size() / 3; + + for (int j = 0; j < facecount; j++) { + + Vector3 vtxs[3]; + Vector2 uvs[3]; + + for (int k = 0; k < 3; k++) { + vtxs[k] = p_xform.xform(vr[j * 3 + k]); + } + + if (read_uv) { + for (int k = 0; k < 3; k++) { + uvs[k] = uvr[j * 3 + k]; + } + } + + //test against original bounds + if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) + continue; + //plot face + _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds); + } + } + } + + max_original_cells = bake_cells.size(); +} + +void VoxelLightBaker::_init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent) { + + bake_light[p_idx].x = p_x; + bake_light[p_idx].y = p_y; + bake_light[p_idx].z = p_z; + + if (p_level == cell_subdiv - 1) { + + bake_light[p_idx].next_leaf = first_leaf; + first_leaf = p_idx; + } else { + + //go down + int half = (1 << (cell_subdiv - 1)) >> (p_level + 1); + for (int i = 0; i < 8; i++) { + + uint32_t child = bake_cells[p_idx].childs[i]; + + if (child == CHILD_EMPTY) + continue; + + int nx = p_x; + int ny = p_y; + int nz = p_z; + + if (i & 1) + nx += half; + if (i & 2) + ny += half; + if (i & 4) + nz += half; + + _init_light_plot(child, p_level + 1, nx, ny, nz, p_idx); + } + } +} + +void VoxelLightBaker::begin_bake_light(BakeQuality p_quality, BakeMode p_bake_mode, float p_propagation, float p_energy) { + _check_init_light(); + propagation = p_propagation; + bake_quality = p_quality; + bake_mode = p_bake_mode; + energy = p_energy; +} + +void VoxelLightBaker::_check_init_light() { + if (bake_light.size() == 0) { + + direct_lights_baked = false; + leaf_voxel_count = 0; + _fixup_plot(0, 0); //pre fixup, so normal, albedo, emission, etc. work for lighting. + bake_light.resize(bake_cells.size()); + zeromem(bake_light.ptrw(), bake_light.size() * sizeof(Light)); + first_leaf = -1; + _init_light_plot(0, 0, 0, 0, 0, CHILD_EMPTY); + } +} + +static float _get_normal_advance(const Vector3 &p_normal) { + + Vector3 normal = p_normal; + Vector3 unorm = normal.abs(); + + if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { + // x code + unorm = normal.x > 0.0 ? Vector3(1.0, 0.0, 0.0) : Vector3(-1.0, 0.0, 0.0); + } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { + // y code + unorm = normal.y > 0.0 ? Vector3(0.0, 1.0, 0.0) : Vector3(0.0, -1.0, 0.0); + } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { + // z code + unorm = normal.z > 0.0 ? Vector3(0.0, 0.0, 1.0) : Vector3(0.0, 0.0, -1.0); + } else { + // oh-no we messed up code + // has to be + unorm = Vector3(1.0, 0.0, 0.0); + } + + return 1.0 / normal.dot(unorm); +} + +static const Vector3 aniso_normal[6] = { + Vector3(-1, 0, 0), + Vector3(1, 0, 0), + Vector3(0, -1, 0), + Vector3(0, 1, 0), + Vector3(0, 0, -1), + Vector3(0, 0, 1) +}; + +uint32_t VoxelLightBaker::_find_cell_at_pos(const Cell *cells, int x, int y, int z) { + + uint32_t cell = 0; + + int ofs_x = 0; + int ofs_y = 0; + int ofs_z = 0; + int size = 1 << (cell_subdiv - 1); + int half = size / 2; + + if (x < 0 || x >= size) + return -1; + if (y < 0 || y >= size) + return -1; + if (z < 0 || z >= size) + return -1; + + for (int i = 0; i < cell_subdiv - 1; i++) { + + const Cell *bc = &cells[cell]; + + int child = 0; + if (x >= ofs_x + half) { + child |= 1; + ofs_x += half; + } + if (y >= ofs_y + half) { + child |= 2; + ofs_y += half; + } + if (z >= ofs_z + half) { + child |= 4; + ofs_z += half; + } + + cell = bc->childs[child]; + if (cell == CHILD_EMPTY) + return CHILD_EMPTY; + + half >>= 1; + } + + return cell; +} +void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, bool p_direct) { + + _check_init_light(); + + float max_len = Vector3(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]).length() * 1.1; + + if (p_direct) + direct_lights_baked = true; + + Vector3 light_axis = p_direction; + Plane clip[3]; + int clip_planes = 0; + + Light *light_data = bake_light.ptrw(); + const Cell *cells = bake_cells.ptr(); + + for (int i = 0; i < 3; i++) { + + if (ABS(light_axis[i]) < CMP_EPSILON) + continue; + clip[clip_planes].normal[i] = 1.0; + + if (light_axis[i] < 0) { + + clip[clip_planes].d = axis_cell_size[i] + 1; + } else { + clip[clip_planes].d -= 1.0; + } + + clip_planes++; + } + + float distance_adv = _get_normal_advance(light_axis); + + int success_count = 0; + + Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy; + + int idx = first_leaf; + while (idx >= 0) { + + //print_line("plot idx " + itos(idx)); + Light *light = &light_data[idx]; + + Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5); + to += -light_axis.sign() * 0.47; //make it more likely to receive a ray + + Vector3 from = to - max_len * light_axis; + + for (int j = 0; j < clip_planes; j++) { + + clip[j].intersects_segment(from, to, &from); + } + + float distance = (to - from).length(); + distance += distance_adv - Math::fmod(distance, distance_adv); //make it reach the center of the box always + from = to - light_axis * distance; + + uint32_t result = 0xFFFFFFFF; + + while (distance > -distance_adv) { //use this to avoid precision errors + + result = _find_cell_at_pos(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z))); + if (result != 0xFFFFFFFF) { + break; + } + + from += light_axis * distance_adv; + distance -= distance_adv; + } + + if (result == idx) { + //cell hit itself! hooray! + + Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]); + if (normal == Vector3()) { + for (int i = 0; i < 6; i++) { + light->accum[i][0] += light_energy.x * cells[idx].albedo[0]; + light->accum[i][1] += light_energy.y * cells[idx].albedo[1]; + light->accum[i][2] += light_energy.z * cells[idx].albedo[2]; + } + + } else { + + for (int i = 0; i < 6; i++) { + float s = MAX(0.0, aniso_normal[i].dot(-normal)); + light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * s; + light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * s; + light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * s; + } + } + + for (int i = 0; i < 6; i++) { + float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct + light->direct_accum[i][0] += light_energy.x * s; + light->direct_accum[i][1] += light_energy.y * s; + light->direct_accum[i][2] += light_energy.z * s; + } + success_count++; + } + + idx = light_data[idx].next_leaf; + } +} + +void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, bool p_direct) { + + _check_init_light(); + + if (p_direct) + direct_lights_baked = true; + + Plane clip[3]; + int clip_planes = 0; + + // uint64_t us = OS::get_singleton()->get_ticks_usec(); + + Vector3 light_pos = to_cell_space.xform(p_pos) + Vector3(0.5, 0.5, 0.5); + //Vector3 spot_axis = -light_cache.transform.basis.get_axis(2).normalized(); + + float local_radius = to_cell_space.basis.xform(Vector3(0, 0, 1)).length() * p_radius; + + Light *light_data = bake_light.ptrw(); + const Cell *cells = bake_cells.ptr(); + Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy; + + int idx = first_leaf; + while (idx >= 0) { + + //print_line("plot idx " + itos(idx)); + Light *light = &light_data[idx]; + + Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5); + to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray + + Vector3 light_axis = (to - light_pos).normalized(); + float distance_adv = _get_normal_advance(light_axis); + + Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]); + + if (normal != Vector3() && normal.dot(-light_axis) < 0.001) { + idx = light_data[idx].next_leaf; + continue; + } + + float att = 1.0; + { + float d = light_pos.distance_to(to); + if (d + distance_adv > local_radius) { + idx = light_data[idx].next_leaf; + continue; // too far away + } + + float dt = CLAMP((d + distance_adv) / local_radius, 0, 1); + att *= powf(1.0 - dt, p_attenutation); + } +#if 0 + if (light_cache.type == VS::LIGHT_SPOT) { + + float angle = Math::rad2deg(acos(light_axis.dot(spot_axis))); + if (angle > light_cache.spot_angle) + continue; + + float d = CLAMP(angle / light_cache.spot_angle, 1, 0); + att *= powf(1.0 - d, light_cache.spot_attenuation); + } +#endif + clip_planes = 0; + + for (int c = 0; c < 3; c++) { + + if (ABS(light_axis[c]) < CMP_EPSILON) + continue; + clip[clip_planes].normal[c] = 1.0; + + if (light_axis[c] < 0) { + + clip[clip_planes].d = (1 << (cell_subdiv - 1)) + 1; + } else { + clip[clip_planes].d -= 1.0; + } + + clip_planes++; + } + + Vector3 from = light_pos; + + for (int j = 0; j < clip_planes; j++) { + + clip[j].intersects_segment(from, to, &from); + } + + float distance = (to - from).length(); + + distance -= Math::fmod(distance, distance_adv); //make it reach the center of the box always, but this tame make it closer + from = to - light_axis * distance; + to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray + + uint32_t result = 0xFFFFFFFF; + + while (distance > -distance_adv) { //use this to avoid precision errors + + result = _find_cell_at_pos(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z))); + if (result != 0xFFFFFFFF) { + break; + } + + from += light_axis * distance_adv; + distance -= distance_adv; + } + + if (result == idx) { + //cell hit itself! hooray! + + if (normal == Vector3()) { + for (int i = 0; i < 6; i++) { + light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * att; + light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * att; + light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * att; + } + + } else { + + for (int i = 0; i < 6; i++) { + float s = MAX(0.0, aniso_normal[i].dot(-normal)); + light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * s * att; + light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * s * att; + light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * s * att; + } + } + + for (int i = 0; i < 6; i++) { + float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct + light->direct_accum[i][0] += light_energy.x * s * att; + light->direct_accum[i][1] += light_energy.y * s * att; + light->direct_accum[i][2] += light_energy.z * s * att; + } + } + + idx = light_data[idx].next_leaf; + } +} + +void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axis, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, float p_spot_angle, float p_spot_attenuation, bool p_direct) { + + _check_init_light(); + + if (p_direct) + direct_lights_baked = true; + + Plane clip[3]; + int clip_planes = 0; + + // uint64_t us = OS::get_singleton()->get_ticks_usec(); + + Vector3 light_pos = to_cell_space.xform(p_pos) + Vector3(0.5, 0.5, 0.5); + Vector3 spot_axis = to_cell_space.basis.xform(p_axis).normalized(); + + float local_radius = to_cell_space.basis.xform(Vector3(0, 0, 1)).length() * p_radius; + + Light *light_data = bake_light.ptrw(); + const Cell *cells = bake_cells.ptr(); + Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy; + + int idx = first_leaf; + while (idx >= 0) { + + //print_line("plot idx " + itos(idx)); + Light *light = &light_data[idx]; + + Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5); + + Vector3 light_axis = (to - light_pos).normalized(); + float distance_adv = _get_normal_advance(light_axis); + + Vector3 normal(cells[idx].normal[0], cells[idx].normal[1], cells[idx].normal[2]); + + if (normal != Vector3() && normal.dot(-light_axis) < 0.001) { + idx = light_data[idx].next_leaf; + continue; + } + + float angle = Math::rad2deg(Math::acos(light_axis.dot(-spot_axis))); + if (angle > p_spot_angle) { + idx = light_data[idx].next_leaf; + continue; // too far away + } + + float att = Math::pow(1.0f - angle / p_spot_angle, p_spot_attenuation); + + { + float d = light_pos.distance_to(to); + if (d + distance_adv > local_radius) { + idx = light_data[idx].next_leaf; + continue; // too far away + } + + float dt = CLAMP((d + distance_adv) / local_radius, 0, 1); + att *= powf(1.0 - dt, p_attenutation); + } +#if 0 + if (light_cache.type == VS::LIGHT_SPOT) { + + float angle = Math::rad2deg(acos(light_axis.dot(spot_axis))); + if (angle > light_cache.spot_angle) + continue; + + float d = CLAMP(angle / light_cache.spot_angle, 1, 0); + att *= powf(1.0 - d, light_cache.spot_attenuation); + } +#endif + clip_planes = 0; + + for (int c = 0; c < 3; c++) { + + if (ABS(light_axis[c]) < CMP_EPSILON) + continue; + clip[clip_planes].normal[c] = 1.0; + + if (light_axis[c] < 0) { + + clip[clip_planes].d = (1 << (cell_subdiv - 1)) + 1; + } else { + clip[clip_planes].d -= 1.0; + } + + clip_planes++; + } + + Vector3 from = light_pos; + + for (int j = 0; j < clip_planes; j++) { + + clip[j].intersects_segment(from, to, &from); + } + + float distance = (to - from).length(); + + distance -= Math::fmod(distance, distance_adv); //make it reach the center of the box always, but this tame make it closer + from = to - light_axis * distance; + + uint32_t result = 0xFFFFFFFF; + + while (distance > -distance_adv) { //use this to avoid precision errors + + result = _find_cell_at_pos(cells, int(floor(from.x)), int(floor(from.y)), int(floor(from.z))); + if (result != 0xFFFFFFFF) { + break; + } + + from += light_axis * distance_adv; + distance -= distance_adv; + } + + if (result == idx) { + //cell hit itself! hooray! + + if (normal == Vector3()) { + for (int i = 0; i < 6; i++) { + light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * att; + light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * att; + light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * att; + } + + } else { + + for (int i = 0; i < 6; i++) { + float s = MAX(0.0, aniso_normal[i].dot(-normal)); + light->accum[i][0] += light_energy.x * cells[idx].albedo[0] * s * att; + light->accum[i][1] += light_energy.y * cells[idx].albedo[1] * s * att; + light->accum[i][2] += light_energy.z * cells[idx].albedo[2] * s * att; + } + } + + for (int i = 0; i < 6; i++) { + float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct + light->direct_accum[i][0] += light_energy.x * s * att; + light->direct_accum[i][1] += light_energy.y * s * att; + light->direct_accum[i][2] += light_energy.z * s * att; + } + } + + idx = light_data[idx].next_leaf; + } +} + +void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) { + + if (p_level == cell_subdiv - 1) { + + leaf_voxel_count++; + float alpha = bake_cells[p_idx].alpha; + + bake_cells[p_idx].albedo[0] /= alpha; + bake_cells[p_idx].albedo[1] /= alpha; + bake_cells[p_idx].albedo[2] /= alpha; + + //transfer emission to light + bake_cells[p_idx].emission[0] /= alpha; + bake_cells[p_idx].emission[1] /= alpha; + bake_cells[p_idx].emission[2] /= alpha; + + bake_cells[p_idx].normal[0] /= alpha; + bake_cells[p_idx].normal[1] /= alpha; + bake_cells[p_idx].normal[2] /= alpha; + + Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]); + if (n.length() < 0.01) { + //too much fight over normal, zero it + bake_cells[p_idx].normal[0] = 0; + bake_cells[p_idx].normal[1] = 0; + bake_cells[p_idx].normal[2] = 0; + } else { + n.normalize(); + bake_cells[p_idx].normal[0] = n.x; + bake_cells[p_idx].normal[1] = n.y; + bake_cells[p_idx].normal[2] = n.z; + } + + bake_cells[p_idx].alpha = 1.0; + + /*if (bake_light.size()) { + for(int i=0;i<6;i++) { + + } + }*/ + + } else { + + //go down + + bake_cells[p_idx].emission[0] = 0; + bake_cells[p_idx].emission[1] = 0; + bake_cells[p_idx].emission[2] = 0; + bake_cells[p_idx].normal[0] = 0; + bake_cells[p_idx].normal[1] = 0; + bake_cells[p_idx].normal[2] = 0; + bake_cells[p_idx].albedo[0] = 0; + bake_cells[p_idx].albedo[1] = 0; + bake_cells[p_idx].albedo[2] = 0; + if (bake_light.size()) { + for (int j = 0; j < 6; j++) { + bake_light[p_idx].accum[j][0] = 0; + bake_light[p_idx].accum[j][1] = 0; + bake_light[p_idx].accum[j][2] = 0; + } + } + + float alpha_average = 0; + int children_found = 0; + + for (int i = 0; i < 8; i++) { + + uint32_t child = bake_cells[p_idx].childs[i]; + + if (child == CHILD_EMPTY) + continue; + + _fixup_plot(child, p_level + 1); + alpha_average += bake_cells[child].alpha; + + if (bake_light.size() > 0) { + for (int j = 0; j < 6; j++) { + bake_light[p_idx].accum[j][0] += bake_light[child].accum[j][0]; + bake_light[p_idx].accum[j][1] += bake_light[child].accum[j][1]; + bake_light[p_idx].accum[j][2] += bake_light[child].accum[j][2]; + } + bake_cells[p_idx].emission[0] += bake_cells[child].emission[0]; + bake_cells[p_idx].emission[1] += bake_cells[child].emission[1]; + bake_cells[p_idx].emission[2] += bake_cells[child].emission[2]; + } + + children_found++; + } + + bake_cells[p_idx].alpha = alpha_average / 8.0; + if (bake_light.size() && children_found) { + float divisor = Math::lerp(8, children_found, propagation); + for (int j = 0; j < 6; j++) { + bake_light[p_idx].accum[j][0] /= divisor; + bake_light[p_idx].accum[j][1] /= divisor; + bake_light[p_idx].accum[j][2] /= divisor; + } + bake_cells[p_idx].emission[0] /= divisor; + bake_cells[p_idx].emission[1] /= divisor; + bake_cells[p_idx].emission[2] /= divisor; + } + } +} + +//make sure any cell (save for the root) has an empty cell previous to it, so it can be interpolated into + +void VoxelLightBaker::_plot_triangle(Vector2 *vertices, Vector3 *positions, Vector3 *normals, LightMap *pixels, int width, int height) { + + int x[3]; + int y[3]; + + for (int j = 0; j < 3; j++) { + + x[j] = vertices[j].x * width; + y[j] = vertices[j].y * height; + //x[j] = CLAMP(x[j], 0, bt.width - 1); + //y[j] = CLAMP(y[j], 0, bt.height - 1); + } + + // sort the points vertically + if (y[1] > y[2]) { + SWAP(x[1], x[2]); + SWAP(y[1], y[2]); + SWAP(positions[1], positions[2]); + SWAP(normals[1], normals[2]); + } + if (y[0] > y[1]) { + SWAP(x[0], x[1]); + SWAP(y[0], y[1]); + SWAP(positions[0], positions[1]); + SWAP(normals[0], normals[1]); + } + if (y[1] > y[2]) { + SWAP(x[1], x[2]); + SWAP(y[1], y[2]); + SWAP(positions[1], positions[2]); + SWAP(normals[1], normals[2]); + } + + double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1); + double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1); + double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1); + double xf = x[0]; + double xt = x[0] + dx_upper; // if y[0] == y[1], special case + for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) { + if (yi >= 0) { + for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) { + //pixels[int(x + y * width)] = color; + + Vector2 v0 = Vector2(x[1] - x[0], y[1] - y[0]); + Vector2 v1 = Vector2(x[2] - x[0], y[2] - y[0]); + //vertices[2] - vertices[0]; + Vector2 v2 = Vector2(xi - x[0], yi - y[0]); + float d00 = v0.dot(v0); + float d01 = v0.dot(v1); + float d11 = v1.dot(v1); + float d20 = v2.dot(v0); + float d21 = v2.dot(v1); + float denom = (d00 * d11 - d01 * d01); + Vector3 pos; + Vector3 normal; + if (denom == 0) { + pos = positions[0]; + normal = normals[0]; + } else { + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + pos = positions[0] * u + positions[1] * v + positions[2] * w; + normal = normals[0] * u + normals[1] * v + normals[2] * w; + } + + int ofs = yi * width + xi; + pixels[ofs].normal = normal; + pixels[ofs].pos = pos; + } + + for (int xi = (xf < width ? int(xf) : width - 1); xi >= (xt > 0 ? xt : 0); xi--) { + //pixels[int(x + y * width)] = color; + Vector2 v0 = Vector2(x[1] - x[0], y[1] - y[0]); + Vector2 v1 = Vector2(x[2] - x[0], y[2] - y[0]); + //vertices[2] - vertices[0]; + Vector2 v2 = Vector2(xi - x[0], yi - y[0]); + float d00 = v0.dot(v0); + float d01 = v0.dot(v1); + float d11 = v1.dot(v1); + float d20 = v2.dot(v0); + float d21 = v2.dot(v1); + float denom = (d00 * d11 - d01 * d01); + Vector3 pos; + Vector3 normal; + if (denom == 0) { + pos = positions[0]; + normal = normals[0]; + } else { + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + pos = positions[0] * u + positions[1] * v + positions[2] * w; + normal = normals[0] * u + normals[1] * v + normals[2] * w; + } + + int ofs = yi * width + xi; + pixels[ofs].normal = normal; + pixels[ofs].pos = pos; + } + } + xf += dx_far; + if (yi < y[1]) + xt += dx_upper; + else + xt += dx_low; + } +} + +void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha) { + + int size = 1 << (cell_subdiv - 1); + + int clamp_v = size - 1; + //first of all, clamp + Vector3 pos; + pos.x = CLAMP(p_posf.x, 0, clamp_v); + pos.y = CLAMP(p_posf.y, 0, clamp_v); + pos.z = CLAMP(p_posf.z, 0, clamp_v); + + float level = (cell_subdiv - 1) - p_level; + + int target_level; + float level_filter; + if (level <= 0.0) { + level_filter = 0; + target_level = 0; + } else { + target_level = Math::ceil(level); + level_filter = target_level - level; + } + + const Cell *cells = bake_cells.ptr(); + const Light *light = bake_light.ptr(); + + Vector3 color[2][8]; + float alpha[2][8]; + zeromem(alpha, sizeof(float) * 2 * 8); + + //find cell at given level first + + for (int c = 0; c < 2; c++) { + + int current_level = MAX(0, target_level - c); + int level_cell_size = (1 << (cell_subdiv - 1)) >> current_level; + + for (int n = 0; n < 8; n++) { + + int x = int(pos.x); + int y = int(pos.y); + int z = int(pos.z); + + if (n & 1) + x += level_cell_size; + if (n & 2) + y += level_cell_size; + if (n & 4) + z += level_cell_size; + + int ofs_x = 0; + int ofs_y = 0; + int ofs_z = 0; + + x = CLAMP(x, 0, clamp_v); + y = CLAMP(y, 0, clamp_v); + z = CLAMP(z, 0, clamp_v); + + int half = size / 2; + uint32_t cell = 0; + for (int i = 0; i < current_level; i++) { + + const Cell *bc = &cells[cell]; + + int child = 0; + if (x >= ofs_x + half) { + child |= 1; + ofs_x += half; + } + if (y >= ofs_y + half) { + child |= 2; + ofs_y += half; + } + if (z >= ofs_z + half) { + child |= 4; + ofs_z += half; + } + + cell = bc->childs[child]; + if (cell == CHILD_EMPTY) + break; + + half >>= 1; + } + + if (cell == CHILD_EMPTY) { + alpha[c][n] = 0; + } else { + alpha[c][n] = cells[cell].alpha; + + for (int i = 0; i < 6; i++) { + //anisotropic read light + float amount = p_direction.dot(aniso_normal[i]); + //if (c == 0) { + // print_line("\t" + itos(n) + " aniso " + itos(i) + " " + rtos(light[cell].accum[i][0]) + " VEC: " + aniso_normal[i]); + //} + if (amount < 0) + amount = 0; + //amount = 1; + color[c][n].x += light[cell].accum[i][0] * amount; + color[c][n].y += light[cell].accum[i][1] * amount; + color[c][n].z += light[cell].accum[i][2] * amount; + } + + color[c][n].x += cells[cell].emission[0]; + color[c][n].y += cells[cell].emission[1]; + color[c][n].z += cells[cell].emission[2]; + } + + //print_line("\tlev " + itos(c) + " - " + itos(n) + " alpha: " + rtos(cells[test_cell].alpha) + " col: " + color[c][n]); + } + } + + float target_level_size = size >> target_level; + Vector3 pos_fract[2]; + + pos_fract[0].x = Math::fmod(pos.x, target_level_size) / target_level_size; + pos_fract[0].y = Math::fmod(pos.y, target_level_size) / target_level_size; + pos_fract[0].z = Math::fmod(pos.z, target_level_size) / target_level_size; + + target_level_size = size >> MAX(0, target_level - 1); + + pos_fract[1].x = Math::fmod(pos.x, target_level_size) / target_level_size; + pos_fract[1].y = Math::fmod(pos.y, target_level_size) / target_level_size; + pos_fract[1].z = Math::fmod(pos.z, target_level_size) / target_level_size; + + float alpha_interp[2]; + Vector3 color_interp[2]; + + for (int i = 0; i < 2; i++) { + + Vector3 color_x00 = color[i][0].linear_interpolate(color[i][1], pos_fract[i].x); + Vector3 color_xy0 = color[i][2].linear_interpolate(color[i][3], pos_fract[i].x); + Vector3 blend_z0 = color_x00.linear_interpolate(color_xy0, pos_fract[i].y); + + Vector3 color_x0z = color[i][4].linear_interpolate(color[i][5], pos_fract[i].x); + Vector3 color_xyz = color[i][6].linear_interpolate(color[i][7], pos_fract[i].x); + Vector3 blend_z1 = color_x0z.linear_interpolate(color_xyz, pos_fract[i].y); + + color_interp[i] = blend_z0.linear_interpolate(blend_z1, pos_fract[i].z); + + float alpha_x00 = Math::lerp(alpha[i][0], alpha[i][1], pos_fract[i].x); + float alpha_xy0 = Math::lerp(alpha[i][2], alpha[i][3], pos_fract[i].x); + float alpha_z0 = Math::lerp(alpha_x00, alpha_xy0, pos_fract[i].y); + + float alpha_x0z = Math::lerp(alpha[i][4], alpha[i][5], pos_fract[i].x); + float alpha_xyz = Math::lerp(alpha[i][6], alpha[i][7], pos_fract[i].x); + float alpha_z1 = Math::lerp(alpha_x0z, alpha_xyz, pos_fract[i].y); + + alpha_interp[i] = Math::lerp(alpha_z0, alpha_z1, pos_fract[i].z); + } + + r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter); + r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter); + + // print_line("pos: " + p_posf + " level " + rtos(p_level) + " down to " + itos(target_level) + "." + rtos(level_filter) + " color " + r_color + " alpha " + rtos(r_alpha)); +} + +Vector3 VoxelLightBaker::_voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture) { + + float bias = 2.5; + float max_distance = (Vector3(1, 1, 1) * (1 << (cell_subdiv - 1))).length(); + + float dist = bias; + float alpha = 0.0; + Vector3 color; + + Vector3 scolor; + float salpha; + + while (dist < max_distance && alpha < 0.95) { + float diameter = MAX(1.0, 2.0 * p_aperture * dist); + //print_line("VCT: pos " + (p_pos + dist * p_normal) + " dist " + rtos(dist) + " mipmap " + rtos(log2(diameter)) + " alpha " + rtos(alpha)); + //Plane scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) ); + _sample_baked_octree_filtered_and_anisotropic(p_pos + dist * p_normal, p_normal, log2(diameter), scolor, salpha); + float a = (1.0 - alpha); + color += scolor * a; + alpha += a * salpha; + dist += diameter * 0.5; + } + + /*if (blend_ambient) { + color.rgb = mix(ambient,color.rgb,min(1.0,alpha/0.95)); + }*/ + + return color; +} + +Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) { + + //find arbitrary tangent and bitangent, then build a matrix + Vector3 v0 = Math::abs(p_normal.z) < 0.999 ? Vector3(0, 0, 1) : Vector3(0, 1, 0); + Vector3 tangent = v0.cross(p_normal).normalized(); + Vector3 bitangent = tangent.cross(p_normal).normalized(); + Basis normal_xform = Basis(tangent, bitangent, p_normal).transposed(); + + // print_line("normal xform: " + normal_xform); + const Vector3 *cone_dirs; + const float *cone_weights; + int cone_dir_count; + float cone_aperture; + + switch (bake_quality) { + case BAKE_QUALITY_LOW: { + //default quality + static const Vector3 dirs[4] = { + Vector3(0.707107, 0, 0.707107), + Vector3(0, 0.707107, 0.707107), + Vector3(-0.707107, 0, 0.707107), + Vector3(0, -0.707107, 0.707107) + }; + + static const float weights[4] = { 0.25, 0.25, 0.25, 0.25 }; + + cone_dirs = dirs; + cone_dir_count = 4; + cone_aperture = 1.0; // tan(angle) 90 degrees + cone_weights = weights; + } break; + case BAKE_QUALITY_MEDIUM: { + //default quality + static const Vector3 dirs[6] = { + Vector3(0, 0, 1), + Vector3(0.866025, 0, 0.5), + Vector3(0.267617, 0.823639, 0.5), + Vector3(-0.700629, 0.509037, 0.5), + Vector3(-0.700629, -0.509037, 0.5), + Vector3(0.267617, -0.823639, 0.5) + }; + static const float weights[6] = { 0.25, 0.15, 0.15, 0.15, 0.15, 0.15 }; + // + cone_dirs = dirs; + cone_dir_count = 6; + cone_aperture = 0.577; // tan(angle) 60 degrees + cone_weights = weights; + } break; + case BAKE_QUALITY_HIGH: { + + //high qualily + static const Vector3 dirs[10] = { + Vector3(0.8781648411741658, 0.0, 0.478358141694643), + Vector3(0.5369754325592234, 0.6794204427701518, 0.5000452447267606), + Vector3(-0.19849436573466497, 0.8429904390140635, 0.49996710542041645), + Vector3(-0.7856196499811189, 0.3639120321329737, 0.5003696617825604), + Vector3(-0.7856196499811189, -0.3639120321329737, 0.5003696617825604), + Vector3(-0.19849436573466497, -0.8429904390140635, 0.49996710542041645), + Vector3(0.5369754325592234, -0.6794204427701518, 0.5000452447267606), + Vector3(-0.4451656858129485, 0.0, 0.8954482185892644), + Vector3(0.19124006749743122, 0.39355745585016605, 0.8991883926788214), + Vector3(0.19124006749743122, -0.39355745585016605, 0.8991883926788214), + }; + static const float weights[10] = { 0.08571, 0.08571, 0.08571, 0.08571, 0.08571, 0.08571, 0.08571, 0.133333, 0.133333, 0.13333 }; + cone_dirs = dirs; + cone_dir_count = 10; + cone_aperture = 0.404; // tan(angle) 45 degrees + cone_weights = weights; + } break; + } + + Vector3 accum; + + for (int i = 0; i < cone_dir_count; i++) { + // if (i > 0) + // continue; + Vector3 dir = normal_xform.xform(cone_dirs[i]).normalized(); //normal may not completely correct when transformed to cell + //print_line("direction: " + dir); + accum += _voxel_cone_trace(p_pos, dir, cone_aperture) * cone_weights[i]; + } + + return accum; +} + +Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) { + + int samples_per_quality[3] = { 48, 128, 512 }; + + int samples = samples_per_quality[bake_quality]; + + //create a basis in Z + Vector3 v0 = Math::abs(p_normal.z) < 0.999 ? Vector3(0, 0, 1) : Vector3(0, 1, 0); + Vector3 tangent = v0.cross(p_normal).normalized(); + Vector3 bitangent = tangent.cross(p_normal).normalized(); + Basis normal_xform = Basis(tangent, bitangent, p_normal).transposed(); + + float bias = 1.5; + int max_level = cell_subdiv - 1; + int size = 1 << max_level; + + Vector3 accum; + float spread = Math::deg2rad(80.0); + + const Light *light = bake_light.ptr(); + const Cell *cells = bake_cells.ptr(); + + for (int i = 0; i < samples; i++) { + + float random_angle1 = (((Math::rand() % 65535) / 65535.0) * 2.0 - 1.0) * spread; + Vector3 axis(0, sin(random_angle1), cos(random_angle1)); + float random_angle2 = ((Math::rand() % 65535) / 65535.0) * Math_PI * 2.0; + Basis rot(Vector3(0, 0, 1), random_angle2); + axis = rot.xform(axis); + + Vector3 direction = normal_xform.xform(axis).normalized(); + + Vector3 pos = p_pos + Vector3(0.5, 0.5, 0.5) + direction * bias; + + Vector3 advance = direction * _get_normal_advance(direction); + + uint32_t cell = CHILD_EMPTY; + + while (cell == CHILD_EMPTY) { + + int x = int(pos.x); + int y = int(pos.y); + int z = int(pos.z); + + int ofs_x = 0; + int ofs_y = 0; + int ofs_z = 0; + int half = size / 2; + + if (x < 0 || x >= size) + break; + if (y < 0 || y >= size) + break; + if (z < 0 || z >= size) + break; + + //int level_limit = max_level; + + cell = 0; //start from root + for (int i = 0; i < max_level; i++) { + + const Cell *bc = &cells[cell]; + + int child = 0; + if (x >= ofs_x + half) { + child |= 1; + ofs_x += half; + } + if (y >= ofs_y + half) { + child |= 2; + ofs_y += half; + } + if (z >= ofs_z + half) { + child |= 4; + ofs_z += half; + } + + cell = bc->childs[child]; + if (cell == CHILD_EMPTY) + break; + + half >>= 1; + } + + pos += advance; + } + + if (cell != CHILD_EMPTY) { + for (int i = 0; i < 6; i++) { + //anisotropic read light + float amount = direction.dot(aniso_normal[i]); + if (amount < 0) + amount = 0; + accum.x += light[cell].accum[i][0] * amount; + accum.y += light[cell].accum[i][1] * amount; + accum.z += light[cell].accum[i][2] * amount; + } + } + } + + return accum / samples; +} + +Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float), void *p_bake_time_ud) { + + //transfer light information to a lightmap + Ref<Mesh> mesh = p_mesh; + + int width = mesh->get_lightmap_size_hint().x; + int height = mesh->get_lightmap_size_hint().y; + + //step 1 - create lightmap + Vector<LightMap> lightmap; + lightmap.resize(width * height); + + Transform xform = to_cell_space * p_xform; + + //step 2 plot faces to lightmap + for (int i = 0; i < mesh->get_surface_count(); i++) { + Array arrays = mesh->surface_get_arrays(i); + PoolVector<Vector3> vertices = arrays[Mesh::ARRAY_VERTEX]; + PoolVector<Vector3> normals = arrays[Mesh::ARRAY_NORMAL]; + PoolVector<Vector2> uv2 = arrays[Mesh::ARRAY_TEX_UV2]; + PoolVector<int> indices = arrays[Mesh::ARRAY_INDEX]; + + ERR_FAIL_COND_V(vertices.size() == 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(normals.size() == 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(uv2.size() == 0, ERR_INVALID_PARAMETER); + + int vc = vertices.size(); + PoolVector<Vector3>::Read vr = vertices.read(); + PoolVector<Vector3>::Read nr = normals.read(); + PoolVector<Vector2>::Read u2r = uv2.read(); + PoolVector<int>::Read ir; + int ic = 0; + + if (indices.size()) { + ic = indices.size(); + ir = indices.read(); + } + + int faces = ic ? ic / 3 : vc / 3; + for (int i = 0; i < faces; i++) { + Vector3 vertex[3]; + Vector3 normal[3]; + Vector2 uv[3]; + for (int j = 0; j < 3; j++) { + int idx = ic ? ir[i * 3 + j] : i * 3 + j; + vertex[j] = xform.xform(vr[idx]); + normal[j] = xform.basis.xform(nr[idx]).normalized(); + uv[j] = u2r[idx]; + } + + _plot_triangle(uv, vertex, normal, lightmap.ptrw(), width, height); + } + } + //step 3 perform voxel cone trace on lightmap pixels + + { + LightMap *lightmap_ptr = lightmap.ptrw(); + uint64_t begin_time = OS::get_singleton()->get_ticks_usec(); + volatile int lines = 0; + + for (int i = 0; i < height; i++) { + + //print_line("bake line " + itos(i) + " / " + itos(height)); +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int j = 0; j < width; j++) { + + //if (i == 125 && j == 280) { + + LightMap *pixel = &lightmap_ptr[i * width + j]; + if (pixel->pos == Vector3()) + continue; //unused, skipe + + //print_line("pos: " + pixel->pos + " normal " + pixel->normal); + switch (bake_mode) { + case BAKE_MODE_CONE_TRACE: { + pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy; + } break; + case BAKE_MODE_RAY_TRACE: { + pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy; + } break; + // pixel->light = Vector3(1, 1, 1); + //} + } + } + + lines = MAX(lines, i); //for multithread + if (p_bake_time_func) { + uint64_t elapsed = OS::get_singleton()->get_ticks_usec() - begin_time; + float elapsed_sec = double(elapsed) / 1000000.0; + float remaining = lines < 1 ? 0 : (elapsed_sec / lines) * (height - lines - 1); + if (p_bake_time_func(p_bake_time_ud, remaining, lines / float(height))) { + return ERR_SKIP; + } + } + } + + if (bake_mode == BAKE_MODE_RAY_TRACE) { + //blur + print_line("bluring, use pos for separatable copy"); + //gauss kernel, 7 step sigma 2 + static const float gauss_kernel[4] = { 0.214607, 0.189879, 0.131514, 0.071303 }; + //horizontal pass + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if (lightmap_ptr[i * width + j].normal == Vector3()) { + continue; //empty + } + float gauss_sum = gauss_kernel[0]; + Vector3 accum = lightmap_ptr[i * width + j].light * gauss_kernel[0]; + for (int k = 1; k < 4; k++) { + int new_x = j + k; + if (new_x >= width || lightmap_ptr[i * width + new_x].normal == Vector3()) + break; + gauss_sum += gauss_kernel[k]; + accum += lightmap_ptr[i * width + new_x].light * gauss_kernel[k]; + } + for (int k = 1; k < 4; k++) { + int new_x = j - k; + if (new_x < 0 || lightmap_ptr[i * width + new_x].normal == Vector3()) + break; + gauss_sum += gauss_kernel[k]; + accum += lightmap_ptr[i * width + new_x].light * gauss_kernel[k]; + } + + lightmap_ptr[i * width + j].pos = accum /= gauss_sum; + } + } + //vertical pass + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if (lightmap_ptr[i * width + j].normal == Vector3()) + continue; //empty, dont write over it anyway + float gauss_sum = gauss_kernel[0]; + Vector3 accum = lightmap_ptr[i * width + j].pos * gauss_kernel[0]; + for (int k = 1; k < 4; k++) { + int new_y = i + k; + if (new_y >= height || lightmap_ptr[new_y * width + j].normal == Vector3()) + break; + gauss_sum += gauss_kernel[k]; + accum += lightmap_ptr[new_y * width + j].pos * gauss_kernel[k]; + } + for (int k = 1; k < 4; k++) { + int new_y = i - k; + if (new_y < 0 || lightmap_ptr[new_y * width + j].normal == Vector3()) + break; + gauss_sum += gauss_kernel[k]; + accum += lightmap_ptr[new_y * width + j].pos * gauss_kernel[k]; + } + + lightmap_ptr[i * width + j].light = accum /= gauss_sum; + } + } + } + + //add directional light (do this after blur) + { + LightMap *lightmap_ptr = lightmap.ptrw(); + const Cell *cells = bake_cells.ptr(); + const Light *light = bake_light.ptr(); + + for (int i = 0; i < height; i++) { + + //print_line("bake line " + itos(i) + " / " + itos(height)); +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int j = 0; j < width; j++) { + + //if (i == 125 && j == 280) { + + LightMap *pixel = &lightmap_ptr[i * width + j]; + if (pixel->pos == Vector3()) + continue; //unused, skipe + + int x = int(pixel->pos.x) - 1; + int y = int(pixel->pos.y) - 1; + int z = int(pixel->pos.z) - 1; + Color accum; + int size = 1 << (cell_subdiv - 1); + + int found = 0; + + for (int k = 0; k < 8; k++) { + + int ofs_x = x; + int ofs_y = y; + int ofs_z = z; + + if (k & 1) + ofs_x++; + if (k & 2) + ofs_y++; + if (k & 4) + ofs_z++; + + if (x < 0 || x >= size) + continue; + if (y < 0 || y >= size) + continue; + if (z < 0 || z >= size) + continue; + + uint32_t cell = _find_cell_at_pos(cells, ofs_x, ofs_y, ofs_z); + + if (cell == CHILD_EMPTY) + continue; + for (int l = 0; l < 6; l++) { + float s = pixel->normal.dot(aniso_normal[l]); + if (s < 0) + s = 0; + accum.r += light[cell].direct_accum[l][0] * s; + accum.g += light[cell].direct_accum[l][1] * s; + accum.b += light[cell].direct_accum[l][2] * s; + } + found++; + } + if (found) { + accum /= found; + pixel->light.x += accum.r; + pixel->light.y += accum.g; + pixel->light.z += accum.b; + } + } + } + } + + { + //fill gaps with neighbour vertices to avoid filter fades to black on edges + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if (lightmap_ptr[i * width + j].normal != Vector3()) { + continue; //filled, skip + } + + //this can't be made separatable.. + + int closest_i = -1, closest_j = 1; + float closest_dist = 1e20; + + const int margin = 3; + for (int y = i - margin; y <= i + margin; y++) { + for (int x = j - margin; x <= j + margin; x++) { + + if (x == j && y == i) + continue; + if (x < 0 || x >= width) + continue; + if (y < 0 || y >= height) + continue; + if (lightmap_ptr[y * width + x].normal == Vector3()) + continue; //also ensures that blitted stuff is not reused + + float dist = Vector2(i - y, j - x).length(); + if (dist > closest_dist) + continue; + + closest_dist = dist; + closest_i = y; + closest_j = x; + } + } + + if (closest_i != -1) { + lightmap_ptr[i * width + j].light = lightmap_ptr[closest_i * width + closest_j].light; + } + } + } + } + + { + //fill the lightmap data + r_lightmap.width = width; + r_lightmap.height = height; + r_lightmap.light.resize(lightmap.size() * 3); + PoolVector<float>::Write w = r_lightmap.light.write(); + for (int i = 0; i < lightmap.size(); i++) { + w[i * 3 + 0] = lightmap[i].light.x; + w[i * 3 + 1] = lightmap[i].light.y; + w[i * 3 + 2] = lightmap[i].light.z; + } + } + +#if 0 + { + PoolVector<uint8_t> img; + int ls = lightmap.size(); + img.resize(ls * 3); + { + PoolVector<uint8_t>::Write w = img.write(); + for (int i = 0; i < ls; i++) { + w[i * 3 + 0] = CLAMP(lightmap_ptr[i].light.x * 255, 0, 255); + w[i * 3 + 1] = CLAMP(lightmap_ptr[i].light.y * 255, 0, 255); + w[i * 3 + 2] = CLAMP(lightmap_ptr[i].light.z * 255, 0, 255); + //w[i * 3 + 0] = CLAMP(lightmap_ptr[i].normal.x * 255, 0, 255); + //w[i * 3 + 1] = CLAMP(lightmap_ptr[i].normal.y * 255, 0, 255); + //w[i * 3 + 2] = CLAMP(lightmap_ptr[i].normal.z * 255, 0, 255); + //w[i * 3 + 0] = CLAMP(lightmap_ptr[i].pos.x / (1 << (cell_subdiv - 1)) * 255, 0, 255); + //w[i * 3 + 1] = CLAMP(lightmap_ptr[i].pos.y / (1 << (cell_subdiv - 1)) * 255, 0, 255); + //w[i * 3 + 2] = CLAMP(lightmap_ptr[i].pos.z / (1 << (cell_subdiv - 1)) * 255, 0, 255); + } + } + + Ref<Image> image; + image.instance(); + image->create(width, height, false, Image::FORMAT_RGB8, img); + + String name = p_mesh->get_name(); + if (name == "") { + name = "Mesh" + itos(p_mesh->get_instance_id()); + } + image->save_png(name + ".png"); + } +#endif + } + + return OK; +} + +void VoxelLightBaker::begin_bake(int p_subdiv, const AABB &p_bounds) { + + original_bounds = p_bounds; + cell_subdiv = p_subdiv; + bake_cells.resize(1); + material_cache.clear(); + + //find out the actual real bounds, power of 2, which gets the highest subdivision + po2_bounds = p_bounds; + int longest_axis = po2_bounds.get_longest_axis_index(); + axis_cell_size[longest_axis] = (1 << (cell_subdiv - 1)); + leaf_voxel_count = 0; + + for (int i = 0; i < 3; i++) { + + if (i == longest_axis) + continue; + + axis_cell_size[i] = axis_cell_size[longest_axis]; + float axis_size = po2_bounds.size[longest_axis]; + + //shrink until fit subdiv + while (axis_size / 2.0 >= po2_bounds.size[i]) { + axis_size /= 2.0; + axis_cell_size[i] >>= 1; + } + + po2_bounds.size[i] = po2_bounds.size[longest_axis]; + } + + Transform to_bounds; + to_bounds.basis.scale(Vector3(po2_bounds.size[longest_axis], po2_bounds.size[longest_axis], po2_bounds.size[longest_axis])); + to_bounds.origin = po2_bounds.position; + + Transform to_grid; + to_grid.basis.scale(Vector3(axis_cell_size[longest_axis], axis_cell_size[longest_axis], axis_cell_size[longest_axis])); + + to_cell_space = to_grid * to_bounds.affine_inverse(); + + cell_size = po2_bounds.size[longest_axis] / axis_cell_size[longest_axis]; +} + +void VoxelLightBaker::end_bake() { + _fixup_plot(0, 0); +} + +//create the data for visual server + +PoolVector<int> VoxelLightBaker::create_gi_probe_data() { + + PoolVector<int> data; + + data.resize(16 + (8 + 1 + 1 + 1 + 1) * bake_cells.size()); //4 for header, rest for rest. + + { + PoolVector<int>::Write w = data.write(); + + uint32_t *w32 = (uint32_t *)w.ptr(); + + w32[0] = 0; //version + w32[1] = cell_subdiv; //subdiv + w32[2] = axis_cell_size[0]; + w32[3] = axis_cell_size[1]; + w32[4] = axis_cell_size[2]; + w32[5] = bake_cells.size(); + w32[6] = leaf_voxel_count; + + int ofs = 16; + + for (int i = 0; i < bake_cells.size(); i++) { + + for (int j = 0; j < 8; j++) { + w32[ofs++] = bake_cells[i].childs[j]; + } + + { //albedo + uint32_t rgba = uint32_t(CLAMP(bake_cells[i].albedo[0] * 255.0, 0, 255)) << 16; + rgba |= uint32_t(CLAMP(bake_cells[i].albedo[1] * 255.0, 0, 255)) << 8; + rgba |= uint32_t(CLAMP(bake_cells[i].albedo[2] * 255.0, 0, 255)) << 0; + + w32[ofs++] = rgba; + } + { //emission + + Vector3 e(bake_cells[i].emission[0], bake_cells[i].emission[1], bake_cells[i].emission[2]); + float l = e.length(); + if (l > 0) { + e.normalize(); + l = CLAMP(l / 8.0, 0, 1.0); + } + + uint32_t em = uint32_t(CLAMP(e[0] * 255, 0, 255)) << 24; + em |= uint32_t(CLAMP(e[1] * 255, 0, 255)) << 16; + em |= uint32_t(CLAMP(e[2] * 255, 0, 255)) << 8; + em |= uint32_t(CLAMP(l * 255, 0, 255)); + + w32[ofs++] = em; + } + + //w32[ofs++]=bake_cells[i].used_sides; + { //normal + + Vector3 n(bake_cells[i].normal[0], bake_cells[i].normal[1], bake_cells[i].normal[2]); + n = n * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + uint32_t norm = 0; + + norm |= uint32_t(CLAMP(n.x * 255.0, 0, 255)) << 16; + norm |= uint32_t(CLAMP(n.y * 255.0, 0, 255)) << 8; + norm |= uint32_t(CLAMP(n.z * 255.0, 0, 255)) << 0; + + w32[ofs++] = norm; + } + + { + uint16_t alpha = CLAMP(uint32_t(bake_cells[i].alpha * 65535.0), 0, 65535); + uint16_t level = bake_cells[i].level; + + w32[ofs++] = (uint32_t(level) << 16) | uint32_t(alpha); + } + } + } + + return data; +} + +void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode) { + + if (p_level == cell_subdiv - 1) { + + Vector3 center = p_aabb.position + p_aabb.size * 0.5; + Transform xform; + xform.origin = center; + xform.basis.scale(p_aabb.size * 0.5); + p_multimesh->set_instance_transform(idx, xform); + Color col; + if (p_mode == DEBUG_ALBEDO) { + col = Color(bake_cells[p_idx].albedo[0], bake_cells[p_idx].albedo[1], bake_cells[p_idx].albedo[2]); + } else if (p_mode == DEBUG_LIGHT) { + for (int i = 0; i < 6; i++) { + col.r += bake_light[p_idx].accum[i][0]; + col.g += bake_light[p_idx].accum[i][1]; + col.b += bake_light[p_idx].accum[i][2]; + col.r += bake_light[p_idx].direct_accum[i][0]; + col.g += bake_light[p_idx].direct_accum[i][1]; + col.b += bake_light[p_idx].direct_accum[i][2]; + } + } + //Color col = Color(bake_cells[p_idx].emission[0], bake_cells[p_idx].emission[1], bake_cells[p_idx].emission[2]); + p_multimesh->set_instance_color(idx, col); + + idx++; + + } else { + + for (int i = 0; i < 8; i++) { + + uint32_t child = bake_cells[p_idx].childs[i]; + + if (child == CHILD_EMPTY || child >= max_original_cells) + continue; + + AABB aabb = p_aabb; + aabb.size *= 0.5; + + if (i & 1) + aabb.position.x += aabb.size.x; + if (i & 2) + aabb.position.y += aabb.size.y; + if (i & 4) + aabb.position.z += aabb.size.z; + + _debug_mesh(bake_cells[p_idx].childs[i], p_level + 1, aabb, p_multimesh, idx, p_mode); + } + } +} + +Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) { + + Ref<MultiMesh> mm; + + ERR_FAIL_COND_V(p_mode == DEBUG_LIGHT && bake_light.size() == 0, mm); + mm.instance(); + + mm->set_transform_format(MultiMesh::TRANSFORM_3D); + mm->set_color_format(MultiMesh::COLOR_8BIT); + print_line("leaf voxels: " + itos(leaf_voxel_count)); + mm->set_instance_count(leaf_voxel_count); + + Ref<ArrayMesh> mesh; + mesh.instance(); + + { + Array arr; + arr.resize(Mesh::ARRAY_MAX); + + PoolVector<Vector3> vertices; + PoolVector<Color> colors; + + int vtx_idx = 0; +#define ADD_VTX(m_idx) \ + ; \ + vertices.push_back(face_points[m_idx]); \ + colors.push_back(Color(1, 1, 1, 1)); \ + vtx_idx++; + + for (int i = 0; i < 6; i++) { + + Vector3 face_points[4]; + + for (int j = 0; j < 4; j++) { + + float v[3]; + v[0] = 1.0; + v[1] = 1 - 2 * ((j >> 1) & 1); + v[2] = v[1] * (1 - 2 * (j & 1)); + + for (int k = 0; k < 3; k++) { + + if (i < 3) + face_points[j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1); + else + face_points[3 - j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1); + } + } + + //tri 1 + ADD_VTX(0); + ADD_VTX(1); + ADD_VTX(2); + //tri 2 + ADD_VTX(2); + ADD_VTX(3); + ADD_VTX(0); + } + + arr[Mesh::ARRAY_VERTEX] = vertices; + arr[Mesh::ARRAY_COLOR] = colors; + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr); + } + + { + Ref<SpatialMaterial> fsm; + fsm.instance(); + fsm->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + fsm->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + fsm->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + fsm->set_albedo(Color(1, 1, 1, 1)); + + mesh->surface_set_material(0, fsm); + } + + mm->set_mesh(mesh); + + int idx = 0; + _debug_mesh(0, 0, po2_bounds, mm, idx, p_mode); + + return mm; +} + +struct VoxelLightBakerOctree { + + enum { + CHILD_EMPTY = 0xFFFFFFFF + }; + + uint16_t light[6][3]; //anisotropic light + float alpha; + uint32_t children[8]; +}; + +PoolVector<uint8_t> VoxelLightBaker::create_capture_octree(int p_subdiv) { + + p_subdiv = MIN(p_subdiv, cell_subdiv); // use the smaller one + + Vector<uint32_t> remap; + int bc = bake_cells.size(); + remap.resize(bc); + Vector<uint32_t> demap; + + int new_size = 0; + for (int i = 0; i < bc; i++) { + uint32_t c = CHILD_EMPTY; + if (bake_cells[i].level < p_subdiv) { + c = new_size; + new_size++; + demap.push_back(i); + } + remap[i] = c; + } + + Vector<VoxelLightBakerOctree> octree; + octree.resize(new_size); + + for (int i = 0; i < new_size; i++) { + octree[i].alpha = bake_cells[demap[i]].alpha; + for (int j = 0; j < 6; j++) { + for (int k = 0; k < 3; k++) { + float l = bake_light[demap[i]].accum[j][k]; //add anisotropic light + l += bake_cells[demap[i]].emission[k]; //add emission + octree[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree + } + } + + for (int j = 0; j < 8; j++) { + uint32_t child = bake_cells[demap[i]].childs[j]; + octree[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child]; + } + } + + PoolVector<uint8_t> ret; + int ret_bytes = octree.size() * sizeof(VoxelLightBakerOctree); + ret.resize(ret_bytes); + { + PoolVector<uint8_t>::Write w = ret.write(); + copymem(w.ptr(), octree.ptr(), ret_bytes); + } + + return ret; +} + +float VoxelLightBaker::get_cell_size() const { + return cell_size; +} + +Transform VoxelLightBaker::get_to_cell_space_xform() const { + return to_cell_space; +} +VoxelLightBaker::VoxelLightBaker() { + color_scan_cell_width = 4; + bake_texture_size = 128; + propagation = 0.85; + energy = 1.0; +} diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h new file mode 100644 index 0000000000..6dee2ee69b --- /dev/null +++ b/scene/3d/voxel_light_baker.h @@ -0,0 +1,148 @@ +#ifndef VOXEL_LIGHT_BAKER_H +#define VOXEL_LIGHT_BAKER_H + +#include "scene/3d/mesh_instance.h" +#include "scene/resources/multimesh.h" + +class VoxelLightBaker { +public: + enum DebugMode { + DEBUG_ALBEDO, + DEBUG_LIGHT + }; + + enum BakeQuality { + BAKE_QUALITY_LOW, + BAKE_QUALITY_MEDIUM, + BAKE_QUALITY_HIGH + }; + + enum BakeMode { + BAKE_MODE_CONE_TRACE, + BAKE_MODE_RAY_TRACE, + }; + +private: + enum { + CHILD_EMPTY = 0xFFFFFFFF + + }; + + struct Cell { + + uint32_t childs[8]; + float albedo[3]; //albedo in RGB24 + float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) + float normal[3]; + uint32_t used_sides; + float alpha; //used for upsampling + int level; + + Cell() { + for (int i = 0; i < 8; i++) { + childs[i] = CHILD_EMPTY; + } + + for (int i = 0; i < 3; i++) { + emission[i] = 0; + albedo[i] = 0; + normal[i] = 0; + } + alpha = 0; + used_sides = 0; + level = 0; + } + }; + + Vector<Cell> bake_cells; + int cell_subdiv; + + struct Light { + int x, y, z; + float accum[6][3]; //rgb anisotropic + float direct_accum[6][3]; //for direct bake + int next_leaf; + }; + + int first_leaf; + + Vector<Light> bake_light; + + struct MaterialCache { + //128x128 textures + Vector<Color> albedo; + Vector<Color> emission; + }; + + Map<Ref<Material>, MaterialCache> material_cache; + int leaf_voxel_count; + bool direct_lights_baked; + + AABB original_bounds; + AABB po2_bounds; + int axis_cell_size[3]; + + Transform to_cell_space; + + int color_scan_cell_width; + int bake_texture_size; + float cell_size; + float propagation; + float energy; + + BakeQuality bake_quality; + BakeMode bake_mode; + + int max_original_cells; + + void _init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent); + + Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add); + MaterialCache _get_material_cache(Ref<Material> p_material); + void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb); + void _fixup_plot(int p_idx, int p_level); + void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode); + void _check_init_light(); + + uint32_t _find_cell_at_pos(const Cell *cells, int x, int y, int z); + + struct LightMap { + Vector3 light; + Vector3 pos; + Vector3 normal; + }; + + void _plot_triangle(Vector2 *vertices, Vector3 *positions, Vector3 *normals, LightMap *pixels, int width, int height); + + _FORCE_INLINE_ void _sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha); + _FORCE_INLINE_ Vector3 _voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture); + _FORCE_INLINE_ Vector3 _compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); + _FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); + +public: + void begin_bake(int p_subdiv, const AABB &p_bounds); + void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material); + void begin_bake_light(BakeQuality p_quality = BAKE_QUALITY_MEDIUM, BakeMode p_bake_mode = BAKE_MODE_CONE_TRACE, float p_propagation = 0.85, float p_energy = 1); + void plot_light_directional(const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, bool p_direct); + void plot_light_omni(const Vector3 &p_pos, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, bool p_direct); + void plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axis, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, float p_spot_angle, float p_spot_attenuation, bool p_direct); + void end_bake(); + + struct LightMapData { + int width; + int height; + PoolVector<float> light; + }; + + Error make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float) = NULL, void *p_bake_time_ud = NULL); + + PoolVector<int> create_gi_probe_data(); + Ref<MultiMesh> create_debug_multimesh(DebugMode p_mode = DEBUG_ALBEDO); + PoolVector<uint8_t> create_capture_octree(int p_subdiv); + + float get_cell_size() const; + Transform get_to_cell_space_xform() const; + VoxelLightBaker(); +}; + +#endif // VOXEL_LIGHT_BAKER_H diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index d4912339da..9a55073bb6 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -289,10 +289,17 @@ bool WindowDialog::get_resizable() const { Size2 WindowDialog::get_minimum_size() const { Ref<Font> font = get_font("title_font", "WindowDialog"); - int msx = close_button->get_combined_minimum_size().x; - msx += font->get_string_size(title).x; - return Size2(msx, 1); + const int button_width = close_button->get_combined_minimum_size().x; + const int title_width = font->get_string_size(title).x; + const int padding = button_width / 2; + const int button_area = button_width + padding; + + // as the title gets centered, title_width + close_button_width is not enough. + // we want a width w, such that w / 2 - title_width / 2 >= button_area, i.e. + // w >= 2 * button_area + title_width + + return Size2(2 * button_area + title_width, 1); } TextureButton *WindowDialog::get_close_button() { diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 32f889e826..698676cc39 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -42,24 +42,6 @@ String PopupMenu::_get_accel_text(int p_item) const { else if (items[p_item].accel) return keycode_get_string(items[p_item].accel); return String(); - - /* - String atxt; - if (p_accel&KEY_MASK_SHIFT) - atxt+="Shift+"; - if (p_accel&KEY_MASK_ALT) - atxt+="Alt+"; - if (p_accel&KEY_MASK_CTRL) - atxt+="Ctrl+"; - if (p_accel&KEY_MASK_META) - atxt+="Meta+"; - - p_accel&=KEY_CODE_MASK; - - atxt+=String::chr(p_accel).to_upper(); - - return atxt; -*/ } Size2 PopupMenu::get_minimum_size() const { @@ -136,7 +118,6 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const { Ref<Font> font = get_font("font"); int vseparation = get_constant("vseparation"); - //int hseparation = get_constant("hseparation"); float font_h = font->get_height(); for (int i = 0; i < items.size(); i++) { @@ -230,6 +211,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { mouse_over = i; update(); + + if (items[i].submenu != "" && submenu_over != i) { + submenu_over = i; + submenu_timer->start(); + } break; } } @@ -245,6 +231,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { mouse_over = i; update(); + + if (items[i].submenu != "" && submenu_over != i) { + submenu_over = i; + submenu_timer->start(); + } break; } } @@ -500,6 +491,13 @@ void PopupMenu::_notification(int p_what) { } break; case NOTIFICATION_MOUSE_EXIT: { + if (mouse_over >= 0 && (items[mouse_over].submenu == "" || submenu_over != -1)) { + mouse_over = -1; + update(); + } + } break; + case NOTIFICATION_POPUP_HIDE: { + if (mouse_over >= 0) { mouse_over = -1; update(); @@ -1217,6 +1215,7 @@ void PopupMenu::set_invalidate_click_until_motion() { PopupMenu::PopupMenu() { mouse_over = -1; + submenu_over = -1; set_focus_mode(FOCUS_ALL); set_as_toplevel(true); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 05c6e9f77e..6fbc58a38a 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -31,6 +31,11 @@ #include "os/keyboard.h" #include "os/os.h" #include "scene/scene_string_names.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_node.h" +#endif + RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) { if (p_free) { @@ -370,7 +375,11 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & Color uc = color; uc.a *= 0.5; int uy = y + lh - fh + ascent + 2; - VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + pofs, uy), p_ofs + Point2(align_ofs + pofs + cw, uy), uc); + float underline_width = 1.0; +#ifdef TOOLS_ENABLED + underline_width *= EDSCALE; +#endif + VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + pofs, uy), p_ofs + Point2(align_ofs + pofs + cw, uy), uc, underline_width); } ofs += cw; } diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 665ae8b6dd..70b8616af1 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -184,10 +184,10 @@ void Slider::_notification(int p_what) { focus->draw(ci,Rect2i(Point2i(),Size2i(style->get_minimum_size().width+style->get_center_size().width,size.height))); */ if (ticks > 1) { - int tickarea = size.height - tick->get_height(); + int grabber_offset = (grabber->get_size().height / 2 - tick->get_height() / 2); for (int i = 0; i < ticks; i++) { if (!ticks_on_borders && (i == 0 || i + 1 == ticks)) continue; - int ofs = i * tickarea / (ticks - 1); + int ofs = (i * areasize / (ticks - 1)) + grabber_offset; tick->draw(ci, Point2i((size.width - widget_width) / 2, ofs)); } } @@ -205,10 +205,10 @@ void Slider::_notification(int p_what) { */ if (ticks > 1) { - int tickarea = size.width - tick->get_width(); + int grabber_offset = (grabber->get_size().width / 2 - tick->get_width() / 2); for (int i = 0; i < ticks; i++) { if ((!ticks_on_borders) && ((i == 0) || ((i + 1) == ticks))) continue; - int ofs = i * tickarea / (ticks - 1); + int ofs = (i * areasize / (ticks - 1)) + grabber_offset; tick->draw(ci, Point2i(ofs, (size.height - widget_height) / 2)); } } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index e5169089f2..2ce709732c 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1664,17 +1664,22 @@ void TextEdit::backspace_at_cursor() { cursor_set_column(prev_column); } -void TextEdit::indent_selection_right() { +void TextEdit::indent_right() { - if (!is_selection_active()) { - return; - } + int start_line; + int end_line; begin_complex_operation(); - int start_line = get_selection_from_line(); - int end_line = get_selection_to_line(); + + if (is_selection_active()) { + start_line = get_selection_from_line(); + end_line = get_selection_to_line(); + } else { + start_line = cursor.line; + end_line = start_line; + } // ignore if the cursor is not past the first column - if (get_selection_to_column() == 0) { + if (is_selection_active() && get_selection_to_column() == 0) { end_line--; } @@ -1688,23 +1693,32 @@ void TextEdit::indent_selection_right() { set_line(i, line_text); } - // fix selection being off by one on the last line - selection.to_column++; + // fix selection and cursor being off by one on the last line + if (is_selection_active()) { + selection.to_column++; + selection.from_column++; + } + cursor.column++; end_complex_operation(); update(); } -void TextEdit::indent_selection_left() { +void TextEdit::indent_left() { - if (!is_selection_active()) { - return; - } + int start_line; + int end_line; begin_complex_operation(); - int start_line = get_selection_from_line(); - int end_line = get_selection_to_line(); + + if (is_selection_active()) { + start_line = get_selection_from_line(); + end_line = get_selection_to_line(); + } else { + start_line = cursor.line; + end_line = start_line; + } // ignore if the cursor is not past the first column - if (get_selection_to_column() == 0) { + if (is_selection_active() && get_selection_to_column() == 0) { end_line--; } String last_line_text = get_line(end_line); @@ -1721,9 +1735,15 @@ void TextEdit::indent_selection_left() { } } - // fix selection being off by one on the last line - if (last_line_text != get_line(end_line) && selection.to_column > 0) { - selection.to_column--; + // fix selection and cursor being off by one on the last line + if (is_selection_active() && last_line_text != get_line(end_line)) { + if (selection.to_column > 0) + selection.to_column--; + if (selection.from_column > 0) + selection.from_column--; + } + if (cursor.column > 0) { + cursor.column--; } end_complex_operation(); update(); @@ -2216,9 +2236,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { case KEY_TAB: { if (k->get_shift()) { - indent_selection_left(); + indent_left(); } else { - indent_selection_right(); + indent_right(); } dobreak = true; accept_event(); @@ -2389,8 +2409,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (readonly) break; - if (selection.active) { - + if (is_selection_active()) { + if (k->get_shift()) { + indent_left(); + } else { + indent_right(); + } } else { if (k->get_shift()) { @@ -5657,4 +5681,4 @@ TextEdit::TextEdit() { } TextEdit::~TextEdit() { -} +}
\ No newline at end of file diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index dd305d5822..edef28cc25 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -443,8 +443,8 @@ public: void set_line(int line, String new_text); void backspace_at_cursor(); - void indent_selection_left(); - void indent_selection_right(); + void indent_left(); + void indent_right(); int get_indent_level(int p_line) const; inline void set_scroll_pass_end_of_file(bool p_enabled) { diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index ab12d123ba..b5b42e8f29 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -30,6 +30,7 @@ #include "tree.h" #include <limits.h> +#include "math_funcs.h" #include "os/input.h" #include "os/keyboard.h" #include "os/os.h" @@ -37,6 +38,10 @@ #include "project_settings.h" #include "scene/main/viewport.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_node.h" +#endif + void TreeItem::move_to_top() { if (!parent || parent->childs == this) @@ -1412,9 +1417,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (c->get_children() != NULL) root_pos -= Point2i(cache.arrow->get_width(), 0); + float line_width = 1.0; +#ifdef TOOLS_ENABLED + line_width *= EDSCALE; +#endif + Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs; - VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x, root_pos.y), cache.relationship_line_color); - VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color); + VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); + VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color, line_width); } int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c); diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 672e893f1b..4afdb56f86 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -36,7 +36,6 @@ void HTTPRequest::_redirect_request(const String &p_new_url) { Error HTTPRequest::_request() { - //print_line("Requesting:\n\tURL: "+url+"\n\tString: "+request_string+"\n\tPort: "+itos(port)+"\n\tSSL: "+itos(use_ssl)+"\n\tValidate SSL: "+itos(validate_ssl)); return client->connect_to_host(url, port, use_ssl, validate_ssl); } @@ -54,37 +53,32 @@ Error HTTPRequest::_parse_url(const String &p_url) { downloaded = 0; redirections = 0; - //print_line("1 url: "+url); - if (url.begins_with("http://")) { - + String url_lower = url.to_lower(); + if (url_lower.begins_with("http://")) { url = url.substr(7, url.length() - 7); - //print_line("no SSL"); - - } else if (url.begins_with("https://")) { + } else if (url_lower.begins_with("https://")) { url = url.substr(8, url.length() - 8); use_ssl = true; port = 443; - //print_line("yes SSL"); } else { ERR_EXPLAIN("Malformed URL"); ERR_FAIL_V(ERR_INVALID_PARAMETER); } - //print_line("2 url: "+url); + if (url.length() < 1) { + ERR_EXPLAIN("URL too short"); + ERR_FAIL_V(ERR_INVALID_PARAMETER); + } int slash_pos = url.find("/"); if (slash_pos != -1) { request_string = url.substr(slash_pos, url.length()); url = url.substr(0, slash_pos); - //print_line("request string: "+request_string); } else { request_string = "/"; - //print_line("no request"); } - //print_line("3 url: "+url); - int colon_pos = url.find(":"); if (colon_pos != -1) { port = url.substr(colon_pos + 1, url.length()).to_int(); @@ -92,8 +86,6 @@ Error HTTPRequest::_parse_url(const String &p_url) { ERR_FAIL_COND_V(port < 1 || port > 65535, ERR_INVALID_PARAMETER); } - //print_line("4 url: "+url); - return OK; } @@ -198,10 +190,8 @@ void HTTPRequest::cancel_request() { } client->close(); body.resize(0); - //downloaded=0; got_response = false; response_code = -1; - //body_len=-1; request_sent = false; requesting = false; } @@ -221,12 +211,12 @@ bool HTTPRequest::_handle_response(bool *ret_value) { response_headers.resize(0); downloaded = 0; for (List<String>::Element *E = rheaders.front(); E; E = E->next()) { - //print_line("HEADER: "+E->get()); response_headers.push_back(E->get()); } if (response_code == 301 || response_code == 302) { - //redirect + // Handle redirect + if (max_redirects >= 0 && redirections >= max_redirects) { call_deferred("_request_done", RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PoolByteArray()); @@ -242,15 +232,13 @@ bool HTTPRequest::_handle_response(bool *ret_value) { } } - //print_line("NEW LOCATION: "+new_request); - if (new_request != "") { - //process redirect + // Process redirect client->close(); - int new_redirs = redirections + 1; //because _request() will clear it + int new_redirs = redirections + 1; // Because _request() will clear it Error err; if (new_request.begins_with("http")) { - //new url, request all again + // New url, request all again err = _parse_url(new_request); } else { request_string = new_request; @@ -258,7 +246,6 @@ bool HTTPRequest::_handle_response(bool *ret_value) { err = _request(); - //print_line("new connection: "+itos(err)); if (err == OK) { request_sent = false; got_response = false; @@ -280,11 +267,11 @@ bool HTTPRequest::_update_connection() { switch (client->get_status()) { case HTTPClient::STATUS_DISCONNECTED: { call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray()); - return true; //end it, since it's doing something + return true; // End it, since it's doing something } break; case HTTPClient::STATUS_RESOLVING: { client->poll(); - //must wait + // Must wait return false; } break; case HTTPClient::STATUS_CANT_RESOLVE: { @@ -294,9 +281,9 @@ bool HTTPRequest::_update_connection() { } break; case HTTPClient::STATUS_CONNECTING: { client->poll(); - //must wait + // Must wait return false; - } break; //connecting to ip + } break; // Connecting to IP case HTTPClient::STATUS_CANT_CONNECT: { call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray()); @@ -309,7 +296,7 @@ bool HTTPRequest::_update_connection() { if (!got_response) { - //no body + // No body bool ret_value; @@ -320,16 +307,16 @@ bool HTTPRequest::_update_connection() { return true; } if (got_response && body_len < 0) { - //chunked transfer is done + // Chunked transfer is done call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); return true; } call_deferred("_request_done", RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PoolByteArray()); return true; - //request migh have been done + // Request migh have been done } else { - //did not request yet, do request + // Did not request yet, do request Error err = client->request(method, request_string, headers, request_data); if (err != OK) { @@ -340,13 +327,13 @@ bool HTTPRequest::_update_connection() { request_sent = true; return false; } - } break; //connected: { } break requests only accepted here + } break; // Connected: break requests only accepted here case HTTPClient::STATUS_REQUESTING: { - //must wait, it's requesting + // Must wait, still requesting client->poll(); return false; - } break; // request in progress + } break; // Request in progress case HTTPClient::STATUS_BODY: { if (!got_response) { @@ -363,7 +350,7 @@ bool HTTPRequest::_update_connection() { } if (client->is_response_chunked()) { - body_len = -1; //no body len because chunked, change your webserver configuration if you want body len + body_len = -1; // No body len because chunked, change your webserver configuration if you want body len } else { body_len = client->get_response_body_length(); @@ -383,7 +370,6 @@ bool HTTPRequest::_update_connection() { } } - //print_line("BODY: "+itos(body.size())); client->poll(); PoolByteArray chunk = client->read_response_body_chunk(); @@ -411,15 +397,11 @@ bool HTTPRequest::_update_connection() { call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); return true; } - /*if (body.size()>=body_len) { - call_deferred("_request_done",RESULT_BODY_SIZE_MISMATCH,response_code,response_headers,ByteArray()); - return true; - }*/ } return false; - } break; // request resulted in body: { } break which must be read + } break; // Request resulted in body: break which must be read case HTTPClient::STATUS_CONNECTION_ERROR: { call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PoolStringArray(), PoolByteArray()); return true; @@ -449,7 +431,7 @@ void HTTPRequest::_notification(int p_what) { if (done) { set_process_internal(false); - //cancel_request(); called from _request done now + // cancel_request(); called from _request done now } } @@ -543,7 +525,7 @@ void HTTPRequest::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_threads"), "set_use_threads", "is_using_threads"); ADD_PROPERTY(PropertyInfo(Variant::INT, "body_size_limit", PROPERTY_HINT_RANGE, "-1,2000000000"), "set_body_size_limit", "get_body_size_limit"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,1024"), "set_max_redirects", "get_max_redirects"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,64"), "set_max_redirects", "get_max_redirects"); ADD_SIGNAL(MethodInfo("request_completed", PropertyInfo(Variant::INT, "result"), PropertyInfo(Variant::INT, "response_code"), PropertyInfo(Variant::POOL_STRING_ARRAY, "headers"), PropertyInfo(Variant::POOL_BYTE_ARRAY, "body"))); diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 790ff5f7ef..ab5a79c40d 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -42,7 +42,6 @@ class HTTPRequest : public Node { public: enum Result { RESULT_SUCCESS, - //RESULT_NO_BODY, RESULT_CHUNKED_BODY_SIZE_MISMATCH, RESULT_CANT_CONNECT, RESULT_CANT_RESOLVE, diff --git a/scene/main/node.cpp b/scene/main/node.cpp index cae368aeca..efc5d269a6 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -177,8 +177,8 @@ void Node::_propagate_ready() { } data.blocked--; if (data.ready_first) { - notification(NOTIFICATION_READY); data.ready_first = false; + notification(NOTIFICATION_READY); } } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 4635de81e8..f5d7043a40 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1421,7 +1421,7 @@ void Viewport::_gui_show_tooltip() { gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP)); gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT)); gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM)); - gui.tooltip_label->set_text(tooltip); + gui.tooltip_label->set_text(tooltip.strip_edges()); Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_combined_minimum_size() + ttp->get_minimum_size()); Rect2 vr = gui.tooltip_label->get_viewport_rect(); if (r.size.x + r.position.x > vr.size.x) diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index d6557f508e..9715e1d6a0 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -160,6 +160,7 @@ #include "scene/3d/area.h" #include "scene/3d/arvr_nodes.h" #include "scene/3d/audio_stream_player_3d.h" +#include "scene/3d/baked_lightmap.h" #include "scene/3d/bone_attachment.h" #include "scene/3d/camera.h" #include "scene/3d/collision_polygon.h" @@ -375,6 +376,8 @@ void register_scene_types() { ClassDB::register_class<ReflectionProbe>(); ClassDB::register_class<GIProbe>(); ClassDB::register_class<GIProbeData>(); + ClassDB::register_class<BakedLightmap>(); + ClassDB::register_class<BakedLightmapData>(); ClassDB::register_class<AnimationTreePlayer>(); ClassDB::register_class<Particles>(); ClassDB::register_class<Position3D>(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index c8ab7c2a04..326320c60f 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -645,7 +645,7 @@ void SpatialMaterial::_update_shader() { code += "\tvec2 base_uv = UV;\n"; } - if ((features[FEATURE_DETAIL] && detail_uv == DETAIL_UV_2) || (features[FEATURE_AMBIENT_OCCLUSION] && flags[FLAG_AO_ON_UV2])) { + if ((features[FEATURE_DETAIL] && detail_uv == DETAIL_UV_2) || (features[FEATURE_AMBIENT_OCCLUSION] && flags[FLAG_AO_ON_UV2]) || (features[FEATURE_EMISSION] && flags[FLAG_EMISSION_ON_UV2])) { code += "\tvec2 base_uv2 = UV2;\n"; } @@ -729,11 +729,20 @@ void SpatialMaterial::_update_shader() { } if (features[FEATURE_EMISSION]) { - if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tvec3 emission_tex = triplanar_texture(texture_emission,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; + if (flags[FLAG_EMISSION_ON_UV2]) { + if (flags[FLAG_UV2_USE_TRIPLANAR]) { + code += "\tvec3 emission_tex = triplanar_texture(texture_emission,uv2_power_normal,uv2_triplanar_pos).rgb;\n"; + } else { + code += "\tvec3 emission_tex = texture(texture_emission,base_uv2).rgb;\n"; + } } else { - code += "\tvec3 emission_tex = texture(texture_emission,base_uv).rgb;\n"; + if (flags[FLAG_UV1_USE_TRIPLANAR]) { + code += "\tvec3 emission_tex = triplanar_texture(texture_emission,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; + } else { + code += "\tvec3 emission_tex = texture(texture_emission,base_uv).rgb;\n"; + } } + if (emission_op == EMISSION_OP_ADD) { code += "\tEMISSION = (emission.rgb+emission_tex)*emission_energy;\n"; } else { @@ -1892,6 +1901,7 @@ void SpatialMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_emission_energy", "get_emission_energy"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_operator", PROPERTY_HINT_ENUM, "Add,Multiply"), "set_emission_operator", "get_emission_operator"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_on_uv2"), "set_flag", "get_flag", FLAG_EMISSION_ON_UV2); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_EMISSION); ADD_GROUP("NormalMap", "normal_"); @@ -2034,6 +2044,7 @@ void SpatialMaterial::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_UV1_USE_TRIPLANAR); BIND_ENUM_CONSTANT(FLAG_UV2_USE_TRIPLANAR); BIND_ENUM_CONSTANT(FLAG_AO_ON_UV2); + BIND_ENUM_CONSTANT(FLAG_EMISSION_ON_UV2); BIND_ENUM_CONSTANT(FLAG_USE_ALPHA_SCISSOR); BIND_ENUM_CONSTANT(FLAG_TRIPLANAR_USE_WORLD); BIND_ENUM_CONSTANT(FLAG_ALBEDO_TEXTURE_FORCE_SRGB); diff --git a/scene/resources/material.h b/scene/resources/material.h index 7cfa38fce4..d5c3ef83e2 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -184,6 +184,7 @@ public: FLAG_UV2_USE_TRIPLANAR, FLAG_TRIPLANAR_USE_WORLD, FLAG_AO_ON_UV2, + FLAG_EMISSION_ON_UV2, FLAG_USE_ALPHA_SCISSOR, FLAG_ALBEDO_TEXTURE_FORCE_SRGB, FLAG_MAX @@ -234,7 +235,7 @@ private: uint64_t blend_mode : 2; uint64_t depth_draw_mode : 2; uint64_t cull_mode : 2; - uint64_t flags : 13; + uint64_t flags : 14; uint64_t detail_blend_mode : 2; uint64_t diffuse_mode : 3; uint64_t specular_mode : 2; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 0b352efca2..bb33962be6 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1123,27 +1123,29 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe PoolVector<int> rindices = arrays[Mesh::ARRAY_INDEX]; int ic = rindices.size(); - int index_ofs = indices.size(); if (ic == 0) { - indices.resize(index_ofs + vc); - face_materials.resize((index_ofs + vc) / 3); - for (int j = 0; j < vc; j++) { - indices[index_ofs + j] = vertex_ofs + j; - } + for (int j = 0; j < vc / 3; j++) { - face_materials[(index_ofs / 3) + j] = i; + if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) + continue; + + indices.push_back(vertex_ofs + j * 3 + 0); + indices.push_back(vertex_ofs + j * 3 + 1); + indices.push_back(vertex_ofs + j * 3 + 2); + face_materials.push_back(i); } } else { PoolVector<int>::Read ri = rindices.read(); - indices.resize(index_ofs + ic); - face_materials.resize((index_ofs + ic) / 3); - for (int j = 0; j < ic; j++) { - indices[index_ofs + j] = vertex_ofs + ri[j]; - } + for (int j = 0; j < ic / 3; j++) { - face_materials[(index_ofs / 3) + j] = i; + if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) + continue; + indices.push_back(vertex_ofs + ri[j * 3 + 0]); + indices.push_back(vertex_ofs + ri[j * 3 + 1]); + indices.push_back(vertex_ofs + ri[j * 3 + 2]); + face_materials.push_back(i); } } diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp index fe23fbf6b3..aebbb5b562 100644 --- a/scene/resources/scene_format_text.cpp +++ b/scene/resources/scene_format_text.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "scene_format_text.h" - +#include "core/io/resource_format_binary.h" #include "os/dir_access.h" #include "project_settings.h" #include "version.h" @@ -53,6 +53,60 @@ Ref<Resource> ResourceInteractiveLoaderText::get_resource() { return resource; } +Error ResourceInteractiveLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { + + VariantParser::Token token; + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_NUMBER) { + r_err_str = "Expected number (sub-resource index)"; + return ERR_PARSE_ERROR; + } + + int index = token.value; + + if (!p_data->resource_map.has(index)) { + Ref<DummyResource> dr; + dr.instance(); + dr->set_subindex(index); + p_data->resource_map[index] = dr; + p_data->resource_set.insert(dr); + } + + r_res = p_data->resource_map[index]; + + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')'"; + return ERR_PARSE_ERROR; + } + + return OK; +} + +Error ResourceInteractiveLoaderText::_parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { + + VariantParser::Token token; + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_NUMBER) { + r_err_str = "Expected number (sub-resource index)"; + return ERR_PARSE_ERROR; + } + + int id = token.value; + + ERR_FAIL_COND_V(!p_data->rev_external_resources.has(id), ERR_PARSE_ERROR); + + r_res = p_data->rev_external_resources[id]; + + VariantParser::get_token(p_stream, token, line, r_err_str); + if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')'"; + return ERR_PARSE_ERROR; + } + + return OK; +} + Error ResourceInteractiveLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { VariantParser::Token token; @@ -131,6 +185,203 @@ Error ResourceInteractiveLoaderText::_parse_ext_resource(VariantParser::Stream * return OK; } +Ref<PackedScene> ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::ResourceParser &parser) { + Ref<PackedScene> packed_scene; + packed_scene.instance(); + + while (true) { + + if (next_tag.name == "node") { + + int parent = -1; + int owner = -1; + int type = -1; + int name = -1; + int instance = -1; + //int base_scene=-1; + + if (next_tag.fields.has("name")) { + name = packed_scene->get_state()->add_name(next_tag.fields["name"]); + } + + if (next_tag.fields.has("parent")) { + NodePath np = next_tag.fields["parent"]; + np.prepend_period(); //compatible to how it manages paths internally + parent = packed_scene->get_state()->add_node_path(np); + } + + if (next_tag.fields.has("type")) { + type = packed_scene->get_state()->add_name(next_tag.fields["type"]); + } else { + type = SceneState::TYPE_INSTANCED; //no type? assume this was instanced + } + + if (next_tag.fields.has("instance")) { + + instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]); + + if (packed_scene->get_state()->get_node_count() == 0 && parent == -1) { + packed_scene->get_state()->set_base_scene(instance); + instance = -1; + } + } + + if (next_tag.fields.has("instance_placeholder")) { + + String path = next_tag.fields["instance_placeholder"]; + + int path_v = packed_scene->get_state()->add_value(path); + + if (packed_scene->get_state()->get_node_count() == 0) { + error = ERR_FILE_CORRUPT; + error_text = "Instance Placeholder can't be used for inheritance."; + _printerr(); + return Ref<PackedScene>(); + } + + instance = path_v | SceneState::FLAG_INSTANCE_IS_PLACEHOLDER; + } + + if (next_tag.fields.has("owner")) { + owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"]); + } else { + if (parent != -1 && !(type == SceneState::TYPE_INSTANCED && instance == -1)) + owner = 0; //if no owner, owner is root + } + + int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance); + + if (next_tag.fields.has("groups")) { + + Array groups = next_tag.fields["groups"]; + for (int i = 0; i < groups.size(); i++) { + packed_scene->get_state()->add_node_group(node_id, packed_scene->get_state()->add_name(groups[i])); + } + } + + while (true) { + + String assign; + Variant value; + + error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &parser); + + if (error) { + if (error != ERR_FILE_EOF) { + _printerr(); + return Ref<PackedScene>(); + } else { + return packed_scene; + } + } + + if (assign != String()) { + int nameidx = packed_scene->get_state()->add_name(assign); + int valueidx = packed_scene->get_state()->add_value(value); + packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx); + //it's assignment + } else if (next_tag.name != String()) { + break; + } + } + } else if (next_tag.name == "connection") { + + if (!next_tag.fields.has("from")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'from' field fron connection tag"; + return Ref<PackedScene>(); + } + + if (!next_tag.fields.has("to")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'to' field fron connection tag"; + return Ref<PackedScene>(); + } + + if (!next_tag.fields.has("signal")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'signal' field fron connection tag"; + return Ref<PackedScene>(); + } + + if (!next_tag.fields.has("method")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'method' field fron connection tag"; + return Ref<PackedScene>(); + } + + NodePath from = next_tag.fields["from"]; + NodePath to = next_tag.fields["to"]; + StringName method = next_tag.fields["method"]; + StringName signal = next_tag.fields["signal"]; + int flags = CONNECT_PERSIST; + Array binds; + + if (next_tag.fields.has("flags")) { + flags = next_tag.fields["flags"]; + } + + if (next_tag.fields.has("binds")) { + binds = next_tag.fields["binds"]; + } + + Vector<int> bind_ints; + for (int i = 0; i < binds.size(); i++) { + bind_ints.push_back(packed_scene->get_state()->add_value(binds[i])); + } + + packed_scene->get_state()->add_connection( + packed_scene->get_state()->add_node_path(from.simplified()), + packed_scene->get_state()->add_node_path(to.simplified()), + packed_scene->get_state()->add_name(signal), + packed_scene->get_state()->add_name(method), + flags, + bind_ints); + + error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser); + + if (error) { + if (error != ERR_FILE_EOF) { + _printerr(); + return Ref<PackedScene>(); + } else { + return packed_scene; + } + } + } else if (next_tag.name == "editable") { + + if (!next_tag.fields.has("path")) { + error = ERR_FILE_CORRUPT; + error_text = "missing 'path' field fron connection tag"; + _printerr(); + return Ref<PackedScene>(); + } + + NodePath path = next_tag.fields["path"]; + + packed_scene->get_state()->add_editable_instance(path.simplified()); + + error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser); + + if (error) { + if (error != ERR_FILE_EOF) { + _printerr(); + return Ref<PackedScene>(); + } else { + return packed_scene; + } + } + } else { + + error = ERR_FILE_CORRUPT; + _printerr(); + return Ref<PackedScene>(); + } + } + + return packed_scene; +} + Error ResourceInteractiveLoaderText::poll() { if (error != OK) @@ -364,231 +615,21 @@ Error ResourceInteractiveLoaderText::poll() { return error; } - /* - int add_name(const StringName& p_name); - int add_value(const Variant& p_value); - int add_node_path(const NodePath& p_path); - int add_node(int p_parent,int p_owner,int p_type,int p_name, int p_instance); - void add_node_property(int p_node,int p_name,int p_value); - void add_node_group(int p_node,int p_group); - void set_base_scene(int p_idx); - void add_connection(int p_from,int p_to, int p_signal, int p_method, int p_flags,const Vector<int>& p_binds); - void add_editable_instance(const NodePath& p_path); - - */ - - int parent = -1; - int owner = -1; - int type = -1; - int name = -1; - int instance = -1; - //int base_scene=-1; - - if (next_tag.fields.has("name")) { - name = packed_scene->get_state()->add_name(next_tag.fields["name"]); - } - - if (next_tag.fields.has("parent")) { - NodePath np = next_tag.fields["parent"]; - np.prepend_period(); //compatible to how it manages paths internally - parent = packed_scene->get_state()->add_node_path(np); - } - - if (next_tag.fields.has("type")) { - type = packed_scene->get_state()->add_name(next_tag.fields["type"]); - } else { - type = SceneState::TYPE_INSTANCED; //no type? assume this was instanced - } - - if (next_tag.fields.has("instance")) { - - instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]); - - if (packed_scene->get_state()->get_node_count() == 0 && parent == -1) { - packed_scene->get_state()->set_base_scene(instance); - instance = -1; - } - } - - if (next_tag.fields.has("instance_placeholder")) { - - String path = next_tag.fields["instance_placeholder"]; - - int path_v = packed_scene->get_state()->add_value(path); - - if (packed_scene->get_state()->get_node_count() == 0) { - error = ERR_FILE_CORRUPT; - error_text = "Instance Placeholder can't be used for inheritance."; - _printerr(); - return error; - } - - instance = path_v | SceneState::FLAG_INSTANCE_IS_PLACEHOLDER; - } - - if (next_tag.fields.has("owner")) { - owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"]); - } else { - if (parent != -1 && !(type == SceneState::TYPE_INSTANCED && instance == -1)) - owner = 0; //if no owner, owner is root - } - - int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance); - - if (next_tag.fields.has("groups")) { - - Array groups = next_tag.fields["groups"]; - for (int i = 0; i < groups.size(); i++) { - packed_scene->get_state()->add_node_group(node_id, packed_scene->get_state()->add_name(groups[i])); - } - } - - while (true) { - - String assign; - Variant value; - - error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp); - - if (error) { - if (error != ERR_FILE_EOF) { - _printerr(); - } else { - resource = packed_scene; - if (!ResourceCache::has(res_path)) { - packed_scene->set_path(res_path); - } - } - return error; - } - - if (assign != String()) { - int nameidx = packed_scene->get_state()->add_name(assign); - int valueidx = packed_scene->get_state()->add_value(value); - packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx); - //it's assignment - } else if (next_tag.name != String()) { - - error = OK; - return error; - } else { - - resource = packed_scene; - error = ERR_FILE_EOF; - return error; - } - } - - return OK; - - } else if (next_tag.name == "connection") { - - if (!is_scene) { - - error_text += "found the 'connection' tag on a resource file!"; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } - - if (!next_tag.fields.has("from")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'from' field fron connection tag"; - return error; - } - - if (!next_tag.fields.has("to")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'to' field fron connection tag"; - return error; - } - - if (!next_tag.fields.has("signal")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'signal' field fron connection tag"; - return error; - } - - if (!next_tag.fields.has("method")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'method' field fron connection tag"; - return error; - } - - NodePath from = next_tag.fields["from"]; - NodePath to = next_tag.fields["to"]; - StringName method = next_tag.fields["method"]; - StringName signal = next_tag.fields["signal"]; - int flags = CONNECT_PERSIST; - Array binds; - - if (next_tag.fields.has("flags")) { - flags = next_tag.fields["flags"]; - } - - if (next_tag.fields.has("binds")) { - binds = next_tag.fields["binds"]; - } - - Vector<int> bind_ints; - for (int i = 0; i < binds.size(); i++) { - bind_ints.push_back(packed_scene->get_state()->add_value(binds[i])); - } - - packed_scene->get_state()->add_connection( - packed_scene->get_state()->add_node_path(from.simplified()), - packed_scene->get_state()->add_node_path(to.simplified()), - packed_scene->get_state()->add_name(signal), - packed_scene->get_state()->add_name(method), - flags, - bind_ints); - - error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); - - if (error) { - if (error != ERR_FILE_EOF) { - _printerr(); - } else { - resource = packed_scene; - } - } - - return error; - } else if (next_tag.name == "editable") { + Ref<PackedScene> packed_scene = _parse_node_tag(rp); - if (!is_scene) { - - error_text += "found the 'editable' tag on a resource file!"; - _printerr(); - error = ERR_FILE_CORRUPT; + if (!packed_scene.is_valid()) return error; - } - if (!next_tag.fields.has("path")) { - error = ERR_FILE_CORRUPT; - error_text = "missing 'path' field fron connection tag"; - _printerr(); - return error; + error = OK; + //get it here + resource = packed_scene; + if (!ResourceCache::has(res_path)) { + packed_scene->set_path(res_path); } - NodePath path = next_tag.fields["path"]; - - packed_scene->get_state()->add_editable_instance(path.simplified()); - - error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); - - if (error) { - if (error != ERR_FILE_EOF) { - _printerr(); - } else { - resource = packed_scene; - } - } - - return error; + return ERR_FILE_EOF; } else { - error_text += "Unknown tag in file: " + next_tag.name; _printerr(); error = ERR_FILE_CORRUPT; @@ -804,7 +845,6 @@ void ResourceInteractiveLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) if (tag.name == "gd_scene") { is_scene = true; - packed_scene.instance(); } else if (tag.name == "gd_resource") { if (!tag.fields.has("type")) { @@ -846,6 +886,281 @@ void ResourceInteractiveLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) rp.userdata = this; } +static void bs_save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false) { + + CharString utf8 = p_string.utf8(); + if (p_bit_on_len) { + f->store_32(utf8.length() + 1 | 0x80000000); + } else { + f->store_32(utf8.length() + 1); + } + f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); +} + +Error ResourceInteractiveLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) { + + if (error) + return error; + + FileAccessRef wf = FileAccess::open(p_path, FileAccess::WRITE); + if (!wf) { + return ERR_CANT_OPEN; + } + + //save header compressed + static const uint8_t header[4] = { 'R', 'S', 'R', 'C' }; + wf->store_buffer(header, 4); + + wf->store_32(0); //endianness, little endian + wf->store_32(0); //64 bits file, false for now + wf->store_32(VERSION_MAJOR); + wf->store_32(VERSION_MINOR); + static const int save_format_version = 3; //use format version 3 for saving + wf->store_32(save_format_version); + + bs_save_unicode_string(wf.f, is_scene ? "PackedScene" : resource_type); + wf->store_64(0); //offset to import metadata, this is no longer used + for (int i = 0; i < 14; i++) + wf->store_32(0); // reserved + + wf->store_32(0); //string table size, will not be in use + size_t ext_res_count_pos = wf->get_position(); + + wf->store_32(0); //zero ext resources, still parsing them + + //go with external resources + + DummyReadData dummy_read; + VariantParser::ResourceParser rp; + rp.ext_func = _parse_ext_resource_dummys; + rp.sub_func = _parse_sub_resource_dummys; + rp.userdata = &dummy_read; + + while (next_tag.name == "ext_resource") { + + if (!next_tag.fields.has("path")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'path' in external resource tag"; + _printerr(); + return error; + } + + if (!next_tag.fields.has("type")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'type' in external resource tag"; + _printerr(); + return error; + } + + if (!next_tag.fields.has("id")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'id' in external resource tag"; + _printerr(); + return error; + } + + String path = next_tag.fields["path"]; + String type = next_tag.fields["type"]; + int index = next_tag.fields["id"]; + + bs_save_unicode_string(wf.f, type); + bs_save_unicode_string(wf.f, path); + + int lindex = dummy_read.external_resources.size(); + Ref<DummyResource> dr; + dr.instance(); + dr->set_path("res://dummy" + itos(lindex)); //anything is good to detect it for saving as external + dummy_read.external_resources[dr] = lindex; + dummy_read.rev_external_resources[index] = dr; + + error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); + + if (error) { + _printerr(); + return error; + } + } + + // save external resource table + wf->seek(ext_res_count_pos); + wf->store_32(dummy_read.external_resources.size()); + wf->seek_end(); + + //now, save resources to a separate file, for now + + size_t sub_res_count_pos = wf->get_position(); + wf->store_32(0); //zero sub resources, still parsing them + + String temp_file = p_path + ".temp"; + FileAccessRef wf2 = FileAccess::open(temp_file, FileAccess::WRITE); + if (!wf2) { + return ERR_CANT_OPEN; + } + + Vector<size_t> local_offsets; + Vector<size_t> local_pointers_pos; + + while (next_tag.name == "sub_resource" || next_tag.name == "resource") { + + String type; + int id = -1; + bool main_res; + + if (next_tag.name == "sub_resource") { + if (!next_tag.fields.has("type")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'type' in external resource tag"; + _printerr(); + return error; + } + + if (!next_tag.fields.has("id")) { + error = ERR_FILE_CORRUPT; + error_text = "Missing 'index' in external resource tag"; + _printerr(); + return error; + } + + type = next_tag.fields["type"]; + id = next_tag.fields["id"]; + main_res = false; + } else { + type = res_type; + id = 0; //used for last anyway + main_res = true; + } + + local_offsets.push_back(wf2->get_position()); + + bs_save_unicode_string(wf, "local://" + itos(id)); + local_pointers_pos.push_back(wf->get_position()); + wf->store_64(0); //temp local offset + + bs_save_unicode_string(wf2, type); + size_t propcount_ofs = wf2->get_position(); + wf2->store_32(0); + + int prop_count = 0; + + while (true) { + + String assign; + Variant value; + + error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp); + + if (error) { + if (main_res && error == ERR_FILE_EOF) { + next_tag.name = ""; //exit + break; + } + + _printerr(); + return error; + } + + if (assign != String()) { + + Map<StringName, int> empty_string_map; //unused + bs_save_unicode_string(wf2, assign, true); + ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_set, dummy_read.external_resources, empty_string_map); + prop_count++; + + } else if (next_tag.name != String()) { + + error = OK; + break; + } else { + error = ERR_FILE_CORRUPT; + error_text = "Premature end of file while parsing [sub_resource]"; + _printerr(); + return error; + } + } + + wf2->seek(propcount_ofs); + wf2->store_32(prop_count); + wf2->seek_end(); + } + + if (next_tag.name == "node") { + //this is a node, must save one more! + + if (!is_scene) { + + error_text += "found the 'node' tag on a resource file!"; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Ref<PackedScene> packed_scene = _parse_node_tag(rp); + + if (!packed_scene.is_valid()) + return error; + + error = OK; + //get it here + List<PropertyInfo> props; + packed_scene->get_property_list(&props); + + bs_save_unicode_string(wf, "local://0"); + local_pointers_pos.push_back(wf->get_position()); + wf->store_64(0); //temp local offset + + local_offsets.push_back(wf2->get_position()); + bs_save_unicode_string(wf2, "PackedScene"); + size_t propcount_ofs = wf2->get_position(); + wf2->store_32(0); + + int prop_count = 0; + + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) + continue; + + String name = E->get().name; + Variant value = packed_scene->get(name); + + Map<StringName, int> empty_string_map; //unused + bs_save_unicode_string(wf2, name, true); + ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_set, dummy_read.external_resources, empty_string_map); + prop_count++; + } + + wf2->seek(propcount_ofs); + wf2->store_32(prop_count); + wf2->seek_end(); + } + + wf2->close(); + + size_t offset_from = wf->get_position(); + wf->seek(sub_res_count_pos); //plus one because the saved one + wf->store_32(local_offsets.size()); + + for (int i = 0; i < local_offsets.size(); i++) { + wf->seek(local_pointers_pos[i]); + wf->store_64(local_offsets[i] + offset_from); + } + + wf->seek_end(); + + Vector<uint8_t> data = FileAccess::get_file_as_array(temp_file); + wf->store_buffer(data.ptr(), data.size()); + { + DirAccessRef dar = DirAccess::open(temp_file.get_base_dir()); + dar->remove(temp_file); + } + + wf->store_buffer((const uint8_t *)"RSRC", 4); //magic at end + + wf->close(); + + return OK; +} + String ResourceInteractiveLoaderText::recognize(FileAccess *p_f) { error = OK; @@ -991,6 +1306,25 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const return ria->rename_dependencies(f, p_path, p_map); } +Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) { + + Error err; + FileAccess *f = FileAccess::open(p_src_path, FileAccess::READ, &err); + + if (err != OK) { + + ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN); + } + + Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText); + String path = p_src_path; + ria->local_path = ProjectSettings::get_singleton()->localize_path(path); + ria->res_path = ria->local_path; + //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) ); + ria->open(f); + return ria->save_as_binary(f, p_dst_path); +} + /*****************************************************************************************************/ /*****************************************************************************************************/ /*****************************************************************************************************/ diff --git a/scene/resources/scene_format_text.h b/scene/resources/scene_format_text.h index a72a62037c..5d3c2004c1 100644 --- a/scene/resources/scene_format_text.h +++ b/scene/resources/scene_format_text.h @@ -78,9 +78,26 @@ class ResourceInteractiveLoaderText : public ResourceInteractiveLoader { Error _parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str); Error _parse_ext_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str); - VariantParser::ResourceParser rp; + // for converter + class DummyResource : public Resource { + public: + }; - Ref<PackedScene> packed_scene; + struct DummyReadData { + + Map<RES, int> external_resources; + Map<int, RES> rev_external_resources; + Set<RES> resource_set; + Map<int, RES> resource_map; + }; + + static Error _parse_sub_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return _parse_sub_resource_dummy((DummyReadData *)(p_self), p_stream, r_res, line, r_err_str); } + static Error _parse_ext_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return _parse_ext_resource_dummy((DummyReadData *)(p_self), p_stream, r_res, line, r_err_str); } + + static Error _parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str); + static Error _parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str); + + VariantParser::ResourceParser rp; friend class ResourceFormatLoaderText; @@ -89,6 +106,8 @@ class ResourceInteractiveLoaderText : public ResourceInteractiveLoader { RES resource; + Ref<PackedScene> _parse_node_tag(VariantParser::ResourceParser &parser); + public: virtual void set_local_path(const String &p_local_path); virtual Ref<Resource> get_resource(); @@ -102,6 +121,7 @@ public: void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types); Error rename_dependencies(FileAccess *p_f, const String &p_path, const Map<String, String> &p_map); + Error save_as_binary(FileAccess *p_f, const String &p_path); ResourceInteractiveLoaderText(); ~ResourceInteractiveLoaderText(); }; @@ -115,6 +135,8 @@ public: virtual String get_resource_type(const String &p_path) const; virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map); + + static Error convert_file_to_binary(const String &p_src_path, const String &p_dst_path); }; class ResourceFormatSaverTextInstance { diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index df41c3b5ce..c5c225a40a 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -112,6 +112,10 @@ public: SelfList<InstanceBase> dependency_item; + InstanceBase *lightmap_capture; + RID lightmap; + Vector<Color> lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader + virtual void base_removed() = 0; virtual void base_changed() = 0; virtual void base_material_changed() = 0; @@ -126,6 +130,7 @@ public: depth_layer = 0; layer_mask = 1; baked_light = false; + lightmap_capture = NULL; } }; @@ -437,6 +442,32 @@ public: virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) = 0; virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) = 0; + /* LIGHTMAP CAPTURE */ + + struct LightmapCaptureOctree { + + enum { + CHILD_EMPTY = 0xFFFFFFFF + }; + + uint16_t light[6][3]; //anisotropic light + float alpha; + uint32_t children[8]; + }; + + virtual RID lightmap_capture_create() = 0; + virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) = 0; + virtual AABB lightmap_capture_get_bounds(RID p_capture) const = 0; + virtual void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) = 0; + virtual PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const = 0; + virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) = 0; + virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const = 0; + virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) = 0; + virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0; + virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0; + virtual float lightmap_capture_get_energy(RID p_capture) const = 0; + virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const = 0; + /* PARTICLES */ virtual RID particles_create() = 0; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index e10a57c571..c69bbb9343 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -755,12 +755,12 @@ void ShaderLanguage::clear() { } } -bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type) { +bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type) { if (p_builtin_types.has(p_identifier)) { if (r_data_type) { - *r_data_type = p_builtin_types[p_identifier]; + *r_data_type = p_builtin_types[p_identifier].type; } if (r_type) { *r_type = IDENTIFIER_BUILTIN_VAR; @@ -2008,7 +2008,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p return false; } -bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) { +bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) { TkPos pos = _get_tkpos(); Token tk = _get_token(); @@ -2261,7 +2261,48 @@ bool ShaderLanguage::_get_completable_identifier(BlockNode *p_block, CompletionT return false; } -ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types) { +bool ShaderLanguage::_is_operator_assign(Operator p_op) const { + switch (p_op) { + case OP_ASSIGN: + case OP_ASSIGN_ADD: + case OP_ASSIGN_SUB: + case OP_ASSIGN_MUL: + case OP_ASSIGN_DIV: + case OP_ASSIGN_MOD: + case OP_ASSIGN_SHIFT_LEFT: + case OP_ASSIGN_SHIFT_RIGHT: + case OP_ASSIGN_BIT_AND: + case OP_ASSIGN_BIT_OR: + case OP_ASSIGN_BIT_XOR: + return true; + default: + return false; + } + + return false; +} + +bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types) { + + if (p_node->type == Node::TYPE_OPERATOR) { + + OperatorNode *op = static_cast<OperatorNode *>(p_node); + if (op->type == OP_INDEX) { + return _validate_assign(op->arguments[0], p_builtin_types); + } + } + + if (p_node->type == Node::TYPE_VARIABLE) { + + VariableNode *var = static_cast<VariableNode *>(p_node); + if (p_builtin_types.has(var->name) && p_builtin_types[var->name].constant) { + return false; //ops not valid + } + } + return true; +} + +ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) { Vector<Expression> expression; //Vector<TokenType> operators; @@ -2765,6 +2806,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons _set_error("Invalid base type for increment/decrement operator"); return NULL; } + + if (!_validate_assign(expr, p_builtin_types)) { + _set_error("Invalid use of increment/decrement operator in constant expression."); + return NULL; + } expr = op; } else { @@ -2948,6 +2994,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons OperatorNode *op = alloc_node<OperatorNode>(); op->op = expression[i].op; + if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_builtin_types)) { + + _set_error("Can't use increment/decrement operator in constant expression."); + return NULL; + } op->arguments.push_back(expression[i + 1].node); expression[i].is_op = false; @@ -3019,6 +3070,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons ERR_FAIL_V(NULL); } + if (_is_operator_assign(op->op) && !_validate_assign(expression[next_op - 1].node, p_builtin_types)) { + + _set_error("Assignment to constant expression."); + return NULL; + } + if (expression[next_op + 1].is_op) { // this is not invalid and can really appear // but it becomes invalid anyway because no binary op @@ -3142,7 +3199,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha return p_node; } -ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types) { +ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) { ShaderLanguage::Node *expr = _parse_expression(p_block, p_builtin_types); if (!expr) //errored @@ -3153,7 +3210,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_ return expr; } -Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types, bool p_just_one, bool p_can_break, bool p_can_continue) { +Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one, bool p_can_break, bool p_can_continue) { while (true) { @@ -3636,7 +3693,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct name = tk.text; - if (_find_identifier(NULL, Map<StringName, DataType>(), name)) { + if (_find_identifier(NULL, Map<StringName, BuiltInInfo>(), name)) { _set_error("Redefinition of '" + String(name) + "'"); return ERR_PARSE_ERROR; } @@ -3660,7 +3717,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type == TK_OP_ASSIGN) { - Node *expr = _parse_and_reduce_expression(NULL, Map<StringName, DataType>()); + Node *expr = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>()); if (!expr) return ERR_PARSE_ERROR; if (expr->type != Node::TYPE_CONSTANT) { @@ -3841,7 +3898,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } - if (_find_identifier(NULL, Map<StringName, DataType>(), name)) { + if (_find_identifier(NULL, Map<StringName, BuiltInInfo>(), name)) { _set_error("Redefinition of '" + String(name) + "'"); return ERR_PARSE_ERROR; } @@ -3852,7 +3909,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } - Map<StringName, DataType> builtin_types; + Map<StringName, BuiltInInfo> builtin_types; if (p_functions.has(name)) { builtin_types = p_functions[name].built_ins; } @@ -4109,7 +4166,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct if (comp_ident && skip_function != StringName() && p_functions.has(skip_function)) { - for (Map<StringName, DataType>::Element *E = p_functions[skip_function].built_ins.front(); E; E = E->next()) { + for (Map<StringName, BuiltInInfo>::Element *E = p_functions[skip_function].built_ins.front(); E; E = E->next()) { matches.insert(E->key()); } } diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index e092bf931f..4cf8560990 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -537,8 +537,18 @@ public: static void get_keyword_list(List<String> *r_keywords); static void get_builtin_funcs(List<String> *r_keywords); + struct BuiltInInfo { + DataType type; + bool constant; + BuiltInInfo() {} + BuiltInInfo(DataType p_type, bool p_constant = false) { + type = p_type; + constant = p_constant; + } + }; + struct FunctionInfo { - Map<StringName, DataType> built_ins; + Map<StringName, BuiltInInfo> built_ins; bool can_discard; }; @@ -601,7 +611,10 @@ private: IDENTIFIER_BUILTIN_VAR, }; - bool _find_identifier(const BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = NULL, IdentifierType *r_type = NULL); + bool _find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = NULL, IdentifierType *r_type = NULL); + + bool _is_operator_assign(Operator p_op) const; + bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types); bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = NULL); @@ -625,14 +638,14 @@ private: static const BuiltinFuncDef builtin_func_defs[]; bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type); - bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = NULL); + bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = NULL); - Node *_parse_expression(BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types); + Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types); ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node); - Node *_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types); + Node *_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types); - Error _parse_block(BlockNode *p_block, const Map<StringName, DataType> &p_builtin_types, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false); + Error _parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false); Error _parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Set<String> &p_render_modes, const Set<String> &p_shader_types); diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 7489ca7e3e..a25c5ca65e 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -45,6 +45,11 @@ const Set<String> &ShaderTypes::get_types() { ShaderTypes *ShaderTypes::singleton = NULL; +static ShaderLanguage::BuiltInInfo constt(ShaderLanguage::DataType p_type) { + + return ShaderLanguage::BuiltInInfo(p_type, true); +} + ShaderTypes::ShaderTypes() { singleton = this; @@ -58,32 +63,32 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["UV2"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_ID"] = ShaderLanguage::TYPE_INT; - shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = ShaderLanguage::TYPE_VEC4; + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["vertex"].can_discard = false; //builtins shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_CAMERA_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_MATRIX"] = ShaderLanguage::TYPE_MAT4; + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4; shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_MATRIX"] = ShaderLanguage::TYPE_MAT4; shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["TIME"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = ShaderLanguage::TYPE_VEC2; + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = ShaderLanguage::TYPE_VEC4; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRONT_FACING"] = ShaderLanguage::TYPE_BOOL; + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRONT_FACING"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["TANGENT"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["BINORMAL"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["UV"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["UV2"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["UV2"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ALBEDO"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["METALLIC"] = ShaderLanguage::TYPE_FLOAT; @@ -103,33 +108,33 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SIDE"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SIDE"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_SCISSOR"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_CAMERA_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["TIME"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEWPORT_SIZE"] = ShaderLanguage::TYPE_VEC2; + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].can_discard = true; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["INV_CAMERA_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["INV_PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["TIME"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["VIEWPORT_SIZE"] = ShaderLanguage::TYPE_VEC2; - - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["VIEW"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT_COLOR"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ATTENUATION"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ALBEDO"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["TRANSMISSION"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); + + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["VIEW"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT_COLOR"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ATTENUATION"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ALBEDO"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["TRANSMISSION"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ROUGHNESS"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3; @@ -177,38 +182,38 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["EXTRA_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TIME"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = ShaderLanguage::TYPE_VEC4; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = ShaderLanguage::TYPE_BOOL; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["EXTRA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = ShaderLanguage::TYPE_VEC4; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["UV"] = ShaderLanguage::TYPE_VEC2; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE_PIXEL_SIZE"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_PIXEL_SIZE"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["POINT_COORD"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TIME"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = ShaderLanguage::TYPE_BOOL; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POSITION"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["UV"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE_PIXEL_SIZE"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POSITION"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_VEC"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_HEIGHT"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_COLOR"] = ShaderLanguage::TYPE_VEC4; @@ -216,8 +221,8 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_SHADOW"] = ShaderLanguage::TYPE_VEC4; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT"] = ShaderLanguage::TYPE_VEC4; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW"] = ShaderLanguage::TYPE_VEC4; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = ShaderLanguage::TYPE_VEC2; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TIME"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true; shader_modes[VS::SHADER_CANVAS_ITEM].modes.insert("skip_vertex_transform"); @@ -237,16 +242,16 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["RESTART"] = ShaderLanguage::TYPE_BOOL; + shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4; shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["TIME"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["LIFETIME"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["DELTA"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["NUMBER"] = ShaderLanguage::TYPE_UINT; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["INDEX"] = ShaderLanguage::TYPE_INT; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["EMISSION_TRANSFORM"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["RANDOM_SEED"] = ShaderLanguage::TYPE_UINT; + shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT); + shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT); shader_modes[VS::SHADER_PARTICLES].functions["vertex"].can_discard = false; shader_modes[VS::SHADER_PARTICLES].modes.insert("billboard"); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index d843c443a2..a0e79e9d3e 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -361,6 +361,24 @@ public: BIND2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &) BIND1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID) + /* LIGHTMAP CAPTURE */ + + BIND0R(RID, lightmap_capture_create) + + BIND2(lightmap_capture_set_bounds, RID, const AABB &) + BIND1RC(AABB, lightmap_capture_get_bounds, RID) + + BIND2(lightmap_capture_set_octree, RID, const PoolVector<uint8_t> &) + BIND1RC(PoolVector<uint8_t>, lightmap_capture_get_octree, RID) + + BIND2(lightmap_capture_set_octree_cell_transform, RID, const Transform &) + BIND1RC(Transform, lightmap_capture_get_octree_cell_transform, RID) + BIND2(lightmap_capture_set_octree_cell_subdiv, RID, int) + BIND1RC(int, lightmap_capture_get_octree_cell_subdiv, RID) + + BIND2(lightmap_capture_set_energy, RID, float) + BIND1RC(float, lightmap_capture_get_energy, RID) + /* PARTICLES */ BIND0R(RID, particles_create) @@ -504,6 +522,7 @@ public: BIND3(instance_set_blend_shape_weight, RID, int, float) BIND3(instance_set_surface_material, RID, int, RID) BIND2(instance_set_visible, RID, bool) + BIND3(instance_set_use_lightmap, RID, RID, RID) BIND2(instance_set_custom_aabb, RID, AABB) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index dde69eedd3..22be2f6ff9 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -133,6 +133,19 @@ void *VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance geom->reflection_dirty = true; return E; //this element should make freeing faster + } else if (B->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) { + + InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + InstanceLightmapCaptureData::PairInfo pinfo; + pinfo.geometry = A; + pinfo.L = geom->lightmap_captures.push_back(B); + + List<InstanceLightmapCaptureData::PairInfo>::Element *E = lightmap_capture->geometries.push_back(pinfo); + ((VisualServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture + + return E; //this element should make freeing faster } else if (B->base_type == VS::INSTANCE_GI_PROBE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) { InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); @@ -193,6 +206,16 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance reflection_probe->geometries.erase(E); geom->reflection_dirty = true; + } else if (B->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) { + + InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + List<InstanceLightmapCaptureData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightmapCaptureData::PairInfo>::Element *>(udata); + + geom->lightmap_captures.erase(E->get().L); + lightmap_capture->geometries.erase(E); + ((VisualServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture } else if (B->base_type == VS::INSTANCE_GI_PROBE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) { @@ -344,6 +367,14 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { reflection_probe_render_list.remove(&reflection_probe->update_list); } } break; + case VS::INSTANCE_LIGHTMAP_CAPTURE: { + + InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(instance->base_data); + //erase dependencies, since no longer a lightmap + while (lightmap_capture->users.front()) { + instance_set_use_lightmap(lightmap_capture->users.front()->get()->self, RID(), RID()); + } + } break; case VS::INSTANCE_GI_PROBE: { InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); @@ -355,6 +386,14 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { VSG::storage->free(gi_probe->dynamic.probe_data); } + if (instance->lightmap_capture) { + Instance *capture = (Instance *)instance->lightmap_capture; + InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(capture->base_data); + lightmap_capture->users.erase(instance); + instance->lightmap_capture = NULL; + instance->lightmap = RID(); + } + VSG::scene_render->free(gi_probe->probe_instance); } break; @@ -412,6 +451,12 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { reflection_probe->instance = VSG::scene_render->reflection_probe_instance_create(p_base); } break; + case VS::INSTANCE_LIGHTMAP_CAPTURE: { + + InstanceLightmapCaptureData *lightmap_capture = memnew(InstanceLightmapCaptureData); + instance->base_data = lightmap_capture; + //lightmap_capture->instance = VSG::scene_render->lightmap_capture_instance_create(p_base); + } break; case VS::INSTANCE_GI_PROBE: { InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData); @@ -591,6 +636,12 @@ void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) { } } break; + case VS::INSTANCE_LIGHTMAP_CAPTURE: { + if (instance->octree_id && instance->scenario) { + instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << VS::INSTANCE_LIGHTMAP_CAPTURE, p_visible ? VS::INSTANCE_GEOMETRY_MASK : 0); + } + + } break; case VS::INSTANCE_GI_PROBE: { if (instance->octree_id && instance->scenario) { instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << VS::INSTANCE_GI_PROBE, p_visible ? (VS::INSTANCE_GEOMETRY_MASK | (1 << VS::INSTANCE_LIGHT)) : 0); @@ -599,11 +650,35 @@ void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) { } break; } } - inline bool is_geometry_instance(VisualServer::InstanceType p_type) { return p_type == VS::INSTANCE_MESH || p_type == VS::INSTANCE_MULTIMESH || p_type == VS::INSTANCE_PARTICLES || p_type == VS::INSTANCE_IMMEDIATE; } +void VisualServerScene::instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap) { + + Instance *instance = instance_owner.get(p_instance); + ERR_FAIL_COND(!instance); + ERR_FAIL_COND(!is_geometry_instance(instance->base_type)); + + if (instance->lightmap_capture) { + InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(((Instance *)instance->lightmap_capture)->base_data); + lightmap_capture->users.erase(instance); + instance->lightmap = RID(); + instance->lightmap_capture = NULL; + } + + if (p_lightmap_instance.is_valid()) { + Instance *lightmap_instance = instance_owner.get(p_lightmap_instance); + ERR_FAIL_COND(!lightmap_instance); + ERR_FAIL_COND(lightmap_instance->base_type != VS::INSTANCE_LIGHTMAP_CAPTURE); + instance->lightmap_capture = lightmap_instance; + + InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(((Instance *)instance->lightmap_capture)->base_data); + lightmap_capture->users.insert(instance); + instance->lightmap = p_lightmap; + } +} + void VisualServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { Instance *instance = instance_owner.get(p_instance); @@ -811,6 +886,15 @@ void VisualServerScene::_update_instance(Instance *p_instance) { light->shadow_dirty = true; } } + + if (!p_instance->lightmap_capture && geom->lightmap_captures.size()) { + //affected by lightmap captures, must update capture info! + _update_instance_lightmap_captures(p_instance); + } else { + if (!p_instance->lightmap_capture_data.empty()) { + !p_instance->lightmap_capture_data.resize(0); //not in use, clear capture data + } + } } p_instance->mirror = p_instance->transform.basis.determinant() < 0.0; @@ -832,7 +916,7 @@ void VisualServerScene::_update_instance(Instance *p_instance) { uint32_t pairable_mask = 0; bool pairable = false; - if (p_instance->base_type == VS::INSTANCE_LIGHT || p_instance->base_type == VS::INSTANCE_REFLECTION_PROBE) { + if (p_instance->base_type == VS::INSTANCE_LIGHT || p_instance->base_type == VS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE) { pairable_mask = p_instance->visible ? VS::INSTANCE_GEOMETRY_MASK : 0; pairable = true; @@ -917,6 +1001,11 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { new_aabb = VSG::storage->gi_probe_get_bounds(p_instance->base); } break; + case VisualServer::INSTANCE_LIGHTMAP_CAPTURE: { + + new_aabb = VSG::storage->lightmap_capture_get_bounds(p_instance->base); + + } break; default: {} } @@ -928,6 +1017,237 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { p_instance->aabb = new_aabb; } +_FORCE_INLINE_ static void _light_capture_sample_octree(const RasterizerStorage::LightmapCaptureOctree *p_octree, int p_cell_subdiv, const Vector3 &p_pos, const Vector3 &p_dir, float p_level, Vector3 &r_color, float &r_alpha) { + + static const Vector3 aniso_normal[6] = { + Vector3(-1, 0, 0), + Vector3(1, 0, 0), + Vector3(0, -1, 0), + Vector3(0, 1, 0), + Vector3(0, 0, -1), + Vector3(0, 0, 1) + }; + + int size = 1 << (p_cell_subdiv - 1); + + int clamp_v = size - 1; + //first of all, clamp + Vector3 pos; + pos.x = CLAMP(p_pos.x, 0, clamp_v); + pos.y = CLAMP(p_pos.y, 0, clamp_v); + pos.z = CLAMP(p_pos.z, 0, clamp_v); + + float level = (p_cell_subdiv - 1) - p_level; + + int target_level; + float level_filter; + if (level <= 0.0) { + level_filter = 0; + target_level = 0; + } else { + target_level = Math::ceil(level); + level_filter = target_level - level; + } + + Vector3 color[2][8]; + float alpha[2][8]; + zeromem(alpha, sizeof(float) * 2 * 8); + + //find cell at given level first + + for (int c = 0; c < 2; c++) { + + int current_level = MAX(0, target_level - c); + int level_cell_size = (1 << (p_cell_subdiv - 1)) >> current_level; + + for (int n = 0; n < 8; n++) { + + int x = int(pos.x); + int y = int(pos.y); + int z = int(pos.z); + + if (n & 1) + x += level_cell_size; + if (n & 2) + y += level_cell_size; + if (n & 4) + z += level_cell_size; + + int ofs_x = 0; + int ofs_y = 0; + int ofs_z = 0; + + x = CLAMP(x, 0, clamp_v); + y = CLAMP(y, 0, clamp_v); + z = CLAMP(z, 0, clamp_v); + + int half = size / 2; + uint32_t cell = 0; + for (int i = 0; i < current_level; i++) { + + const RasterizerStorage::LightmapCaptureOctree *bc = &p_octree[cell]; + + int child = 0; + if (x >= ofs_x + half) { + child |= 1; + ofs_x += half; + } + if (y >= ofs_y + half) { + child |= 2; + ofs_y += half; + } + if (z >= ofs_z + half) { + child |= 4; + ofs_z += half; + } + + cell = bc->children[child]; + if (cell == RasterizerStorage::LightmapCaptureOctree::CHILD_EMPTY) + break; + + half >>= 1; + } + + if (cell == RasterizerStorage::LightmapCaptureOctree::CHILD_EMPTY) { + alpha[c][n] = 0; + } else { + alpha[c][n] = p_octree[cell].alpha; + + for (int i = 0; i < 6; i++) { + //anisotropic read light + float amount = p_dir.dot(aniso_normal[i]); + if (amount < 0) + amount = 0; + color[c][n].x += p_octree[cell].light[i][0] / 1024.0 * amount; + color[c][n].y += p_octree[cell].light[i][1] / 1024.0 * amount; + color[c][n].z += p_octree[cell].light[i][2] / 1024.0 * amount; + } + } + + //print_line("\tlev " + itos(c) + " - " + itos(n) + " alpha: " + rtos(cells[test_cell].alpha) + " col: " + color[c][n]); + } + } + + float target_level_size = size >> target_level; + Vector3 pos_fract[2]; + + pos_fract[0].x = Math::fmod(pos.x, target_level_size) / target_level_size; + pos_fract[0].y = Math::fmod(pos.y, target_level_size) / target_level_size; + pos_fract[0].z = Math::fmod(pos.z, target_level_size) / target_level_size; + + target_level_size = size >> MAX(0, target_level - 1); + + pos_fract[1].x = Math::fmod(pos.x, target_level_size) / target_level_size; + pos_fract[1].y = Math::fmod(pos.y, target_level_size) / target_level_size; + pos_fract[1].z = Math::fmod(pos.z, target_level_size) / target_level_size; + + float alpha_interp[2]; + Vector3 color_interp[2]; + + for (int i = 0; i < 2; i++) { + + Vector3 color_x00 = color[i][0].linear_interpolate(color[i][1], pos_fract[i].x); + Vector3 color_xy0 = color[i][2].linear_interpolate(color[i][3], pos_fract[i].x); + Vector3 blend_z0 = color_x00.linear_interpolate(color_xy0, pos_fract[i].y); + + Vector3 color_x0z = color[i][4].linear_interpolate(color[i][5], pos_fract[i].x); + Vector3 color_xyz = color[i][6].linear_interpolate(color[i][7], pos_fract[i].x); + Vector3 blend_z1 = color_x0z.linear_interpolate(color_xyz, pos_fract[i].y); + + color_interp[i] = blend_z0.linear_interpolate(blend_z1, pos_fract[i].z); + + float alpha_x00 = Math::lerp(alpha[i][0], alpha[i][1], pos_fract[i].x); + float alpha_xy0 = Math::lerp(alpha[i][2], alpha[i][3], pos_fract[i].x); + float alpha_z0 = Math::lerp(alpha_x00, alpha_xy0, pos_fract[i].y); + + float alpha_x0z = Math::lerp(alpha[i][4], alpha[i][5], pos_fract[i].x); + float alpha_xyz = Math::lerp(alpha[i][6], alpha[i][7], pos_fract[i].x); + float alpha_z1 = Math::lerp(alpha_x0z, alpha_xyz, pos_fract[i].y); + + alpha_interp[i] = Math::lerp(alpha_z0, alpha_z1, pos_fract[i].z); + } + + r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter); + r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter); + + // print_line("pos: " + p_posf + " level " + rtos(p_level) + " down to " + itos(target_level) + "." + rtos(level_filter) + " color " + r_color + " alpha " + rtos(r_alpha)); +} + +_FORCE_INLINE_ static Color _light_capture_voxel_cone_trace(const RasterizerStorage::LightmapCaptureOctree *p_octree, const Vector3 &p_pos, const Vector3 &p_dir, float p_aperture, int p_cell_subdiv) { + + float bias = 0.0; //no need for bias here + float max_distance = (Vector3(1, 1, 1) * (1 << (p_cell_subdiv - 1))).length(); + + float dist = bias; + float alpha = 0.0; + Vector3 color; + + Vector3 scolor; + float salpha; + + while (dist < max_distance && alpha < 0.95) { + float diameter = MAX(1.0, 2.0 * p_aperture * dist); + _light_capture_sample_octree(p_octree, p_cell_subdiv, p_pos + dist * p_dir, p_dir, log2(diameter), scolor, salpha); + float a = (1.0 - alpha); + color += scolor * a; + alpha += a * salpha; + dist += diameter * 0.5; + } + + return Color(color.x, color.y, color.z, alpha); +} + +void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance) { + + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + + static const Vector3 cone_traces[12] = { + Vector3(0, 0, 1), + Vector3(0.866025, 0, 0.5), + Vector3(0.267617, 0.823639, 0.5), + Vector3(-0.700629, 0.509037, 0.5), + Vector3(-0.700629, -0.509037, 0.5), + Vector3(0.267617, -0.823639, 0.5), + Vector3(0, 0, -1), + Vector3(0.866025, 0, -0.5), + Vector3(0.267617, 0.823639, -0.5), + Vector3(-0.700629, 0.509037, -0.5), + Vector3(-0.700629, -0.509037, -0.5), + Vector3(0.267617, -0.823639, -0.5) + }; + + float cone_aperture = 0.577; // tan(angle) 60 degrees + + if (p_instance->lightmap_capture_data.empty()) { + p_instance->lightmap_capture_data.resize(12); + } + + //print_line("update captures for pos: " + p_instance->transform.origin); + + zeromem(p_instance->lightmap_capture_data.ptrw(), 12 * sizeof(Color)); + //this could use some sort of blending.. + for (List<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) { + const PoolVector<RasterizerStorage::LightmapCaptureOctree> *octree = VSG::storage->lightmap_capture_get_octree_ptr(E->get()->base); + //print_line("octree size: " + itos(octree->size())); + if (octree->size() == 0) + continue; + Transform to_cell_xform = VSG::storage->lightmap_capture_get_octree_cell_transform(E->get()->base); + int cell_subdiv = VSG::storage->lightmap_capture_get_octree_cell_subdiv(E->get()->base); + to_cell_xform = to_cell_xform * E->get()->transform.affine_inverse(); + + PoolVector<RasterizerStorage::LightmapCaptureOctree>::Read octree_r = octree->read(); + + Vector3 pos = to_cell_xform.xform(p_instance->transform.origin); + + for (int i = 0; i < 12; i++) { + + Vector3 dir = to_cell_xform.basis.xform(cone_traces[i]).normalized(); + Color capture = _light_capture_voxel_cone_trace(octree_r.ptr(), pos, dir, cone_aperture, cell_subdiv); + p_instance->lightmap_capture_data[i] += capture; + } + } +} + void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario) { InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); @@ -2188,6 +2508,8 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co InstanceGIProbeData::LocalData *light = &local_data[idx]; Vector3 to(light->pos[0] + 0.5, light->pos[1] + 0.5, light->pos[2] + 0.5); + to += -light_axis.sign() * 0.47; //make it more likely to receive a ray + Vector3 norm( (((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0, (((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0, @@ -2254,6 +2576,8 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co InstanceGIProbeData::LocalData *light = &local_data[idx]; Vector3 to(light->pos[0] + 0.5, light->pos[1] + 0.5, light->pos[2] + 0.5); + to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray + Vector3 norm( (((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0, (((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0, @@ -2927,12 +3251,12 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { } } + _instance_update_list.remove(&p_instance->update_item); + _update_instance(p_instance); p_instance->update_aabb = false; p_instance->update_materials = false; - - _instance_update_list.remove(&p_instance->update_item); } void VisualServerScene::update_dirty_instances() { diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 9e4701de65..4b0c4af09d 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -281,6 +281,8 @@ public: List<Instance *> gi_probes; bool gi_probes_dirty; + List<Instance *> lightmap_captures; + InstanceGeometryData() { lighting_dirty = false; @@ -445,6 +447,20 @@ public: SelfList<InstanceGIProbeData>::List gi_probe_update_list; + struct InstanceLightmapCaptureData : public InstanceBaseData { + + struct PairInfo { + List<Instance *>::Element *L; //iterator in geometry + Instance *geometry; + }; + List<PairInfo> geometries; + + Set<Instance *> users; + + InstanceLightmapCaptureData() { + } + }; + Instance *instance_cull_result[MAX_INSTANCE_CULL]; Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps Instance *light_cull_result[MAX_LIGHTS_CULLED]; @@ -466,6 +482,7 @@ public: virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material); virtual void instance_set_visible(RID p_instance, bool p_visible); + virtual void instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap); virtual void instance_set_custom_aabb(RID p_insatnce, AABB aabb); @@ -489,6 +506,7 @@ public: _FORCE_INLINE_ void _update_instance(Instance *p_instance); _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance); _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); + _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); _FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 94f450c024..cb6f67474e 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -294,6 +294,22 @@ public: FUNC2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &) FUNC1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID) + /* LIGHTMAP CAPTURE */ + + FUNCRID(lightmap_capture) + + FUNC2(lightmap_capture_set_bounds, RID, const AABB &) + FUNC1RC(AABB, lightmap_capture_get_bounds, RID) + + FUNC2(lightmap_capture_set_octree, RID, const PoolVector<uint8_t> &) + FUNC1RC(PoolVector<uint8_t>, lightmap_capture_get_octree, RID) + FUNC2(lightmap_capture_set_octree_cell_transform, RID, const Transform &) + FUNC1RC(Transform, lightmap_capture_get_octree_cell_transform, RID) + FUNC2(lightmap_capture_set_octree_cell_subdiv, RID, int) + FUNC1RC(int, lightmap_capture_get_octree_cell_subdiv, RID) + FUNC2(lightmap_capture_set_energy, RID, float) + FUNC1RC(float, lightmap_capture_get_energy, RID) + /* PARTICLES */ FUNCRID(particles) @@ -425,6 +441,8 @@ public: FUNC3(instance_set_blend_shape_weight, RID, int, float) FUNC3(instance_set_surface_material, RID, int, RID) FUNC2(instance_set_visible, RID, bool) + FUNC3(instance_set_use_lightmap, RID, RID, RID) + FUNC2(instance_set_custom_aabb, RID, AABB) FUNC2(instance_attach_skeleton, RID, RID) diff --git a/servers/visual_server.h b/servers/visual_server.h index de5ef7da0a..ad4d32b967 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -485,6 +485,20 @@ public: virtual void gi_probe_set_compress(RID p_probe, bool p_enable) = 0; virtual bool gi_probe_is_compressed(RID p_probe) const = 0; + /* LIGHTMAP CAPTURE */ + + virtual RID lightmap_capture_create() = 0; + virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) = 0; + virtual AABB lightmap_capture_get_bounds(RID p_capture) const = 0; + virtual void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) = 0; + virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) = 0; + virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const = 0; + virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) = 0; + virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0; + virtual PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const = 0; + virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0; + virtual float lightmap_capture_get_energy(RID p_capture) const = 0; + /* PARTICLES API */ virtual RID particles_create() = 0; @@ -735,6 +749,7 @@ public: INSTANCE_LIGHT, INSTANCE_REFLECTION_PROBE, INSTANCE_GI_PROBE, + INSTANCE_LIGHTMAP_CAPTURE, INSTANCE_MAX, /*INSTANCE_BAKED_LIGHT_SAMPLER,*/ @@ -755,6 +770,8 @@ public: virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0; virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; + virtual void instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap) = 0; + virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0; virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0; diff --git a/thirdparty/README.md b/thirdparty/README.md index dd931b2fcb..8c50081782 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -62,8 +62,8 @@ Use UI font if exists, because it has tight vertical metrics and good for UI. ### Hack Regular - Upstream: https://github.com/source-foundry/Hack -- Version: 2.020 -- License: Hack Open Font License v2.0 +- Version: 3.000 +- License: MIT + Bitstream Vera License ### DroidSans*.ttf @@ -179,6 +179,9 @@ Files extracted from upstream source: TODO. +Important: File `libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c` has +Godot-made change marked with `// -- GODOT --` comments. + ## libwebp @@ -269,7 +272,7 @@ Collection of single-file libraries used in Godot components. ### poshlib - Upstream: http://poshlib.hookatooka.com/poshlib/trac.cgi (username guest, password guest123) -- Version: 1.3.002 +- Version: 1.3.002 - License: MIT Files extracted from the upstream source: @@ -305,6 +308,10 @@ Files extracted from the upstream source: - Relevant sources from src/ - License.txt +Important: Some files have Godot-made changes, those +changes are marked with `// -- GODOT --` comments. + + ## nanosvg - Upstream: https://github.com/memononen/nanosvg diff --git a/thirdparty/fonts/Hack_Regular.ttf b/thirdparty/fonts/Hack_Regular.ttf Binary files differindex a35ea2e4f4..f342700811 100644 --- a/thirdparty/fonts/Hack_Regular.ttf +++ b/thirdparty/fonts/Hack_Regular.ttf diff --git a/thirdparty/fonts/LICENSE_Hack.md b/thirdparty/fonts/LICENSE_Hack.md index e9fc8a1f87..ddd23a2b81 100644 --- a/thirdparty/fonts/LICENSE_Hack.md +++ b/thirdparty/fonts/LICENSE_Hack.md @@ -1,49 +1,30 @@ -## License +The work in the Hack project is Copyright 2017 Source Foundry Authors and licensed under the MIT License -Hack Copyright 2015, Christopher Simpkins with Reserved Font Name "Hack". +The work in the DejaVu project was committed to the public domain. Bitstream Vera Sans Mono Copyright 2003 Bitstream Inc. and licensed under the Bitstream Vera License with Reserved Font Names "Bitstream" and "Vera" -DejaVu modifications of the original Bitstream Vera Sans Mono typeface have been committed to the public domain. +### MIT License +Copyright (c) 2017 Source Foundry Authors +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: -This Font Software is licensed under the Hack Open Font License v2.0 and the Bitstream Vera License. - -These licenses are copied below. - - -### Hack Open Font License v2.0 - -(Version 1.0 - 06 September 2015) - -(Version 2.0 - 27 September 2015) - -Copyright 2015 by Christopher Simpkins. All Rights Reserved. - -DEFINITIONS - -"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. - -PERMISSION AND CONDITIONS - -Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated source code, documentation, and binary files (the "Font Software"), to reproduce and distribute the modifications to the Bitstream Vera Font Software, including without limitation the rights to use, study, copy, merge, embed, modify, redistribute, and/or sell modified or unmodified copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: - -(1) The above copyright notice and this permission notice shall be included in all modified and unmodified copies of the Font Software typefaces. These notices can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. - -(2) The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing the word "Hack". - -(3) Neither the Font Software nor any of its individual components, in original or modified versions, may be sold by itself. - -TERMINATION - -This license becomes null and void if any of the above conditions are not met. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. - -Except as contained in this notice, the names of Christopher Simpkins and the Author(s) of the Font Software shall not be used to promote, endorse or advertise any modified version, except to acknowledge the contribution(s) of Christopher Simpkins and the Author(s) or with their explicit written permission. For further information, contact: chris at sourcefoundry dot org. - +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. ### BITSTREAM VERA LICENSE diff --git a/thirdparty/libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c b/thirdparty/libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c index b718678537..d8a92354c9 100644 --- a/thirdparty/libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c +++ b/thirdparty/libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c @@ -40,11 +40,12 @@ DECLARE_ALIGNED(32, static const uint8_t, filt4_global_avx2[32]) = { }; #if defined(__clang__) +// -- GODOT start - # if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ <= 3) || \ - (defined(__APPLE__) && \ + (!defined(__MACPORTS__) && defined(__APPLE__) && \ ((__clang_major__ == 4 && __clang_minor__ <= 2) || \ (__clang_major__ == 5 && __clang_minor__ == 0))) - +// -- GODOT end -- # define MM256_BROADCASTSI128_SI256(x) \ _mm_broadcastsi128_si256((__m128i const *)&(x)) # else // clang > 3.3, and not 5.0 on macosx. diff --git a/thirdparty/thekla_atlas/nvcore/Debug.cpp b/thirdparty/thekla_atlas/nvcore/Debug.cpp index 113c551de8..4980ffa916 100644 --- a/thirdparty/thekla_atlas/nvcore/Debug.cpp +++ b/thirdparty/thekla_atlas/nvcore/Debug.cpp @@ -14,6 +14,7 @@ # define VC_EXTRALEAN # include <windows.h> # include <direct.h> +// -- GODOT start - # include <crtdbg.h> # if _MSC_VER < 1300 # define DECLSPEC_DEPRECATED @@ -24,6 +25,7 @@ // VC7: ships with updated headers # include <dbghelp.h> # endif +// -- GODOT end - # pragma comment(lib,"dbghelp.lib") #endif @@ -107,8 +109,9 @@ namespace #endif - +// -- GODOT start - #if NV_OS_WIN32 || NV_OS_DURANGO +// -- GODOT end - // We should try to simplify the top level filter as much as possible. // http://www.nynaeve.net/?p=128 @@ -391,8 +394,10 @@ namespace #pragma warning(disable:4748) static NV_NOINLINE int backtrace(void * trace[], int maxcount) { CONTEXT ctx = { 0 }; +// -- GODOT start -- #if NV_CPU_X86 && !NV_CPU_X86_64 ctx.ContextFlags = CONTEXT_CONTROL; +#if NV_CC_MSVC _asm { call x x: pop eax @@ -401,6 +406,13 @@ namespace mov ctx.Esp, esp } #else + register long unsigned int ebp asm("ebp"); + ctx.Eip = (DWORD) __builtin_return_address(0); + ctx.Ebp = ebp; + ctx.Esp = (DWORD) __builtin_frame_address(0); +#endif +// -- GODOT end -- +#else RtlCaptureContext(&ctx); // Not implemented correctly in x86. #endif diff --git a/thirdparty/thekla_atlas/nvcore/DefsGnucWin32.h b/thirdparty/thekla_atlas/nvcore/DefsGnucWin32.h index 4f97b90f3a..e1c8d6e4f8 100644 --- a/thirdparty/thekla_atlas/nvcore/DefsGnucWin32.h +++ b/thirdparty/thekla_atlas/nvcore/DefsGnucWin32.h @@ -19,7 +19,9 @@ #endif #define NV_FASTCALL __attribute__((fastcall)) +// -- GODOT start - #define NV_FORCEINLINE __attribute__((always_inline)) inline +// -- GODOT end - #define NV_DEPRECATED __attribute__((deprecated)) #if __GNUC__ > 2 diff --git a/thirdparty/thekla_atlas/nvmath/ftoi.h b/thirdparty/thekla_atlas/nvmath/ftoi.h index bee15c0908..182c56d1c3 100644 --- a/thirdparty/thekla_atlas/nvmath/ftoi.h +++ b/thirdparty/thekla_atlas/nvmath/ftoi.h @@ -53,7 +53,10 @@ namespace nv return (val<0) ? ftoi_ceil_xs(val) : ftoi_floor_xs(val); } -#if NV_CPU_X86 || NV_CPU_X86_64 +// -- GODOT start -- +//#if NV_CPU_X86 || NV_CPU_X86_64 +#if NV_USE_SSE +// -- GODOT end -- NV_FORCEINLINE int ftoi_round_sse(float f) { return _mm_cvt_ss2si(_mm_set_ss(f)); diff --git a/thirdparty/thekla_atlas/nvmath/nvmath.h b/thirdparty/thekla_atlas/nvmath/nvmath.h index 695f452c1d..f2b69426e1 100644 --- a/thirdparty/thekla_atlas/nvmath/nvmath.h +++ b/thirdparty/thekla_atlas/nvmath/nvmath.h @@ -14,10 +14,12 @@ #include <float.h> // finite, isnan #endif -#if NV_CPU_X86 || NV_CPU_X86_64 - //#include <intrin.h> - #include <xmmintrin.h> -#endif +// -- GODOT start -- +//#if NV_CPU_X86 || NV_CPU_X86_64 +// //#include <intrin.h> +// #include <xmmintrin.h> +//#endif +// -- GODOT end -- @@ -65,6 +67,13 @@ #endif +// -- GODOT start -- +#if NV_USE_SSE + //#include <intrin.h> + #include <xmmintrin.h> +#endif +// -- GODOT end -- + #ifndef PI #define PI float(3.1415926535897932384626433833) |