diff options
174 files changed, 6383 insertions, 2445 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 5097898314..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,23 +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" - }; - 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"; @@ -112,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(); @@ -142,23 +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" - }; - 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"; @@ -172,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; @@ -251,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: { @@ -283,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) { @@ -294,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; @@ -310,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: { @@ -326,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(); @@ -334,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; @@ -361,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; } @@ -379,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: { @@ -422,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); @@ -465,7 +471,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() { } if (len == 0) { - //end! + // End reached! status = STATUS_CONNECTED; chunk.clear(); return PoolByteArray(); @@ -523,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; } @@ -538,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; @@ -591,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; @@ -651,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); @@ -683,16 +689,17 @@ void HTTPClient::_bind_methods() { BIND_ENUM_CONSTANT(METHOD_OPTIONS); BIND_ENUM_CONSTANT(METHOD_TRACE); BIND_ENUM_CONSTANT(METHOD_CONNECT); + BIND_ENUM_CONSTANT(METHOD_PATCH); 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); @@ -709,6 +716,7 @@ void HTTPClient::_bind_methods() { BIND_ENUM_CONSTANT(RESPONSE_RESET_CONTENT); BIND_ENUM_CONSTANT(RESPONSE_PARTIAL_CONTENT); BIND_ENUM_CONSTANT(RESPONSE_MULTI_STATUS); + BIND_ENUM_CONSTANT(RESPONSE_ALREADY_REPORTED); BIND_ENUM_CONSTANT(RESPONSE_IM_USED); // 3xx redirection @@ -718,7 +726,9 @@ void HTTPClient::_bind_methods() { BIND_ENUM_CONSTANT(RESPONSE_SEE_OTHER); BIND_ENUM_CONSTANT(RESPONSE_NOT_MODIFIED); BIND_ENUM_CONSTANT(RESPONSE_USE_PROXY); + BIND_ENUM_CONSTANT(RESPONSE_SWITCH_PROXY); BIND_ENUM_CONSTANT(RESPONSE_TEMPORARY_REDIRECT); + BIND_ENUM_CONSTANT(RESPONSE_PERMANENT_REDIRECT); // 4xx client error BIND_ENUM_CONSTANT(RESPONSE_BAD_REQUEST); @@ -739,10 +749,16 @@ void HTTPClient::_bind_methods() { BIND_ENUM_CONSTANT(RESPONSE_UNSUPPORTED_MEDIA_TYPE); BIND_ENUM_CONSTANT(RESPONSE_REQUESTED_RANGE_NOT_SATISFIABLE); BIND_ENUM_CONSTANT(RESPONSE_EXPECTATION_FAILED); + BIND_ENUM_CONSTANT(RESPONSE_IM_A_TEAPOT); + BIND_ENUM_CONSTANT(RESPONSE_MISDIRECTED_REQUEST); BIND_ENUM_CONSTANT(RESPONSE_UNPROCESSABLE_ENTITY); BIND_ENUM_CONSTANT(RESPONSE_LOCKED); BIND_ENUM_CONSTANT(RESPONSE_FAILED_DEPENDENCY); BIND_ENUM_CONSTANT(RESPONSE_UPGRADE_REQUIRED); + BIND_ENUM_CONSTANT(RESPONSE_PRECONDITION_REQUIRED); + BIND_ENUM_CONSTANT(RESPONSE_TOO_MANY_REQUESTS); + BIND_ENUM_CONSTANT(RESPONSE_REQUEST_HEADER_FIELDS_TOO_LARGE); + BIND_ENUM_CONSTANT(RESPONSE_UNAVAILABLE_FOR_LEGAL_REASONS); // 5xx server error BIND_ENUM_CONSTANT(RESPONSE_INTERNAL_SERVER_ERROR); @@ -751,6 +767,9 @@ void HTTPClient::_bind_methods() { BIND_ENUM_CONSTANT(RESPONSE_SERVICE_UNAVAILABLE); BIND_ENUM_CONSTANT(RESPONSE_GATEWAY_TIMEOUT); BIND_ENUM_CONSTANT(RESPONSE_HTTP_VERSION_NOT_SUPPORTED); + BIND_ENUM_CONSTANT(RESPONSE_VARIANT_ALSO_NEGOTIATES); BIND_ENUM_CONSTANT(RESPONSE_INSUFFICIENT_STORAGE); + BIND_ENUM_CONSTANT(RESPONSE_LOOP_DETECTED); BIND_ENUM_CONSTANT(RESPONSE_NOT_EXTENDED); + BIND_ENUM_CONSTANT(RESPONSE_NETWORK_AUTH_REQUIRED); } diff --git a/core/io/http_client.h b/core/io/http_client.h index db5dd115bd..3d8953c156 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -56,6 +56,7 @@ public: RESPONSE_RESET_CONTENT = 205, RESPONSE_PARTIAL_CONTENT = 206, RESPONSE_MULTI_STATUS = 207, + RESPONSE_ALREADY_REPORTED = 208, RESPONSE_IM_USED = 226, // 3xx redirection @@ -65,7 +66,9 @@ public: RESPONSE_SEE_OTHER = 303, RESPONSE_NOT_MODIFIED = 304, RESPONSE_USE_PROXY = 305, + RESPONSE_SWITCH_PROXY = 306, RESPONSE_TEMPORARY_REDIRECT = 307, + RESPONSE_PERMANENT_REDIRECT = 308, // 4xx client error RESPONSE_BAD_REQUEST = 400, @@ -86,10 +89,16 @@ public: RESPONSE_UNSUPPORTED_MEDIA_TYPE = 415, RESPONSE_REQUESTED_RANGE_NOT_SATISFIABLE = 416, RESPONSE_EXPECTATION_FAILED = 417, + RESPONSE_IM_A_TEAPOT = 418, + RESPONSE_MISDIRECTED_REQUEST = 421, RESPONSE_UNPROCESSABLE_ENTITY = 422, RESPONSE_LOCKED = 423, RESPONSE_FAILED_DEPENDENCY = 424, RESPONSE_UPGRADE_REQUIRED = 426, + RESPONSE_PRECONDITION_REQUIRED = 428, + RESPONSE_TOO_MANY_REQUESTS = 429, + RESPONSE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + RESPONSE_UNAVAILABLE_FOR_LEGAL_REASONS = 451, // 5xx server error RESPONSE_INTERNAL_SERVER_ERROR = 500, @@ -98,8 +107,11 @@ public: RESPONSE_SERVICE_UNAVAILABLE = 503, RESPONSE_GATEWAY_TIMEOUT = 504, RESPONSE_HTTP_VERSION_NOT_SUPPORTED = 505, + RESPONSE_VARIANT_ALSO_NEGOTIATES = 506, RESPONSE_INSUFFICIENT_STORAGE = 507, + RESPONSE_LOOP_DETECTED = 508, RESPONSE_NOT_EXTENDED = 510, + RESPONSE_NETWORK_AUTH_REQUIRED = 511, }; @@ -113,24 +125,37 @@ public: METHOD_OPTIONS, METHOD_TRACE, METHOD_CONNECT, + METHOD_PATCH, METHOD_MAX + }; 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; @@ -167,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; @@ -186,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/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index d61211bb6b..570f5e9741 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -90,6 +90,13 @@ Returns the list of stored animation names. </description> </method> + <method name="get_autoplay" qualifiers="const"> + <return type="String"> + </return> + <description> + Returns the name of the animation that will be automatically played when the scene is loaded. + </description> + </method> <method name="get_blend_time" qualifiers="const"> <return type="float"> </return> @@ -101,11 +108,18 @@ Get the blend time (in seconds) between two animations, referenced by their names. </description> </method> + <method name="get_current_animation" qualifiers="const"> + <return type="String"> + </return> + <description> + Returns the name of the animation being played. + </description> + </method> <method name="get_current_animation_length" qualifiers="const"> <return type="float"> </return> <description> - Get the length (in seconds) of the currently playing animation. + Get the length (in seconds) of the currently being played animation. </description> </method> <method name="get_current_animation_position" qualifiers="const"> @@ -115,6 +129,12 @@ Get the position (in seconds) of the currently playing animation. </description> </method> + <method name="get_speed_scale" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="has_animation" qualifiers="const"> <return type="bool"> </return> @@ -124,6 +144,13 @@ Returns [code]true[/code] if the [code]AnimationPlayer[/code] stores an [Animation] with key [code]name[/code]. </description> </method> + <method name="is_active" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if the player is active. + </description> + </method> <method name="is_playing" qualifiers="const"> <return type="bool"> </return> @@ -143,7 +170,8 @@ <argument index="3" name="from_end" type="bool" default="false"> </argument> <description> - Play the animation with key [code]name[/code]. Custom speed and blend times can be set. If custom speed is negative (-1), 'from_end' being true can play the animation backwards. + Play the animation with key [code]name[/code]. Custom speed and blend times can be set. If custom speed is negative (-1), 'from_end' being true can play the + animation backwards. </description> </method> <method name="play_backwards"> @@ -194,7 +222,25 @@ <argument index="1" name="update" type="bool" default="false"> </argument> <description> - Seek the animation to the [code]seconds[/code] point in time (in seconds). If 'update' is true, the animation updates too, otherwise it updates at process time. + Seek the animation to the [code]seconds[/code] point in time (in seconds). If [code]update[/code] is [code]true[/code], the animation updates too, otherwise it updates at process time. + </description> + </method> + <method name="set_active"> + <return type="void"> + </return> + <argument index="0" name="active" type="bool"> + </argument> + <description> + Sets the player as active (playing). If [code]true[/code], updates animations in response to process-related notifications. Default value: [code]true[/code]. + </description> + </method> + <method name="set_autoplay"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + Defines the name of the animation to play when the scene loads. Default value: [code]""[/code]. </description> </method> <method name="set_blend_time"> @@ -210,34 +256,37 @@ Specify a blend time (in seconds) between two animations, referenced by their names. </description> </method> - <method name="stop"> + <method name="set_current_animation"> <return type="void"> </return> - <argument index="0" name="reset" type="bool" default="true"> + <argument index="0" name="anim" type="String"> </argument> <description> - Stop the currently playing animation. If [code]reset[/code] is [code]true[/code], the anim position is reset to [code]0[/code]. + Sets the name of the current animation. If already playing, restarts the animation. Ensure [member active] is [code]true[/code] to simulate [method play]. Default value: [code]""[/code]. </description> </method> - <method name="stop_all"> + <method name="set_speed_scale"> <return type="void"> </return> + <argument index="0" name="speed" type="float"> + </argument> <description> - Stop playback of animations (deprecated). + Sets the speed scaling ratio in a given animation channel (or channel 0 if none is provided). Default value: [code]1[/code]. + </description> + </method> + <method name="stop"> + <return type="void"> + </return> + <argument index="0" name="reset" type="bool" default="true"> + </argument> + <description> + Stop the currently playing animation. If [code]reset[/code] is [code]true[/code], the anim position is reset to [code]0[/code]. </description> </method> </methods> <members> - <member name="active" type="bool" setter="set_active" getter="is_active"> - If [code]true[/code] updates animations in response to process-related notifications. Default value: [code]true[/code]. - </member> - <member name="autoplay" type="String" setter="set_autoplay" getter="get_autoplay"> - The name of the animation to play when the scene loads. Default value: [code]""[/code]. - </member> - <member name="current_animation" type="String" setter="set_current_animation" getter="get_current_animation"> - The name of the current animation. Default value: [code]""[/code]. - </member> <member name="playback_default_blend_time" type="float" setter="set_default_blend_time" getter="get_default_blend_time"> + The default time in which to blend animations. Ranges from 0 to 4096 with 0.01 precision. Default value: [code]0[/code]. </member> <member name="playback_process_mode" type="int" setter="set_animation_process_mode" getter="get_animation_process_mode" enum="AnimationPlayer.AnimationProcessMode"> The process notification in which to update animations. Default value: [enum ANIMATION_PROCESS_IDLE]. @@ -245,9 +294,6 @@ <member name="root_node" type="NodePath" setter="set_root" getter="get_root"> The node from which node path references will travel. Default value: [code]".."[/code]. </member> - <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale"> - The speed scaling ratio in a given animation channel (or channel 0 if none is provided). Default value: [code]1[/code]. - </member> </members> <signals> <signal name="animation_changed"> @@ -256,21 +302,21 @@ <argument index="1" name="new_name" type="String"> </argument> <description> - Emitted when the [Animation] with key [member current_anim] is modified. + If the currently being played animation changes, this signal will notify of such change. </description> </signal> <signal name="animation_finished"> <argument index="0" name="name" type="String"> </argument> <description> - Emitted when an animation finishes. + Notifies when an animation finished playing. </description> </signal> <signal name="animation_started"> <argument index="0" name="name" type="String"> </argument> <description> - Emitted when an animation starts. + Notifies when an animation starts playing. </description> </signal> </signals> 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/HTTPClient.xml b/doc/classes/HTTPClient.xml index b90c49b5c0..9d4b45a8d7 100644 --- a/doc/classes/HTTPClient.xml +++ b/doc/classes/HTTPClient.xml @@ -224,7 +224,10 @@ <constant name="METHOD_CONNECT" value="7" enum="Method"> HTTP CONNECT method. The CONNECT method establishes a tunnel to the server identified by the target resource. Rarely used. </constant> - <constant name="METHOD_MAX" value="8" enum="Method"> + <constant name="METHOD_PATCH" value="8" enum="Method"> + HTTP PATCH method. The PATCH method is used to apply partial modifications to a resource. + </constant> + <constant name="METHOD_MAX" value="9" enum="Method"> Marker for end of [code]METHOD_*[/code] enum. Not used. </constant> <constant name="STATUS_DISCONNECTED" value="0" enum="Status"> @@ -290,6 +293,9 @@ <constant name="RESPONSE_MULTI_STATUS" value="207" enum="ResponseCode"> HTTP status code [code]207 Multi-Status[/code] (WebDAV). A Multi-Status response conveys information about multiple resources in situations where multiple status codes might be appropriate. </constant> + <constant name="RESPONSE_ALREADY_REPORTED" value="208" enum="ResponseCode"> + HTTP status code [code]208 Already Reported[/code] (WebDAV). Used inside a DAV: propstat response element to avoid enumerating the internal members of multiple bindings to the same collection repeatedly. + </constant> <constant name="RESPONSE_IM_USED" value="226" enum="ResponseCode"> HTTP status code [code]226 IM Used[/code] (WebDAV). The server has fulfilled a GET request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance. </constant> @@ -311,9 +317,15 @@ <constant name="RESPONSE_USE_PROXY" value="305" enum="ResponseCode"> HTTP status code [code]305 Use Proxy[/code]. Deprecated. Do not use. </constant> + <constant name="RESPONSE_SWITCH_PROXY" value="306" enum="ResponseCode"> + HTTP status code [code]306 Switch Proxy[/code]. Deprecated. Do not use. + </constant> <constant name="RESPONSE_TEMPORARY_REDIRECT" value="307" enum="ResponseCode"> HTTP status code [code]307 Temporary Redirect[/code]. The target resource resides temporarily under a different URI and the user agent MUST NOT change the request method if it performs an automatic redirection to that URI. </constant> + <constant name="RESPONSE_PERMANENT_REDIRECT" value="308" enum="ResponseCode"> + HTTP status code [code]308 Permanent Redirect[/code]. The target resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs. + </constant> <constant name="RESPONSE_BAD_REQUEST" value="400" enum="ResponseCode"> HTTP status code [code]400 Bad Request[/code]. The request was invalid. The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, invalid request contents, or deceptive request routing). </constant> @@ -368,6 +380,12 @@ <constant name="RESPONSE_EXPECTATION_FAILED" value="417" enum="ResponseCode"> HTTP status code [code]417 Expectation Failed[/code]. The expectation given in the request's Expect header field could not be met by at least one of the inbound servers. </constant> + <constant name="RESPONSE_IM_A_TEAPOT" value="418" enum="ResponseCode"> + HTTP status code [code]418 I'm A Teapot[/code]. Any attempt to brew coffee with a teapot should result in the error code "418 I'm a teapot". The resulting entity body MAY be short and stout. + </constant> + <constant name="RESPONSE_MISDIRECTED_REQUEST" value="421" enum="ResponseCode"> + HTTP status code [code]421 Misdirected Request[/code]. The request was directed at a server that is not able to produce a response. This can be sent by a server that is not configured to produce responses for the combination of scheme and authority that are included in the request URI. + </constant> <constant name="RESPONSE_UNPROCESSABLE_ENTITY" value="422" enum="ResponseCode"> HTTP status code [code]422 Unprocessable Entity[/code] (WebDAV). The server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions. </constant> @@ -380,6 +398,18 @@ <constant name="RESPONSE_UPGRADE_REQUIRED" value="426" enum="ResponseCode"> HTTP status code [code]426 Upgrade Required[/code]. The server refuses to perform the request using the current protocol but might be willing to do so after the client upgrades to a different protocol. </constant> + <constant name="RESPONSE_PRECONDITION_REQUIRED" value="428" enum="ResponseCode"> + HTTP status code [code]428 Precondition Required[/code]. The origin server requires the request to be conditional. + </constant> + <constant name="RESPONSE_TOO_MANY_REQUESTS" value="429" enum="ResponseCode"> + HTTP status code [code]429 Too Many Requests[/code]. The user has sent too many requests in a given amount of time (see "rate limiting"). Back off and increase time between requests or try again later. + </constant> + <constant name="RESPONSE_REQUEST_HEADER_FIELDS_TOO_LARGE" value="431" enum="ResponseCode"> + HTTP status code [code]431 Rquest Header Fields Too Large[/code]. The server is unwilling to process the request because its header fields are too large. The request MAY be resubmitted after reducing the size of the request header fields. + </constant> + <constant name="RESPONSE_UNAVAILABLE_FOR_LEGAL_REASONS" value="451" enum="ResponseCode"> + HTTP status code [code]451 Response Unavailable For Legal Reasons[/code]. The server is denying access to the resource as a consequence of a legal demand. + </constant> <constant name="RESPONSE_INTERNAL_SERVER_ERROR" value="500" enum="ResponseCode"> HTTP status code [code]500 Internal Server Error[/code]. The server encountered an unexpected condition that prevented it from fulfilling the request. </constant> @@ -398,11 +428,20 @@ <constant name="RESPONSE_HTTP_VERSION_NOT_SUPPORTED" value="505" enum="ResponseCode"> HTTP status code [code]505 HTTP Version Not Supported[/code]. The server does not support, or refuses to support, the major version of HTTP that was used in the request message. </constant> + <constant name="RESPONSE_VARIANT_ALSO_NEGOTIATES" value="506" enum="ResponseCode"> + HTTP status code [code]506 Variant Also Negotiates[/code]. The server has an internal configuration error: the chosen variant resource is configured to engage in transparent content negotiation itself, and is therefore not a proper end point in the negotiation process. + </constant> <constant name="RESPONSE_INSUFFICIENT_STORAGE" value="507" enum="ResponseCode"> HTTP status code [code]507 Insufficient Storage[/code]. The method could not be performed on the resource because the server is unable to store the representation needed to successfully complete the request. </constant> + <constant name="RESPONSE_LOOP_DETECTED" value="508" enum="ResponseCode"> + HTTP status code [code]508 Loop Detected[/code]. The server terminated an operation because it encountered an infinite loop while processing a request with "Depth: infinity". This status indicates that the entire operation failed. + </constant> <constant name="RESPONSE_NOT_EXTENDED" value="510" enum="ResponseCode"> HTTP status code [code]510 Not Extended[/code]. The policy for accessing the resource has not been met in the request. The server should send back all the information necessary for the client to issue an extended request. </constant> + <constant name="RESPONSE_NETWORK_AUTH_REQUIRED" value="511" enum="ResponseCode"> + HTTP status code [code]511 Network Authentication Required[/code]. The client needs to authenticate to gain network access. + </constant> </constants> </class> diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index bb48833878..28f04c3eb0 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -4,7 +4,7 @@ Helper class for parsing JSON data. </brief_description> <description> - Helper class for parsing JSON data. + Helper class for parsing JSON data. For usage example, see [JSONParseResult]. </description> <tutorials> </tutorials> diff --git a/doc/classes/JSONParseResult.xml b/doc/classes/JSONParseResult.xml index 77145eff6a..835920818a 100644 --- a/doc/classes/JSONParseResult.xml +++ b/doc/classes/JSONParseResult.xml @@ -14,23 +14,23 @@ </methods> <members> <member name="error" type="int" setter="set_error" getter="get_error" enum="Error"> - The error type if JSON source was not successfully parsed. See [@GlobalScope]ERR_* constants. + The error type if JSON source was not successfully parsed. See [@GlobalScope] ERR_* constants. </member> <member name="error_line" type="int" setter="set_error_line" getter="get_error_line"> The line number where the error occurred if JSON source was not successfully parsed. </member> <member name="error_string" type="String" setter="set_error_string" getter="get_error_string"> - The error message if JSON source was not successfully parsed. See [@GlobalScope]ERR_* constants. + The error message if JSON source was not successfully parsed. See [@GlobalScope] ERR_* constants. </member> <member name="result" type="Variant" setter="set_result" getter="get_result"> - A [Variant] containing the parsed JSON. Use typeof() to check if it is what you expect. For example, if JSON source starts with braces [code]{}[/code] a [Dictionary] will be returned, if JSON source starts with array braces [code][][/code] an [Array] will be returned. + A [Variant] containing the parsed JSON. Use typeof() to check if it is what you expect. For example, if JSON source starts with curly braces ([code]{}[/code]) a [Dictionary] will be returned, if JSON source starts with braces ([code][][/code]) an [Array] will be returned. [i]Be aware that the JSON specification does not define integer or float types, but only a number type. Therefore, parsing a JSON text will convert all numerical values to float types.[/i] [codeblock] p = JSON.parse('["hello", "world", "!"]') if typeof(p) == TYPE_ARRAY: - print(p[0]) # prints 'hello' + print(p[0]) # prints 'hello' else: - print("unexpected results") + print("unexpected results") [/codeblock] </member> </members> 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/Node.xml b/doc/classes/Node.xml index a36587c606..e56733f102 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -225,7 +225,7 @@ <argument index="0" name="path" type="NodePath"> </argument> <description> - Fetches a node. The [NodePath] can be either a relative path (from the current node) or an absolute path (in the scene tree) to a node. If the path does not exist, a [code]null instance[/code] is returned and attempts to access it will result in an "Attempt to call <method> on a null instance." error. + Fetches a node. The [NodePath] can be either a relative path (from the current node) or an absolute path (in the scene tree) to a node. If the path does not exist, a [code]null instance[/code] is returned and attempts to access it will result in an "Attempt to call <method> on a null instance." error. Note: fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_tree]). [i]Example:[/i] Assume your current node is Character and the following tree: [codeblock] diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index 372a97ecd9..13cf16d2ee 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -379,24 +379,24 @@ Sets the metadata of an item, which might be of any type. You can later get it with [method get_item_metadata], which provides a simple way of assigning context data to items. </description> </method> - <method name="set_item_shortcut"> + <method name="set_item_multistate"> <return type="void"> </return> <argument index="0" name="idx" type="int"> </argument> - <argument index="1" name="shortcut" type="ShortCut"> - </argument> - <argument index="2" name="global" type="bool" default="false"> + <argument index="1" name="state" type="int"> </argument> <description> </description> </method> - <method name="set_item_multistate"> + <method name="set_item_shortcut"> <return type="void"> </return> <argument index="0" name="idx" type="int"> </argument> - <argument index="1" name="state" type="int"> + <argument index="1" name="shortcut" type="ShortCut"> + </argument> + <argument index="2" name="global" type="bool" default="false"> </argument> <description> </description> 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 9b817c7a4e..9bc2bc079d 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -35,14 +35,14 @@ 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 uniform float normal_mult; #ifdef USE_SKELETON -layout(location=6) in ivec4 bone_indices; // attrib:6 +layout(location=6) in uvec4 bone_indices; // attrib:6 layout(location=7) in vec4 bone_weights; // attrib:7 #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 @@ -302,14 +299,16 @@ void main() { #ifdef USE_SKELETON { //skeleton transform - ivec2 tex_ofs = ivec2( bone_indices.x%256, (bone_indices.x/256)*3 ); + ivec4 bone_indicesi = ivec4(bone_indices); // cast to signed int + + ivec2 tex_ofs = ivec2( bone_indicesi.x%256, (bone_indicesi.x/256)*3 ); highp mat3x4 m = mat3x4( texelFetch(skeleton_texture,tex_ofs,0), texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0), texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0) ) * bone_weights.x; - tex_ofs = ivec2( bone_indices.y%256, (bone_indices.y/256)*3 ); + tex_ofs = ivec2( bone_indicesi.y%256, (bone_indicesi.y/256)*3 ); m+= mat3x4( texelFetch(skeleton_texture,tex_ofs,0), @@ -317,7 +316,7 @@ void main() { texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0) ) * bone_weights.y; - tex_ofs = ivec2( bone_indices.z%256, (bone_indices.z/256)*3 ); + tex_ofs = ivec2( bone_indicesi.z%256, (bone_indicesi.z/256)*3 ); m+= mat3x4( texelFetch(skeleton_texture,tex_ofs,0), @@ -326,7 +325,7 @@ void main() { ) * bone_weights.z; - tex_ofs = ivec2( bone_indices.w%256, (bone_indices.w/256)*3 ); + tex_ofs = ivec2( bone_indicesi.w%256, (bone_indicesi.w/256)*3 ); m+= mat3x4( texelFetch(skeleton_texture,tex_ofs,0), @@ -354,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 @@ -547,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 @@ -1355,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 @@ -1401,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 @@ -1630,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 @@ -1743,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); @@ -1752,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 @@ -1936,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 @@ -1950,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/animation_editor.cpp b/editor/animation_editor.cpp index c6757ba98f..c6381864b3 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -324,7 +324,7 @@ public: int existing = animation->track_find_key(track, new_time, true); setting = true; - undo_redo->create_action(TTR("Move Add Key"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Anim Change Keyframe Time"), UndoRedo::MERGE_ENDS); Variant val = animation->track_get_key_value(track, key); float trans = animation->track_get_key_transition(track, key); @@ -391,7 +391,7 @@ public: } setting = true; - undo_redo->create_action(TTR("Anim Change Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); Variant prev = animation->track_get_key_value(track, key); undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value); undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index cd60455f4f..c095229374 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -88,12 +88,6 @@ public: void ConnectDialog::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - - //RID ci = get_canvas_item(); - //get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size())); - } - if (p_what == NOTIFICATION_ENTER_TREE) { bind_editor->edit(cdbinds); } @@ -117,11 +111,6 @@ void ConnectDialog::_tree_node_selected() { dst_path->set_text(node->get_path_to(current)); } -void ConnectDialog::_dst_method_list_selected(int p_idx) { - - //dst_method->set_text( dst_method_list->get_popup()->get_item_text(p_idx)); -} - void ConnectDialog::edit(Node *p_node) { node = p_node; @@ -247,9 +236,7 @@ void ConnectDialog::set_dst_method(const StringName &p_method) { void ConnectDialog::_bind_methods() { - //ClassDB::bind_method("_ok",&ConnectDialog::_ok_pressed); ClassDB::bind_method("_cancel", &ConnectDialog::_cancel_pressed); - //ClassDB::bind_method("_dst_method_list_selected",&ConnectDialog::_dst_method_list_selected); ClassDB::bind_method("_tree_node_selected", &ConnectDialog::_tree_node_selected); ClassDB::bind_method("_add_bind", &ConnectDialog::_add_bind); @@ -355,18 +342,6 @@ ConnectDialog::ConnectDialog() { oneshot->set_text(TTR("Oneshot")); dstm_hb->add_child(oneshot); - /* - realtime = memnew( CheckButton ); - realtime->set_anchor( MARGIN_TOP, ANCHOR_END ); - realtime->set_anchor( MARGIN_BOTTOM, ANCHOR_END ); - realtime->set_anchor( MARGIN_RIGHT, ANCHOR_END ); - realtime->set_begin( Point2( 120, button_margin-10 ) ); - realtime->set_end( Point2( 80, margin ) ); - realtime->set_text("Realtime"); - add_child(realtime); -*/ - - //dst_method_list->get_popup()->connect("id_pressed", this,"_dst_method_list_selected"); tree->connect("node_selected", this, "_tree_node_selected"); set_as_toplevel(true); @@ -377,7 +352,6 @@ ConnectDialog::ConnectDialog() { add_child(error); error->get_ok()->set_text(TTR("Close")); get_ok()->set_text(TTR("Connect")); - //error->get_cancel()->set_text("Close"); } ConnectDialog::~ConnectDialog() { @@ -386,12 +360,6 @@ ConnectDialog::~ConnectDialog() { void ConnectionsDock::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - - //RID ci = get_canvas_item(); - //get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size())); - } - if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { update_tree(); } @@ -478,7 +446,7 @@ void ConnectionsDock::_connect_pressed() { Connection c = item->get_metadata(0); ERR_FAIL_COND(c.source != node); //shouldn't happen but...bugcheck - undo_redo->create_action(TTR("Create Subscription")); + undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), c.signal, c.method)); undo_redo->add_do_method(node, "disconnect", c.signal, c.target, c.method); undo_redo->add_undo_method(node, "connect", c.signal, c.target, c.method, Vector<Variant>(), c.flags); undo_redo->add_do_method(this, "update_tree"); @@ -491,42 +459,6 @@ void ConnectionsDock::_connect_pressed() { update_tree(); } } -/* -void ConnectionsDock::_remove() { - - if (!tree->get_selected()) - return; - - TreeItem *selected=tree->get_selected(); - if (!selected) - return; - - Dictionary meta=selected->get_metadata(0); - - remove_confirm->set_text(String()+"Remove Connection \""+meta["from_event"].operator String()+"\" ?"); - remove_confirm->popup_centered(Size2(340,80)); -} -*/ -/* -void ConnectionsDock::_remove_confirm() { - - if (!tree->get_selected()) - return; - TreeItem *selected=tree->get_selected(); - if (!selected) - return; - - Dictionary meta=selected->get_metadata(0); - - undo_redo->create_action("Remove Subscription"); - undo_redo->add_do_method(node,"unsubscribe_path_event",meta["from_event"].operator String(),meta["from_path"].operator NodePath(),meta["to_method"].operator String()); - undo_redo->add_undo_method(node,"subscribe_path_event_persist",meta["from_event"].operator String(),meta["from_path"].operator NodePath(),meta["to_method"].operator String(),Array(),false); - undo_redo->add_do_method(this,"update_tree"); - undo_redo->add_undo_method(this,"update_tree"); - undo_redo->commit_action(); - -} -*/ struct _ConnectionsDockMethodInfoSort { diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 53f4d857bf..99a83ff599 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -55,7 +55,6 @@ class ConnectDialog : public ConfirmationDialog { LineEdit *dst_path; LineEdit *dst_method; SceneTreeEditor *tree; - //MenuButton *dst_method_list; OptionButton *type_list; CheckButton *deferred; CheckButton *oneshot; @@ -66,7 +65,6 @@ class ConnectDialog : public ConfirmationDialog { void ok_pressed(); void _cancel_pressed(); void _tree_node_selected(); - void _dst_method_list_selected(int p_idx); void _add_bind(); void _remove_bind(); @@ -84,8 +82,6 @@ public: void set_dst_method(const StringName &p_method); void set_dst_node(Node *p_node); - //Button *get_ok() { return ok; } - //Button *get_cancel() { return cancel; } void edit(Node *p_node); ConnectDialog(); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index c058d290bf..2584d26fc4 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -370,7 +370,7 @@ void CreateDialog::_notification(int p_what) { void CreateDialog::set_base_type(const String &p_base) { base_type = p_base; - set_title(TTR("Create New") + " " + p_base); + set_title(vformat(TTR("Create New %s"), p_base)); _update_search(); } 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/export_template_manager.cpp b/editor/export_template_manager.cpp index 2aad4774b0..cdb7256329 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -385,7 +385,7 @@ void ExportTemplateManager::_http_download_templates_completed(int p_status, int template_list_state->set_text(TTR("No response.")); } break; case HTTPRequest::RESULT_REQUEST_FAILED: { - template_list_state->set_text(TTR("Req. Failed.")); + template_list_state->set_text(TTR("Request Failed.")); } break; case HTTPRequest::RESULT_REDIRECT_LIMIT_REACHED: { template_list_state->set_text(TTR("Redirect Loop.")); @@ -465,7 +465,7 @@ void ExportTemplateManager::_notification(int p_what) { break; case HTTPClient::STATUS_CONNECTING: status = TTR("Connecting.."); break; case HTTPClient::STATUS_CANT_CONNECT: - status = TTR("Can't Conect"); + status = TTR("Can't Connect"); errored = true; break; case HTTPClient::STATUS_CONNECTED: status = TTR("Connected"); break; 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/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 3ab8f318a7..f04bc04d92 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -340,7 +340,7 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int } break; case HTTPRequest::RESULT_REQUEST_FAILED: { error_text = TTR("Request failed, return code:") + " " + itos(p_code); - status->set_text(TTR("Req. Failed.")); + status->set_text(TTR("Request Failed.")); } break; case HTTPRequest::RESULT_REDIRECT_LIMIT_REACHED: { error_text = TTR("Request failed, too many redirects"); 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/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp index 5eaa248224..ff8a9f93d6 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/particles_2d_editor_plugin.cpp @@ -77,11 +77,6 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) { case MENU_CLEAR_EMISSION_MASK: { emission_mask->popup_centered_minsize(); - - /*undo_redo->create_action(TTR("Clear Emission Mask")); - undo_redo->add_do_method(particles, "set_emission_points", PoolVector<Vector2>()); - undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points()); - undo_redo->commit_action();*/ } break; } } @@ -309,14 +304,6 @@ void Particles2DEditorPlugin::_generate_emission_mask() { } else { pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); } - - /*undo_redo->create_action(TTR("Set Emission Mask")); - undo_redo->add_do_method(particles, "set_emission_points", epoints); - undo_redo->add_do_method(particles, "set_emission_half_extents", extents); - undo_redo->add_undo_method(particles, "set_emission_points", particles->get_emission_points()); - undo_redo->add_undo_method(particles, "set_emission_half_extents", particles->get_emission_half_extents()); - undo_redo->commit_action(); - */ } void Particles2DEditorPlugin::_notification(int p_what) { diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index f4a9960087..52eba099c6 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -40,11 +40,6 @@ void ParticlesEditor::_node_removed(Node *p_node) { } } -void ParticlesEditor::_resource_seleted(const String &p_res) { - - //print_line("selected resource path: "+p_res); -} - void ParticlesEditor::_node_selected(const NodePath &p_path) { Node *sel = get_node(p_path); @@ -84,23 +79,6 @@ void ParticlesEditor::_node_selected(const NodePath &p_path) { emission_dialog->popup_centered(Size2(300, 130)); } -/* - -void ParticlesEditor::_populate() { - - if(!node) - return; - - - if (node->get_particles().is_null()) - return; - - node->get_particles()->set_instance_count(populate_amount->get_text().to_int()); - node->populate_parent(populate_rotate_random->get_val(),populate_tilt_random->get_val(),populate_scale_random->get_text().to_double(),populate_scale->get_text().to_double()); - -} -*/ - void ParticlesEditor::_notification(int p_notification) { if (p_notification == NOTIFICATION_ENTER_TREE) { @@ -132,13 +110,7 @@ void ParticlesEditor::_menu_option(int p_option) { EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required.")); return; } - /* - Node *root = get_scene()->get_root_node(); - ERR_FAIL_COND(!root); - EditorNode *en = Object::cast_to<EditorNode>(root); - ERR_FAIL_COND(!en); - Node * node = en->get_edited_scene(); -*/ + emission_tree_dialog->popup_centered_ratio(); } break; @@ -365,20 +337,14 @@ void ParticlesEditor::_generate_emission_points() { material->set_emission_point_count(point_count); material->set_emission_point_texture(tex); } - - //print_line("point count: "+itos(points.size())); - //node->set_emission_points(points); } void ParticlesEditor::_bind_methods() { ClassDB::bind_method("_menu_option", &ParticlesEditor::_menu_option); - ClassDB::bind_method("_resource_seleted", &ParticlesEditor::_resource_seleted); ClassDB::bind_method("_node_selected", &ParticlesEditor::_node_selected); ClassDB::bind_method("_generate_emission_points", &ParticlesEditor::_generate_emission_points); ClassDB::bind_method("_generate_aabb", &ParticlesEditor::_generate_aabb); - - //ClassDB::bind_method("_populate",&ParticlesEditor::_populate); } ParticlesEditor::ParticlesEditor() { @@ -394,8 +360,6 @@ ParticlesEditor::ParticlesEditor() { options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Emission Points From Mesh"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH); options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); - // options->get_popup()->add_item(TTR("Clear Emitter"), MENU_OPTION_CLEAR_EMISSION_VOLUME); - options->get_popup()->connect("id_pressed", this, "_menu_option"); emission_dialog = memnew(ConfirmationDialog); @@ -420,7 +384,6 @@ ParticlesEditor::ParticlesEditor() { emission_dialog->connect("confirmed", this, "_generate_emission_points"); err_dialog = memnew(ConfirmationDialog); - //err_dialog->get_cancel()->hide(); add_child(err_dialog); emission_file_dialog = memnew(EditorFileDialog); @@ -454,9 +417,6 @@ ParticlesEditor::ParticlesEditor() { add_child(generate_aabb); generate_aabb->connect("confirmed", this, "_generate_aabb"); - - //options->set_anchor(MARGIN_LEFT,Control::ANCHOR_END); - //options->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END); } void ParticlesEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/particles_editor_plugin.h b/editor/plugins/particles_editor_plugin.h index 2c8ce88eb2..a65538c7fa 100644 --- a/editor/plugins/particles_editor_plugin.h +++ b/editor/plugins/particles_editor_plugin.h @@ -73,7 +73,6 @@ class ParticlesEditor : public Control { void _generate_aabb(); void _generate_emission_points(); - void _resource_seleted(const String &p_res); void _node_selected(const NodePath &p_path); void _menu_option(int); 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/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 4d06342fe0..40abc4026a 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -751,6 +751,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (id != TileMap::INVALID_CELL) { + _set_cell(over_tile, id, flip_h, flip_v, transpose); undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index b8c57fd959..ae726b69ef 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -244,7 +244,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { MenuButton *options = memnew(MenuButton); panel->add_child(options); options->set_position(Point2(1, 1)); - options->set_text("Theme"); + options->set_text(TTR("Tile Set")); options->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); options->get_popup()->add_item(TTR("Remove Item"), MENU_OPTION_REMOVE_ITEM); options->get_popup()->add_separator(); 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/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 76fd20ca12..1a7b7f3575 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -531,7 +531,7 @@ void ProjectSettingsEditor::_action_button_pressed(Object *p_obj, int p_column, Variant old_val = ProjectSettings::get_singleton()->get(name); int order = ProjectSettings::get_singleton()->get_order(name); - undo_redo->create_action(TTR("Add Input Action")); + undo_redo->create_action(TTR("Erase Input Action")); undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", name); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_val); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", name, order); @@ -852,7 +852,7 @@ void ProjectSettingsEditor::_action_add() { Array va; String name = "input/" + action_name->get_text(); - undo_redo->create_action(TTR("Add Input Action Event")); + undo_redo->create_action(TTR("Add Input Action")); undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, va); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name); undo_redo->add_do_method(this, "_update_actions"); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 59acd9ded9..d22bee40d9 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -900,10 +900,10 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: int id = TYPE_BASE_ID + idx; if (has_icon(t, "EditorIcons")) { - menu->add_icon_item(get_icon(t, "EditorIcons"), TTR("New") + " " + t, id); + menu->add_icon_item(get_icon(t, "EditorIcons"), vformat(TTR("New %s"), t), id); } else { - menu->add_item(TTR("New") + " " + t, id); + menu->add_item(vformat(TTR("New %s"), t), id); } idx++; @@ -2831,7 +2831,7 @@ void PropertyEditor::update_tree() { class_descr_cache[type] = descr.word_wrap(80); } - sep->set_tooltip(0, TTR("Class:") + " " + p.name + ":\n\n" + class_descr_cache[type]); + sep->set_tooltip(0, TTR("Class:") + " " + p.name + (class_descr_cache[type] == "" ? "" : "\n\n" + class_descr_cache[type])); } continue; @@ -2963,7 +2963,7 @@ void PropertyEditor::update_tree() { descr_cache[classname][propname] = descr; } - item->set_tooltip(0, TTR("Property:") + " " + p.name + "\n\n" + descr); + item->set_tooltip(0, TTR("Property:") + " " + p.name + (descr == "" ? "" : "\n\n" + descr)); } Dictionary d; 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 c4cea83784..25e63319d0 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -465,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/bullet/SCsub b/modules/bullet/SCsub index 7a37cca130..0967bca3f2 100644 --- a/modules/bullet/SCsub +++ b/modules/bullet/SCsub @@ -1,9 +1,13 @@ #!/usr/bin/env python Import('env') +Import('env_modules') # build only version 2 # Bullet 2.87 + +env_bullet = env_modules.Clone() + bullet_src__2_x = [ # BulletCollision "BulletCollision/BroadphaseCollision/btAxisSweep3.cpp" @@ -181,11 +185,11 @@ thirdparty_src = thirdparty_dir + "src/" bullet_sources = [thirdparty_src + file for file in bullet_src__2_x] # include headers -env.Append(CPPPATH=[thirdparty_src]) +env_bullet.Append(CPPPATH=[thirdparty_src]) -env.add_source_files(env.modules_sources, bullet_sources) +env_bullet.add_source_files(env.modules_sources, bullet_sources) # Godot source files -env.add_source_files(env.modules_sources, "*.cpp") +env_bullet.add_source_files(env.modules_sources, "*.cpp") Export('env') 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/etc/SCsub b/modules/etc/SCsub index 9c3e703f11..31d8f00ef3 100644 --- a/modules/etc/SCsub +++ b/modules/etc/SCsub @@ -34,7 +34,8 @@ env_etc.Append(CPPPATH=[thirdparty_dir]) env_etc.add_source_files(env.modules_sources, "*.cpp") # upstream uses c++11 -env_etc.Append(CCFLAGS="-std=gnu++11") +if (not env_etc.msvc): + env_etc.Append(CCFLAGS="-std=c++11") # -ffast-math seems to be incompatible with ec2comp on recent versions of # GCC and Clang if '-ffast-math' in env_etc['CCFLAGS']: 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/SCsub b/modules/gdscript/SCsub index 0882406761..13870170a5 100644 --- a/modules/gdscript/SCsub +++ b/modules/gdscript/SCsub @@ -1,7 +1,10 @@ #!/usr/bin/env python Import('env') +Import('env_modules') -env.add_source_files(env.modules_sources, "*.cpp") +env_gdscript = env_modules.Clone() + +env_gdscript.add_source_files(env.modules_sources, "*.cpp") Export('env') 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/SCsub b/modules/gridmap/SCsub index 0882406761..2ffe15cd33 100644 --- a/modules/gridmap/SCsub +++ b/modules/gridmap/SCsub @@ -1,7 +1,10 @@ #!/usr/bin/env python Import('env') +Import('env_modules') -env.add_source_files(env.modules_sources, "*.cpp") +env_gridmap = env_modules.Clone() + +env_gridmap.add_source_files(env.modules_sources, "*.cpp") Export('env') 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/mono/SCsub b/modules/mono/SCsub index 18a20ecac4..320bbe7090 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -1,6 +1,9 @@ #!/usr/bin/env python Import('env') +Import('env_modules') + +env_mono = env_modules.Clone() from compat import byte_to_str @@ -43,12 +46,12 @@ def make_cs_files_header(src, dst): header.write('#endif // _CS_FILES_DATA_H') -env.add_source_files(env.modules_sources, '*.cpp') -env.add_source_files(env.modules_sources, 'mono_gd/*.cpp') -env.add_source_files(env.modules_sources, 'utils/*.cpp') +env_mono.add_source_files(env.modules_sources, '*.cpp') +env_mono.add_source_files(env.modules_sources, 'mono_gd/*.cpp') +env_mono.add_source_files(env.modules_sources, 'utils/*.cpp') if env['tools']: - env.add_source_files(env.modules_sources, 'editor/*.cpp') + env_mono.add_source_files(env.modules_sources, 'editor/*.cpp') make_cs_files_header('glue/cs_files', 'glue/cs_compressed.gen.h') vars = Variables() @@ -58,12 +61,12 @@ vars.Update(env) # Glue sources if env['mono_glue']: - env.add_source_files(env.modules_sources, 'glue/*.cpp') + env_mono.add_source_files(env.modules_sources, 'glue/*.cpp') else: - env.Append(CPPDEFINES=['MONO_GLUE_DISABLED']) + env_mono.Append(CPPDEFINES=['MONO_GLUE_DISABLED']) if ARGUMENTS.get('yolo_copy', False): - env.Append(CPPDEFINES=['YOLO_COPY']) + env_mono.Append(CPPDEFINES=['YOLO_COPY']) # Build GodotSharpTools solution @@ -201,8 +204,8 @@ def mono_build_solution(source, target, env): mono_sln_builder = Builder(action = mono_build_solution) -env.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder}) -env.MonoBuildSolution( +env_mono.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder}) +env_mono.MonoBuildSolution( os.path.join(Dir('#bin').abspath, 'GodotSharpTools.dll'), 'editor/GodotSharpTools/GodotSharpTools.sln' ) diff --git a/modules/openssl/stream_peer_openssl.cpp b/modules/openssl/stream_peer_openssl.cpp index 6d1d5485f3..7e8b308cf8 100644 --- a/modules/openssl/stream_peer_openssl.cpp +++ b/modules/openssl/stream_peer_openssl.cpp @@ -412,8 +412,12 @@ void StreamPeerOpenSSL::_print_error(int err) { err = SSL_get_error(ssl, err); switch (err) { - case SSL_ERROR_NONE: ERR_PRINT("NO ERROR: The TLS/SSL I/O operation completed"); break; - case SSL_ERROR_ZERO_RETURN: ERR_PRINT("The TLS/SSL connection has been closed."); + case SSL_ERROR_NONE: + ERR_PRINT("NO ERROR: The TLS/SSL I/O operation completed"); + break; + case SSL_ERROR_ZERO_RETURN: + ERR_PRINT("The TLS/SSL connection has been closed."); + break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: ERR_PRINT("The operation did not complete."); diff --git a/modules/thekla_unwrap/SCsub b/modules/thekla_unwrap/SCsub index 1d4b086848..c57bf326ea 100644 --- a/modules/thekla_unwrap/SCsub +++ b/modules/thekla_unwrap/SCsub @@ -56,14 +56,19 @@ if env['builtin_thekla_atlas']: env_thekla_unwrap.Append(CPPPATH=[thirdparty_dir, thirdparty_dir + "/poshlib", thirdparty_dir + "/nvcore", thirdparty_dir + "/nvmesh"]) # upstream uses c++11 - env_thekla_unwrap.Append(CXXFLAGS="-std=gnu++11") + if (not env_thekla_unwrap.msvc): + env_thekla_unwrap.Append(CXXFLAGS="-std=c++11") if env["platform"] == 'x11': - env_thekla_unwrap.Append(CCFLAGS=["-DNV_OS_LINUX"]) + env_thekla_unwrap.Append(CCFLAGS=["-DNV_OS_LINUX", "-DPOSH_COMPILER_GCC"]) elif env["platform"] == 'osx': - env_thekla_unwrap.Append(CCFLAGS=["-DNV_OS_DARWIN"]) + env_thekla_unwrap.Append(CCFLAGS=["-DNV_OS_DARWIN", "-DPOSH_COMPILER_GCC"]) elif env["platform"] == 'windows': - env_thekla_unwrap.Append(CCFLAGS=["-DNV_OS_WIN32"]) + 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", "-U__STRICT_ANSI__"]) + env.Append(LIBS=["dbghelp"]) # Godot source files env_thekla_unwrap.add_source_files(env.modules_sources, "*.cpp") 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/modules/visual_script/SCsub b/modules/visual_script/SCsub index 0882406761..96ee911ba0 100644 --- a/modules/visual_script/SCsub +++ b/modules/visual_script/SCsub @@ -1,7 +1,10 @@ #!/usr/bin/env python Import('env') +Import('env_modules') -env.add_source_files(env.modules_sources, "*.cpp") +env_vs = env_modules.Clone() + +env_vs.add_source_files(env.modules_sources, "*.cpp") Export('env') 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/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index f8f94926b7..de28fef929 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -355,38 +355,21 @@ void AnimatedSprite::_notification(int p_what) { case NOTIFICATION_DRAW: { - if (frames.is_null()) { - print_line("no draw no faemos"); + if (frames.is_null()) return; - } - - if (frame < 0) { - print_line("no draw frame <0"); + if (frame < 0) return; - } - - if (!frames->has_animation(animation)) { - print_line("no draw no anim: " + String(animation)); + if (!frames->has_animation(animation)) return; - } Ref<Texture> texture = frames->get_frame(animation, frame); - if (texture.is_null()) { - print_line("no draw texture is null"); + if (texture.is_null()) return; - } Ref<Texture> normal = frames->get_normal_frame(animation, frame); - //print_line("DECIDED TO DRAW"); - RID ci = get_canvas_item(); - /* - texture->draw(ci,Point2()); - break; - */ - Size2i s; s = texture->get_size(); Point2 ofs = offset; @@ -403,9 +386,7 @@ void AnimatedSprite::_notification(int p_what) { if (vflip) dst_rect.size.y = -dst_rect.size.y; - //texture->draw_rect(ci,dst_rect,false,modulate); texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal); - //VisualServer::get_singleton()->canvas_item_add_texture_rect_region(ci,dst_rect,texture->get_rid(),src_rect,modulate); } break; } 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/animation/animation_player.cpp b/scene/animation/animation_player.cpp index e866e665d8..5e776c5a1a 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -233,7 +233,6 @@ void AnimationPlayer::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { - //stop_all(); clear_caches(); } break; } @@ -738,7 +737,7 @@ void AnimationPlayer::remove_animation(const StringName &p_name) { ERR_FAIL_COND(!animation_set.has(p_name)); - stop_all(); + stop(); _unref_anim(animation_set[p_name].animation); animation_set.erase(p_name); @@ -775,9 +774,7 @@ void AnimationPlayer::rename_animation(const StringName &p_name, const StringNam ERR_FAIL_COND(String(p_new_name).find("/") != -1 || String(p_new_name).find(":") != -1); ERR_FAIL_COND(animation_set.has(p_new_name)); - //print_line("Rename anim: "+String(p_name)+" name: "+String(p_new_name)); - - stop_all(); + stop(); AnimationData ad = animation_set[p_name]; ad.name = p_new_name; animation_set.erase(p_name); @@ -1019,13 +1016,6 @@ void AnimationPlayer::stop(bool p_reset) { playing = false; } -void AnimationPlayer::stop_all() { - - stop(); - - _set_process(false); // always process when starting an animation -} - void AnimationPlayer::set_speed_scale(float p_speed) { speed_scale = p_speed; @@ -1307,8 +1297,8 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("play", "name", "custom_blend", "custom_speed", "from_end"), &AnimationPlayer::play, DEFVAL(""), DEFVAL(-1), DEFVAL(1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("play_backwards", "name", "custom_blend"), &AnimationPlayer::play_backwards, DEFVAL(""), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("stop", "reset"), &AnimationPlayer::stop, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("stop_all"), &AnimationPlayer::stop_all); ClassDB::bind_method(D_METHOD("is_playing"), &AnimationPlayer::is_playing); + ClassDB::bind_method(D_METHOD("set_current_animation", "anim"), &AnimationPlayer::set_current_animation); ClassDB::bind_method(D_METHOD("get_current_animation"), &AnimationPlayer::get_current_animation); ClassDB::bind_method(D_METHOD("queue", "name"), &AnimationPlayer::queue); @@ -1326,9 +1316,6 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root", "path"), &AnimationPlayer::set_root); ClassDB::bind_method(D_METHOD("get_root"), &AnimationPlayer::get_root); - ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance); - ClassDB::bind_method(D_METHOD("find_animation", "animation"), &AnimationPlayer::find_animation); ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationPlayer::clear_caches); @@ -1339,15 +1326,13 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_current_animation_position"), &AnimationPlayer::get_current_animation_position); ClassDB::bind_method(D_METHOD("get_current_animation_length"), &AnimationPlayer::get_current_animation_length); + ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance); + ADD_GROUP("Playback Options", "playback_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root", "get_root"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "autoplay"), "set_autoplay", "get_autoplay"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale"), "set_speed_scale", "get_speed_scale"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_animation"), "set_current_animation", "get_current_animation"); ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name"))); 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 45188c3a52..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; } @@ -453,7 +462,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & for (int i = 0; i < frame->lines.size(); i++) { _process_line(frame, Point2(), ly, p_width, i, PROCESS_CACHE, cfont, Color()); - table->columns[column].min_width = MAX(table->columns[i].min_width, frame->lines[i].minimum_width); + table->columns[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width); } idx++; } diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index e88742a3e3..70b8616af1 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -171,47 +171,48 @@ void Slider::_notification(int p_what) { Ref<StyleBox> grabber_area = get_stylebox("grabber_area"); Ref<Texture> grabber = get_icon(editable ? ((mouse_inside || has_focus()) ? "grabber_highlight" : "grabber") : "grabber_disabled"); Ref<Texture> tick = get_icon("tick"); + double ratio = Math::is_nan(get_as_ratio()) ? 0 : get_as_ratio(); if (orientation == VERTICAL) { int widget_width = style->get_minimum_size().width + style->get_center_size().width; float areasize = size.height - grabber->get_size().height; style->draw(ci, Rect2i(Point2i(size.width / 2 - widget_width / 2, 0), Size2i(widget_width, size.height))); - grabber_area->draw(ci, Rect2i(Point2i((size.width - widget_width) / 2, size.height - areasize * get_as_ratio() - grabber->get_size().height / 2), Size2i(widget_width, areasize * get_as_ratio() + grabber->get_size().width / 2))); + grabber_area->draw(ci, Rect2i(Point2i((size.width - widget_width) / 2, size.height - areasize * ratio - grabber->get_size().height / 2), Size2i(widget_width, areasize * ratio + grabber->get_size().width / 2))); /* if (mouse_inside||has_focus()) 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)); } } - grabber->draw(ci, Point2i(size.width / 2 - grabber->get_size().width / 2, size.height - get_as_ratio() * areasize - grabber->get_size().height)); + grabber->draw(ci, Point2i(size.width / 2 - grabber->get_size().width / 2, size.height - ratio * areasize - grabber->get_size().height)); } else { int widget_height = style->get_minimum_size().height + style->get_center_size().height; float areasize = size.width - grabber->get_size().width; style->draw(ci, Rect2i(Point2i(0, (size.height - widget_height) / 2), Size2i(size.width, widget_height))); - grabber_area->draw(ci, Rect2i(Point2i(0, (size.height - widget_height) / 2), Size2i(areasize * get_as_ratio() + grabber->get_size().width / 2, widget_height))); + grabber_area->draw(ci, Rect2i(Point2i(0, (size.height - widget_height) / 2), Size2i(areasize * ratio + grabber->get_size().width / 2, widget_height))); /* if (mouse_inside||has_focus()) focus->draw(ci,Rect2i(Point2i(),Size2i(size.width,style->get_minimum_size().height+style->get_center_size().height))); */ 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)); } } - grabber->draw(ci, Point2i(get_as_ratio() * areasize, size.height / 2 - grabber->get_size().height / 2)); + grabber->draw(ci, Point2i(ratio * areasize, size.height / 2 - grabber->get_size().height / 2)); } } break; 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 75ac6beb75..4980ffa916 100644 --- a/thirdparty/thekla_atlas/nvcore/Debug.cpp +++ b/thirdparty/thekla_atlas/nvcore/Debug.cpp @@ -14,18 +14,18 @@ # define VC_EXTRALEAN # include <windows.h> # include <direct.h> -# if NV_CC_MSVC -# include <crtdbg.h> -# if _MSC_VER < 1300 -# define DECLSPEC_DEPRECATED +// -- GODOT start - +# include <crtdbg.h> +# if _MSC_VER < 1300 +# define DECLSPEC_DEPRECATED // VC6: change this path to your Platform SDK headers -# include <dbghelp.h> // must be XP version of file -// include "M:\\dev7\\vs\\devtools\\common\\win32sdk\\include\\dbghelp.h" -# else +# include <dbghelp.h> // must be XP version of file +// include "M:\\dev7\\vs\\devtools\\common\\win32sdk\\include\\dbghelp.h" +# else // VC7: ships with updated headers -# include <dbghelp.h> -# endif +# include <dbghelp.h> # endif +// -- GODOT end - # pragma comment(lib,"dbghelp.lib") #endif @@ -109,8 +109,9 @@ namespace #endif - -#if (NV_OS_WIN32 && NV_CC_MSVC) || NV_OS_DURANGO +// -- 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 @@ -393,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 @@ -403,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 f35ed88575..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)) -#define NV_FORCEINLINE __attribute__((always_inline)) +// -- 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) |