summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig4
-rw-r--r--.travis.yml12
-rw-r--r--SConstruct2
-rw-r--r--core/io/http_client.cpp143
-rw-r--r--core/io/http_client.h42
-rw-r--r--core/io/resource_format_binary.cpp68
-rw-r--r--core/io/resource_format_binary.h7
-rw-r--r--core/io/resource_loader.cpp68
-rw-r--r--core/io/resource_loader.h4
-rw-r--r--core/os/os.h3
-rw-r--r--doc/classes/Animation.xml3
-rw-r--r--doc/classes/AnimationPlayer.xml92
-rw-r--r--doc/classes/CanvasItem.xml30
-rw-r--r--doc/classes/Curve.xml27
-rw-r--r--doc/classes/Curve3D.xml2
-rw-r--r--doc/classes/HTTPClient.xml41
-rw-r--r--doc/classes/JSON.xml2
-rw-r--r--doc/classes/JSONParseResult.xml10
-rw-r--r--doc/classes/Navigation.xml11
-rw-r--r--doc/classes/Node.xml2
-rw-r--r--doc/classes/PopupMenu.xml14
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp28
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h28
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp117
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h32
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp1
-rw-r--r--drivers/gles3/shaders/scene.glsl88
-rw-r--r--editor/animation_editor.cpp4
-rw-r--r--editor/connections_dialog.cpp70
-rw-r--r--editor/connections_dialog.h4
-rw-r--r--editor/create_dialog.cpp2
-rw-r--r--editor/dependency_editor.cpp2
-rw-r--r--editor/editor_export.cpp31
-rw-r--r--editor/editor_export.h9
-rw-r--r--editor/editor_node.cpp16
-rw-r--r--editor/editor_node.h10
-rw-r--r--editor/export_template_manager.cpp4
-rw-r--r--editor/icons/icon_GUI_visibility_hidden.svg56
-rw-r--r--editor/icons/icon_GUI_visibility_visible.svg64
-rw-r--r--editor/icons/icon_GUI_visibility_xray.svg65
-rw-r--r--editor/icons/icon_bake.svg4
-rw-r--r--editor/icons/icon_baked_light.svg5
-rw-r--r--editor/icons/icon_baked_light_instance.svg5
-rw-r--r--editor/icons/icon_baked_light_sampler.svg5
-rw-r--r--editor/icons/icon_baked_lightmap.svg3
-rw-r--r--editor/icons/icon_baked_lightmap_data.svg3
-rw-r--r--editor/icons/icon_editor_handle.svg8
-rw-r--r--editor/icons/icon_editor_handle_add.svg6
-rw-r--r--editor/icons/icon_editor_plugin.svg8
-rw-r--r--editor/icons/icon_gizmo_baked_lightmap.svg4
-rw-r--r--editor/icons/icon_hidden.svg5
-rw-r--r--editor/icons/icon_kinematic_body_2d.svg4
-rw-r--r--editor/icons/icon_plugin_script.svg3
-rw-r--r--editor/icons/icon_proxy_texture.svg5
-rw-r--r--editor/icons/icon_sprite.svg2
-rw-r--r--editor/icons/icon_visible.svg5
-rw-r--r--editor/import/resource_importer_scene.cpp4
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/baked_lightmap_editor_plugin.cpp95
-rw-r--r--editor/plugins/baked_lightmap_editor_plugin.h39
-rw-r--r--editor/plugins/gi_probe_editor_plugin.cpp2
-rw-r--r--editor/plugins/particles_2d_editor_plugin.cpp13
-rw-r--r--editor/plugins/particles_editor_plugin.cpp42
-rw-r--r--editor/plugins/particles_editor_plugin.h1
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp5
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp1
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp2
-rw-r--r--editor/progress_dialog.cpp36
-rw-r--r--editor/progress_dialog.h11
-rw-r--r--editor/project_settings_editor.cpp4
-rw-r--r--editor/property_editor.cpp8
-rw-r--r--editor/scene_tree_editor.cpp12
-rw-r--r--editor/script_create_dialog.cpp2
-rw-r--r--editor/spatial_editor_gizmos.cpp121
-rw-r--r--editor/spatial_editor_gizmos.h17
-rw-r--r--main/input_default.cpp24
-rw-r--r--main/main.cpp5
-rw-r--r--modules/bullet/SCsub10
-rw-r--r--modules/etc/SCsub3
-rw-r--r--modules/gdnative/gdnative_api.json12
-rw-r--r--modules/gdscript/SCsub5
-rw-r--r--modules/gdscript/register_types.cpp44
-rw-r--r--modules/gridmap/SCsub5
-rw-r--r--modules/mono/SCsub21
-rw-r--r--modules/openssl/stream_peer_openssl.cpp8
-rw-r--r--modules/thekla_unwrap/SCsub13
-rw-r--r--modules/thekla_unwrap/register_types.cpp7
-rw-r--r--modules/visual_script/SCsub5
-rw-r--r--platform/javascript/http_client_javascript.cpp39
-rw-r--r--platform/osx/SCsub7
-rw-r--r--platform/osx/detect.py13
-rw-r--r--platform/osx/os_osx.h4
-rw-r--r--platform/osx/os_osx.mm8
-rw-r--r--platform/windows/context_gl_win.cpp2
-rw-r--r--platform/windows/detect.py7
-rw-r--r--platform/windows/os_windows.cpp6
-rw-r--r--platform/windows/os_windows.h4
-rw-r--r--platform/x11/detect.py6
-rw-r--r--platform/x11/os_x11.cpp9
-rw-r--r--platform/x11/os_x11.h3
-rw-r--r--scene/2d/animated_sprite.cpp27
-rw-r--r--scene/3d/baked_lightmap.cpp717
-rw-r--r--scene/3d/baked_lightmap.h189
-rw-r--r--scene/3d/gi_probe.cpp1028
-rw-r--r--scene/3d/gi_probe.h80
-rw-r--r--scene/3d/light.cpp17
-rw-r--r--scene/3d/light.h11
-rw-r--r--scene/3d/voxel_light_baker.cpp2373
-rw-r--r--scene/3d/voxel_light_baker.h148
-rw-r--r--scene/animation/animation_player.cpp27
-rw-r--r--scene/gui/popup_menu.cpp28
-rw-r--r--scene/gui/popup_menu.h12
-rw-r--r--scene/gui/rich_text_label.cpp2
-rw-r--r--scene/gui/slider.cpp17
-rw-r--r--scene/main/http_request.cpp72
-rw-r--r--scene/main/http_request.h1
-rw-r--r--scene/main/node.cpp2
-rw-r--r--scene/register_scene_types.cpp3
-rw-r--r--scene/resources/material.cpp19
-rw-r--r--scene/resources/material.h3
-rw-r--r--scene/resources/mesh.cpp28
-rw-r--r--scene/resources/scene_format_text.cpp774
-rw-r--r--scene/resources/scene_format_text.h26
-rw-r--r--servers/visual/rasterizer.h31
-rw-r--r--servers/visual/visual_server_raster.h19
-rw-r--r--servers/visual/visual_server_scene.cpp332
-rw-r--r--servers/visual/visual_server_scene.h18
-rw-r--r--servers/visual/visual_server_wrap_mt.h18
-rw-r--r--servers/visual_server.h17
-rw-r--r--thirdparty/README.md13
-rw-r--r--thirdparty/fonts/Hack_Regular.ttfbin399724 -> 307420 bytes
-rw-r--r--thirdparty/fonts/LICENSE_Hack.md57
-rw-r--r--thirdparty/libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c5
-rw-r--r--thirdparty/thekla_atlas/nvcore/Debug.cpp23
-rw-r--r--thirdparty/thekla_atlas/nvcore/DefsGnucWin32.h4
135 files changed, 5969 insertions, 2152 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/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/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..995cb5b179 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,6 +61,7 @@
<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">
@@ -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/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 &lt;method&gt; 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 42ed57e4af..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_statable">
+ <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>
@@ -441,7 +441,7 @@
<description>
</description>
</method>
- <method name="toggle_item_statable">
+ <method name="toggle_item_multistate">
<return type="void">
</return>
<argument index="0" name="idx" type="int">
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/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/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 80638c6f1e..cefc957ebf 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -4268,7 +4268,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
case MENU_VISIBILITY_SKELETON: {
const int idx = view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON);
- view_menu->get_popup()->toggle_item_statable(idx);
+ view_menu->get_popup()->toggle_item_multistate(idx);
// Change icon
const int state = view_menu->get_popup()->get_item_state(idx);
@@ -5077,8 +5077,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings")), MENU_VIEW_CAMERA_SETTINGS);
p->add_separator();
- p->add_statable_item(TTR("Skeleton Gizmo visibility"), 3, 1, MENU_VISIBILITY_SKELETON);
- p->add_separator();
+ p->add_multistate_item(TTR("Skeleton Gizmo visibility"), 3, 1, MENU_VISIBILITY_SKELETON);
p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
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..3e503c45a5 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);
}
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 3cab14b0c4..f99a2eafdd 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -459,7 +459,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/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/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/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..bc8be7f034 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(LIBS=['gomp'])
+
## Compile flags
env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows'])
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 41730d33af..5916c8f06c 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -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/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
new file mode 100644
index 0000000000..8af8c2f7da
--- /dev/null
+++ b/scene/3d/baked_lightmap.cpp
@@ -0,0 +1,717 @@
+#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;
+}
+
+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/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/popup_menu.cpp b/scene/gui/popup_menu.cpp
index e37cdd5cc9..32f889e826 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -624,7 +624,7 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo
update();
}
-void PopupMenu::add_statable_item(const String &p_label, int p_max_states, int p_default_state, int p_ID, uint32_t p_accel) {
+void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_ID, uint32_t p_accel) {
Item item;
item.text = p_label;
@@ -839,14 +839,14 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) {
update();
}
-void PopupMenu::set_item_statable(int p_idx, int p_state) {
+void PopupMenu::set_item_multistate(int p_idx, int p_state) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].state = p_state;
update();
}
-void PopupMenu::toggle_item_statable(int p_idx) {
+void PopupMenu::toggle_item_multistate(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
if (0 >= items[p_idx].max_states) {
@@ -940,7 +940,7 @@ void PopupMenu::activate_item(int p_item) {
if (!hide_on_checkable_item_selection || !pop->is_hide_on_checkable_item_selection())
break;
} else if (0 < items[p_item].max_states) {
- if (!hide_on_statable_item_selection || !pop->is_hide_on_statable_item_selection())
+ if (!hide_on_multistate_item_selection || !pop->is_hide_on_multistate_item_selection())
break;
} else if (!hide_on_item_selection || !pop->is_hide_on_item_selection())
break;
@@ -957,7 +957,7 @@ void PopupMenu::activate_item(int p_item) {
if (!hide_on_checkable_item_selection)
return;
} else if (0 < items[p_item].max_states) {
- if (!hide_on_statable_item_selection)
+ if (!hide_on_multistate_item_selection)
return;
} else if (!hide_on_item_selection)
return;
@@ -1093,14 +1093,14 @@ bool PopupMenu::is_hide_on_checkable_item_selection() const {
return hide_on_checkable_item_selection;
}
-void PopupMenu::set_hide_on_statable_item_selection(bool p_enabled) {
+void PopupMenu::set_hide_on_multistate_item_selection(bool p_enabled) {
- hide_on_statable_item_selection = p_enabled;
+ hide_on_multistate_item_selection = p_enabled;
}
-bool PopupMenu::is_hide_on_statable_item_selection() const {
+bool PopupMenu::is_hide_on_multistate_item_selection() const {
- return hide_on_statable_item_selection;
+ return hide_on_multistate_item_selection;
}
String PopupMenu::get_tooltip(const Point2 &p_pos) const {
@@ -1161,10 +1161,10 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_as_checkable", "idx", "enable"), &PopupMenu::set_item_as_checkable);
ClassDB::bind_method(D_METHOD("set_item_tooltip", "idx", "tooltip"), &PopupMenu::set_item_tooltip);
ClassDB::bind_method(D_METHOD("set_item_shortcut", "idx", "shortcut", "global"), &PopupMenu::set_item_shortcut, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("set_item_statable", "idx", "state"), &PopupMenu::set_item_statable);
+ ClassDB::bind_method(D_METHOD("set_item_multistate", "idx", "state"), &PopupMenu::set_item_multistate);
ClassDB::bind_method(D_METHOD("toggle_item_checked", "idx"), &PopupMenu::toggle_item_checked);
- ClassDB::bind_method(D_METHOD("toggle_item_statable", "idx"), &PopupMenu::toggle_item_statable);
+ ClassDB::bind_method(D_METHOD("toggle_item_multistate", "idx"), &PopupMenu::toggle_item_multistate);
ClassDB::bind_method(D_METHOD("get_item_text", "idx"), &PopupMenu::get_item_text);
ClassDB::bind_method(D_METHOD("get_item_icon", "idx"), &PopupMenu::get_item_icon);
@@ -1196,8 +1196,8 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hide_on_checkable_item_selection", "enable"), &PopupMenu::set_hide_on_checkable_item_selection);
ClassDB::bind_method(D_METHOD("is_hide_on_checkable_item_selection"), &PopupMenu::is_hide_on_checkable_item_selection);
- ClassDB::bind_method(D_METHOD("set_hide_on_state_item_selection", "enable"), &PopupMenu::set_hide_on_statable_item_selection);
- ClassDB::bind_method(D_METHOD("is_hide_on_state_item_selection"), &PopupMenu::is_hide_on_statable_item_selection);
+ ClassDB::bind_method(D_METHOD("set_hide_on_state_item_selection", "enable"), &PopupMenu::set_hide_on_multistate_item_selection);
+ ClassDB::bind_method(D_METHOD("is_hide_on_state_item_selection"), &PopupMenu::is_hide_on_multistate_item_selection);
ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout);
@@ -1222,7 +1222,7 @@ PopupMenu::PopupMenu() {
set_as_toplevel(true);
set_hide_on_item_selection(true);
set_hide_on_checkable_item_selection(true);
- set_hide_on_statable_item_selection(false);
+ set_hide_on_multistate_item_selection(false);
submenu_timer = memnew(Timer);
submenu_timer->set_wait_time(0.3);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index 5a10bf0765..ee514f4c4b 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -90,7 +90,7 @@ class PopupMenu : public Popup {
bool invalidated_click;
bool hide_on_item_selection;
bool hide_on_checkable_item_selection;
- bool hide_on_statable_item_selection;
+ bool hide_on_multistate_item_selection;
Vector2 moved;
Array _get_items() const;
@@ -120,7 +120,7 @@ public:
void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false);
void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false);
- void add_statable_item(const String &p_label, int p_max_states, int p_default_state, int p_ID = -1, uint32_t p_accel = 0);
+ void add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_ID = -1, uint32_t p_accel = 0);
void set_item_text(int p_idx, const String &p_text);
void set_item_icon(int p_idx, const Ref<Texture> &p_icon);
@@ -135,8 +135,8 @@ public:
void set_item_tooltip(int p_idx, const String &p_tooltip);
void set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global = false);
void set_item_h_offset(int p_idx, int p_offset);
- void set_item_statable(int p_idx, int p_state);
- void toggle_item_statable(int p_idx);
+ void set_item_multistate(int p_idx, int p_state);
+ void toggle_item_multistate(int p_idx);
void toggle_item_checked(int p_idx);
@@ -183,8 +183,8 @@ public:
void set_hide_on_checkable_item_selection(bool p_enabled);
bool is_hide_on_checkable_item_selection() const;
- void set_hide_on_statable_item_selection(bool p_enabled);
- bool is_hide_on_statable_item_selection() const;
+ void set_hide_on_multistate_item_selection(bool p_enabled);
+ bool is_hide_on_multistate_item_selection() const;
PopupMenu();
~PopupMenu();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 45188c3a52..05c6e9f77e 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -453,7 +453,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/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/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/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
index a35ea2e4f4..f342700811 100644
--- a/thirdparty/fonts/Hack_Regular.ttf
+++ b/thirdparty/fonts/Hack_Regular.ttf
Binary files differ
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..81498c219e 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
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