diff options
186 files changed, 3081 insertions, 1947 deletions
diff --git a/SConstruct b/SConstruct index 1c55e0be93..17518706aa 100644 --- a/SConstruct +++ b/SConstruct @@ -333,12 +333,13 @@ if selected_platform in platform_list: # Set exception handling model to avoid warnings caused by Windows system headers. env.Append(CCFLAGS=['/EHsc']) else: # Rest of the world + disable_nonessential_warnings = ['-Wno-sign-compare'] if (env["warnings"] == 'extra'): env.Append(CCFLAGS=['-Wall', '-Wextra']) elif (env["warnings"] == 'all' or env["warnings"] == 'yes'): - env.Append(CCFLAGS=['-Wall']) + env.Append(CCFLAGS=['-Wall'] + disable_nonessential_warnings) elif (env["warnings"] == 'moderate'): - env.Append(CCFLAGS=['-Wall', '-Wno-unused']) + env.Append(CCFLAGS=['-Wall', '-Wno-unused'] + disable_nonessential_warnings) else: # 'no' env.Append(CCFLAGS=['-w']) env.Append(CCFLAGS=['-Werror=return-type']) diff --git a/core/SCsub b/core/SCsub index 6746cc871a..17b6e2c7ea 100644 --- a/core/SCsub +++ b/core/SCsub @@ -117,7 +117,6 @@ SConscript('os/SCsub') SConscript('math/SCsub') SConscript('io/SCsub') SConscript('bind/SCsub') -SConscript('helper/SCsub') # Build it all as a library diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index ac563df0c3..36dd688e77 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -374,6 +374,7 @@ Error HTTPClient::poll() { } break; } } break; + case STATUS_BODY: case STATUS_CONNECTED: { // Check if we are still connected if (ssl) { @@ -480,7 +481,8 @@ Error HTTPClient::poll() { case STATUS_DISCONNECTED: { return ERR_UNCONFIGURED; } break; - case STATUS_CONNECTION_ERROR: { + case STATUS_CONNECTION_ERROR: + case STATUS_SSL_HANDSHAKE_ERROR: { return ERR_CONNECTION_ERROR; } break; case STATUS_CANT_CONNECT: { diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index e15519da47..d33d436b74 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -824,6 +824,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo flags |= ENCODE_FLAG_OBJECT_AS_ID; } } break; + default: {} // nothing to do at this stage } if (buf) { diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 5503b8d59c..17b77bc535 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -38,20 +38,23 @@ _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_mas switch (mode) { case MultiplayerAPI::RPC_MODE_DISABLED: { - //do nothing + // Do nothing. } break; case MultiplayerAPI::RPC_MODE_REMOTE: { - //do nothing also, no need to call local + // Do nothing also. Remote cannot produce a local call. } break; + case MultiplayerAPI::RPC_MODE_MASTERSYNC: { + if (is_master) + r_skip_rpc = true; // I am the master, so skip remote call. + } // Do not break, fall over to other sync. case MultiplayerAPI::RPC_MODE_REMOTESYNC: - case MultiplayerAPI::RPC_MODE_MASTERSYNC: case MultiplayerAPI::RPC_MODE_PUPPETSYNC: { - //call it, sync always results in call + // Call it, sync always results in a local call. return true; } break; case MultiplayerAPI::RPC_MODE_MASTER: { if (is_master) - r_skip_rpc = true; //no other master so.. + r_skip_rpc = true; // I am the master, so skip remote call. return is_master; } break; case MultiplayerAPI::RPC_MODE_PUPPET: { @@ -91,7 +94,7 @@ void MultiplayerAPI::poll() { network_peer->poll(); - if (!network_peer.is_valid()) //it's possible that polling might have resulted in a disconnection, so check here + if (!network_peer.is_valid()) // It's possible that polling might have resulted in a disconnection, so check here. return; while (network_peer->get_available_packet_count()) { @@ -110,7 +113,7 @@ void MultiplayerAPI::poll() { rpc_sender_id = 0; if (!network_peer.is_valid()) { - break; //it's also possible that a packet or RPC caused a disconnection, so also check here + break; // It's also possible that a packet or RPC caused a disconnection, so also check here. } } } @@ -157,7 +160,9 @@ Ref<NetworkedMultiplayerPeer> MultiplayerAPI::get_network_peer() const { void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) { + ERR_EXPLAIN("Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it"); ERR_FAIL_COND(root_node == NULL); + ERR_EXPLAIN("Invalid packet received. Size too small."); ERR_FAIL_COND(p_packet_len < 1); uint8_t packet_type = p_packet[0]; @@ -177,13 +182,15 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ case NETWORK_COMMAND_REMOTE_CALL: case NETWORK_COMMAND_REMOTE_SET: { + ERR_EXPLAIN("Invalid packet received. Size too small."); ERR_FAIL_COND(p_packet_len < 6); Node *node = _process_get_node(p_from, p_packet, p_packet_len); + ERR_EXPLAIN("Invalid packet received. Requested node was not found."); ERR_FAIL_COND(node == NULL); - //detect cstring end + // Detect cstring end. int len_end = 5; for (; len_end < p_packet_len; len_end++) { if (p_packet[len_end] == 0) { @@ -191,6 +198,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ } } + ERR_EXPLAIN("Invalid packet received. Size too small."); ERR_FAIL_COND(len_end >= p_packet_len); StringName name = String::utf8((const char *)&p_packet[5]); @@ -219,9 +227,11 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int Node *node = NULL; if (target & 0x80000000) { - //use full path (not cached yet) + // Use full path (not cached yet). int ofs = target & 0x7FFFFFFF; + + ERR_EXPLAIN("Invalid packet received. Size smaller than declared."); ERR_FAIL_COND_V(ofs >= p_packet_len, NULL); String paths; @@ -234,17 +244,19 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int if (!node) ERR_PRINTS("Failed to get path from RPC: " + String(np)); } else { - //use cached path + // Use cached path. int id = target; Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from); + ERR_EXPLAIN("Invalid packet received. Requests invalid peer cache."); ERR_FAIL_COND_V(!E, NULL); Map<int, PathGetCache::NodeInfo>::Element *F = E->get().nodes.find(id); + ERR_EXPLAIN("Invalid packet received. Unabled to find requested cached node."); ERR_FAIL_COND_V(!F, NULL); PathGetCache::NodeInfo *ni = &F->get(); - //do proper caching later + // Do proper caching later. node = root_node->get_node(ni->path); if (!node) @@ -255,9 +267,10 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { + ERR_EXPLAIN("Invalid packet received. Size too small."); ERR_FAIL_COND(p_offset >= p_packet_len); - // Check that remote can call the RPC on this node + // Check that remote can call the RPC on this node. RPCMode rpc_mode = RPC_MODE_DISABLED; const Map<StringName, RPCMode>::Element *E = p_node->get_node_rpc_mode(p_name); if (E) { @@ -265,6 +278,8 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ } else if (p_node->get_script_instance()) { rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name); } + + ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); ERR_FAIL_COND(!_can_call_mode(p_node, rpc_mode, p_from)); int argc = p_packet[p_offset]; @@ -277,11 +292,14 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ for (int i = 0; i < argc; i++) { + ERR_EXPLAIN("Invalid packet received. Size too small."); ERR_FAIL_COND(p_offset >= p_packet_len); + int vlen; Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen); + ERR_EXPLAIN("Invalid packet received. Unable to decode RPC argument."); ERR_FAIL_COND(err != OK); - //args[i]=p_packet[3+i]; + argp.write[i] = &args[i]; p_offset += vlen; } @@ -298,9 +316,10 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { + ERR_EXPLAIN("Invalid packet received. Size too small."); ERR_FAIL_COND(p_offset >= p_packet_len); - // Check that remote can call the RSET on this node + // Check that remote can call the RSET on this node. RPCMode rset_mode = RPC_MODE_DISABLED; const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_name); if (E) { @@ -308,10 +327,15 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p } else if (p_node->get_script_instance()) { rset_mode = p_node->get_script_instance()->get_rset_mode(p_name); } + + ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + "."); ERR_FAIL_COND(!_can_call_mode(p_node, rset_mode, p_from)); Variant value; - decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset); + Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset); + + ERR_EXPLAIN("Invalid packet received. Unable to decode RSET value."); + ERR_FAIL_COND(err != OK); bool valid; @@ -324,6 +348,7 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) { + ERR_EXPLAIN("Invalid packet received. Size too small."); ERR_FAIL_COND(p_packet_len < 5); int id = decode_uint32(&p_packet[1]); @@ -342,9 +367,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, path_get_cache[p_from].nodes[id] = ni; - //send ack - - //encode path + // Encode path to send ack. CharString pname = String(path).utf8(); int len = encode_cstring(pname.get_data(), NULL); @@ -361,6 +384,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) { + ERR_EXPLAIN("Invalid packet received. Size too small."); ERR_FAIL_COND(p_packet_len < 2); String paths; @@ -369,31 +393,33 @@ void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet, NodePath path = paths; PathSentCache *psc = path_send_cache.getptr(path); + ERR_EXPLAIN("Invalid packet received. Tries to confirm a path which was not found in cache."); ERR_FAIL_COND(!psc); Map<int, bool>::Element *E = psc->confirmed_peers.find(p_from); + ERR_EXPLAIN("Invalid packet received. Source peer was not found in cache for the given path."); ERR_FAIL_COND(!E); E->get() = true; } bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int p_target) { bool has_all_peers = true; - List<int> peers_to_add; //if one is missing, take note to add it + List<int> peers_to_add; // If one is missing, take note to add it. for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { if (p_target < 0 && E->get() == -p_target) - continue; //continue, excluded + continue; // Continue, excluded. if (p_target > 0 && E->get() != p_target) - continue; //continue, not for this peer + continue; // Continue, not for this peer. Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); if (!F || F->get() == false) { - //path was not cached, or was cached but is unconfirmed + // Path was not cached, or was cached but is unconfirmed. if (!F) { - //not cached at all, take note + // Not cached at all, take note. peers_to_add.push_back(E->get()); } @@ -401,11 +427,11 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int } } - //those that need to be added, send a message for this + // Those that need to be added, send a message for this. for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) { - //encode function name + // Encode function name. CharString pname = String(p_path).utf8(); int len = encode_cstring(pname.get_data(), NULL); @@ -416,11 +442,11 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int encode_uint32(psc->id, &packet.write[1]); encode_cstring(pname.get_data(), &packet.write[5]); - network_peer->set_target_peer(E->get()); //to all of you + network_peer->set_target_peer(E->get()); // To all of you. network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); network_peer->put_packet(packet.ptr(), packet.size()); - psc->confirmed_peers.insert(E->get(), false); //insert into confirmed, but as false since it was not confirmed + psc->confirmed_peers.insert(E->get(), false); // Insert into confirmed, but as false since it was not confirmed. } return has_all_peers; @@ -459,35 +485,36 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p } NodePath from_path = (root_node->get_path()).rel_path_to(p_from->get_path()); + ERR_EXPLAIN("Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(from_path.is_empty()); - //see if the path is cached + // See if the path is cached. PathSentCache *psc = path_send_cache.getptr(from_path); if (!psc) { - //path is not cached, create + // Path is not cached, create. path_send_cache[from_path] = PathSentCache(); psc = path_send_cache.getptr(from_path); psc->id = last_send_cache_id++; } - //create base packet, lots of hardcode because it must be tight + // Create base packet, lots of hardcode because it must be tight. int ofs = 0; #define MAKE_ROOM(m_amount) \ if (packet_cache.size() < m_amount) packet_cache.resize(m_amount); - //encode type + // Encode type. MAKE_ROOM(1); packet_cache.write[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; ofs += 1; - //encode ID + // Encode ID. MAKE_ROOM(ofs + 4); encode_uint32(psc->id, &(packet_cache.write[ofs])); ofs += 4; - //encode function name + // Encode function name. CharString name = String(p_name).utf8(); int len = encode_cstring(name.get_data(), NULL); MAKE_ROOM(ofs + len); @@ -495,20 +522,22 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p ofs += len; if (p_set) { - //set argument + // Set argument. Error err = encode_variant(*p_arg[0], NULL, len); + ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len); ofs += len; } else { - //call arguments + // Call arguments. MAKE_ROOM(ofs + 1); packet_cache.write[ofs] = p_argcount; ofs += 1; for (int i = 0; i < p_argcount; i++) { Error err = encode_variant(*p_arg[i], NULL, len); + ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len); @@ -516,21 +545,21 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p } } - //see if all peers have cached path (is so, call can be fast) + // See if all peers have cached path (is so, call can be fast). bool has_all_peers = _send_confirm_path(from_path, psc, p_to); - //take chance and set transfer mode, since all send methods will use it + // Take chance and set transfer mode, since all send methods will use it. network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); if (has_all_peers) { - //they all have verified paths, so send fast - network_peer->set_target_peer(p_to); //to all of you - network_peer->put_packet(packet_cache.ptr(), ofs); //a message with love + // They all have verified paths, so send fast. + network_peer->set_target_peer(p_to); // To all of you. + network_peer->put_packet(packet_cache.ptr(), ofs); // A message with love. } else { - //not all verified path, so send one by one + // Not all verified path, so send one by one. - //apend path at the end, since we will need it for some packets + // Append path at the end, since we will need it for some packets. CharString pname = String(from_path).utf8(); int path_len = encode_cstring(pname.get_data(), NULL); MAKE_ROOM(ofs + path_len); @@ -539,23 +568,23 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { if (p_to < 0 && E->get() == -p_to) - continue; //continue, excluded + continue; // Continue, excluded. if (p_to > 0 && E->get() != p_to) - continue; //continue, not for this peer + continue; // Continue, not for this peer. Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); - ERR_CONTINUE(!F); //should never happen + ERR_CONTINUE(!F); // Should never happen. - network_peer->set_target_peer(E->get()); //to this one specifically + network_peer->set_target_peer(E->get()); // To this one specifically. if (F->get() == true) { - //this one confirmed path, so use id + // This one confirmed path, so use id. encode_uint32(psc->id, &(packet_cache.write[1])); network_peer->put_packet(packet_cache.ptr(), ofs); } else { - //this one did not confirm path yet, so use entire path (sorry!) - encode_uint32(0x80000000 | ofs, &(packet_cache.write[1])); //offset to path and flag + // This one did not confirm path yet, so use entire path (sorry!). + encode_uint32(0x80000000 | ofs, &(packet_cache.write[1])); // Offset to path and flag. network_peer->put_packet(packet_cache.ptr(), ofs + path_len); } } @@ -570,7 +599,7 @@ void MultiplayerAPI::_add_peer(int p_id) { void MultiplayerAPI::_del_peer(int p_id) { connected_peers.erase(p_id); - path_get_cache.erase(p_id); //I no longer need your cache, sorry + path_get_cache.erase(p_id); // I no longer need your cache, sorry. emit_signal("network_peer_disconnected", p_id); } @@ -591,8 +620,12 @@ void MultiplayerAPI::_server_disconnected() { void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) { - ERR_FAIL_COND(!p_node->is_inside_tree()); + ERR_EXPLAIN("Trying to call an RPC while no network peer is active."); ERR_FAIL_COND(!network_peer.is_valid()); + ERR_EXPLAIN("Trying to call an RPC on a node which is not inside SceneTree."); + ERR_FAIL_COND(!p_node->is_inside_tree()); + ERR_EXPLAIN("Trying to call an RPC via a network peer which is not connected."); + ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED); int node_id = network_peer->get_unique_id(); bool skip_rpc = false; @@ -601,7 +634,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const bool is_master = p_node->is_network_master(); if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { - //check that send mode can use local call + // Check that send mode can use local call. const Map<StringName, RPCMode>::Element *E = p_node->get_node_rpc_mode(p_method); if (E) { @@ -609,9 +642,9 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const } if (call_local_native) { - // done below + // Done below. } else if (p_node->get_script_instance()) { - //attempt with script + // Attempt with script. RPCMode rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method); call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc); } @@ -647,15 +680,19 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) { - ERR_FAIL_COND(!p_node->is_inside_tree()); + ERR_EXPLAIN("Trying to RSET while no network peer is active."); ERR_FAIL_COND(!network_peer.is_valid()); + ERR_EXPLAIN("Trying to RSET on a node which is not inside SceneTree."); + ERR_FAIL_COND(!p_node->is_inside_tree()); + ERR_EXPLAIN("Trying to send an RSET via a network peer which is not connected."); + ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED); int node_id = network_peer->get_unique_id(); bool is_master = p_node->is_network_master(); bool skip_rset = false; if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { - //check that send mode can use local call + // Check that send mode can use local call. bool set_local = false; @@ -675,7 +712,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const return; } } else if (p_node->get_script_instance()) { - //attempt with script + // Attempt with script. RPCMode rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property); set_local = _should_call_local(rpc_mode, is_master, skip_rset); @@ -703,8 +740,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) { + ERR_EXPLAIN("Trying to send an empty raw packet."); ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_DATA); + ERR_EXPLAIN("Trying to send a raw packet while no network peer is active."); ERR_FAIL_COND_V(!network_peer.is_valid(), ERR_UNCONFIGURED); + ERR_EXPLAIN("Trying to send a raw packet via a network peer which is not connected."); ERR_FAIL_COND_V(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED); MAKE_ROOM(p_data.size() + 1); @@ -720,6 +760,7 @@ Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, Networked void MultiplayerAPI::_process_raw(int p_from, const uint8_t *p_packet, int p_packet_len) { + ERR_EXPLAIN("Invalid packet received. Size too small."); ERR_FAIL_COND(p_packet_len < 2); PoolVector<uint8_t> out; @@ -734,30 +775,36 @@ void MultiplayerAPI::_process_raw(int p_from, const uint8_t *p_packet, int p_pac int MultiplayerAPI::get_network_unique_id() const { + ERR_EXPLAIN("No network peer is assigned. Unable to get unique network ID."); ERR_FAIL_COND_V(!network_peer.is_valid(), 0); return network_peer->get_unique_id(); } bool MultiplayerAPI::is_network_server() const { + // XXX Maybe fail silently? Maybe should actually return true to make development of both local and online multiplayer easier? + ERR_EXPLAIN("No network peer is assigned. I can't be a server."); ERR_FAIL_COND_V(!network_peer.is_valid(), false); return network_peer->is_server(); } void MultiplayerAPI::set_refuse_new_network_connections(bool p_refuse) { + ERR_EXPLAIN("No network peer is assigned. Unable to set 'refuse_new_connections'."); ERR_FAIL_COND(!network_peer.is_valid()); network_peer->set_refuse_new_connections(p_refuse); } bool MultiplayerAPI::is_refusing_new_network_connections() const { + ERR_EXPLAIN("No network peer is assigned. Unable to get 'refuse_new_connections'."); ERR_FAIL_COND_V(!network_peer.is_valid(), false); return network_peer->is_refusing_new_connections(); } Vector<int> MultiplayerAPI::get_network_connected_peers() const { + ERR_EXPLAIN("No network peer is assigned. Assume no peers are connected."); ERR_FAIL_COND_V(!network_peer.is_valid(), Vector<int>()); Vector<int> ret; @@ -802,9 +849,9 @@ void MultiplayerAPI::_bind_methods() { BIND_ENUM_CONSTANT(RPC_MODE_REMOTE); BIND_ENUM_CONSTANT(RPC_MODE_MASTER); BIND_ENUM_CONSTANT(RPC_MODE_PUPPET); - BIND_ENUM_CONSTANT(RPC_MODE_SLAVE); // deprecated + BIND_ENUM_CONSTANT(RPC_MODE_SLAVE); // Deprecated. BIND_ENUM_CONSTANT(RPC_MODE_REMOTESYNC); - BIND_ENUM_CONSTANT(RPC_MODE_SYNC); // deprecated + BIND_ENUM_CONSTANT(RPC_MODE_SYNC); // Deprecated. BIND_ENUM_CONSTANT(RPC_MODE_MASTERSYNC); BIND_ENUM_CONSTANT(RPC_MODE_PUPPETSYNC); } diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 02c2c6ce1a..e5741014a4 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -1718,7 +1718,7 @@ void ResourceFormatSaverBinaryInstance::save_unicode_string(FileAccess *f, const CharString utf8 = p_string.utf8(); if (p_bit_on_len) { - f->store_32(utf8.length() + 1 | 0x80000000); + f->store_32((utf8.length() + 1) | 0x80000000); } else { f->store_32(utf8.length() + 1); } diff --git a/core/node_path.cpp b/core/node_path.cpp index 35d6fdcf10..91e2aa5f4e 100644 --- a/core/node_path.cpp +++ b/core/node_path.cpp @@ -276,7 +276,7 @@ NodePath NodePath::get_as_property_path() const { String initial_subname = data->path[0]; - for (size_t i = 1; i < data->path.size(); i++) { + for (int i = 1; i < data->path.size(); i++) { initial_subname += "/" + data->path[i]; } new_path.insert(0, initial_subname); diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h index a2d76381ca..3705762d6c 100644 --- a/core/oa_hash_map.h +++ b/core/oa_hash_map.h @@ -166,7 +166,7 @@ private: values = memnew_arr(TValue, capacity); hashes = memnew_arr(uint32_t, capacity); - for (int i = 0; i < capacity; i++) { + for (uint32_t i = 0; i < capacity; i++) { hashes[i] = 0; } @@ -311,7 +311,7 @@ public: values = memnew_arr(TValue, p_initial_capacity); hashes = memnew_arr(uint32_t, p_initial_capacity); - for (int i = 0; i < p_initial_capacity; i++) { + for (uint32_t i = 0; i < p_initial_capacity; i++) { hashes[i] = 0; } } diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index dbd62cb3bb..daa3eacd5f 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -227,6 +227,7 @@ String DirAccess::fix_path(String p_path) const { return p_path; } break; + case ACCESS_MAX: break; // Can't happen, but silences warning } return p_path; diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 224dea3343..e09e5e16ad 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -46,7 +46,6 @@ bool FileAccess::backup_save = false; FileAccess *FileAccess::create(AccessType p_access) { - ERR_FAIL_COND_V(!create_func, 0); ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, 0); FileAccess *ret = create_func[p_access](); @@ -166,6 +165,7 @@ String FileAccess::fix_path(const String &p_path) const { return r_path; } break; + case ACCESS_MAX: break; // Can't happen, but silences warning } return r_path; diff --git a/core/typedefs.h b/core/typedefs.h index 76778429b0..2b26bf08f7 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -105,11 +105,11 @@ T *_nullptr() { /** Generic ABS function, for math uses please use Math::abs */ #ifndef ABS -#define ABS(m_v) ((m_v < 0) ? (-(m_v)) : (m_v)) +#define ABS(m_v) (((m_v) < 0) ? (-(m_v)) : (m_v)) #endif #ifndef SGN -#define SGN(m_v) ((m_v < 0) ? (-1.0) : (+1.0)) +#define SGN(m_v) (((m_v) < 0) ? (-1.0) : (+1.0)) #endif #ifndef MIN diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 3bd621799a..b134650f8d 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -321,7 +321,7 @@ static func sort(a, b): if a[0] < b[0]: return true - return false + return false var my_items = [[5, "Potato"], [9, "Rice"], [4, "Tomato"]] my_items.sort_custom(MyCustomSorter, "sort") diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml index 453f28fe5a..ed3d2d2205 100644 --- a/doc/classes/ArrayMesh.xml +++ b/doc/classes/ArrayMesh.xml @@ -3,6 +3,23 @@ <brief_description> </brief_description> <description> + The [code]ArrayMesh[/code] is used to construct a [Mesh] by specifying the attributes as arrays. The most basic example is the creation of a single triangle + [codeblock] + var vertices = PoolVector3Array() + vertices.push_back(Vector3(0,1,0)) + vertices.push_back(Vector3(1,0,0)) + vertices.push_back(Vector3(0,0,1)) + # Initialize the ArrayMesh. + var arr_mesh = ArrayMesh.new() + var arrays = [] + arrays.resize(ArrayMesh.ARRAY_MAX) + arrays[ArrayMesh.ARRAY_VERTEX] = vertices + # Create the Mesh. + arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) + var m = MeshInstance.new() + m.mesh = arr_mesh + [/codeblock] + The [code]MeshInstance[/code] is ready to be added to the SceneTree to be shown. </description> <tutorials> </tutorials> diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml index 50641dceed..a3a9055087 100644 --- a/doc/classes/InputEventMouseButton.xml +++ b/doc/classes/InputEventMouseButton.xml @@ -18,7 +18,7 @@ Mouse button identifier, one of the BUTTON_* or BUTTON_WHEEL_* constants in [@GlobalScope]. </member> <member name="doubleclick" type="bool" setter="set_doubleclick" getter="is_doubleclick"> - If [code]true[/code] the mouse button's state is a double-click. If [code]false[/code] the mouse button's state is released. + If [code]true[/code] the mouse button's state is a double-click. </member> <member name="factor" type="float" setter="set_factor" getter="get_factor"> Magnitude. Amount (or delta) of the event. Used for scroll events, indicates scroll amount (vertically or horizontally). Only supported on some platforms, sensitivity varies by platform. May be 0 if not supported. diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index c41084f853..dad4ce898d 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -101,7 +101,7 @@ </argument> <description> Execute the file at the given path with the arguments passed as an array of strings. Platform path resolution will take place. The resolved file must exist and be executable. - The arguments are used in the given order and separated by a space, so [code]OS.execute('ping', ['-c', '3', 'godotengine.org'])[/code] will resolve to [code]ping -c 3 godotengine.org[/code] in the system's shell. + The arguments are used in the given order and separated by a space, so [code]OS.execute('ping', ['-w', '3', 'godotengine.org'], false)[/code] will resolve to [code]ping -w 3 godotengine.org[/code] in the system's shell. This method has slightly different behaviour based on whether the [code]blocking[/code] mode is enabled. When [code]blocking[/code] is enabled, the Godot thread will pause its execution while waiting for the process to terminate. The shell output of the process will be written to the [code]output[/code] array as a single string. When the process terminates, the Godot thread will resume execution. When [code]blocking[/code] is disabled, the Godot thread will continue while the new process runs. It is not possible to retrieve the shell output in non-blocking mode, so [code]output[/code] will be empty. diff --git a/doc/classes/PhysicsServer.xml b/doc/classes/PhysicsServer.xml index 88a104cb11..f79baea0be 100644 --- a/doc/classes/PhysicsServer.xml +++ b/doc/classes/PhysicsServer.xml @@ -1518,9 +1518,7 @@ <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode"> Constant for rigid bodies. </constant> - <constant name="BODY_MODE_SOFT" value="3" enum="BodyMode"> - </constant> - <constant name="BODY_MODE_CHARACTER" value="4" enum="BodyMode"> + <constant name="BODY_MODE_CHARACTER" value="3" enum="BodyMode"> Constant for rigid bodies in character mode. In this mode, a body can not rotate, and only its linear velocity is affected by physics. </constant> <constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter"> diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 4ae4441462..263f210fa2 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -811,8 +811,6 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons bool rebind_shader = true; - Size2 rt_size = Size2(storage->frame.current_rt->width, storage->frame.current_rt->height); - state.current_tex = RID(); state.current_tex_ptr = NULL; state.current_normal = RID(); diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index ca9f6dcbf8..7b05d9a231 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -110,8 +110,8 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) { glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadow_atlas->size, shadow_atlas->size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -604,6 +604,8 @@ RID RasterizerSceneGLES2::light_instance_create(RID p_light) { light_instance->light = p_light; light_instance->light_ptr = storage->light_owner.getornull(p_light); + light_instance->light_index = 0xFFFF; + ERR_FAIL_COND_V(!light_instance->light_ptr, RID()); light_instance->self = light_instance_owner.make_rid(light_instance); @@ -709,9 +711,39 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G bool has_blend_alpha = p_material->shader->spatial.blend_mode != RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX; bool has_alpha = has_base_alpha || has_blend_alpha; - // TODO add this stuff - // bool mirror = p_instance->mirror; - // bool no_cull = false; + bool mirror = p_instance->mirror; + + if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED) { + mirror = false; + } else if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_FRONT) { + mirror = !mirror; + } + + //if (p_material->shader->spatial.uses_sss) { + // state.used_sss = true; + //} + + if (p_material->shader->spatial.uses_screen_texture) { + state.used_screen_texture = true; + } + + if (p_depth_pass) { + + if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) + return; //bye + + if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + //shader does not use discard and does not write a vertex position, use generic material + if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { + p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided); + mirror = false; + } else { + p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); + } + } + + has_alpha = false; + } RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); @@ -724,46 +756,107 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G e->instance = p_instance; e->owner = p_owner; e->sort_key = 0; + e->depth_key = 0; + e->use_accum = false; + e->light_index = RenderList::MAX_LIGHTS; + e->use_accum_ptr = &e->use_accum; + + if (e->geometry->last_pass != render_pass) { + e->geometry->last_pass = render_pass; + e->geometry->index = current_geometry_index++; + } - // TODO check render pass of geometry - - // TODO check directional light flag + e->geometry_index = e->geometry->index; - if (p_depth_pass) { - // if we are in the depth pass we can sort out a few things to improve performance + if (e->material->last_pass != render_pass) { + e->material->last_pass = render_pass; + e->material->index = current_material_index++; - if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) { - return; + if (e->material->shader->last_pass != render_pass) { + e->material->shader->index = current_shader_index++; } + } - if (p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + e->material_index = e->material->index; - // shader doesn't use discard or writes a custom vertex position, - // so we can use a stripped down shader instead + e->refprobe_0_index = 0xFF; //refprobe disabled by default + e->refprobe_1_index = 0xFF; //refprobe disabled by default - // TODO twosided and worldcoord stuff + if (!p_depth_pass) { - p_material = storage->material_owner.getptr(default_material_twosided); - } + e->depth_layer = e->instance->depth_layer; + e->priority = p_material->render_priority; - has_alpha = false; - } + //if (e->instance->reflection_probe_instances.size() > 0 ) { + // RasterizerStorageGLES2:: + //} - e->sort_key |= uint64_t(e->geometry->index) << RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT; - e->sort_key |= uint64_t(e->instance->base_type) << RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT; + //add directional lights - if (p_material->shader->spatial.unshaded) { - e->sort_key |= SORT_KEY_UNSHADED_FLAG; - } + if (p_material->shader->spatial.unshaded) { + e->light_mode = LIGHTMODE_UNSHADED; + } else { - if (!p_depth_pass) { - e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; + bool copy = false; - e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT; - } else { - // TODO + for (int i = 0; i < render_directional_lights; i++) { + + if (copy) { + RenderList::Element *e2 = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); + if (!e2) { + break; + } + *e2 = *e; //this includes accum ptr :) + e = e2; + } + + //directional sort key + e->light_type1 = 0; + e->light_type2 = 1; + e->light_index = i; + + copy = true; + } + + //add omni / spots + + for (int i = 0; i < e->instance->light_instances.size(); i++) { + + LightInstance *li = light_instance_owner.getornull(e->instance->light_instances[i]); + + if (li->light_index >= render_light_instance_count) { + continue; // too many + } + + if (copy) { + RenderList::Element *e2 = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); + if (!e2) { + break; + } + *e2 = *e; //this includes accum ptr :) + e = e2; + } + + //directional sort key + e->light_type1 = 1; + e->light_type2 = li->light_ptr->type == VisualServer::LIGHT_OMNI ? 0 : 1; + e->light_index = li->light_index; + + copy = true; + } + + if (e->instance->lightmap.is_valid()) { + e->light_mode = LIGHTMODE_LIGHTMAP; + } else if (!e->instance->lightmap_capture_data.empty()) { + e->light_mode = LIGHTMODE_LIGHTMAP_CAPTURE; + } else { + e->light_mode = LIGHTMODE_NORMAL; + } + } } + // do not add anything here, as lights are duplicated elements.. + if (p_material->shader->spatial.uses_time) { VisualServerRaster::redraw_request(); } @@ -771,6 +864,13 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass) { + render_pass++; + current_material_index = 0; + current_geometry_index = 0; + current_light_index = 0; + current_refprobe_index = 0; + current_shader_index = 0; + for (int i = 0; i < p_cull_count; i++) { InstanceBase *instance = p_cull_result[i]; @@ -821,9 +921,7 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p } break; - default: { - - } break; + default: {} } } } @@ -838,13 +936,13 @@ static const GLenum gl_primitive[] = { GL_TRIANGLE_FAN }; -void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size) { +bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size) { // material parameters state.scene_shader.set_custom_shader(p_material->shader->custom_code_id); - state.scene_shader.bind(); + bool shader_rebind = state.scene_shader.bind(); if (p_material->shader->spatial.no_depth_test) { glDisable(GL_DEPTH_TEST); @@ -923,193 +1021,167 @@ void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m glBindTexture(t->target, t->tex_id); } state.scene_shader.use_material((void *)p_material); + + return shader_rebind; } void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, p_skeleton != NULL); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, !storage->config.float_texture_supported); - // state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, true); - switch (p_element->instance->base_type) { case VS::INSTANCE_MESH: { RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, s->attribs[VS::ARRAY_COLOR].enabled); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, s->attribs[VS::ARRAY_TEX_UV].enabled); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, s->attribs[VS::ARRAY_TEX_UV2].enabled); - - } break; - - case VS::INSTANCE_MULTIMESH: { - RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner); - RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, true); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, true); - - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, s->attribs[VS::ARRAY_TEX_UV].enabled); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, s->attribs[VS::ARRAY_TEX_UV2].enabled); - } break; - - case VS::INSTANCE_IMMEDIATE: { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, true); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, true); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, true); - } break; - - default: { - - } break; - } - - if (storage->config.float_texture_supported) { - if (p_skeleton) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, p_skeleton->tex_id); - } - - return; - } - - if (p_skeleton) { - ERR_FAIL_COND(p_skeleton->use_2d); - - PoolVector<float> &transform_buffer = storage->resources.skeleton_transform_cpu_buffer; - - switch (p_element->instance->base_type) { - case VS::INSTANCE_MESH: { - RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); + glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - if (!s->attribs[VS::ARRAY_BONES].enabled || !s->attribs[VS::ARRAY_WEIGHTS].enabled) { - break; // the whole instance has a skeleton, but this surface is not affected by it. - } + if (s->index_array_len > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); + } - // 3 * vec4 per vertex - if (transform_buffer.size() < s->array_len * 12) { - transform_buffer.resize(s->array_len * 12); + for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { + if (s->attribs[i].enabled) { + glEnableVertexAttribArray(i); + glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, (uint8_t *)0 + s->attribs[i].offset); + } else { + glDisableVertexAttribArray(i); + switch (i) { + case VS::ARRAY_NORMAL: { + glVertexAttrib4f(VS::ARRAY_COLOR, 0.0, 0.0, 1, 1); + } break; + case VS::ARRAY_COLOR: { + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + + } break; + default: {} + } } + } - const size_t bones_offset = s->attribs[VS::ARRAY_BONES].offset; - const size_t bones_stride = s->attribs[VS::ARRAY_BONES].stride; - const size_t bone_weight_offset = s->attribs[VS::ARRAY_WEIGHTS].offset; - const size_t bone_weight_stride = s->attribs[VS::ARRAY_WEIGHTS].stride; - - { - PoolVector<float>::Write write = transform_buffer.write(); - float *buffer = write.ptr(); + bool clear_skeleton_buffer = !storage->config.float_texture_supported; - PoolVector<uint8_t>::Read vertex_array_read = s->data.read(); - const uint8_t *vertex_data = vertex_array_read.ptr(); + if (p_skeleton) { - for (int i = 0; i < s->array_len; i++) { + if (storage->config.float_texture_supported) { + //use float texture workflow + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); + glBindTexture(GL_TEXTURE_2D, p_skeleton->tex_id); + } else { + //use transform buffer workflow + ERR_FAIL_COND(p_skeleton->use_2d); - // do magic + PoolVector<float> &transform_buffer = storage->resources.skeleton_transform_cpu_buffer; - size_t bones[4]; - float bone_weight[4]; + if (!s->attribs[VS::ARRAY_BONES].enabled || !s->attribs[VS::ARRAY_WEIGHTS].enabled) { + break; // the whole instance has a skeleton, but this surface is not affected by it. + } - if (s->attribs[VS::ARRAY_BONES].type == GL_UNSIGNED_BYTE) { - // read as byte - const uint8_t *bones_ptr = vertex_data + bones_offset + (i * bones_stride); - bones[0] = bones_ptr[0]; - bones[1] = bones_ptr[1]; - bones[2] = bones_ptr[2]; - bones[3] = bones_ptr[3]; - } else { - // read as short - const uint16_t *bones_ptr = (const uint16_t *)(vertex_data + bones_offset + (i * bones_stride)); - bones[0] = bones_ptr[0]; - bones[1] = bones_ptr[1]; - bones[2] = bones_ptr[2]; - bones[3] = bones_ptr[3]; - } + // 3 * vec4 per vertex + if (transform_buffer.size() < s->array_len * 12) { + transform_buffer.resize(s->array_len * 12); + } - if (s->attribs[VS::ARRAY_WEIGHTS].type == GL_FLOAT) { - // read as float - const float *weight_ptr = (const float *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); - bone_weight[0] = weight_ptr[0]; - bone_weight[1] = weight_ptr[1]; - bone_weight[2] = weight_ptr[2]; - bone_weight[3] = weight_ptr[3]; - } else { - // read as half - const uint16_t *weight_ptr = (const uint16_t *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); - bone_weight[0] = (weight_ptr[0] / (float)0xFFFF); - bone_weight[1] = (weight_ptr[1] / (float)0xFFFF); - bone_weight[2] = (weight_ptr[2] / (float)0xFFFF); - bone_weight[3] = (weight_ptr[3] / (float)0xFFFF); + const size_t bones_offset = s->attribs[VS::ARRAY_BONES].offset; + const size_t bones_stride = s->attribs[VS::ARRAY_BONES].stride; + const size_t bone_weight_offset = s->attribs[VS::ARRAY_WEIGHTS].offset; + const size_t bone_weight_stride = s->attribs[VS::ARRAY_WEIGHTS].stride; + + { + PoolVector<float>::Write write = transform_buffer.write(); + float *buffer = write.ptr(); + + PoolVector<uint8_t>::Read vertex_array_read = s->data.read(); + const uint8_t *vertex_data = vertex_array_read.ptr(); + + for (int i = 0; i < s->array_len; i++) { + + // do magic + + size_t bones[4]; + float bone_weight[4]; + + if (s->attribs[VS::ARRAY_BONES].type == GL_UNSIGNED_BYTE) { + // read as byte + const uint8_t *bones_ptr = vertex_data + bones_offset + (i * bones_stride); + bones[0] = bones_ptr[0]; + bones[1] = bones_ptr[1]; + bones[2] = bones_ptr[2]; + bones[3] = bones_ptr[3]; + } else { + // read as short + const uint16_t *bones_ptr = (const uint16_t *)(vertex_data + bones_offset + (i * bones_stride)); + bones[0] = bones_ptr[0]; + bones[1] = bones_ptr[1]; + bones[2] = bones_ptr[2]; + bones[3] = bones_ptr[3]; + } + + if (s->attribs[VS::ARRAY_WEIGHTS].type == GL_FLOAT) { + // read as float + const float *weight_ptr = (const float *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); + bone_weight[0] = weight_ptr[0]; + bone_weight[1] = weight_ptr[1]; + bone_weight[2] = weight_ptr[2]; + bone_weight[3] = weight_ptr[3]; + } else { + // read as half + const uint16_t *weight_ptr = (const uint16_t *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); + bone_weight[0] = (weight_ptr[0] / (float)0xFFFF); + bone_weight[1] = (weight_ptr[1] / (float)0xFFFF); + bone_weight[2] = (weight_ptr[2] / (float)0xFFFF); + bone_weight[3] = (weight_ptr[3] / (float)0xFFFF); + } + + Transform transform; + + Transform bone_transforms[4] = { + storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[0]), + storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[1]), + storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[2]), + storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[3]), + }; + + transform.origin = + bone_weight[0] * bone_transforms[0].origin + + bone_weight[1] * bone_transforms[1].origin + + bone_weight[2] * bone_transforms[2].origin + + bone_weight[3] * bone_transforms[3].origin; + + transform.basis = + bone_transforms[0].basis * bone_weight[0] + + bone_transforms[1].basis * bone_weight[1] + + bone_transforms[2].basis * bone_weight[2] + + bone_transforms[3].basis * bone_weight[3]; + + float row[3][4] = { + { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] }, + { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] }, + { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] }, + }; + + size_t transform_buffer_offset = i * 12; + + copymem(&buffer[transform_buffer_offset], row, sizeof(row)); } - - size_t offset = i * 12; - - Transform transform; - - Transform bone_transforms[4] = { - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[0]), - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[1]), - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[2]), - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[3]), - }; - - transform.origin = - bone_weight[0] * bone_transforms[0].origin + - bone_weight[1] * bone_transforms[1].origin + - bone_weight[2] * bone_transforms[2].origin + - bone_weight[3] * bone_transforms[3].origin; - - transform.basis = - bone_transforms[0].basis * bone_weight[0] + - bone_transforms[1].basis * bone_weight[1] + - bone_transforms[2].basis * bone_weight[2] + - bone_transforms[3].basis * bone_weight[3]; - - float row[3][4] = { - { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] }, - { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] }, - { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] }, - }; - - size_t transform_buffer_offset = i * 12; - - copymem(&buffer[transform_buffer_offset], row, sizeof(row)); } - } - storage->_update_skeleton_transform_buffer(transform_buffer, s->array_len * 12); - } break; + storage->_update_skeleton_transform_buffer(transform_buffer, s->array_len * 12); - default: { + //enable transform buffer and bind it + glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - } break; - } - } -} - -void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { - - switch (p_element->instance->base_type) { - - case VS::INSTANCE_MESH: { - - RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - - // set up + glEnableVertexAttribArray(VS::ARRAY_MAX + 0); + glEnableVertexAttribArray(VS::ARRAY_MAX + 1); + glEnableVertexAttribArray(VS::ARRAY_MAX + 2); - if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { - glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); + glVertexAttribPointer(VS::ARRAY_MAX + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); + glVertexAttribPointer(VS::ARRAY_MAX + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); + glVertexAttribPointer(VS::ARRAY_MAX + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); - glEnableVertexAttribArray(VS::ARRAY_MAX + 0); - glEnableVertexAttribArray(VS::ARRAY_MAX + 1); - glEnableVertexAttribArray(VS::ARRAY_MAX + 2); + clear_skeleton_buffer = false; + } + } - glVertexAttribPointer(VS::ARRAY_MAX + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); - glVertexAttribPointer(VS::ARRAY_MAX + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); - glVertexAttribPointer(VS::ARRAY_MAX + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); - } else { + if (clear_skeleton_buffer) { // just to make sure glDisableVertexAttribArray(VS::ARRAY_MAX + 0); glDisableVertexAttribArray(VS::ARRAY_MAX + 1); @@ -1120,6 +1192,11 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); } + } break; + + case VS::INSTANCE_MULTIMESH: { + RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); + glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); if (s->index_array_len > 0) { @@ -1132,61 +1209,59 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, (uint8_t *)0 + s->attribs[i].offset); } else { glDisableVertexAttribArray(i); + switch (i) { + case VS::ARRAY_NORMAL: { + glVertexAttrib4f(VS::ARRAY_COLOR, 0.0, 0.0, 1, 1); + } break; + case VS::ARRAY_COLOR: { + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + + } break; + default: {} + } } } - // drawing - - if (s->index_array_len > 0) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - } - - // tear down - - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - glDisableVertexAttribArray(i); - } - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { - glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - + if (!storage->config.float_texture_supported) { + // just to make sure, clear skeleton buffer too glDisableVertexAttribArray(VS::ARRAY_MAX + 0); glDisableVertexAttribArray(VS::ARRAY_MAX + 1); glDisableVertexAttribArray(VS::ARRAY_MAX + 2); + + glVertexAttrib4f(VS::ARRAY_MAX + 0, 1, 0, 0, 0); + glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0); + glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); } - glBindBuffer(GL_ARRAY_BUFFER, 0); + } break; + case VS::INSTANCE_IMMEDIATE: { } break; - case VS::INSTANCE_MULTIMESH: { + default: {} + } +} + +void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { + + switch (p_element->instance->base_type) { + + case VS::INSTANCE_MESH: { - RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner); RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - if (amount == -1) { - amount = multi_mesh->size; + // drawing + + if (s->index_array_len > 0) { + glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); + } else { + glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); } if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { + //clean up after skeleton glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - glEnableVertexAttribArray(VS::ARRAY_MAX + 0); - glEnableVertexAttribArray(VS::ARRAY_MAX + 1); - glEnableVertexAttribArray(VS::ARRAY_MAX + 2); - - glVertexAttribPointer(VS::ARRAY_MAX + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); - glVertexAttribPointer(VS::ARRAY_MAX + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); - glVertexAttribPointer(VS::ARRAY_MAX + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); - } else { - // just to make sure glDisableVertexAttribArray(VS::ARRAY_MAX + 0); glDisableVertexAttribArray(VS::ARRAY_MAX + 1); glDisableVertexAttribArray(VS::ARRAY_MAX + 2); @@ -1196,36 +1271,19 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); } - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); - } + } break; - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - if (s->attribs[i].enabled) { - glEnableVertexAttribArray(i); - glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, (uint8_t *)0 + s->attribs[i].offset); - } else { - glDisableVertexAttribArray(i); - } - } + case VS::INSTANCE_MULTIMESH: { - glDisableVertexAttribArray(12); // transform 0 - glDisableVertexAttribArray(13); // transform 1 - glDisableVertexAttribArray(14); // transform 2 - glDisableVertexAttribArray(15); // color - glDisableVertexAttribArray(8); // custom data + RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner); + RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - if (!s->attribs[VS::ARRAY_COLOR].enabled) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); + int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + if (amount == -1) { + amount = multi_mesh->size; } - glVertexAttrib4f(15, 1, 1, 1, 1); - glVertexAttrib4f(8, 0, 0, 0, 0); - int stride = multi_mesh->color_floats + multi_mesh->custom_data_floats + multi_mesh->xform_floats; int color_ofs = multi_mesh->xform_floats; @@ -1260,22 +1318,27 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] }, }; - glVertexAttrib4fv(12, row[0]); - glVertexAttrib4fv(13, row[1]); - glVertexAttrib4fv(14, row[2]); + glVertexAttrib4fv(VS::ARRAY_MAX + 0, row[0]); + glVertexAttrib4fv(VS::ARRAY_MAX + 1, row[1]); + glVertexAttrib4fv(VS::ARRAY_MAX + 2, row[2]); } if (multi_mesh->color_floats) { if (multi_mesh->color_format == VS::MULTIMESH_COLOR_8BIT) { uint8_t *color_data = (uint8_t *)(buffer + color_ofs); - glVertexAttrib4f(15, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); + glVertexAttrib4f(VS::ARRAY_MAX + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); } else { - glVertexAttrib4fv(15, buffer + color_ofs); + glVertexAttrib4fv(VS::ARRAY_MAX + 3, buffer + color_ofs); } } if (multi_mesh->custom_data_floats) { - glVertexAttrib4fv(8, buffer + custom_data_ofs); + if (multi_mesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { + uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs); + glVertexAttrib4f(VS::ARRAY_MAX + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); + } else { + glVertexAttrib4fv(VS::ARRAY_MAX + 4, buffer + custom_data_ofs); + } } if (s->index_array_len > 0) { @@ -1285,25 +1348,6 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { } } - // tear down - - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - glDisableVertexAttribArray(i); - } - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { - glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - - glDisableVertexAttribArray(VS::ARRAY_MAX + 0); - glDisableVertexAttribArray(VS::ARRAY_MAX + 1); - glDisableVertexAttribArray(VS::ARRAY_MAX + 2); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); } break; case VS::INSTANCE_IMMEDIATE: { @@ -1417,508 +1461,552 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { } } break; + default: {} } } -void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const RID *p_directional_lights, int p_directional_light_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add) { - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - - Vector2 screen_pixel_size; - screen_pixel_size.x = 1.0 / storage->frame.current_rt->width; - screen_pixel_size.y = 1.0 / storage->frame.current_rt->height; - - bool use_radiance_map = false; - - VMap<RID, Vector<RenderList::Element *> > lit_objects; - - for (int i = 0; i < p_element_count; i++) { - RenderList::Element *e = p_elements[i]; - - RasterizerStorageGLES2::Material *material = e->material; - - RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); +void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas) { - if (p_base_env) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_CUBE_MAP, p_base_env); - use_radiance_map = true; - } - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, use_radiance_map); - - if (material->shader->spatial.unshaded) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); - } else { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, use_radiance_map); - } - - // opaque pass - - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, false); - - _setup_geometry(e, skeleton); - - _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + //turn off all by default + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, false); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, false); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_DIRECTIONAL, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, false); - if (use_radiance_map) { - state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, p_view_transform); - } + if (!p_light) { //no light, return off + return; + } - if (p_shadow) { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_BIAS, p_shadow_bias); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_NORMAL_BIAS, p_shadow_normal_bias); - } + //turn on lighting + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, true); - if (p_env) { - state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, p_env->bg_energy); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, p_env->ambient_sky_contribution); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, p_env->ambient_color); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, p_env->ambient_energy); + switch (p_light->light_ptr->type) { + case VS::LIGHT_DIRECTIONAL: { - } else { - state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, Color(1.0, 1.0, 1.0, 1.0)); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0); - } + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_DIRECTIONAL, true); + switch (p_light->light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { + //no need + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true); - glEnable(GL_BLEND); + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true); + } break; + } - if (p_alpha_pass || p_directional_add) { - int desired_blend_mode; - if (p_directional_add) { - desired_blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD; - } else { - desired_blend_mode = material->shader->spatial.blend_mode; + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, p_light->light_ptr->directional_blend_splits); + if (p_light->light_ptr->shadow) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); } - switch (desired_blend_mode) { + } break; + case VS::LIGHT_OMNI: { + + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, true); + if (shadow_atlas && p_light->light_ptr->shadow) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); + } + } break; + case VS::LIGHT_SPOT: { + + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, true); + if (shadow_atlas && p_light->light_ptr->shadow) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); + } + } break; + } +} - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } +void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform) { - } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD: { + RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(p_alpha_pass ? GL_SRC_ALPHA : GL_ONE, GL_ONE); + //common parameters + float energy = light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + float specular = light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + float sign = light_ptr->negative ? -1 : 1; - } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB: { + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular); + Color color = light_ptr->color * sign * energy * Math_PI; + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_COLOR, color); - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MUL: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); - } else { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); - } + //specific parameters - } break; - } - } else { - // no blend mode given - assume mix - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - } + switch (light_ptr->type) { + case VS::LIGHT_DIRECTIONAL: { + //not using inverse for performance, view should be normalized anyway + Vector3 direction = p_view_transform.basis.xform_inv(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); + CameraMatrix matrices[4]; - state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + if (light_ptr->shadow && directional_shadow.depth) { - state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? - state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); + int shadow_count = 0; + Color split_offsets; - _render_geometry(e); + switch (light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { + shadow_count = 1; + } break; - if (material->shader->spatial.unshaded) - continue; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { + shadow_count = 2; + } break; - if (p_shadow) - continue; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { + shadow_count = 4; + } break; + } - for (int light = 0; light < e->instance->light_instances.size(); light++) { + for (int k = 0; k < shadow_count; k++) { - RID light_instance = e->instance->light_instances[light]; + uint32_t x = light->directional_rect.position.x; + uint32_t y = light->directional_rect.position.y; + uint32_t width = light->directional_rect.size.x; + uint32_t height = light->directional_rect.size.y; - lit_objects[light_instance].push_back(e); - } - } + if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { - if (p_shadow) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); - return; - } + width /= 2; + height /= 2; - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, true); + if (k == 0) { - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } else if (k == 1) { + x += width; + } else if (k == 2) { + y += height; + } else if (k == 3) { + x += width; + y += height; + } - for (int lo = 0; lo < lit_objects.size(); lo++) { + } else if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - RID key = lit_objects.getk(lo); + height /= 2; - LightInstance *light = light_instance_owner.getornull(key); - RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; + if (k == 0) { - const Vector<RenderList::Element *> &list = lit_objects.getv(lo); + } else { + y += height; + } + } - for (int i = 0; i < list.size(); i++) { + split_offsets[k] = light->shadow_transform[k].split; - RenderList::Element *e = list[i]; - RasterizerStorageGLES2::Material *material = e->material; + Transform modelview = (p_view_transform.inverse() * light->shadow_transform[k].transform).affine_inverse(); - RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); + CameraMatrix bias; + bias.set_light_bias(); + CameraMatrix rectm; + Rect2 atlas_rect = Rect2(float(x) / directional_shadow.size, float(y) / directional_shadow.size, float(width) / directional_shadow.size, float(height) / directional_shadow.size); + rectm.set_light_atlas_rect(atlas_rect); - { - _setup_geometry(e, skeleton); + CameraMatrix shadow_mtx = rectm * bias * light->shadow_transform[k].camera * modelview; + matrices[k] = shadow_mtx; - _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); - if (shadow_atlas != NULL) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + /*Color light_clamp; + light_clamp[0] = atlas_rect.position.x; + light_clamp[1] = atlas_rect.position.y; + light_clamp[2] = atlas_rect.size.x; + light_clamp[3] = atlas_rect.size.y;*/ } - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); + // state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / directional_shadow.size, 1.0 / directional_shadow.size)); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPLIT_OFFSETS, split_offsets); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, matrices[0]); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX2, matrices[1]); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX3, matrices[2]); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX4, matrices[3]); + } + } break; + case VS::LIGHT_OMNI: { - state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + Vector3 position = p_view_transform.xform_inv(light->transform.origin); - state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? - state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); - } + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); - switch (light_ptr->type) { - case VS::LIGHT_OMNI: { + float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)1); + Color attenuation = Color(0.0, 0.0, 0.0, 0.0); + attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); - Vector3 position = p_view_transform.inverse().xform(light->transform.origin); + if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); + uint32_t key = shadow_atlas->shadow_owners[light->self]; - float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - Color attenuation = Color(0.0, 0.0, 0.0, 0.0); - attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); + ERR_BREAK(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); - if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) { + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size >> 1; - uint32_t key = shadow_atlas->shadow_owners[light->self]; + uint32_t x = (quadrant & 1) * quadrant_size; + uint32_t y = (quadrant >> 1) * quadrant_size; - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); + uint32_t width = shadow_size; + uint32_t height = shadow_size; - uint32_t atlas_size = shadow_atlas->size; - uint32_t quadrant_size = atlas_size >> 1; + if (light->light_ptr->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + height /= 2; + } else { + width /= 2; + } - uint32_t x = (quadrant & 1) * quadrant_size; - uint32_t y = (quadrant >> 1) * quadrant_size; + Transform proj = (p_view_transform.inverse() * light->transform).inverse(); - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + Color light_clamp; + light_clamp[0] = float(x) / atlas_size; + light_clamp[1] = float(y) / atlas_size; + light_clamp[2] = float(width) / atlas_size; + light_clamp[3] = float(height) / atlas_size; - uint32_t width = shadow_size; - uint32_t height = shadow_size; + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / shadow_atlas->size, 1.0 / shadow_atlas->size)); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, proj); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + } + } break; - if (light->light_ptr->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { - height /= 2; - } else { - width /= 2; - } + case VS::LIGHT_SPOT: { - Transform proj = (p_view_transform.inverse() * light->transform).inverse(); + Vector3 position = p_view_transform.xform_inv(light->transform.origin); - Color light_clamp; - light_clamp[0] = float(x) / atlas_size; - light_clamp[1] = float(y) / atlas_size; - light_clamp[2] = float(width) / atlas_size; - light_clamp[3] = float(height) / atlas_size; + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, proj); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); + Color attenuation = Color(0.0, 0.0, 0.0, 0.0); + attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; + float spot_attenuation = light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; + float angle = light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE]; + angle = Math::cos(Math::deg2rad(angle)); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ATTENUATION, spot_attenuation); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_RANGE, spot_attenuation); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 1.0); - } else { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 0.0); - } - } break; + if (light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { + uint32_t key = shadow_atlas->shadow_owners[light->self]; - case VS::LIGHT_SPOT: { - Vector3 position = p_view_transform.inverse().xform(light->transform.origin); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)2); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); - Color attenuation = Color(0.0, 0.0, 0.0, 0.0); - attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; - float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; - float spot_attenuation = light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; - float angle = light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE]; - angle = Math::cos(Math::deg2rad(angle)); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ATTENUATION, spot_attenuation); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_RANGE, spot_attenuation); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); + ERR_BREAK(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); - if (light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { - uint32_t key = shadow_atlas->shadow_owners[light->self]; + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size >> 1; - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + uint32_t x = (quadrant & 1) * quadrant_size; + uint32_t y = (quadrant >> 1) * quadrant_size; - ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - uint32_t atlas_size = shadow_atlas->size; - uint32_t quadrant_size = atlas_size >> 1; + uint32_t width = shadow_size; + uint32_t height = shadow_size; - uint32_t x = (quadrant & 1) * quadrant_size; - uint32_t y = (quadrant >> 1) * quadrant_size; + Rect2 rect(float(x) / atlas_size, float(y) / atlas_size, float(width) / atlas_size, float(height) / atlas_size); - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + Color light_clamp; + light_clamp[0] = rect.position.x; + light_clamp[1] = rect.position.y; + light_clamp[2] = rect.size.x; + light_clamp[3] = rect.size.y; - uint32_t width = shadow_size; - uint32_t height = shadow_size; + Transform modelview = (p_view_transform.inverse() * light->transform).inverse(); - Rect2 rect(float(x) / atlas_size, float(y) / atlas_size, float(width) / atlas_size, float(height) / atlas_size); + CameraMatrix bias; + bias.set_light_bias(); - Color light_clamp; - light_clamp[0] = rect.position.x; - light_clamp[1] = rect.position.y; - light_clamp[2] = rect.size.x; - light_clamp[3] = rect.size.y; + CameraMatrix rectm; + rectm.set_light_atlas_rect(rect); - Transform modelview = (p_view_transform.inverse() * light->transform).inverse(); + CameraMatrix shadow_matrix = rectm * bias * light->shadow_transform[0].camera * modelview; - CameraMatrix bias; - bias.set_light_bias(); + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / shadow_atlas->size, 1.0 / shadow_atlas->size)); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, shadow_matrix); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + } - CameraMatrix rectm; - rectm.set_light_atlas_rect(rect); + } break; + default: {} + } +} - CameraMatrix shadow_matrix = rectm * bias * light->shadow_transform[0].camera * modelview; +void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow) { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, shadow_matrix); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - } else { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 0.0); - } + Vector2 screen_pixel_size; + screen_pixel_size.x = 1.0 / storage->frame.current_rt->width; + screen_pixel_size.y = 1.0 / storage->frame.current_rt->height; - } break; + bool use_radiance_map = false; + if (!p_shadow && p_base_env) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); + glBindTexture(GL_TEXTURE_CUBE_MAP, p_base_env); + use_radiance_map = true; + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, true); //since prev unshaded is false, this needs to be true if exists + } - default: break; - } + bool prev_unshaded = false; + bool prev_instancing = false; + state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); + RasterizerStorageGLES2::Material *prev_material = NULL; + RasterizerStorageGLES2::Geometry *prev_geometry = NULL; + RasterizerStorageGLES2::Skeleton *prev_skeleton = NULL; - float energy = light->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - float specular = light->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + Transform view_transform_inverse = p_view_transform.inverse(); + CameraMatrix projection_inverse = p_projection.inverse(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ENERGY, energy); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_COLOR, light->light_ptr->color.to_linear()); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular); + bool prev_base_pass = false; + LightInstance *prev_light = NULL; + bool prev_vertex_lit = false; - _render_geometry(e); - } - } + int prev_blend_mode = -2; //will always catch the first go - for (int dl = 0; dl < p_directional_light_count; dl++) { - RID light_rid = p_directional_lights[dl]; - LightInstance *light = light_instance_owner.getornull(light_rid); - RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; + if (p_alpha_pass) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + } - switch (light_ptr->directional_shadow_mode) { - case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { - } break; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits); - } break; + for (int i = 0; i < p_element_count; i++) { + RenderList::Element *e = p_elements[i]; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits); - } break; - default: - break; - } + RasterizerStorageGLES2::Material *material = e->material; - for (int i = 0; i < p_element_count; i++) { + bool rebind = false; + bool accum_pass = *e->use_accum_ptr; + *e->use_accum_ptr = true; //set to accum for next time this is found + LightInstance *light = NULL; - RenderList::Element *e = p_elements[i]; - RasterizerStorageGLES2::Material *material = e->material; - RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); + if (!p_shadow) { - { - _setup_material(material, p_reverse_cull, false, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + bool unshaded = material->shader->spatial.unshaded; - if (directional_shadow.depth) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); // TODO move into base pass - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + if (unshaded != prev_unshaded) { + rebind = true; + if (unshaded) { + state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, true); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, false); + } else { + state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, use_radiance_map); } - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); + prev_unshaded = unshaded; + } - state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + bool base_pass = !accum_pass && !unshaded; //conditions for a base pass - state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? - state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); + if (base_pass != prev_base_pass) { + state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, base_pass); + rebind = true; + prev_base_pass = base_pass; } - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)0); - Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); - float energy = light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - float specular = light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + if (!unshaded && e->light_index < RenderList::MAX_LIGHTS) { + light = render_light_instances[e->light_index]; + } - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ENERGY, energy); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular); + if (light != prev_light) { - float sign = light_ptr->negative ? -1 : 1; + _setup_light_type(light, shadow_atlas); + rebind = true; + } - Color linear_col = light_ptr->color.to_linear(); - Color color; - for (int c = 0; c < 3; c++) - color[c] = linear_col[c] * sign * energy * Math_PI; + int blend_mode = p_alpha_pass ? material->shader->spatial.blend_mode : -1; // -1 no blend, no mix - color[3] = 0; + if (accum_pass) { //accum pass force pass + blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD; + } - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_COLOR, color); + if (prev_blend_mode != blend_mode) { - CameraMatrix matrices[4]; + if (prev_blend_mode == -1 && blend_mode != -1) { + //does blend + glEnable(GL_BLEND); + } else if (blend_mode == -1 && prev_blend_mode != -1) { + //do not blend + glDisable(GL_BLEND); + } - if (light_ptr->shadow && directional_shadow.depth) { + switch (blend_mode) { + //-1 not handled because not blend is enabled anyway + case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - int shadow_count = 0; - Color split_offsets; + } break; + case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD: { + + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(p_alpha_pass ? GL_SRC_ALPHA : GL_ONE, GL_ONE); - switch (light_ptr->directional_shadow_mode) { - case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { - shadow_count = 1; } break; + case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB: { - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { - shadow_count = 2; + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); } break; + case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MUL: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); + } else { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); + } - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { - shadow_count = 4; } break; } - for (int k = 0; k < shadow_count; k++) { + prev_blend_mode = blend_mode; + } - uint32_t x = light->directional_rect.position.x; - uint32_t y = light->directional_rect.position.y; - uint32_t width = light->directional_rect.size.x; - uint32_t height = light->directional_rect.size.y; + //condition to enable vertex lighting on this object + bool vertex_lit = light && (material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading) && !unshaded; - if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + if (vertex_lit != prev_vertex_lit) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, vertex_lit); + prev_vertex_lit = vertex_lit; + } + } - width /= 2; - height /= 2; + bool instancing = e->instancing; - if (k == 0) { + if (instancing != prev_instancing) { - } else if (k == 1) { - x += width; - } else if (k == 2) { - y += height; - } else if (k == 3) { - x += width; - y += height; - } + state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, instancing); + rebind = true; + } - } else if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { + RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); - height /= 2; + if (skeleton != prev_skeleton) { - if (k == 0) { + if (skeleton) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, skeleton != NULL); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, !storage->config.float_texture_supported); + } else { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, false); + } - } else { - y += height; - } - } + rebind = true; + } - split_offsets[k] = light->shadow_transform[k].split; + if (e->geometry != prev_geometry || skeleton != prev_skeleton) { + _setup_geometry(e, skeleton); + } - Transform modelview = (p_view_transform * light->shadow_transform[k].transform).inverse(); + bool shader_rebind = false; + if (rebind || material != prev_material) { + shader_rebind = _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + } - CameraMatrix bias; - bias.set_light_bias(); - CameraMatrix rectm; - Rect2 atlas_rect = Rect2(float(x) / directional_shadow.size, float(y) / directional_shadow.size, float(width) / directional_shadow.size, float(height) / directional_shadow.size); - rectm.set_light_atlas_rect(atlas_rect); + if (i == 0 || shader_rebind) { //first time must rebindmakin - CameraMatrix shadow_mtx = rectm * bias * light->shadow_transform[k].camera * modelview; - matrices[k] = shadow_mtx.inverse(); + if (p_shadow) { + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_BIAS, p_shadow_bias); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_NORMAL_BIAS, p_shadow_normal_bias); + if (state.shadow_is_dual_parabolloid) { + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_DUAL_PARABOLOID_RENDER_SIDE, state.dual_parbolloid_direction); + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_DUAL_PARABOLOID_RENDER_ZFAR, state.dual_parbolloid_zfar); + } + } else { + if (use_radiance_map) { + state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, p_view_transform); + } - Color light_clamp; - light_clamp[0] = atlas_rect.position.x; - light_clamp[1] = atlas_rect.position.y; - light_clamp[2] = atlas_rect.size.x; - light_clamp[3] = atlas_rect.size.y; + if (p_env) { + state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, p_env->bg_energy); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, p_env->ambient_sky_contribution); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, p_env->ambient_color); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, p_env->ambient_energy); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPLIT_OFFSETS, split_offsets); + } else { + state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, 1.0); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, 1.0); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, Color(1.0, 1.0, 1.0, 1.0)); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0); } - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX1, matrices[0]); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX2, matrices[1]); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX3, matrices[2]); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX4, matrices[3]); - } else { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 0.0); + if (light) { + _setup_light(light, shadow_atlas, p_view_transform); + } } - _render_geometry(e); + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, view_transform_inverse); + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); + state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); + state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, projection_inverse); + + state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + + state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); + state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? } - } - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, false); + state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); + _render_geometry(e); + + prev_geometry = e->geometry; + prev_material = material; + prev_skeleton = skeleton; + prev_instancing = instancing; + prev_light = light; + } + + _setup_light_type(NULL, NULL); //clear light stuff + state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); + state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false); } void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy) { @@ -2013,6 +2101,38 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { + //push back the directional lights + + if (p_light_cull_count) { + //harcoded limit of 256 lights + render_light_instance_count = MIN(RenderList::MAX_LIGHTS, p_light_cull_count); + render_light_instances = (LightInstance **)alloca(sizeof(LightInstance *) * render_light_instance_count); + render_directional_lights = 0; + + //doing this because directional lights are at the end, put them at the beginning + int index = 0; + for (int i = render_light_instance_count - 1; i >= 0; i--) { + RID light_rid = p_light_cull_result[i]; + + LightInstance *light = light_instance_owner.getornull(light_rid); + + if (light->light_ptr->type == VS::LIGHT_DIRECTIONAL) { + render_directional_lights++; + //as goin in reverse, directional lights are always first anyway + } + + light->light_index = index; + render_light_instances[index] = light; + + index++; + } + + } else { + render_light_instances = NULL; + render_directional_lights = 0; + render_light_instance_count = 0; + } + glEnable(GL_BLEND); GLuint current_fb = storage->frame.current_rt->fbo; @@ -2069,34 +2189,23 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const } } - Vector<RID> directional_lights; - - for (int i = 0; i < p_light_cull_count; i++) { - RID light_rid = p_light_cull_result[i]; - - LightInstance *light = light_instance_owner.getornull(light_rid); - - if (light->light_ptr->type == VS::LIGHT_DIRECTIONAL) { - directional_lights.push_back(light_rid); - } - } - // render opaque things first render_list.sort_by_key(false); - _render_render_list(render_list.elements, render_list.element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false, false); + _render_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false); // alpha pass glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - render_list.sort_by_key(true); - _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false, false); + render_list.sort_by_depth(true); + + _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); - // #define GLES2_SHADOW_ATLAS_DEBUG_VIEW + //#define GLES2_SHADOW_ATLAS_DEBUG_VIEW #ifdef GLES2_SHADOW_ATLAS_DEBUG_VIEW ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); @@ -2115,6 +2224,25 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const storage->_copy_screen(); } #endif + + //#define GLES2_SHADOW_DIRECTIONAL_DEBUG_VIEW + +#ifdef GLES2_SHADOW_DIRECTIONAL_DEBUG_VIEW + if (true) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + + glViewport(0, 0, storage->frame.current_rt->width / 4, storage->frame.current_rt->height / 4); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false); + storage->shaders.copy.bind(); + + storage->_copy_screen(); + } +#endif } void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { @@ -2129,13 +2257,13 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ uint32_t y; uint32_t width; uint32_t height; - uint32_t vp_height; float zfar = 0; bool flip_facing = false; int custom_vp_size = 0; - GLuint fbo = 0; + state.shadow_is_dual_parabolloid = false; + state.dual_parbolloid_direction = 0.0; int current_cubemap = -1; float bias = 0; @@ -2214,14 +2342,12 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult; fbo = directional_shadow.fbo; - vp_height = directional_shadow.size; } else { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); fbo = shadow_atlas->fbo; - vp_height = shadow_atlas->size; uint32_t key = shadow_atlas->shadow_owners[p_light]; @@ -2264,8 +2390,32 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ zfar = light->param[VS::LIGHT_PARAM_RANGE]; current_cubemap = cubemap_index; + } else { + //dual parabolloid + state.shadow_is_dual_parabolloid = true; + light_projection = light_instance->shadow_transform[0].camera; + light_transform = light_instance->shadow_transform[0].transform; + + if (light->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + + height /= 2; + y += p_pass * height; + } else { + width /= 2; + x += p_pass * width; + } + + state.dual_parbolloid_direction = p_pass == 0 ? 1.0 : -1.0; + flip_facing = (p_pass == 1); + zfar = light->param[VS::LIGHT_PARAM_RANGE]; + bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; + + state.dual_parbolloid_zfar = zfar; + + state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH_DUAL_PARABOLOID, true); } - } else { + + } else if (light->type == VS::LIGHT_SPOT) { light_projection = light_instance->shadow_transform[0].camera; light_transform = light_instance->shadow_transform[0].transform; @@ -2304,11 +2454,16 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ glClear(GL_DEPTH_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); + if (light->reverse_cull) { + flip_facing = !flip_facing; + } + state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, true); - _render_render_list(render_list.elements, render_list.element_count, NULL, 0, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, false, false, true, false); + _render_render_list(render_list.elements, render_list.element_count, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, flip_facing, false, true); state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, false); + state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH_DUAL_PARABOLOID, false); // convert cubemap to dual paraboloid if needed if (light->type == VS::LIGHT_OMNI && light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE && p_pass == 5) { @@ -2358,6 +2513,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ } glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + glColorMask(1, 1, 1, 1); } void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) { @@ -2377,6 +2533,8 @@ void RasterizerSceneGLES2::initialize() { render_list.init(); + render_pass = 1; + shadow_atlas_realloc_tolerance_msec = 500; { @@ -2394,6 +2552,27 @@ void RasterizerSceneGLES2::initialize() { } { + default_worldcoord_shader = storage->shader_create(); + storage->shader_set_code(default_worldcoord_shader, "shader_type spatial; render_mode world_vertex_coords;\n"); + default_worldcoord_material = storage->material_create(); + storage->material_set_shader(default_worldcoord_material, default_worldcoord_shader); + + default_worldcoord_shader_twosided = storage->shader_create(); + default_worldcoord_material_twosided = storage->material_create(); + storage->shader_set_code(default_worldcoord_shader_twosided, "shader_type spatial; render_mode cull_disabled,world_vertex_coords;\n"); + storage->material_set_shader(default_worldcoord_material_twosided, default_worldcoord_shader_twosided); + } + + { + //default material and shader + + default_overdraw_shader = storage->shader_create(); + storage->shader_set_code(default_overdraw_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); + default_overdraw_material = storage->material_create(); + storage->material_set_shader(default_overdraw_material, default_overdraw_shader); + } + + { glGenBuffers(1, &state.sky_verts); glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, NULL, GL_DYNAMIC_DRAW); @@ -2463,8 +2642,8 @@ void RasterizerSceneGLES2::initialize() { glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -2475,9 +2654,12 @@ void RasterizerSceneGLES2::initialize() { ERR_PRINT("Directional shadow framebuffer status invalid"); } } + + shadow_filter_mode = SHADOW_FILTER_NEAREST; } void RasterizerSceneGLES2::iteration() { + shadow_filter_mode = ShadowFilterMode(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); } void RasterizerSceneGLES2::finalize() { diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index c5d28e55f4..27cbc35299 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -53,12 +53,34 @@ class RasterizerSceneGLES2 : public RasterizerScene { public: + enum ShadowFilterMode { + SHADOW_FILTER_NEAREST, + SHADOW_FILTER_PCF5, + SHADOW_FILTER_PCF13, + }; + + ShadowFilterMode shadow_filter_mode; + RID default_material; RID default_material_twosided; RID default_shader; RID default_shader_twosided; + RID default_worldcoord_material; + RID default_worldcoord_material_twosided; + RID default_worldcoord_shader; + RID default_worldcoord_shader_twosided; + + RID default_overdraw_material; + RID default_overdraw_shader; + + uint64_t render_pass; uint64_t scene_pass; + uint32_t current_material_index; + uint32_t current_geometry_index; + uint32_t current_light_index; + uint32_t current_refprobe_index; + uint32_t current_shader_index; RasterizerStorageGLES2 *storage; struct State { @@ -172,11 +194,16 @@ public: bool cull_front; bool cull_disabled; bool used_sss; - bool used_screen_texture; bool using_contact_shadows; VS::ViewportDebugDraw debug_draw; */ + + bool used_screen_texture; + bool shadow_is_dual_parabolloid; + float dual_parbolloid_direction; + float dual_parbolloid_zfar; + } state; /* SHADOW ATLAS API */ @@ -373,6 +400,10 @@ public: virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0); virtual void light_instance_mark_visible(RID p_light_instance); + LightInstance **render_light_instances; + int render_directional_lights; + int render_light_instance_count; + /* REFLECTION INSTANCE */ virtual RID gi_probe_instance_create(); @@ -382,40 +413,18 @@ public: /* RENDER LIST */ + enum LightMode { + LIGHTMODE_NORMAL, + LIGHTMODE_UNSHADED, + LIGHTMODE_LIGHTMAP, + LIGHTMODE_LIGHTMAP_CAPTURE, + }; + struct RenderList { + enum { - DEFAULT_MAX_ELEMENTS = 65536, - SORT_FLAG_SKELETON = 1, - SORT_FLAG_INSTANCING = 2, - MAX_DIRECTIONAL_LIGHTS = 16, - MAX_LIGHTS = 4096, - MAX_REFLECTIONS = 1024, - - SORT_KEY_PRIORITY_SHIFT = 56, - SORT_KEY_PRIORITY_MASK = 0xFF, - //depth layer for opaque (56-52) - 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) << 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, - SORT_KEY_MIRROR_FLAG = 1 + MAX_LIGHTS = 255, + DEFAULT_MAX_ELEMENTS = 65536 }; int max_elements; @@ -427,7 +436,38 @@ public: RasterizerStorageGLES2::Material *material; RasterizerStorageGLES2::GeometryOwner *owner; - uint64_t sort_key; + bool use_accum; //is this an add pass for multipass + bool *use_accum_ptr; + + union { + //TODO: should be endian swapped on big endian + struct { + int32_t depth_layer : 16; + int32_t priority : 16; + }; + + uint32_t depth_key; + }; + + union { + struct { + //from least significant to most significant in sort, TODO: should be endian swapped on big endian + + uint64_t geometry_index : 14; + uint64_t instancing : 1; + uint64_t skeleton : 1; + uint64_t shader_index : 10; + uint64_t material_index : 10; + uint64_t light_index : 8; + uint64_t light_type2 : 1; // if 1==0 : nolight/directional, else omni/spot + uint64_t refprobe_1_index : 8; + uint64_t refprobe_0_index : 8; + uint64_t light_type1 : 1; //no light, directional is 0, omni spot is 1 + uint64_t light_mode : 2; // LightMode enum + }; + + uint64_t sort_key; + }; }; Element *base_elements; @@ -445,7 +485,11 @@ public: struct SortByKey { _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->sort_key < B->sort_key; + if (A->depth_key == B->depth_key) { + return A->sort_key < B->sort_key; + } else { + return A->depth_key < B->depth_key; + } } }; @@ -476,29 +520,6 @@ public: } } - struct SortByReverseDepthAndPriority { - - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - uint32_t layer_A = uint32_t(A->sort_key >> SORT_KEY_PRIORITY_SHIFT); - uint32_t layer_B = uint32_t(B->sort_key >> SORT_KEY_PRIORITY_SHIFT); - if (layer_A == layer_B) { - return A->instance->depth > B->instance->depth; - } else { - return layer_A < layer_B; - } - } - }; - - void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha - - SortArray<Element *, SortByReverseDepthAndPriority> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - // element adding and stuff _FORCE_INLINE_ Element *add_element() { @@ -549,7 +570,6 @@ public: void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass); void _render_render_list(RenderList::Element **p_elements, int p_element_count, - const RID *p_directional_lights, int p_directional_light_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, @@ -559,14 +579,15 @@ public: float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, - bool p_shadow, - bool p_directional_add); + bool p_shadow); void _draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy); - void _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size = Size2i(0, 0)); - void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton); - void _render_geometry(RenderList::Element *p_element); + _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size = Size2i(0, 0)); + _FORCE_INLINE_ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton); + _FORCE_INLINE_ void _setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas); + _FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform); + _FORCE_INLINE_ void _render_geometry(RenderList::Element *p_element); virtual void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index d945132dc2..73207754b9 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -52,6 +52,8 @@ GLuint RasterizerStorageGLES2::system_fbo = 0; #define _GL_HALF_FLOAT_OES 0x8D61 #endif +#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F + void RasterizerStorageGLES2::bind_quad_array() const { glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); @@ -354,7 +356,6 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ GLenum type; bool compressed = false; - bool srgb = false; if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { p_flags &= ~VS::TEXTURE_FLAG_MIPMAPS; // no mipies for video @@ -1308,8 +1309,13 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn pi.hint_string = "CubeMap"; } break; - default: { - + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + // Not implemented in GLES2 } break; } @@ -3109,6 +3115,7 @@ void RasterizerStorageGLES2::light_set_param(RID p_light, VS::LightParam p_param light->version++; light->instance_change_notify(); } break; + default: {} } light->param[p_param] = p_value; @@ -4088,15 +4095,14 @@ void RasterizerStorageGLES2::initialize() { } config.shrink_textures_x2 = false; - config.float_texture_supported = config.extensions.find("GL_ARB_texture_float") != NULL || config.extensions.find("GL_OES_texture_float") != NULL; - config.s3tc_supported = config.extensions.find("GL_EXT_texture_compression_s3tc") != NULL; - config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") != NULL; + config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); + config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc"); + config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture"); frame.count = 0; frame.delta = 0; frame.current_rt = NULL; frame.clear_request = false; - // config.keep_original_textures = false; glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); @@ -4225,6 +4231,16 @@ void RasterizerStorageGLES2::initialize() { glBindTexture(GL_TEXTURE_2D, 0); } + +#ifdef GLES_OVER_GL + //this needs to be enabled manually in OpenGL 2.1 + + glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); +#endif + + config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); } void RasterizerStorageGLES2::finalize() { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index d9bf6b3ccb..e6708914ec 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -406,6 +406,9 @@ public: String path; + uint32_t index; + uint64_t last_pass; + struct CanvasItem { enum BlendMode { @@ -491,6 +494,7 @@ public: valid = false; custom_code_id = 0; version = 1; + last_pass = 0; } }; diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 83b61dc288..bedcfbb798 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -31,6 +31,7 @@ #include "shader_compiler_gles2.h" #include "core/os/os.h" +#include "core/project_settings.h" #include "core/string_buffer.h" #include "core/string_builder.h" @@ -830,6 +831,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize"; // gl_InstanceID is not available in OpenGL ES 2.0 actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0"; + actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; //builtins @@ -900,16 +902,30 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); + + if (!force_lambert) { + actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + } + actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); + + if (!force_blinn) { + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + } else { + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; + } + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; /* PARTICLES SHADER */ diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index 445428acc5..628a57c06d 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -57,7 +57,7 @@ ShaderGLES2 *ShaderGLES2::active = NULL; -// #define DEBUG_SHADER +//#define DEBUG_SHADER #ifdef DEBUG_SHADER @@ -132,6 +132,11 @@ bool ShaderGLES2::bind() { ERR_FAIL_COND_V(!version, false); + if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation). + glUseProgram(0); + return false; + } + glUseProgram(version->id); // find out uniform names and locations @@ -171,72 +176,24 @@ void ShaderGLES2::unbind() { active = NULL; } -static String _fix_error_code_line(const String &p_error, int p_code_start, int p_offset) { - - int last_find_pos = -1; - // NVIDIA - String error = p_error; - while ((last_find_pos = p_error.find("(", last_find_pos + 1)) != -1) { - - int end_pos = last_find_pos + 1; - - while (true) { - - if (p_error[end_pos] >= '0' && p_error[end_pos] <= '9') { +static void _display_error_with_code(const String &p_error, const Vector<const char *> &p_code) { - end_pos++; - continue; - } else if (p_error[end_pos] == ')') { - break; - } else { - - end_pos = -1; - break; - } - } + int line = 1; + String total_code; - if (end_pos == -1) - continue; - - String numstr = error.substr(last_find_pos + 1, (end_pos - last_find_pos) - 1); - String begin = error.substr(0, last_find_pos + 1); - String end = error.substr(end_pos, error.length()); - int num = numstr.to_int() + p_code_start - p_offset; - error = begin + itos(num) + end; + for (int i = 0; i < p_code.size(); i++) { + total_code += String(p_code[i]); } - // ATI - last_find_pos = -1; - while ((last_find_pos = p_error.find("ERROR: ", last_find_pos + 1)) != -1) { - - last_find_pos += 6; - int end_pos = last_find_pos + 1; + Vector<String> lines = String(total_code).split("\n"); - while (true) { + for (int j = 0; j < lines.size(); j++) { - if (p_error[end_pos] >= '0' && p_error[end_pos] <= '9') { - - end_pos++; - continue; - } else if (p_error[end_pos] == ':') { - break; - } else { - - end_pos = -1; - break; - } - } - continue; - if (end_pos == -1) - continue; - - String numstr = error.substr(last_find_pos + 1, (end_pos - last_find_pos) - 1); - String begin = error.substr(0, last_find_pos + 1); - String end = error.substr(end_pos, error.length()); - int num = numstr.to_int() + p_code_start - p_offset; - error = begin + itos(num) + end; + print_line(itos(line) + ": " + lines[j]); + line++; } - return error; + + ERR_PRINTS(p_error); } ShaderGLES2::Version *ShaderGLES2::get_current_version() { @@ -316,7 +273,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { if (cc) { for (int i = 0; i < cc->custom_defines.size(); i++) { strings.push_back(cc->custom_defines.write[i]); - DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i])); + DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i].get_data())); } } @@ -375,9 +332,8 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { String err_string = get_shader_name() + ": Vertex shader compilation failed:\n"; err_string += ilogmem; - err_string = _fix_error_code_line(err_string, vertex_code_start, define_line_ofs); - ERR_PRINTS(err_string); + _display_error_with_code(err_string, strings); Memory::free_static(ilogmem); glDeleteShader(v.vert_id); @@ -451,9 +407,8 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { String err_string = get_shader_name() + ": Fragment shader compilation failed:\n"; err_string += ilogmem; - err_string = _fix_error_code_line(err_string, fragment_code_start, define_line_ofs); - ERR_PRINTS(err_string); + _display_error_with_code(err_string, strings); Memory::free_static(ilogmem); glDeleteShader(v.frag_id); @@ -503,9 +458,8 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { String err_string = get_shader_name() + ": Program linking failed:\n"; err_string += ilogmem; - err_string = _fix_error_code_line(err_string, fragment_code_start, define_line_ofs); - ERR_PRINTS(err_string); + _display_error_with_code(err_string, strings); Memory::free_static(ilogmem); glDeleteShader(v.frag_id); @@ -736,11 +690,6 @@ void ShaderGLES2::use_material(void *p_material) { Version *v = version_map.getptr(conditional_version); - CustomCode *cc = NULL; - if (v) { - cc = custom_code_map.getptr(v->code_version); - } - // bind uniforms for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) { @@ -1028,7 +977,7 @@ void ShaderGLES2::use_material(void *p_material) { value.second.resize(default_arg_size); - for (int i = 0; i < default_arg_size; i++) { + for (size_t i = 0; i < default_arg_size; i++) { if (is_float) { value.second.write[i].real = 0.0; } else { @@ -1038,8 +987,6 @@ void ShaderGLES2::use_material(void *p_material) { } } - // GLint location = get_uniform_location(E->key()); - GLint location; if (v->custom_uniform_locations.has(E->key())) { location = v->custom_uniform_locations[E->key()]; @@ -1059,8 +1006,6 @@ void ShaderGLES2::use_material(void *p_material) { int tc = material->textures.size(); Pair<StringName, RID> *textures = material->textures.ptrw(); - ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = material->shader->texture_hints.ptrw(); - for (int i = 0; i < tc; i++) { Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > value; diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h index 8e274b4f57..9160a7c265 100644 --- a/drivers/gles2/shader_gles2.h +++ b/drivers/gles2/shader_gles2.h @@ -335,6 +335,19 @@ public: case ShaderLanguage::TYPE_SAMPLERCUBE: { } break; + + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + // Not implemented in GLES2 + } break; + + case ShaderLanguage::TYPE_VOID: { + // Nothing to do? + } break; } } @@ -468,7 +481,8 @@ public: // like forward declared nested classes. void use_material(void *p_material); - uint32_t get_version() const { return new_conditional_version.version; } + _FORCE_INLINE_ uint32_t get_version() const { return new_conditional_version.version; } + _FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; } void set_uniform_camera(int p_idx, const CameraMatrix &p_mat) { diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 906c089170..da4c3a84f1 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -5,12 +5,16 @@ #define mediump #define highp #else -precision mediump float; -precision mediump int; +precision highp float; +precision highp int; #endif #include "stdlib.glsl" +#define SHADER_IS_SRGB true + +#define M_PI 3.14159265359 + // // attributes // @@ -39,9 +43,9 @@ attribute vec2 uv2_attrib; // attrib:5 #ifdef USE_SKELETON_SOFTWARE -attribute highp vec4 bone_transform_row_0; // attrib:9 -attribute highp vec4 bone_transform_row_1; // attrib:10 -attribute highp vec4 bone_transform_row_2; // attrib:11 +attribute highp vec4 bone_transform_row_0; // attrib:8 +attribute highp vec4 bone_transform_row_1; // attrib:9 +attribute highp vec4 bone_transform_row_2; // attrib:10 #else @@ -57,12 +61,12 @@ uniform ivec2 skeleton_texture_size; #ifdef USE_INSTANCING -attribute highp vec4 instance_xform_row_0; // attrib:12 -attribute highp vec4 instance_xform_row_1; // attrib:13 -attribute highp vec4 instance_xform_row_2; // attrib:14 +attribute highp vec4 instance_xform_row_0; // attrib:8 +attribute highp vec4 instance_xform_row_1; // attrib:9 +attribute highp vec4 instance_xform_row_2; // attrib:10 -attribute highp vec4 instance_color; // attrib:15 -attribute highp vec4 instance_custom_data; // attrib:8 +attribute highp vec4 instance_color; // attrib:11 +attribute highp vec4 instance_custom_data; // attrib:12 #endif @@ -116,6 +120,148 @@ VERTEX_SHADER_GLOBALS /* clang-format on */ +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + +varying highp float dp_clip; +uniform highp float shadow_dual_paraboloid_render_zfar; +uniform highp float shadow_dual_paraboloid_render_side; + +#endif + +#if defined(USE_SHADOW) && defined(USE_LIGHTING) + +#ifdef LIGHT_MODE_DIRECTIONAL +uniform highp sampler2D light_directional_shadow; // texunit:-3 +uniform highp vec4 light_split_offsets; +#endif + +uniform highp mat4 light_shadow_matrix; +varying highp vec4 shadow_coord; + +#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) +uniform highp mat4 light_shadow_matrix2; +varying highp vec4 shadow_coord2; +#endif + +#if defined(LIGHT_USE_PSSM4) + +uniform highp mat4 light_shadow_matrix3; +uniform highp mat4 light_shadow_matrix4; +varying highp vec4 shadow_coord3; +varying highp vec4 shadow_coord4; + +#endif + +#endif + +#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) + +varying highp vec3 diffuse_interp; +varying highp vec3 specular_interp; + +// general for all lights +uniform vec4 light_color; +uniform float light_specular; + +// directional +uniform vec3 light_direction; + +// omni +uniform vec3 light_position; + +uniform float light_range; +uniform vec4 light_attenuation; + +// spot +uniform float light_spot_attenuation; +uniform float light_spot_range; +uniform float light_spot_angle; + +void light_compute( + vec3 N, + vec3 L, + vec3 V, + vec3 light_color, + vec3 attenuation, + float roughness) { + +//this makes lights behave closer to linear, but then addition of lights looks bad +//better left disabled + +//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); +/* +#define SRGB_APPROX(m_var) {\ + float S1 = sqrt(m_var);\ + float S2 = sqrt(S1);\ + float S3 = sqrt(S2);\ + m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ + } +*/ +#define SRGB_APPROX(m_var) + + float NdotL = dot(N, L); + float cNdotL = max(NdotL, 0.0); // clamped NdotL + float NdotV = dot(N, V); + float cNdotV = max(NdotV, 0.0); + +#if defined(DIFFUSE_OREN_NAYAR) + vec3 diffuse_brdf_NL; +#else + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#endif + +#if defined(DIFFUSE_LAMBERT_WRAP) + // energy conserving lambert wrap shader + diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); + +#elif defined(DIFFUSE_OREN_NAYAR) + + { + // see http://mimosa-pudica.net/improved-oren-nayar.html + float LdotV = dot(L, V); + + float s = LdotV - NdotL * NdotV; + float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); + + float sigma2 = roughness * roughness; // TODO: this needs checking + vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); + float B = 0.45 * sigma2 / (sigma2 + 0.09); + + diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); + } +#else + // lambert by default for everything else + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + SRGB_APPROX(diffuse_brdf_NL) + + diffuse_interp += light_color * diffuse_brdf_NL * attenuation; + + if (roughness > 0.0) { + + // D + float specular_brdf_NL = 0.0; + +#if !defined(SPECULAR_DISABLED) + //normalized blinn always unless disabled + vec3 H = normalize(V + L); + float cNdotH = max(dot(N, H), 0.0); + float cVdotH = max(dot(V, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) / (8.0 * 3.141592654); + specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); +#endif + + SRGB_APPROX(specular_brdf_NL) + specular_interp += specular_brdf_NL * light_color * attenuation; + } +} + +#endif + void main() { highp vec4 vertex = vertex_attrib; @@ -209,6 +355,7 @@ void main() { #endif mat4 modelview = camera_matrix * world_matrix; + float roughness = 1.0; #define world_transform world_matrix @@ -252,13 +399,105 @@ VERTEX_SHADER_CODE #ifdef RENDER_DEPTH +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + + vertex_interp.z *= shadow_dual_paraboloid_render_side; + normal_interp.z *= shadow_dual_paraboloid_render_side; + + dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias + + //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges + + highp vec3 vtx = vertex_interp + normalize(vertex_interp) * light_bias; + highp float distance = length(vtx); + vtx = normalize(vtx); + vtx.xy /= 1.0 - vtx.z; + vtx.z = (distance / shadow_dual_paraboloid_render_zfar); + vtx.z = vtx.z * 2.0 - 1.0; + + vertex_interp = vtx; + +#else float z_ofs = light_bias; z_ofs += (1.0 - abs(normal_interp.z)) * light_normal_bias; vertex_interp.z -= z_ofs; +#endif //dual parabolloid + +#endif //depth + +//vertex lighting +#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) + //vertex shaded version of lighting (more limited) + vec3 L; + vec3 light_att; + +#ifdef LIGHT_MODE_OMNI + vec3 light_vec = light_position - vertex_interp; + float light_length = length(light_vec); + + float normalized_distance = light_length / light_range; + + float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); + + vec3 attenuation = vec3(omni_attenuation); + light_att = vec3(omni_attenuation); + + L = normalize(light_vec); + +#endif + +#ifdef LIGHT_MODE_SPOT + + vec3 light_rel_vec = light_position - vertex_interp; + float light_length = length(light_rel_vec); + float normalized_distance = light_length / light_range; + + float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); + vec3 spot_dir = light_direction; + + float spot_cutoff = light_spot_angle; + + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + + spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); + + light_att = vec3(spot_attenuation); + L = normalize(light_rel_vec); #endif +#ifdef LIGHT_MODE_DIRECTIONAL + vec3 light_vec = -light_direction; + light_att = vec3(1.0); //no base attenuation + L = normalize(light_vec); +#endif + + diffuse_interp = vec3(0.0); + specular_interp = vec3(0.0); + light_compute(normal_interp, L, -normalize(vertex_interp), light_color.rgb, light_att, roughness); + +#endif + +//shadows (for both vertex and fragment) +#if defined(USE_SHADOW) && defined(USE_LIGHTING) + + vec4 vi4 = vec4(vertex_interp, 1.0); + shadow_coord = light_shadow_matrix * vi4; + +#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) + shadow_coord2 = light_shadow_matrix2 * vi4; +#endif + +#if defined(LIGHT_USE_PSSM4) + shadow_coord3 = light_shadow_matrix3 * vi4; + shadow_coord3 = light_shadow_matrix3 * vi4; + +#endif + +#endif //use shadow and use lighting + gl_Position = projection_matrix * vec4(vertex_interp, 1.0); } @@ -276,12 +515,13 @@ VERTEX_SHADER_CODE #define highp #else precision mediump float; -precision mediump int; +precision highp int; #endif #include "stdlib.glsl" #define M_PI 3.14159265359 +#define SHADER_IS_SRGB true // // uniforms @@ -301,10 +541,11 @@ uniform highp float time; uniform vec2 screen_pixel_size; #endif -uniform highp sampler2D depth_buffer; //texunit:-5 +// I think supporting this in GLES2 is difficult +// uniform highp sampler2D depth_buffer; #if defined(SCREEN_TEXTURE_USED) -uniform highp sampler2D screen_texture; //texunit:-6 +uniform highp sampler2D screen_texture; //texunit:-4 #endif #ifdef USE_RADIANCE_MAP @@ -323,49 +564,68 @@ uniform float ambient_sky_contribution; uniform vec4 ambient_color; uniform float ambient_energy; -#ifdef LIGHT_PASS +#ifdef USE_LIGHTING -#define LIGHT_TYPE_DIRECTIONAL 0 -#define LIGHT_TYPE_OMNI 1 -#define LIGHT_TYPE_SPOT 2 +#ifdef USE_VERTEX_LIGHTING -// general for all lights -uniform int light_type; +//get from vertex +varying highp vec3 diffuse_interp; +varying highp vec3 specular_interp; -uniform float light_energy; +#else +//done in fragment +// general for all lights uniform vec4 light_color; uniform float light_specular; // directional uniform vec3 light_direction; - // omni uniform vec3 light_position; -uniform float light_range; uniform vec4 light_attenuation; // spot uniform float light_spot_attenuation; uniform float light_spot_range; uniform float light_spot_angle; +#endif -// shadows -uniform highp sampler2D light_shadow_atlas; //texunit:-4 -uniform float light_has_shadow; +//this is needed outside above if because dual paraboloid wants it +uniform float light_range; + +#ifdef USE_SHADOW + +uniform highp vec2 shadow_pixel_size; + +#if defined(LIGHT_MODE_OMNI) || defined(LIGHT_MODE_SPOT) +uniform highp sampler2D light_shadow_atlas; //texunit:-3 +#endif + +#ifdef LIGHT_MODE_DIRECTIONAL +uniform highp sampler2D light_directional_shadow; // texunit:-3 +uniform highp vec4 light_split_offsets; +#endif + +varying highp vec4 shadow_coord; + +#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) +varying highp vec4 shadow_coord2; +#endif + +#if defined(LIGHT_USE_PSSM4) + +varying highp vec4 shadow_coord3; +varying highp vec4 shadow_coord4; + +#endif -uniform mat4 light_shadow_matrix; uniform vec4 light_clamp; -// directional shadow +#endif // light shadow -uniform highp sampler2D light_directional_shadow; // texunit:-4 -uniform vec4 light_split_offsets; +// directional shadow -uniform mat4 light_shadow_matrix1; -uniform mat4 light_shadow_matrix2; -uniform mat4 light_shadow_matrix3; -uniform mat4 light_shadow_matrix4; #endif // @@ -406,7 +666,79 @@ FRAGMENT_SHADER_GLOBALS /* clang-format on */ -#ifdef LIGHT_PASS +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + +varying highp float dp_clip; + +#endif + +#ifdef USE_LIGHTING + +// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. +// We're dividing this factor off because the overall term we'll end up looks like +// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): +// +// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) +// +// We're basically regouping this as +// +// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] +// +// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. +// +// The contents of the D and G (G1) functions (GGX) are taken from +// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). +// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). + +float G_GGX_2cos(float cos_theta_m, float alpha) { + // Schlick's approximation + // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) + // Eq. (19), although see Heitz (2014) the about the problems with his derivation. + // It nevertheless approximates GGX well with k = alpha/2. + float k = 0.5 * alpha; + return 0.5 / (cos_theta_m * (1.0 - k) + k); + + // float cos2 = cos_theta_m * cos_theta_m; + // float sin2 = (1.0 - cos2); + // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); +} + +float D_GGX(float cos_theta_m, float alpha) { + float alpha2 = alpha * alpha; + float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; + return alpha2 / (M_PI * d * d); +} + +float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float s_x = alpha_x * cos_phi; + float s_y = alpha_y * sin_phi; + return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); +} + +float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float r_x = cos_phi / alpha_x; + float r_y = sin_phi / alpha_y; + float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); + return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); +} + +float SchlickFresnel(float u) { + float m = 1.0 - u; + float m2 = m * m; + return m2 * m2 * m; // pow(m,5) +} + +float GTR1(float NdotH, float a) { + if (a >= 1.0) return 1.0 / M_PI; + float a2 = a * a; + float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; + return (a2 - 1.0) / (M_PI * log(a2) * t); +} + void light_compute( vec3 N, vec3 L, @@ -428,52 +760,267 @@ void light_compute( inout vec3 diffuse_light, inout vec3 specular_light) { +//this makes lights behave closer to linear, but then addition of lights looks bad +//better left disabled + +//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); +/* +#define SRGB_APPROX(m_var) {\ + float S1 = sqrt(m_var);\ + float S2 = sqrt(S1);\ + float S3 = sqrt(S2);\ + m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ + } +*/ +#define SRGB_APPROX(m_var) + +#if defined(USE_LIGHT_SHADER_CODE) + // light is written by the light shader + + vec3 normal = N; + vec3 albedo = diffuse_color; + vec3 light = L; + vec3 view = V; + + /* clang-format off */ + +LIGHT_SHADER_CODE + + /* clang-format on */ + +#else float NdotL = dot(N, L); - float cNdotL = max(NdotL, 0.0); + float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); - { - // calculate diffuse reflection - - // TODO hardcode Oren Nayar for now - float diffuse_brdf_NL; + if (metallic < 1.0) { +#if defined(DIFFUSE_OREN_NAYAR) + vec3 diffuse_brdf_NL; +#else + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#endif +#if defined(DIFFUSE_LAMBERT_WRAP) + // energy conserving lambert wrap shader diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); - // diffuse_brdf_NL = cNdotL * (1.0 / M_PI); + +#elif defined(DIFFUSE_OREN_NAYAR) + + { + // see http://mimosa-pudica.net/improved-oren-nayar.html + float LdotV = dot(L, V); + + float s = LdotV - NdotL * NdotV; + float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); + + float sigma2 = roughness * roughness; // TODO: this needs checking + vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); + float B = 0.45 * sigma2 / (sigma2 + 0.09); + + diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); + } + +#elif defined(DIFFUSE_TOON) + + diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); + +#elif defined(DIFFUSE_BURLEY) + + { + + vec3 H = normalize(V + L); + float cLdotH = max(0.0, dot(L, H)); + + float FD90 = 0.5 + 2.0 * cLdotH * cLdotH * roughness; + float FdV = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotV); + float FdL = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotL); + diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; + /* + float energyBias = mix(roughness, 0.0, 0.5); + float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); + float fd90 = energyBias + 2.0 * VoH * VoH * roughness; + float f0 = 1.0; + float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); + float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); + + diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; + */ + } +#else + // lambert + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + SRGB_APPROX(diffuse_brdf_NL) diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; + +#if defined(TRANSMISSION_USED) + diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; +#endif + +#if defined(LIGHT_USE_RIM) + float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); + diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; +#endif } - { - // calculate specular reflection + if (roughness > 0.0) { + + // D + + float specular_brdf_NL; + +#if defined(SPECULAR_BLINN) + + //normalized blinn + vec3 H = normalize(V + L); + float cNdotH = max(dot(N, H), 0.0); + float cVdotH = max(dot(V, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) / (8.0 * 3.141592654); + specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); + +#elif defined(SPECULAR_PHONG) vec3 R = normalize(-reflect(L, N)); - float cRdotV = max(dot(R, V), 0.0); - float blob_intensity = pow(cRdotV, (1.0 - roughness) * 256.0); - specular_light += light_color * attenuation * blob_intensity * specular_blob_intensity; + float cRdotV = max(0.0, dot(R, V)); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float phong = pow(cRdotV, shininess); + phong *= (shininess + 8.0) / (8.0 * 3.141592654); + specular_brdf_NL = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); + +#elif defined(SPECULAR_TOON) + + vec3 R = normalize(-reflect(L, N)); + float RdotV = dot(R, V); + float mid = 1.0 - roughness; + mid *= mid; + specular_brdf_NL = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; + +#elif defined(SPECULAR_DISABLED) + // none.. + specular_brdf_NL = 0.0; +#elif defined(SPECULAR_SCHLICK_GGX) + // shlick+ggx as default + + vec3 H = normalize(V + L); + + float cNdotH = max(dot(N, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + +#if defined(LIGHT_USE_ANISOTROPY) + + float aspect = sqrt(1.0 - anisotropy * 0.9); + float rx = roughness / aspect; + float ry = roughness * aspect; + float ax = rx * rx; + float ay = ry * ry; + float XdotH = dot(T, H); + float YdotH = dot(B, H); + float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); + float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + +#else + float alpha = roughness * roughness; + float D = D_GGX(cNdotH, alpha); + float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); +#endif + // F + //float F0 = 1.0; + //float cLdotH5 = SchlickFresnel(cLdotH); + //float F = mix(cLdotH5, 1.0, F0); + + specular_brdf_NL = cNdotL * D /* F */ * G; + +#endif + + SRGB_APPROX(specular_brdf_NL) + specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; + +#if defined(LIGHT_USE_CLEARCOAT) + if (clearcoat_gloss > 0.0) { +#if !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) + vec3 H = normalize(V + L); +#endif +#if !defined(SPECULAR_SCHLICK_GGX) + float cNdotH = max(dot(N, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + float cLdotH5 = SchlickFresnel(cLdotH); +#endif + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Fr = mix(.04, 1.0, cLdotH5); + float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + + float specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + + specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; + } +#endif } + +#endif //defined(USE_LIGHT_SHADER_CODE) } +#endif // shadows +#ifdef USE_SHADOW + +#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, texture2D(p_shadow, p_pos).r) + float sample_shadow( highp sampler2D shadow, - vec2 shadow_pixel_size, - vec2 pos, - float depth, - vec4 clamp_rect) { - // vec4 depth_value = texture2D(shadow, pos); - - // return depth_value.z; - return texture2DProj(shadow, vec4(pos, depth, 1.0)).r; - // return (depth_value.x + depth_value.y + depth_value.z + depth_value.w) / 4.0; + highp vec2 pos, + highp float depth) { + +#ifdef SHADOW_MODE_PCF_13 + + float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth); + return avg * (1.0 / 13.0); +#endif + +#ifdef SHADOW_MODE_PCF_5 + + float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); + return avg * (1.0 / 5.0); + +#endif + +#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) + + return SAMPLE_SHADOW_TEXEL(shadow, pos, depth); +#endif } #endif void main() { +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + + if (dp_clip > 0.0) + discard; +#endif highp vec3 vertex = vertex_interp; vec3 albedo = vec3(1.0); vec3 transmission = vec3(0.0); @@ -540,11 +1087,8 @@ FRAGMENT_SHADER_CODE vec3 specular_light = vec3(0.0, 0.0, 0.0); vec3 diffuse_light = vec3(0.0, 0.0, 0.0); - vec3 ambient_light = vec3(0.0, 0.0, 0.0); - vec3 env_reflection_light = vec3(0.0, 0.0, 0.0); - vec3 eye_position = -normalize(vertex_interp); #ifdef ALPHA_SCISSOR_USED @@ -553,287 +1097,288 @@ FRAGMENT_SHADER_CODE } #endif +#ifdef BASE_PASS + //none +#ifdef USE_RADIANCE_MAP + + vec3 ref_vec = reflect(-eye_position, N); + ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz); + + ref_vec.z *= -1.0; + + specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy; + + { + vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz); + vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).xyz * bg_energy; + + ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution); + } + +#else + + ambient_light = ambient_color.rgb; + +#endif + + ambient_light *= ambient_energy; + +#endif //BASE PASS + // // Lighting // -#ifdef LIGHT_PASS - - if (light_type == LIGHT_TYPE_OMNI) { - vec3 light_vec = light_position - vertex; - float light_length = length(light_vec); +#ifdef USE_LIGHTING - float normalized_distance = light_length / light_range; +#ifndef USE_VERTEX_LIGHTING + vec3 L; +#endif + vec3 light_att = vec3(1.0); - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); +#ifdef LIGHT_MODE_OMNI - vec3 attenuation = vec3(omni_attenuation); +#ifndef USE_VERTEX_LIGHTING + vec3 light_vec = light_position - vertex; + float light_length = length(light_vec); - if (light_has_shadow > 0.5) { - highp vec3 splane = (light_shadow_matrix * vec4(vertex, 1.0)).xyz; - float shadow_len = length(splane); + float normalized_distance = light_length / light_range; - splane = normalize(splane); + float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); - vec4 clamp_rect = light_clamp; + light_att = vec3(omni_attenuation); + L = normalize(light_vec); - if (splane.z >= 0.0) { - splane.z += 1.0; +#endif - clamp_rect.y += clamp_rect.w; - } else { - splane.z = 1.0 - splane.z; - } +#ifdef USE_SHADOW + { + highp vec3 splane = shadow_coord.xyz; + float shadow_len = length(splane); - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len / light_range; + splane = normalize(splane); - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + vec4 clamp_rect = light_clamp; - float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), splane.xy, splane.z, clamp_rect); + if (splane.z >= 0.0) { + splane.z += 1.0; - if (shadow > splane.z) { - } else { - attenuation = vec3(0.0); - } + clamp_rect.y += clamp_rect.w; + } else { + splane.z = 1.0 - splane.z; } - light_compute( - normal, - normalize(light_vec), - eye_position, - binormal, - tangent, - light_color.xyz * light_energy, - attenuation, - albedo, - transmission, - specular * light_specular, - roughness, - metallic, - rim, - rim_tint, - clearcoat, - clearcoat_gloss, - anisotropy, - diffuse_light, - specular_light); - - } else if (light_type == LIGHT_TYPE_DIRECTIONAL) { - - vec3 light_vec = -light_direction; - vec3 attenuation = vec3(1.0, 1.0, 1.0); - - float depth_z = -vertex.z; - - if (light_has_shadow > 0.5) { + splane.xy /= splane.z; + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = shadow_len / light_range; + + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + + float shadow = sample_shadow(light_shadow_atlas, splane.xy, splane.z); + + light_att *= shadow; + } +#endif + +#endif //type omni +#ifdef LIGHT_MODE_DIRECTIONAL + +#ifndef USE_VERTEX_LIGHTING + vec3 light_vec = -light_direction; + L = normalize(light_vec); +#endif + float depth_z = -vertex.z; + +#ifdef USE_SHADOW + { #ifdef LIGHT_USE_PSSM4 - if (depth_z < light_split_offsets.w) { + if (depth_z < light_split_offsets.w) { #elif defined(LIGHT_USE_PSSM2) - if (depth_z < light_split_offsets.y) { + if (depth_z < light_split_offsets.y) { #else - if (depth_z < light_split_offsets.x) { -#endif + if (depth_z < light_split_offsets.x) { +#endif //pssm2 - vec3 pssm_coord; - float pssm_fade = 0.0; + vec3 pssm_coord; + float pssm_fade = 0.0; #ifdef LIGHT_USE_PSSM_BLEND - float pssm_blend; - vec3 pssm_coord2; - bool use_blend = true; + float pssm_blend; + vec3 pssm_coord2; + bool use_blend = true; #endif #ifdef LIGHT_USE_PSSM4 - if (depth_z < light_split_offsets.y) { - if (depth_z < light_split_offsets.x) { - highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; + if (depth_z < light_split_offsets.y) { + if (depth_z < light_split_offsets.x) { + highp vec4 splane = shadow_coord; + pssm_coord = splane.xyz / splane.w; #ifdef LIGHT_USE_PSSM_BLEND - splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; + splane = shadow_coord2; + pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); #endif - } else { - highp vec4 splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; + } else { + highp vec4 splane = shadow_coord2; + pssm_coord = splane.xyz / splane.w; #ifdef LIGHT_USE_PSSM_BLEND - splane = (light_shadow_matrix3 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; + splane = shadow_coord3; + pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); + pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); #endif - } - } else { - if (depth_z < light_split_offsets.z) { + } + } else { + if (depth_z < light_split_offsets.z) { - highp vec4 splane = (light_shadow_matrix3 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; + highp vec4 splane = shadow_coord3; + pssm_coord = splane.xyz / splane.w; #if defined(LIGHT_USE_PSSM_BLEND) - splane = (light_shadow_matrix4 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); + splane = shadow_coord4; + pssm_coord2 = splane.xyz / splane.w; + pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); #endif - } else { + } else { - highp vec4 splane = (light_shadow_matrix4 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); + highp vec4 splane = shadow_coord4; + pssm_coord = splane.xyz / splane.w; + pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); #if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; + use_blend = false; #endif - } } + } #endif // LIGHT_USE_PSSM4 #ifdef LIGHT_USE_PSSM2 - if (depth_z < light_split_offsets.x) { + if (depth_z < light_split_offsets.x) { - highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; + highp vec4 splane = shadow_coord; + pssm_coord = splane.xyz / splane.w; #ifdef LIGHT_USE_PSSM_BLEND - splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); + splane = shadow_coord2; + pssm_coord2 = splane.xyz / splane.w; + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); #endif - } else { - highp vec4 splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); + } else { + highp vec4 splane = shadow_coord2; + pssm_coord = splane.xyz / splane.w; + pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); #ifdef LIGHT_USE_PSSM_BLEND - use_blend = false; + use_blend = false; #endif - } + } #endif // LIGHT_USE_PSSM2 #if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - { - highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - } + { + highp vec4 splane = shadow_coord; + pssm_coord = splane.xyz / splane.w; + } #endif - float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord.xy, pssm_coord.z, light_clamp); + float shadow = sample_shadow(light_directional_shadow, pssm_coord.xy, pssm_coord.z); #ifdef LIGHT_USE_PSSM_BLEND - if (use_blend) { - shadow = mix(shadow, sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord2.xy, pssm_coord2.z, light_clamp), pssm_blend); - } + if (use_blend) { + shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2.xy, pssm_coord2.z), pssm_blend); + } #endif - attenuation *= shadow; - } + light_att *= shadow; } + } +#endif //use shadow - light_compute(normal, - normalize(light_vec), - eye_position, - binormal, - tangent, - light_color.xyz * light_energy, - attenuation, - albedo, - transmission, - specular * light_specular, - roughness, - metallic, - rim, - rim_tint, - clearcoat, - clearcoat_gloss, - anisotropy, - diffuse_light, - specular_light); - } else if (light_type == LIGHT_TYPE_SPOT) { - - vec3 light_att = vec3(1.0); - - if (light_has_shadow > 0.5) { - highp vec4 splane = (light_shadow_matrix * vec4(vertex, 1.0)); - splane.xyz /= splane.w; - - float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), splane.xy, splane.z, light_clamp); - - if (shadow > splane.z) { - } else { - light_att = vec3(0.0); - } - } +#endif - vec3 light_rel_vec = light_position - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length / light_range; - - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); - vec3 spot_dir = light_direction; - - float spot_cutoff = light_spot_angle; - - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); - - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - - light_att *= vec3(spot_attenuation); - - light_compute( - normal, - normalize(light_rel_vec), - eye_position, - binormal, - tangent, - light_color.xyz * light_energy, - light_att, - albedo, - transmission, - specular * light_specular, - roughness, - metallic, - rim, - rim_tint, - clearcoat, - clearcoat_gloss, - anisotropy, - diffuse_light, - specular_light); - } +#ifdef LIGHT_MODE_SPOT - gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); -#else + light_att = vec3(1.0); -#ifdef RENDER_DEPTH +#ifndef USE_VERTEX_LIGHTING -#else + vec3 light_rel_vec = light_position - vertex; + float light_length = length(light_rel_vec); + float normalized_distance = light_length / light_range; -#ifdef USE_RADIANCE_MAP + float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); + vec3 spot_dir = light_direction; - vec3 ref_vec = reflect(-eye_position, N); - ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz); + float spot_cutoff = light_spot_angle; - ref_vec.z *= -1.0; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + + spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - env_reflection_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy; + light_att = vec3(spot_attenuation); + + L = normalize(light_rel_vec); + +#endif +#ifdef USE_SHADOW { - vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz); - vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).xyz * bg_energy; + highp vec4 splane = shadow_coord; + splane.xyz /= splane.w; - ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution); + float shadow = sample_shadow(light_shadow_atlas, splane.xy, splane.z); + light_att *= shadow; } +#endif - ambient_light *= ambient_energy; +#endif + +#ifdef USE_VERTEX_LIGHTING + //vertex lighting + + specular_light += specular_interp * specular * light_att; + diffuse_light += diffuse_interp * albedo * light_att; + +#else + //fragment lighting + light_compute( + normal, + L, + eye_position, + binormal, + tangent, + light_color.xyz, + light_att, + albedo, + transmission, + specular * light_specular, + roughness, + metallic, + rim, + rim_tint, + clearcoat, + clearcoat_gloss, + anisotropy, + diffuse_light, + specular_light); + +#endif //vertex lighting + +#endif //USE_LIGHTING + //compute and merge + +#ifndef RENDER_DEPTH + +#ifdef SHADELESS - specular_light += env_reflection_light; + gl_FragColor = vec4(albedo, alpha); +#else ambient_light *= albedo; @@ -865,10 +1410,7 @@ FRAGMENT_SHADER_CODE gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); // gl_FragColor = vec4(normal, 1.0); -#else - gl_FragColor = vec4(albedo, alpha); -#endif -#endif // RENDER_DEPTH +#endif //unshaded -#endif // lighting +#endif // not RENDER_DEPTH } diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index c9bdc6f5c3..856c83e297 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1223,8 +1223,6 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons bool rebind_shader = true; - Size2 rt_size = Size2(storage->frame.current_rt->width, storage->frame.current_rt->height); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false); glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 1e43651d54..1fcd4e02ac 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1282,6 +1282,8 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m case ShaderLanguage::TYPE_SAMPLER2DARRAY: { // TODO } break; + + default: {} } } @@ -1509,6 +1511,7 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo } } break; + default: {} } } @@ -1557,8 +1560,11 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES3::MultiMesh *>(e->owner); RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry); - int amount = MAX(multi_mesh->size, multi_mesh->visible_instances); + int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); + if (amount == -1) { + amount = multi_mesh->size; + } #ifdef DEBUG_ENABLED if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->array_wireframe_id) { @@ -1827,6 +1833,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { } } break; + default: {} } } @@ -2364,14 +2371,15 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G e->sort_key |= uint64_t(e->geometry->index) << RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT; e->sort_key |= uint64_t(e->instance->base_type) << RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT; - if (!p_depth_pass) { + if (e->material->last_pass != render_pass) { + e->material->last_pass = render_pass; + e->material->index = current_material_index++; + } - if (e->material->last_pass != render_pass) { - e->material->last_pass = render_pass; - e->material->index = current_material_index++; - } + e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; + e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT; - e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; + if (!p_depth_pass) { if (e->instance->gi_probe_instances.size()) { e->sort_key |= SORT_KEY_GI_PROBES_FLAG; @@ -2386,9 +2394,6 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G } 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; - e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; } /* @@ -2738,7 +2743,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform ubo_data.shadow_split_offsets[j] = li->shadow_transform[j].split; - Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse(); + Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).affine_inverse(); CameraMatrix bias; bias.set_light_bias(); @@ -3035,13 +3040,14 @@ void RasterizerSceneGLES3::_setup_reflections(RID *p_reflection_probe_cull_resul reflection_ubo.ambient[3] = rpi->probe_ptr->interior_ambient_probe_contrib; } else { Color ambient_linear; - float contrib = 0; + // FIXME: contrib was retrieved but never used, is it meant to be set as ambient[3]? (GH-20361) + //float contrib = 0; if (p_env) { ambient_linear = p_env->ambient_color.to_linear(); ambient_linear.r *= p_env->ambient_energy; ambient_linear.g *= p_env->ambient_energy; ambient_linear.b *= p_env->ambient_energy; - contrib = p_env->ambient_sky_contribution; + //contrib = p_env->ambient_sky_contribution; } reflection_ubo.ambient[0] = ambient_linear.r; @@ -3131,7 +3137,6 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p current_material_index = 0; state.used_sss = false; state.used_screen_texture = false; - //fill list for (int i = 0; i < p_cull_count; i++) { @@ -3209,6 +3214,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p } } break; + default: {} } } } @@ -4295,7 +4301,6 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const if (env) { switch (env->bg_mode) { case VS::ENV_BG_COLOR_SKY: - case VS::ENV_BG_SKY: sky = storage->sky_owner.getornull(env->sky); @@ -4333,6 +4338,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); break; + default: {} } } @@ -4501,7 +4507,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ RasterizerStorageGLES3::Light *light = storage->light_owner.getornull(light_instance->light); ERR_FAIL_COND(!light); - uint32_t x, y, width, height, vp_height; + uint32_t x, y, width, height; float dp_direction = 0.0; float zfar = 0; @@ -4583,7 +4589,6 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS] * bias_mult; normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult; fbo = directional_shadow.fbo; - vp_height = directional_shadow.size; } else { //set from shadow atlas @@ -4593,7 +4598,6 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); fbo = shadow_atlas->fbo; - vp_height = shadow_atlas->size; uint32_t key = shadow_atlas->shadow_owners[p_light]; @@ -5147,13 +5151,13 @@ void RasterizerSceneGLES3::initialize() { void RasterizerSceneGLES3::iteration() { - shadow_filter_mode = ShadowFilterMode(int(ProjectSettings::get_singleton()->get("rendering/quality/shadows/filter_mode"))); - subsurface_scatter_follow_surface = ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/follow_surface"); - subsurface_scatter_weight_samples = ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/weight_samples"); - subsurface_scatter_quality = SubSurfaceScatterQuality(int(ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/quality"))); - subsurface_scatter_size = ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/scale"); + shadow_filter_mode = ShadowFilterMode(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); + subsurface_scatter_follow_surface = GLOBAL_GET("rendering/quality/subsurface_scattering/follow_surface"); + subsurface_scatter_weight_samples = GLOBAL_GET("rendering/quality/subsurface_scattering/weight_samples"); + subsurface_scatter_quality = SubSurfaceScatterQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/quality"))); + subsurface_scatter_size = GLOBAL_GET("rendering/quality/subsurface_scattering/scale"); - state.scene_shader.set_conditional(SceneShaderGLES3::VCT_QUALITY_HIGH, ProjectSettings::get_singleton()->get("rendering/quality/voxel_cone_tracing/high_quality")); + state.scene_shader.set_conditional(SceneShaderGLES3::VCT_QUALITY_HIGH, GLOBAL_GET("rendering/quality/voxel_cone_tracing/high_quality")); } void RasterizerSceneGLES3::finalize() { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 25e7bd0424..c72e8eecda 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1072,7 +1072,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) uint32_t *ptr = (uint32_t *)wb.ptr(); uint32_t num_pixels = data_size / 4; - for (int ofs = 0; ofs < num_pixels; ofs++) { + for (uint32_t ofs = 0; ofs < num_pixels; ofs++) { uint32_t px = ptr[ofs]; uint32_t a = px >> 30 & 0xFF; @@ -1905,6 +1905,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { actions = &shaders.actions_particles; actions->uniforms = &p_shader->uniforms; } break; + case VS::SHADER_MAX: break; // Can't happen, but silences warning } Error err = shaders.compiler.compile(p_shader->mode, p_shader->code, actions, p_shader->path, gen_code); @@ -2028,6 +2029,14 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyIn pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture"; } break; + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: { + + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "TextureArray"; + } break; case ShaderLanguage::TYPE_SAMPLER3D: case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: { @@ -4961,6 +4970,7 @@ void RasterizerStorageGLES3::light_set_param(RID p_light, VS::LightParam p_param light->version++; light->instance_change_notify(); } break; + default: {} } light->param[p_param] = p_value; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 11c84e7db8..dbc8507951 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -31,6 +31,7 @@ #include "shader_compiler_gles3.h" #include "core/os/os.h" +#include "core/project_settings.h" #define SL ShaderLanguage @@ -78,6 +79,12 @@ static int _get_datatype_size(SL::DataType p_type) { case SL::TYPE_SAMPLER2D: return 16; case SL::TYPE_ISAMPLER2D: return 16; case SL::TYPE_USAMPLER2D: return 16; + case SL::TYPE_SAMPLER2DARRAY: return 16; + case SL::TYPE_ISAMPLER2DARRAY: return 16; + case SL::TYPE_USAMPLER2DARRAY: return 16; + case SL::TYPE_SAMPLER3D: return 16; + case SL::TYPE_ISAMPLER3D: return 16; + case SL::TYPE_USAMPLER3D: return 16; case SL::TYPE_SAMPLERCUBE: return 16; } @@ -111,6 +118,12 @@ static int _get_datatype_alignment(SL::DataType p_type) { case SL::TYPE_SAMPLER2D: return 16; case SL::TYPE_ISAMPLER2D: return 16; case SL::TYPE_USAMPLER2D: return 16; + case SL::TYPE_SAMPLER2DARRAY: return 16; + case SL::TYPE_ISAMPLER2DARRAY: return 16; + case SL::TYPE_USAMPLER2DARRAY: return 16; + case SL::TYPE_SAMPLER3D: return 16; + case SL::TYPE_ISAMPLER3D: return 16; + case SL::TYPE_USAMPLER3D: return 16; case SL::TYPE_SAMPLERCUBE: return 16; } @@ -860,6 +873,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer"; actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; + actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; //for light actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view"; @@ -901,12 +915,24 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); + + if (!force_lambert) { + actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + } + actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); + + if (!force_blinn) { + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + } else { + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; + } + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 2a3b8a9b91..799179e8d4 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -122,6 +122,11 @@ bool ShaderGLES3::bind() { ERR_FAIL_COND_V(!version, false); + if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation). + glUseProgram(0); + return false; + } + glUseProgram(version->id); DEBUG_TEST_ERROR("Use Program"); diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h index ca74317218..9db4942163 100644 --- a/drivers/gles3/shader_gles3.h +++ b/drivers/gles3/shader_gles3.h @@ -336,6 +336,7 @@ public: } uint32_t get_version() const { return new_conditional_version.version; } + _FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; } void set_uniform_camera(int p_idx, const CameraMatrix &p_mat) { diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 12cbe02d0c..7da20dfa00 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -3,6 +3,8 @@ #define M_PI 3.14159265359 +#define SHADER_IS_SRGB false + /* from VisualServer: @@ -514,6 +516,7 @@ VERTEX_SHADER_CODE /* clang-format off */ [fragment] + /* texture unit usage, N is max_texture_unity-N 1-skeleton @@ -533,6 +536,7 @@ uniform highp mat4 world_transform; /* clang-format on */ #define M_PI 3.14159265359 +#define SHADER_IS_SRGB false /* Varyings */ @@ -1020,16 +1024,27 @@ LIGHT_SHADER_CODE #if defined(SPECULAR_BLINN) + //normalized blinn vec3 H = normalize(V + L); float cNdotH = max(dot(N, H), 0.0); - float intensity = pow(cNdotH, (1.0 - roughness) * 256.0); + float cVdotH = max(dot(V, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) / (8.0 * 3.141592654); + float intensity = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); + specular_light += light_color * intensity * specular_blob_intensity * attenuation; #elif defined(SPECULAR_PHONG) vec3 R = normalize(-reflect(L, N)); float cRdotV = max(0.0, dot(R, V)); - float intensity = pow(cRdotV, (1.0 - roughness) * 256.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float phong = pow(cRdotV, shininess); + phong *= (shininess + 8.0) / (8.0 * 3.141592654); + float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); + specular_light += light_color * intensity * specular_blob_intensity * attenuation; #elif defined(SPECULAR_TOON) @@ -1070,11 +1085,11 @@ LIGHT_SHADER_CODE float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); #endif // F - float F0 = 1.0; // FIXME - float cLdotH5 = SchlickFresnel(cLdotH); - float F = mix(cLdotH5, 1.0, F0); + //float F0 = 1.0; + //float cLdotH5 = SchlickFresnel(cLdotH); + //float F = mix(cLdotH5, 1.0, F0); - float specular_brdf_NL = cNdotL * D * F * G; + float specular_brdf_NL = cNdotL * D /* F */ * G; specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; #endif diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 7578fbc0a0..9c02549e39 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -43,10 +43,13 @@ void AudioDriverPulseAudio::pa_state_cb(pa_context *c, void *userdata) { case PA_CONTEXT_FAILED: ad->pa_ready = -1; break; - case PA_CONTEXT_READY: ad->pa_ready = 1; break; + default: + // TODO: Check if we want to handle some of the other + // PA context states like PA_CONTEXT_UNCONNECTED. + break; } } @@ -340,7 +343,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { unsigned int out_idx = 0; for (unsigned int i = 0; i < ad->buffer_frames; i++) { - for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) { + for (int j = 0; j < ad->pa_map.channels - 1; j++) { ad->samples_out.write[out_idx++] = ad->samples_in[in_idx++] >> 16; } uint32_t l = ad->samples_in[in_idx++]; diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 6e0bf97711..3f03175403 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -94,7 +94,7 @@ #endif -static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) { +size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) { memset(p_addr, 0, sizeof(struct sockaddr_storage)); if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket @@ -126,12 +126,12 @@ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Addres addr4->sin_addr.s_addr = INADDR_ANY; } - copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16); + copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4); return sizeof(sockaddr_in); } } -static void _set_ip_port(IP_Address &r_ip, uint16_t &r_port, struct sockaddr_storage *p_addr) { +void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) { if (p_addr->ss_family == AF_INET) { @@ -559,7 +559,7 @@ void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) { void NetSocketPosix::set_tcp_no_delay_enabled(bool p_enabled) { ERR_FAIL_COND(!is_open()); - ERR_FAIL_COND(_ip_type != TYPE_TCP); + ERR_FAIL_COND(!_is_stream); // Not TCP int par = p_enabled ? 1 : 0; if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, SOCK_CBUF(&par), sizeof(int)) < 0) { @@ -612,7 +612,7 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { SOCKET_TYPE fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size); ERR_FAIL_COND_V(fd == SOCK_EMPTY, out); - _set_ip_port(r_ip, r_port, &their_addr); + _set_ip_port(&their_addr, r_ip, r_port); NetSocketPosix *ns = memnew(NetSocketPosix); ns->_set_socket(fd, _ip_type, _is_stream); diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index 8177e01987..010f2ea6e0 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -39,6 +39,7 @@ #define SOCKET_TYPE SOCKET #else +#include <sys/socket.h> #define SOCKET_TYPE int #endif @@ -68,6 +69,8 @@ protected: public: static void make_default(); static void cleanup(); + static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port); + static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type); virtual Error open(Type p_sock_type, IP::Type &ip_type); virtual void close(); diff --git a/drivers/unix/socket_helpers.h b/drivers/unix/socket_helpers.h deleted file mode 100644 index 5b42c13eae..0000000000 --- a/drivers/unix/socket_helpers.h +++ /dev/null @@ -1,156 +0,0 @@ -/*************************************************************************/ -/* socket_helpers.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SOCKET_HELPERS_H -#define SOCKET_HELPERS_H - -#include <string.h> - -#if defined(__MINGW32__) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4) -// Workaround for mingw-w64 < 4.0 -#ifndef IPV6_V6ONLY -#define IPV6_V6ONLY 27 -#endif -#endif - -// helpers for sockaddr -> IP_Address and back, should work for posix and winsock. All implementations should use this - -static size_t _set_sockaddr(struct sockaddr_storage *p_addr, const IP_Address &p_ip, int p_port, IP::Type p_sock_type = IP::TYPE_ANY) { - - memset(p_addr, 0, sizeof(struct sockaddr_storage)); - - ERR_FAIL_COND_V(!p_ip.is_valid(), 0); - - // IPv6 socket - if (p_sock_type == IP::TYPE_IPV6 || p_sock_type == IP::TYPE_ANY) { - - // IPv6 only socket with IPv4 address - ERR_FAIL_COND_V(p_sock_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0); - - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - addr6->sin6_family = AF_INET6; - addr6->sin6_port = htons(p_port); - copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16); - return sizeof(sockaddr_in6); - - } else { // IPv4 socket - - // IPv4 socket with IPv6 address - ERR_FAIL_COND_V(!p_ip.is_ipv4(), 0); - - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - addr4->sin_family = AF_INET; - addr4->sin_port = htons(p_port); // short, network byte order - copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16); - return sizeof(sockaddr_in); - }; -}; - -static size_t _set_listen_sockaddr(struct sockaddr_storage *p_addr, int p_port, IP::Type p_sock_type, const IP_Address p_bind_address) { - - memset(p_addr, 0, sizeof(struct sockaddr_storage)); - if (p_sock_type == IP::TYPE_IPV4) { - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - addr4->sin_family = AF_INET; - addr4->sin_port = htons(p_port); - if (p_bind_address.is_valid()) { - copymem(&addr4->sin_addr.s_addr, p_bind_address.get_ipv4(), 4); - } else { - addr4->sin_addr.s_addr = INADDR_ANY; - } - return sizeof(sockaddr_in); - } else { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - - addr6->sin6_family = AF_INET6; - addr6->sin6_port = htons(p_port); - if (p_bind_address.is_valid()) { - copymem(&addr6->sin6_addr.s6_addr, p_bind_address.get_ipv6(), 16); - } else { - addr6->sin6_addr = in6addr_any; - } - return sizeof(sockaddr_in6); - }; -}; - -static int _socket_create(IP::Type &p_type, int type, int protocol) { - - ERR_FAIL_COND_V(p_type > IP::TYPE_ANY || p_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER); - - int family = p_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6; - int sockfd = socket(family, type, protocol); - - if (sockfd == -1 && p_type == IP::TYPE_ANY) { - // Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket - // in place of a dual stack one, and further calls to _set_sock_addr will work as expected. - p_type = IP::TYPE_IPV4; - family = AF_INET; - sockfd = socket(family, type, protocol); - } - - ERR_FAIL_COND_V(sockfd == -1, -1); - - if (family == AF_INET6) { - // Select IPv4 over IPv6 mapping - int opt = p_type != IP::TYPE_ANY; - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&opt, sizeof(opt)) != 0) { - WARN_PRINT("Unable to set/unset IPv4 address mapping over IPv6"); - } - } - if (protocol == IPPROTO_UDP && p_type != IP::TYPE_IPV6) { - // Enable broadcasting for UDP sockets if it's not IPv6 only (IPv6 has no broadcast option). - int broadcast = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)) != 0) { - WARN_PRINT("Error when enabling broadcasting"); - } - } - - return sockfd; -} - -static void _set_ip_addr_port(IP_Address &r_ip, int &r_port, struct sockaddr_storage *p_addr) { - - if (p_addr->ss_family == AF_INET) { - - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); - - r_port = ntohs(addr4->sin_port); - - } else if (p_addr->ss_family == AF_INET6) { - - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - r_ip.set_ipv6(addr6->sin6_addr.s6_addr); - - r_port = ntohs(addr6->sin6_port); - }; -}; - -#endif diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index ac28fb9b99..77be561477 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "animation_track_editor.h" + #include "animation_track_editor_plugins.h" #include "core/os/keyboard.h" #include "editor/animation_bezier_editor.h" @@ -772,9 +773,6 @@ void AnimationTimelineEdit::_notification(int p_what) { hsize_rect = Rect2(get_name_limit() - hsize_icon->get_width() - 2 * EDSCALE, (get_size().height - hsize_icon->get_height()) / 2, hsize_icon->get_width(), hsize_icon->get_height()); draw_texture(hsize_icon, hsize_rect.position); - float keys_from = get_value(); - float keys_to = keys_from + zoomw / scale; - { float time_min = 0; float time_max = animation->get_length(); @@ -4923,8 +4921,8 @@ AnimationTrackEditor::AnimationTrackEditor() { //this shortcut will be checked from the track itself. so no need to enable it here (will conflict with scenetree dock) edit->get_popup()->add_separator(); - edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Goto Next Step"), KEY_MASK_CMD | KEY_RIGHT), EDIT_GOTO_NEXT_STEP); - edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Goto Prev Step"), KEY_MASK_CMD | KEY_LEFT), EDIT_GOTO_PREV_STEP); + edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KEY_MASK_CMD | KEY_RIGHT), EDIT_GOTO_NEXT_STEP); + edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KEY_MASK_CMD | KEY_LEFT), EDIT_GOTO_PREV_STEP); edit->get_popup()->add_separator(); edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION); edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 08fd8a1319..38bdba31ea 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -209,6 +209,10 @@ void EditorFileDialog::update_dir() { case MODE_OPEN_DIR: get_ok()->set_text(TTR("Select Current Folder")); break; + case MODE_OPEN_ANY: + case MODE_SAVE_FILE: + // FIXME: Implement, or refactor to avoid duplication with set_mode + break; } } @@ -504,6 +508,11 @@ void EditorFileDialog::_items_clear_selection() { get_ok()->set_disabled(false); get_ok()->set_text(TTR("Select Current Folder")); break; + + case MODE_OPEN_ANY: + case MODE_SAVE_FILE: + // FIXME: Implement, or refactor to avoid duplication with set_mode + break; } } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 36c3102840..49d9dca701 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -267,11 +267,6 @@ void EditorProperty::_notification(int p_what) { } else { keying_rect = Rect2(); } - - //int vs = get_constant("vseparation", "Tree"); - Color guide_color = get_color("guide_color", "Tree"); - int vs_height = get_size().height; // vs / 2; - // draw_line(Point2(0, vs_height), Point2(get_size().width, vs_height), guide_color); } } diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 3fc35810df..5f5c46f4a7 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -49,11 +49,6 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f err_str = String(p_file) + ":" + itos(p_line) + " - " + String(p_error); } - /* - if (!self->is_visible_in_tree()) - self->emit_signal("show_request"); - */ - if (p_type == ERR_HANDLER_WARNING) { self->add_message(err_str, MSG_TYPE_WARNING); } else { @@ -76,17 +71,6 @@ void EditorLog::_notification(int p_what) { } } } - - /*if (p_what==NOTIFICATION_DRAW) { - - RID ci = get_canvas_item(); - get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size())); - int top_ofs = 20; - int border_ofs=4; - Ref<StyleBox> style = get_stylebox("normal","TextEdit"); - - style->draw(ci,Rect2( Point2(border_ofs,top_ofs),get_size()-Size2(border_ofs*2,top_ofs+border_ofs))); - }*/ } void EditorLog::_clear_request() { @@ -105,6 +89,8 @@ void EditorLog::add_message(const String &p_msg, MessageType p_type) { bool restore = p_type != MSG_TYPE_STD; switch (p_type) { + case MSG_TYPE_STD: { + } break; case MSG_TYPE_ERROR: { log->push_color(get_color("error_color", "Editor")); Ref<Texture> icon = get_icon("Error", "EditorIcons"); @@ -122,7 +108,6 @@ void EditorLog::add_message(const String &p_msg, MessageType p_type) { } log->add_text(p_msg); - //button->set_text(p_msg); if (restore) log->pop(); @@ -132,21 +117,6 @@ void EditorLog::set_tool_button(ToolButton *p_tool_button) { tool_button = p_tool_button; } -/* -void EditorLog::_dragged(const Point2& p_ofs) { - - int ofs = ec->get_minsize().height; - ofs = ofs-p_ofs.y; - if (ofs<50) - ofs=50; - if (ofs>300) - ofs=300; - ec->set_minsize(Size2(ec->get_minsize().width,ofs)); - minimum_size_changed(); - -} -*/ - void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) { EditorLog *self = (EditorLog *)p_self; @@ -156,7 +126,6 @@ void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) { void EditorLog::_bind_methods() { ClassDB::bind_method(D_METHOD("_clear_request"), &EditorLog::_clear_request); - //ClassDB::bind_method(D_METHOD("_dragged"),&EditorLog::_dragged ); ADD_SIGNAL(MethodInfo("clear_request")); } @@ -187,7 +156,6 @@ EditorLog::EditorLog() { log->set_h_size_flags(SIZE_EXPAND_FILL); vb->add_child(log); add_message(VERSION_FULL_NAME " (c) 2007-2018 Juan Linietsky, Ariel Manzur & Godot Contributors."); - //log->add_text("Initialization Complete.\n"); //because it looks cool. eh.errfunc = _error_handler; eh.userdata = this; diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 1ad23963a9..dd3a8aa307 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -39,6 +39,7 @@ #include "scene/3d/camera.h" #include "scene/gui/popup_menu.h" #include "servers/visual_server.h" + Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_size) { Vector<Ref<Mesh> > meshes; @@ -522,7 +523,7 @@ int EditorPlugin::update_overlays() const { if (SpatialEditor::get_singleton()->is_visible()) { int count = 0; - for (int i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) { + for (uint32_t i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) { SpatialEditorViewport *vp = SpatialEditor::get_singleton()->get_editor_viewport(i); if (vp->is_visible()) { vp->update_surface(); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 3439133809..f6937386c9 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -108,6 +108,7 @@ void EditorPropertyMultilineText::_open_big_text() { if (!big_text_dialog) { big_text = memnew(TextEdit); big_text->connect("text_changed", this, "_big_text_changed"); + big_text->set_wrap_enabled(true); big_text_dialog = memnew(AcceptDialog); big_text_dialog->add_child(big_text); big_text_dialog->set_title("Edit Text:"); @@ -152,6 +153,7 @@ EditorPropertyMultilineText::EditorPropertyMultilineText() { set_bottom_editor(hb); text = memnew(TextEdit); text->connect("text_changed", this, "_text_changed"); + text->set_wrap_enabled(true); add_focusable(text); hb->add_child(text); text->set_h_size_flags(SIZE_EXPAND_FILL); @@ -817,10 +819,10 @@ void EditorPropertyInteger::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyInteger::_value_changed); } -void EditorPropertyInteger::setup(int p_min, int p_max, bool p_allow_greater, bool p_allow_lesser) { +void EditorPropertyInteger::setup(int p_min, int p_max, int p_step, bool p_allow_greater, bool p_allow_lesser) { spin->set_min(p_min); spin->set_max(p_max); - spin->set_step(1); + spin->set_step(p_step); spin->set_allow_greater(p_allow_greater); spin->set_allow_lesser(p_allow_lesser); } @@ -2663,7 +2665,7 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ } else { EditorPropertyInteger *editor = memnew(EditorPropertyInteger); - int min = 0, max = 65535; + int min = 0, max = 65535, step = 1; bool greater = true, lesser = true; if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { @@ -2671,6 +2673,11 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ lesser = false; min = p_hint_text.get_slice(",", 0).to_int(); max = p_hint_text.get_slice(",", 1).to_int(); + + if (p_hint_text.get_slice_count(",") >= 3) { + step = p_hint_text.get_slice(",", 2).to_int(); + } + for (int i = 2; i < p_hint_text.get_slice_count(","); i++) { String slice = p_hint_text.get_slice(",", i).strip_edges(); if (slice == "or_greater") { @@ -2682,7 +2689,7 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ } } - editor->setup(min, max, greater, lesser); + editor->setup(min, max, step, greater, lesser); add_property_editor(p_path, editor); } diff --git a/editor/editor_properties.h b/editor/editor_properties.h index cfc433b880..18e70345aa 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -265,7 +265,7 @@ protected: public: virtual void update_property(); - void setup(int p_min, int p_max, bool p_allow_greater, bool p_allow_lesser); + void setup(int p_min, int p_max, int p_step, bool p_allow_greater, bool p_allow_lesser); EditorPropertyInteger(); }; diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 808a8ac2f8..4e638cb4ac 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -337,7 +337,7 @@ void EditorPropertyArray::update_property() { } break; case Variant::INT: { EditorPropertyInteger *editor = memnew(EditorPropertyInteger); - editor->setup(-100000, 100000, true, true); + editor->setup(-100000, 100000, 1, true, true); prop = editor; } break; @@ -744,7 +744,7 @@ void EditorPropertyDictionary::update_property() { page->connect("value_changed", this, "_page_changed"); } else { // Queue childs for deletion, delete immediately might cause errors. - for (size_t i = 1; i < vbox->get_child_count(); i++) { + for (int i = 1; i < vbox->get_child_count(); i++) { vbox->get_child(i)->queue_delete(); } } @@ -800,7 +800,7 @@ void EditorPropertyDictionary::update_property() { } break; case Variant::INT: { EditorPropertyInteger *editor = memnew(EditorPropertyInteger); - editor->setup(-100000, 100000, true, true); + editor->setup(-100000, 100000, 1, true, true); prop = editor; } break; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 29ce8d1830..2dec21fffb 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -485,6 +485,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/2d/bone_outline_color", Color(0.35, 0.35, 0.35)); _initial_set("editors/2d/bone_outline_size", 2); _initial_set("editors/2d/keep_margins_when_changing_anchors", false); + _initial_set("editors/2d/viewport_border_color", Color(0.4, 0.4, 1.0, 0.4)); _initial_set("editors/2d/warped_mouse_panning", true); _initial_set("editors/2d/simple_spacebar_panning", false); _initial_set("editors/2d/scroll_to_pan", false); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 7ed7b920d9..8575d7be96 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -36,7 +36,6 @@ #include "editor_scale.h" #include "editor_settings.h" #include "modules/svg/image_loader_svg.h" -#include "time.h" static Ref<StyleBoxTexture> make_stylebox(Ref<Texture> p_texture, float p_left, float p_top, float p_right, float p_botton, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_botton = -1, bool p_draw_center = true) { Ref<StyleBoxTexture> style(memnew(StyleBoxTexture)); @@ -199,8 +198,6 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = exceptions.push_back("StatusWarning"); exceptions.push_back("NodeWarning"); - clock_t begin_time = clock(); - ImageLoaderSVG::set_convert_colors(&dark_icon_color_dictionary); // generate icons @@ -235,8 +232,6 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = } ImageLoaderSVG::set_convert_colors(NULL); - - clock_t end_time = clock(); #else print_line("SVG support disabled, editor icons won't be rendered."); #endif @@ -260,8 +255,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { bool use_gn_headers = EDITOR_DEF("interface/theme/use_graph_node_headers", false); - Color script_bg_color = EDITOR_DEF("text_editor/highlighting/background_color", Color(0, 0, 0, 0)); - Color preset_accent_color; Color preset_base_color; float preset_contrast; @@ -945,6 +938,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // TooltipPanel Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate(); + float v = MAX(border_size * EDSCALE, 1.0); + style_tooltip->set_default_margin(MARGIN_LEFT, v); + style_tooltip->set_default_margin(MARGIN_TOP, v); + style_tooltip->set_default_margin(MARGIN_RIGHT, v); + style_tooltip->set_default_margin(MARGIN_BOTTOM, v); style_tooltip->set_bg_color(Color(mono_color.r, mono_color.g, mono_color.b, 0.9)); style_tooltip->set_border_width_all(border_width); style_tooltip->set_border_color_all(mono_color); @@ -1064,8 +1062,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const float mono_value = mono_color.r; const Color alpha1 = Color(mono_value, mono_value, mono_value, 0.07); const Color alpha2 = Color(mono_value, mono_value, mono_value, 0.14); - const Color alpha3 = Color(mono_value, mono_value, mono_value, 0.5); - const Color alpha4 = Color(mono_value, mono_value, mono_value, 0.7); + const Color alpha3 = Color(mono_value, mono_value, mono_value, 0.7); // editor main color const Color main_color = Color::html(dark_theme ? "#57b3ff" : "#0480ff"); @@ -1099,9 +1096,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color member_variable_color = main_color.linear_interpolate(mono_color, 0.6); const Color mark_color = Color(error_color.r, error_color.g, error_color.b, 0.3); const Color breakpoint_color = error_color; - const Color code_folding_color = alpha4; + const Color code_folding_color = alpha3; const Color search_result_color = alpha1; - const Color search_result_border_color = alpha4; + const Color search_result_border_color = alpha3; EditorSettings *setting = EditorSettings::get_singleton(); String text_editor_color_theme = setting->get("text_editor/theme/color_theme"); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 46f89439c0..4794d4d8a0 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -395,6 +395,9 @@ void FileSystemDock::_notification(int p_what) { } void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_selected) { + // Update the import dock + import_dock_needs_update = true; + call_deferred("_update_import_dock"); // Return if we don't select something new if (!p_selected) @@ -1535,7 +1538,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> p_selected) if (!fpath.ends_with("/")) { fpath = fpath.get_base_dir(); } - make_script_dialog_text->config("Node", fpath + "new_script.gd"); + make_script_dialog_text->config("Node", fpath + "new_script.gd", false); make_script_dialog_text->popup_centered(Size2(300, 300) * EDSCALE); } break; @@ -1856,7 +1859,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori } String ltarget = files->get_item_metadata(pos); - target = ltarget.ends_with("/") ? target : path; + target = ltarget.ends_with("/") ? ltarget : path; return; } @@ -2122,15 +2125,33 @@ void FileSystemDock::_update_import_dock() { if (!import_dock_needs_update) return; - //check import + // List selected + Vector<String> selected; + if (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) { + // Use the tree + selected = _tree_get_selected(); + + } else { + // Use the file list + for (int i = 0; i < files->get_item_count(); i++) { + if (!files->is_selected(i)) + continue; + + selected.push_back(files->get_item_metadata(i)); + } + } + + // Check import Vector<String> imports; String import_type; + for (int i = 0; i < selected.size(); i++) { + String fpath = selected[i]; - for (int i = 0; i < files->get_item_count(); i++) { - if (!files->is_selected(i)) - continue; + if (fpath.ends_with("/")) { + imports.clear(); + break; + } - String fpath = files->get_item_metadata(i); if (!FileAccess::exists(fpath + ".import")) { imports.clear(); break; @@ -2317,7 +2338,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { tree->set_drag_forwarding(this); tree->set_allow_rmb_select(true); tree->set_select_mode(Tree::SELECT_MULTI); - tree->set_custom_minimum_size(Size2(0, 200 * EDSCALE)); + tree->set_custom_minimum_size(Size2(0, 15 * EDSCALE)); split_box->add_child(tree); tree->connect("item_edited", this, "_favorite_toggled"); @@ -2356,6 +2377,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { files->connect("gui_input", this, "_file_list_gui_input"); files->connect("multi_selected", this, "_file_multi_selected"); files->connect("rmb_clicked", this, "_file_list_rmb_pressed"); + files->set_custom_minimum_size(Size2(0, 15 * EDSCALE)); files->set_allow_rmb_select(true); file_list_vb->add_child(files); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 11d0b67bd6..2fdf1c82c0 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -302,7 +302,7 @@ FindInFilesDialog::FindInFilesDialog() { set_custom_minimum_size(Size2(400, 190)); set_resizable(true); - set_title(TTR("Find in files")); + set_title(TTR("Find in Files")); VBoxContainer *vbc = memnew(VBoxContainer); vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 8 * EDSCALE); diff --git a/editor/icons/icon_text_file.svg b/editor/icons/icon_text_file.svg new file mode 100644 index 0000000000..342a407b79 --- /dev/null +++ b/editor/icons/icon_text_file.svg @@ -0,0 +1,57 @@ +<?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="svg8" + sodipodi:docname="icon_text_file.svg" + inkscape:version="0.92.2 2405546, 2018-03-11" + enable-background="new"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="2560" + inkscape:window-height="1440" + id="namedview10" + showgrid="false" + inkscape:zoom="64" + inkscape:cx="-0.11275433" + inkscape:cy="5.0633688" + inkscape:window-x="1920" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" + inkscape:snap-grids="true" /> + <path + style="display:inline;fill:#e0e0e0" + d="m 13.370548,12.198712 c 0.359546,-0.0075 0.719092,-0.015 1.078638,-0.0225 -0.004,-0.738576 -0.008,-1.477152 -0.01198,-2.215728 -1.429703,0.011985 -2.859406,0.02397 -4.289109,0.035955 0.004,0.759672 0.008,1.519344 0.01198,2.279016 0.40349,-0.01135 0.806981,-0.02271 1.210471,-0.03406 0,1.251681 0,2.503363 0,3.755044 0.666667,0 1.333333,0 2,0 M 6.1005477,12.247152 c 0.332722,0.21587 0.665444,0.431741 0.998166,0.647611 -0.3328629,0.218648 -0.6657258,0.437297 -0.9985887,0.655945 -1e-7,0.818044 -2e-7,1.636088 -3e-7,2.454132 0.5662705,-0.533749 1.1325409,-1.067498 1.6988114,-1.601247 0.6353035,0.532396 1.2706071,1.064791 1.9059106,1.597187 -9.5e-4,-0.757409 -0.0019,-1.514817 -0.00285,-2.272226 -0.2987204,-0.278501 -0.5974407,-0.557002 -0.8961611,-0.835503 0.2983766,-0.205775 0.5967531,-0.41155 0.8951297,-0.617325 0.00283,-0.73844 0.00565,-1.476881 0.00848,-2.215321 -0.63732,0.474447 -1.27464,0.948893 -1.91196,1.42334 C 7.2318406,10.979446 6.6661958,10.475146 6.1005511,9.9708468 M 4.6399123,12.202271 c 0.3595459,-0.0075 0.7190917,-0.015 1.0786376,-0.0225 -0.00399,-0.738576 -0.00799,-1.477152 -0.011985,-2.2157276 -1.4297028,0.011985 -2.8594057,0.02397 -4.2891085,0.035955 0.00399,0.7596716 0.00799,1.5193436 0.011985,2.2790156 0.4034903,-0.01135 0.8069806,-0.02271 1.2104709,-0.03406 0,1.251681 0,2.503363 0,3.755044 0.6666667,0 1.3333333,0 2,0 M 7,1 C 6.81185,1.7526 6.6237,2.5052 6.43555,3.2578 6.0521572,3.3957205 5.6943609,3.6619566 5.3589944,3.3047548 4.8252629,2.9844032 4.2915315,2.6640516 3.7578,2.3437 3.2864333,2.8150667 2.8150667,3.2864333 2.3437,3.7578 2.7421333,4.4225 3.1405667,5.0872 3.539,5.7519 3.3683054,6.121632 3.3058712,6.5625877 2.8157946,6.5467719 2.2105097,6.6978312 1.6052249,6.8488906 0.99994,6.99995 c 0,0.6666667 0,1.3333333 0,2 1.7571667,0 3.5143333,0 5.2715,0 C 5.5845118,7.9199003 6.2580962,6.3373839 7.5001288,6.0629153 8.7083679,5.7047153 10.045643,6.7406952 9.99996,7.99995 c 0.104409,0.4657408 -0.6052318,1.1778026 0.181951,1 1.606006,0 3.212013,0 4.818019,0 0,-0.6666667 0,-1.3333333 0,-2 C 14.24733,6.8118 13.49473,6.62365 12.74213,6.4355 12.603459,6.0528244 12.33852,5.6958457 12.695012,5.3607965 13.015418,4.8264643 13.335824,4.2921322 13.65623,3.7578 13.184863,3.2864333 12.713497,2.8150667 12.24213,2.3437 11.57743,2.7421333 10.91273,3.1405667 10.24803,3.539 9.8782981,3.3683053 9.4373423,3.3058712 9.4531581,2.8157946 9.3020988,2.2105097 9.1510394,1.6052249 8.99998,0.99994 8.3333478,0.99998002 7.6664935,0.99985998 7,1 Z" + id="path4781-7" + inkscape:connector-curvature="0" /> +</svg> diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index 85383fd69d..a6b754de3b 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -1910,15 +1910,15 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye NodePath node_path; GLTFNode *node = state.nodes[E->key()]; - for (int i = 0; i < node->godot_nodes.size(); i++) { + for (int n = 0; n < node->godot_nodes.size(); n++) { if (node->joints.size()) { - Skeleton *sk = (Skeleton *)node->godot_nodes[i]; + Skeleton *sk = (Skeleton *)node->godot_nodes[n]; String path = ap->get_parent()->get_path_to(sk); - String bone = sk->get_bone_name(node->joints[i].godot_bone_index); + String bone = sk->get_bone_name(node->joints[n].godot_bone_index); node_path = path + ":" + bone; } else { - node_path = ap->get_parent()->get_path_to(node->godot_nodes[i]); + node_path = ap->get_parent()->get_path_to(node->godot_nodes[n]); } for (int i = 0; i < track.rotation_track.times.size(); i++) { @@ -1993,8 +1993,8 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye xform.basis.set_quat_scale(rot, scale); xform.origin = pos; - Skeleton *skeleton = skeletons[node->joints[i].skin]; - int bone = node->joints[i].godot_bone_index; + Skeleton *skeleton = skeletons[node->joints[n].skin]; + int bone = node->joints[n].godot_bone_index; xform = skeleton->get_bone_rest(bone).affine_inverse() * xform; rot = xform.basis.get_rotation_quat(); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 19d5243776..205458fb1d 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -131,10 +131,6 @@ void AnimationNodeBlendTreeEditor::_update_graph() { Ref<AnimationNode> agnode = blend_tree->get_node(E->get()); - if (!agnode->is_connected("changed", this, "_node_changed")) { - agnode->connect("changed", this, "_node_changed", varray(agnode->get_instance_id()), CONNECT_DEFERRED); - } - node->set_offset(blend_tree->get_node_position(E->get()) * EDSCALE); node->set_title(agnode->get_caption()); @@ -721,14 +717,6 @@ void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) { updating = false; } -void AnimationNodeBlendTreeEditor::_node_changed(ObjectID p_node) { - - AnimationNode *an = Object::cast_to<AnimationNode>(ObjectDB::get_instance(p_node)); - //if (an && an->get_parent() == blend_tree) { - _update_graph(); - //} -} - void AnimationNodeBlendTreeEditor::_bind_methods() { ClassDB::bind_method("_update_graph", &AnimationNodeBlendTreeEditor::_update_graph); @@ -746,7 +734,6 @@ void AnimationNodeBlendTreeEditor::_bind_methods() { ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters); ClassDB::bind_method("_filter_edited", &AnimationNodeBlendTreeEditor::_filter_edited); ClassDB::bind_method("_filter_toggled", &AnimationNodeBlendTreeEditor::_filter_toggled); - ClassDB::bind_method("_node_changed", &AnimationNodeBlendTreeEditor::_node_changed); ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendTreeEditor::_removed_from_graph); ClassDB::bind_method("_property_changed", &AnimationNodeBlendTreeEditor::_property_changed); ClassDB::bind_method("_file_opened", &AnimationNodeBlendTreeEditor::_file_opened); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index 9616e8b5da..e2daefdec6 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -104,8 +104,6 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { void _filter_toggled(); Ref<AnimationNode> _filter_edit; - void _node_changed(ObjectID p_node); - void _property_changed(const StringName &p_property, const Variant &p_value); void _removed_from_graph(); diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/baked_lightmap_editor_plugin.cpp index 59b79bd070..e65a697857 100644 --- a/editor/plugins/baked_lightmap_editor_plugin.cpp +++ b/editor/plugins/baked_lightmap_editor_plugin.cpp @@ -50,6 +50,7 @@ void BakedLightmapEditorPlugin::_bake() { case BakedLightmap::BAKE_ERROR_CANT_CREATE_IMAGE: EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable.")); break; + default: {} } } } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 2ea17fda1c..f65c8cbd0d 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1654,6 +1654,8 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized(); Transform2D simple_xform = viewport->get_transform() * unscaled_transform; + drag_type = DRAG_SCALE_BOTH; + Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE); Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { @@ -1663,18 +1665,17 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { drag_type = DRAG_SCALE_Y; } - if (drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) { - drag_from = transform.affine_inverse().xform(b->get_position()); - drag_selection = List<CanvasItem *>(); - drag_selection.push_back(canvas_item); - _save_canvas_item_state(drag_selection); - return true; - } + + drag_from = transform.affine_inverse().xform(b->get_position()); + drag_selection = List<CanvasItem *>(); + drag_selection.push_back(canvas_item); + _save_canvas_item_state(drag_selection); + return true; } } } - if (drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) { + if (drag_type == DRAG_SCALE_BOTH || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) { // Resize the node if (m.is_valid()) { _restore_canvas_item_state(drag_selection); @@ -1682,24 +1683,49 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { drag_to = transform.affine_inverse().xform(m->get_position()); + Transform2D parent_xform = canvas_item->get_global_transform_with_canvas() * canvas_item->get_transform().affine_inverse(); + Transform2D unscaled_transform = (transform * parent_xform * Transform2D(canvas_item->_edit_get_rotation(), canvas_item->_edit_get_position())).orthonormalized(); + Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform; + bool uniform = m->get_shift(); - Point2 offset = drag_to - drag_from; + + Point2 drag_from_local = simple_xform.xform(drag_from); + Point2 drag_to_local = simple_xform.xform(drag_to); + Point2 offset = drag_to_local - drag_from_local; + Size2 scale = canvas_item->call("get_scale"); float ratio = scale.y / scale.x; - if (drag_type == DRAG_SCALE_X) { - scale.x += offset.x / SCALE_HANDLE_DISTANCE; + if (drag_type == DRAG_SCALE_BOTH) { + Size2 scale_factor = drag_to_local / drag_from_local; if (uniform) { - scale.y = scale.x * ratio; + if (ABS(offset.x) > ABS(offset.y)) { + scale.x *= scale_factor.x; + scale.y = scale.x * ratio; + } else { + scale.y *= scale_factor.y; + scale.x = scale.y / ratio; + } + } else { + scale *= scale_factor; } - canvas_item->call("set_scale", scale); - - } else if (drag_type == DRAG_SCALE_Y) { - scale.y -= offset.y / SCALE_HANDLE_DISTANCE; - if (uniform) { - scale.x = scale.y / ratio; + } else { + Size2 scale_factor = Vector2(offset.x, -offset.y) / SCALE_HANDLE_DISTANCE; + Size2 parent_scale = parent_xform.get_scale(); + scale_factor *= Vector2(1.0 / parent_scale.x, 1.0 / parent_scale.y); + if (drag_type == DRAG_SCALE_X) { + scale.x += scale_factor.x; + if (uniform) { + scale.y = scale.x * ratio; + } + } else if (drag_type == DRAG_SCALE_Y) { + scale.y += scale_factor.y; + if (uniform) { + scale.x = scale.y / ratio; + } } - canvas_item->call("set_scale", scale); } + canvas_item->call("set_scale", scale); + return true; } // Confirm resize @@ -2352,7 +2378,7 @@ void CanvasItemEditor::_draw_rulers() { if (i % minor_subdivision == 0) { viewport->draw_line(Point2(position.x, RULER_WIDTH * 0.33), Point2(position.x, RULER_WIDTH), graduation_color); } else { - viewport->draw_line(Point2(position.x, RULER_WIDTH * 0.66), Point2(position.x, RULER_WIDTH), graduation_color); + viewport->draw_line(Point2(position.x, RULER_WIDTH * 0.75), Point2(position.x, RULER_WIDTH), graduation_color); } } } @@ -2364,12 +2390,17 @@ void CanvasItemEditor::_draw_rulers() { if (i % (major_subdivision * minor_subdivision) == 0) { viewport->draw_line(Point2(0, position.y), Point2(RULER_WIDTH, position.y), graduation_color); float val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(0, i)).y; - viewport->draw_string(font, Point2(2, position.y + 2 + font->get_height()), vformat(((int)val == val) ? "%d" : "%.1f", val), font_color); + + Transform2D text_xform = Transform2D(-Math_PI / 2.0, Point2(font->get_height(), position.y - 2)); + viewport->draw_set_transform_matrix(viewport->get_transform() * text_xform); + viewport->draw_string(font, Point2(), vformat(((int)val == val) ? "%d" : "%.1f", val), font_color); + viewport->draw_set_transform_matrix(viewport->get_transform()); + } else { if (i % minor_subdivision == 0) { viewport->draw_line(Point2(RULER_WIDTH * 0.33, position.y), Point2(RULER_WIDTH, position.y), graduation_color); } else { - viewport->draw_line(Point2(RULER_WIDTH * 0.66, position.y), Point2(RULER_WIDTH, position.y), graduation_color); + viewport->draw_line(Point2(RULER_WIDTH * 0.75, position.y), Point2(RULER_WIDTH, position.y), graduation_color); } } } @@ -2815,7 +2846,7 @@ void CanvasItemEditor::_draw_axis() { RID ci = viewport->get_canvas_item(); - Color area_axis_color(0.4, 0.4, 1.0, 0.4); + Color area_axis_color = EditorSettings::get_singleton()->get("editors/2d/viewport_border_color"); Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 2d539d6727..c788a63d56 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -195,6 +195,7 @@ private: DRAG_MOVE, DRAG_SCALE_X, DRAG_SCALE_Y, + DRAG_SCALE_BOTH, DRAG_ROTATE, DRAG_PIVOT, DRAG_V_GUIDE, diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index e3f364790a..d1a94f5b49 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -323,7 +323,6 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e if (mb.is_valid()) { Vector2 gpoint = mb->get_position(); - Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position()))); if (mb->get_button_index() == BUTTON_LEFT) { if (mb->is_pressed()) { diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index 7b7e23531a..73a216e96f 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -65,14 +65,6 @@ void MeshEditor::_notification(int p_what) { first_enter = false; } } - - if (p_what == NOTIFICATION_DRAW) { - - Ref<Texture> checkerboard = get_icon("Checkerboard", "EditorIcons"); - Size2 size = get_size(); - - //draw_texture_rect(checkerboard, Rect2(Point2(), size), true); - } } void MeshEditor::_update_rotation() { diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index e0c8cf41ff..f937744d45 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -767,6 +767,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { node->set_polygon(uv_new); } } break; + default: {} } if (bone_painting) { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index c8e7bfb74b..5e000ca6ef 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3013,7 +3013,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/show_in_file_system", TTR("Show In File System")), SHOW_IN_FILE_SYSTEM); file_menu->get_popup()->add_separator(); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Prev"), KEY_MASK_ALT | KEY_LEFT), WINDOW_PREV); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Previous"), KEY_MASK_ALT | KEY_LEFT), WINDOW_PREV); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_next", TTR("History Next"), KEY_MASK_ALT | KEY_RIGHT), WINDOW_NEXT); file_menu->get_popup()->add_separator(); @@ -3060,7 +3060,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { debug_menu->get_popup()->add_separator(); //debug_menu->get_popup()->add_check_item("Show Debugger",DEBUG_SHOW); debug_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("debugger/keep_debugger_open", TTR("Keep Debugger Open")), DEBUG_SHOW_KEEP_OPEN); - debug_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("debugger/debug_with_exteral_editor", TTR("Debug with external editor")), DEBUG_WITH_EXTERNAL_EDITOR); + debug_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("debugger/debug_with_external_editor", TTR("Debug with External Editor")), DEBUG_WITH_EXTERNAL_EDITOR); debug_menu->get_popup()->connect("id_pressed", this, "_menu_option"); debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_NEXT), true); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index d4ddaf274f..23babdf07b 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -941,6 +941,7 @@ void ScriptTextEditor::_edit_option(int p_op) { case SEARCH_LOCATE_FUNCTION: { quick_open->popup(get_functions()); + quick_open->set_title(TTR("Go to Function")); } break; case SEARCH_GOTO_LINE: { @@ -1275,7 +1276,6 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { word_at_mouse = tx->get_selection_text(); bool has_color = (word_at_mouse == "Color"); - int fold_state = 0; bool foldable = tx->can_fold(row) || tx->is_folded(row); bool open_docs = false; bool goto_definition = false; @@ -1567,8 +1567,8 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9); #endif ED_SHORTCUT("script_text_editor/remove_all_breakpoints", TTR("Remove All Breakpoints"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F9); - ED_SHORTCUT("script_text_editor/goto_next_breakpoint", TTR("Goto Next Breakpoint"), KEY_MASK_CMD | KEY_PERIOD); - ED_SHORTCUT("script_text_editor/goto_previous_breakpoint", TTR("Goto Previous Breakpoint"), KEY_MASK_CMD | KEY_COMMA); + ED_SHORTCUT("script_text_editor/goto_next_breakpoint", TTR("Go to Next Breakpoint"), KEY_MASK_CMD | KEY_PERIOD); + ED_SHORTCUT("script_text_editor/goto_previous_breakpoint", TTR("Go to Previous Breakpoint"), KEY_MASK_CMD | KEY_COMMA); ED_SHORTCUT("script_text_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F); #ifdef OSX_ENABLED @@ -1581,14 +1581,14 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/replace", TTR("Replace..."), KEY_MASK_CMD | KEY_R); #endif - ED_SHORTCUT("script_text_editor/find_in_files", TTR("Find in files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F); + ED_SHORTCUT("script_text_editor/find_in_files", TTR("Find in Files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F); #ifdef OSX_ENABLED - ED_SHORTCUT("script_text_editor/goto_function", TTR("Goto Function..."), KEY_MASK_CTRL | KEY_MASK_CMD | KEY_J); + ED_SHORTCUT("script_text_editor/goto_function", TTR("Go to Function..."), KEY_MASK_CTRL | KEY_MASK_CMD | KEY_J); #else - ED_SHORTCUT("script_text_editor/goto_function", TTR("Goto Function..."), KEY_MASK_ALT | KEY_MASK_CMD | KEY_F); + ED_SHORTCUT("script_text_editor/goto_function", TTR("Go to Function..."), KEY_MASK_ALT | KEY_MASK_CMD | KEY_F); #endif - ED_SHORTCUT("script_text_editor/goto_line", TTR("Goto Line..."), KEY_MASK_CMD | KEY_L); + ED_SHORTCUT("script_text_editor/goto_line", TTR("Go to Line..."), KEY_MASK_CMD | KEY_L); #ifdef OSX_ENABLED ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_ALT | KEY_MASK_SHIFT | KEY_SPACE); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 361271af89..775fca308e 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -86,10 +86,7 @@ void ShaderTextEditor::_load_theme_settings() { Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color"); - Color type_color = EDITOR_GET("text_editor/highlighting/engine_type_color"); Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); - Color string_color = EDITOR_GET("text_editor/highlighting/string_color"); get_text_edit()->add_color_override("background_color", background_color); get_text_edit()->add_color_override("completion_background_color", completion_background_color); @@ -140,26 +137,9 @@ void ShaderTextEditor::_load_theme_settings() { get_text_edit()->add_keyword_color(E->get(), keyword_color); } - //colorize core types - //Color basetype_color= EDITOR_DEF("text_editor/base_type_color",Color(0.3,0.3,0.0)); - //colorize comments get_text_edit()->add_color_region("/*", "*/", comment_color, false); get_text_edit()->add_color_region("//", "", comment_color, false); - - /*//colorize strings - Color string_color = EDITOR_DEF("text_editor/string_color",Color::hex(0x6b6f00ff)); - - List<String> strings; - shader->get_shader_mode()->get_string_delimiters(&strings); - - for (List<String>::Element *E=strings.front();E;E=E->next()) { - - String string = E->get(); - String beg = string.get_slice(" ",0); - String end = string.get_slice_count(" ")>1?string.get_slice(" ",1):String(); - get_text_edit()->add_color_region(beg,end,string_color,end==""); - }*/ } void ShaderTextEditor::_check_shader_mode() { diff --git a/editor/plugins/skeleton_editor_plugin.cpp b/editor/plugins/skeleton_editor_plugin.cpp index 50deb80668..e7d9f1b702 100644 --- a/editor/plugins/skeleton_editor_plugin.cpp +++ b/editor/plugins/skeleton_editor_plugin.cpp @@ -29,9 +29,10 @@ /*************************************************************************/ #include "skeleton_editor_plugin.h" + #include "scene/3d/collision_shape.h" #include "scene/3d/physics_body.h" -#include "scene/3d/physics_joint.h"; +#include "scene/3d/physics_joint.h" #include "scene/resources/capsule_shape.h" #include "scene/resources/sphere_shape.h" #include "spatial_editor_plugin.h" diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 3e6a0ae81a..271f753003 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -997,6 +997,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { set_message(TTR("View Plane Transform."), 2); } break; + case TRANSFORM_YZ: + case TRANSFORM_XZ: + case TRANSFORM_XY: { + } break; } } } break; @@ -1545,6 +1549,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2)); axis = Vector3(0, 0, 1); break; + case TRANSFORM_YZ: + case TRANSFORM_XZ: + case TRANSFORM_XY: + break; } Vector3 intersection; @@ -2075,7 +2083,7 @@ void SpatialEditorViewport::set_message(String p_message, float p_time) { } void SpatialEditorPlugin::edited_scene_changed() { - for (int i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) { + for (uint32_t i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) { SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(i); if (viewport->is_visible()) { viewport->notification(Control::NOTIFICATION_VISIBILITY_CHANGED); @@ -2199,7 +2207,7 @@ void SpatialEditorViewport::_notification(int p_what) { bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION)); - if (shrink != viewport_container->get_stretch_shrink() > 1) { + if (shrink != (viewport_container->get_stretch_shrink() > 1)) { viewport_container->set_stretch_shrink(shrink ? 2 : 1); } @@ -4093,7 +4101,7 @@ void SpatialEditor::set_state(const Dictionary &p_state) { for (int j = 0; j < gizmo_plugins.size(); ++j) { if (!gizmo_plugins[j]->can_be_hidden()) continue; int state = EditorSpatialGizmoPlugin::ON_TOP; - for (uint32_t i = 0; i < keys.size(); i++) { + for (int i = 0; i < keys.size(); i++) { if (gizmo_plugins.write[j]->get_name() == keys[i]) { state = gizmos_status[keys[i]]; } @@ -4979,32 +4987,29 @@ void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) { if (!k->is_pressed()) return; - if (ED_IS_SHORTCUT("spatial_editor/tool_select", p_event)) + if (ED_IS_SHORTCUT("spatial_editor/tool_select", p_event)) { _menu_item_pressed(MENU_TOOL_SELECT); - - else if (ED_IS_SHORTCUT("spatial_editor/tool_move", p_event)) + } else if (ED_IS_SHORTCUT("spatial_editor/tool_move", p_event)) { _menu_item_pressed(MENU_TOOL_MOVE); - - else if (ED_IS_SHORTCUT("spatial_editor/tool_rotate", p_event)) + } else if (ED_IS_SHORTCUT("spatial_editor/tool_rotate", p_event)) { _menu_item_pressed(MENU_TOOL_ROTATE); - - else if (ED_IS_SHORTCUT("spatial_editor/tool_scale", p_event)) + } else if (ED_IS_SHORTCUT("spatial_editor/tool_scale", p_event)) { _menu_item_pressed(MENU_TOOL_SCALE); - else if (ED_IS_SHORTCUT("spatial_editor/snap_to_floor", p_event)) + } else if (ED_IS_SHORTCUT("spatial_editor/snap_to_floor", p_event)) { snap_selected_nodes_to_floor(); - - else if (ED_IS_SHORTCUT("spatial_editor/local_coords", p_event)) + } else if (ED_IS_SHORTCUT("spatial_editor/local_coords", p_event)) { if (are_local_coords_enabled()) { _menu_item_toggled(false, MENU_TOOL_LOCAL_COORDS); } else { _menu_item_toggled(true, MENU_TOOL_LOCAL_COORDS); } - else if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) + } else if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) { if (is_snap_enabled()) { _menu_item_toggled(false, MENU_TOOL_USE_SNAP); } else { _menu_item_toggled(true, MENU_TOOL_USE_SNAP); } + } } } } diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index b7317cd593..773739d6e0 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -86,7 +86,7 @@ public: Vector<Vector3> handles; Vector<Vector3> secondary_handles; - float selectable_icon_size = -1.0f; + float selectable_icon_size; bool billboard_handle; bool valid; diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index 58a1835e68..c574b5e8ba 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -97,7 +97,7 @@ Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float int lasti = p2->Contour.size() - 1; Vector2 prev = Vector2(p2->Contour[lasti].X / PRECISION, p2->Contour[lasti].Y / PRECISION); - for (int i = 0; i < p2->Contour.size(); i++) { + for (unsigned int i = 0; i < p2->Contour.size(); i++) { Vector2 cur = Vector2(p2->Contour[i].X / PRECISION, p2->Contour[i].Y / PRECISION); if (cur.distance_to(prev) > 0.5) { diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index a6a256f0d6..3de2284cea 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -795,6 +795,7 @@ void TileSetEditor::_on_workspace_draw() { spin_priority->set_suffix(" / " + String::num(total, 0)); draw_highlight_subtile(edited_shape_coord, queue_others); } break; + default: {} } draw_tile_subdivision(get_current_tile(), Color(0.347214, 0.722656, 0.617063)); @@ -1365,6 +1366,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } break; + default: {} } } } @@ -1434,6 +1436,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { workspace->update(); } } break; + default: {} } } } else if (p_tool == ZOOM_OUT) { @@ -1862,6 +1865,7 @@ void TileSetEditor::draw_polygon_shapes() { } } } break; + default: {} } if (creating_shape) { for (int j = 0; j < current_shape.size() - 1; j++) { diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index d8de775d36..df704706af 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -50,7 +50,11 @@ void ScriptCreateDialog::_notification(int p_what) { } } -void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_path) { +bool ScriptCreateDialog::_can_be_built_in() { + return (supports_built_in && built_in_enabled); +} + +void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_path, bool p_built_in_enabled) { class_name->set_text(""); class_name->deselect(); @@ -66,6 +70,8 @@ void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_ } file_path->deselect(); + built_in_enabled = p_built_in_enabled; + _lang_changed(current_language); _class_name_changed(""); _path_changed(file_path->get_text()); @@ -544,7 +550,7 @@ void ScriptCreateDialog::_update_dialog() { } } - if (!supports_built_in) + if (!_can_be_built_in()) internal->set_pressed(false); /* Is Script created or loaded from existing file */ @@ -553,14 +559,14 @@ void ScriptCreateDialog::_update_dialog() { get_ok()->set_text(TTR("Create")); parent_name->set_editable(true); parent_browse_button->set_disabled(false); - internal->set_disabled(!supports_built_in); + internal->set_disabled(!_can_be_built_in()); _msg_path_valid(true, TTR("Built-in script (into scene file)")); } else if (is_new_script_created) { // New Script Created get_ok()->set_text(TTR("Create")); parent_name->set_editable(true); parent_browse_button->set_disabled(false); - internal->set_disabled(!supports_built_in); + internal->set_disabled(!_can_be_built_in()); if (is_path_valid) { _msg_path_valid(true, TTR("Create new script file")); } @@ -569,7 +575,7 @@ void ScriptCreateDialog::_update_dialog() { get_ok()->set_text(TTR("Load")); parent_name->set_editable(false); parent_browse_button->set_disabled(true); - internal->set_disabled(!supports_built_in); + internal->set_disabled(!_can_be_built_in()); if (is_path_valid) { _msg_path_valid(true, TTR("Load existing script file")); } @@ -588,7 +594,7 @@ void ScriptCreateDialog::_bind_methods() { ClassDB::bind_method("_path_entered", &ScriptCreateDialog::_path_entered); ClassDB::bind_method("_template_changed", &ScriptCreateDialog::_template_changed); - ClassDB::bind_method(D_METHOD("config", "inherits", "path"), &ScriptCreateDialog::config); + ClassDB::bind_method(D_METHOD("config", "inherits", "path", "built_in_enabled"), &ScriptCreateDialog::config, DEFVAL(true)); ADD_SIGNAL(MethodInfo("script_created", PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script"))); } @@ -793,6 +799,7 @@ ScriptCreateDialog::ScriptCreateDialog() { has_named_classes = false; supports_built_in = false; can_inherit_from_file = false; + built_in_enabled = true; is_built_in = false; is_new_script_created = true; diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 1ad4a1b7a1..e0bf336b56 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -69,11 +69,13 @@ class ScriptCreateDialog : public ConfirmationDialog { bool is_parent_name_valid; bool is_class_name_valid; bool is_built_in; + bool built_in_enabled; int current_language; bool re_check_path; String script_template; Vector<String> template_list; + bool _can_be_built_in(); void _path_changed(const String &p_path = String()); void _path_entered(const String &p_path = String()); void _lang_changed(int l = 0); @@ -96,8 +98,7 @@ protected: static void _bind_methods(); public: - void config(const String &p_base_name, const String &p_base_path); - + void config(const String &p_base_name, const String &p_base_path, bool p_built_in_enabled = true); ScriptCreateDialog(); }; diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 3097f0d0b9..96bca86f83 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -715,6 +715,7 @@ EditorSpatialGizmo::EditorSpatialGizmo() { instanced = false; spatial_node = NULL; gizmo_plugin = NULL; + selectable_icon_size = -1.0f; } EditorSpatialGizmo::~EditorSpatialGizmo() { diff --git a/gles_builders.py b/gles_builders.py index b5a2b24aa3..8ed9f39393 100644 --- a/gles_builders.py +++ b/gles_builders.py @@ -232,7 +232,11 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2 fd.write("\t_FORCE_INLINE_ int get_uniform(Uniforms p_uniform) const { return _get_uniform(p_uniform); }\n\n") if header_data.conditionals: fd.write("\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) { _set_conditional(p_conditional,p_enable); }\n\n") - fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; ERR_FAIL_COND( get_active()!=this );\n\n ") + fd.write("\t#ifdef DEBUG_ENABLED\n ") + fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; if (!is_version_valid()) return; ERR_FAIL_COND( get_active()!=this ); \n\n ") + fd.write("\t#else\n ") + fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; \n\n ") + fd.write("\t#endif\n") fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n") fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n") fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n") diff --git a/main/input_default.cpp b/main/input_default.cpp index 10be291b8d..913c143025 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -343,9 +343,9 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool button_event->set_pressed(st->is_pressed()); button_event->set_button_index(BUTTON_LEFT); if (st->is_pressed()) { - button_event->set_button_mask(mouse_button_mask | (1 << BUTTON_LEFT - 1)); + button_event->set_button_mask(mouse_button_mask | (1 << (BUTTON_LEFT - 1))); } else { - button_event->set_button_mask(mouse_button_mask & ~(1 << BUTTON_LEFT - 1)); + button_event->set_button_mask(mouse_button_mask & ~(1 << (BUTTON_LEFT - 1))); } _parse_input_event_impl(button_event, true); @@ -576,7 +576,7 @@ void InputDefault::ensure_touch_mouse_raised() { button_event->set_global_position(mouse_pos); button_event->set_pressed(false); button_event->set_button_index(BUTTON_LEFT); - button_event->set_button_mask(mouse_button_mask & ~(1 << BUTTON_LEFT - 1)); + button_event->set_button_mask(mouse_button_mask & ~(1 << (BUTTON_LEFT - 1))); _parse_input_event_impl(button_event, true); } @@ -636,6 +636,7 @@ InputDefault::InputDefault() { emulate_mouse_from_touch = false; mouse_from_touch_index = -1; main_loop = NULL; + default_shape = CURSOR_ARROW; hat_map_default[HAT_UP].type = TYPE_BUTTON; hat_map_default[HAT_UP].index = JOY_DPAD_UP; diff --git a/main/input_default.h b/main/input_default.h index 4441ade04e..b420ec124b 100644 --- a/main/input_default.h +++ b/main/input_default.h @@ -119,7 +119,8 @@ class InputDefault : public Input { SpeedTrack mouse_speed_track; Map<int, Joypad> joy_names; int fallback_mapping; - CursorShape default_shape = CURSOR_ARROW; + + CursorShape default_shape; public: enum HatMask { diff --git a/main/main.cpp b/main/main.cpp index dac646ba70..5320d73c7f 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -129,7 +129,6 @@ static bool init_always_on_top = false; static bool init_use_custom_pos = false; static Vector2 init_custom_pos; static bool force_lowdpi = false; -static bool use_vsync = true; // Debug diff --git a/main/tests/test_gdscript.cpp b/main/tests/test_gdscript.cpp index 412e809732..4d2fa2a26d 100644 --- a/main/tests/test_gdscript.cpp +++ b/main/tests/test_gdscript.cpp @@ -357,6 +357,9 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i _parser_show_block(cf_node->body, p_indent + 1); } break; + case GDScriptParser::ControlFlowNode::CF_MATCH: { + // FIXME: Implement + } break; case GDScriptParser::ControlFlowNode::CF_SWITCH: { } break; diff --git a/main/tests/test_shader_lang.cpp b/main/tests/test_shader_lang.cpp index 2cd39d0208..9df5973376 100644 --- a/main/tests/test_shader_lang.cpp +++ b/main/tests/test_shader_lang.cpp @@ -194,6 +194,9 @@ static String dump_node_code(SL::Node *p_node, int p_level) { code = vnode->name; } break; + case SL::Node::TYPE_VARIABLE_DECLARATION: { + // FIXME: Implement + } break; case SL::Node::TYPE_CONSTANT: { SL::ConstantNode *cnode = (SL::ConstantNode *)p_node; return get_constant_text(cnode->datatype, cnode->values); diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index 3200b4a214..662a477f79 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -94,6 +94,9 @@ void AreaBullet::dispatch_callbacks() { otherObj.object->on_exit_area(this); overlappingObjects.remove(i); // Remove after callback break; + case OVERLAP_STATE_DIRTY: + case OVERLAP_STATE_INSIDE: + break; } } } diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp index a0fe598227..f9b7126173 100644 --- a/modules/bullet/bullet_types_converter.cpp +++ b/modules/bullet/bullet_types_converter.cpp @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#pragma once - #include "bullet_types_converter.h" /** diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp index 86c6a632cd..3a4459a581 100644 --- a/modules/bullet/hinge_joint_bullet.cpp +++ b/modules/bullet/hinge_joint_bullet.cpp @@ -117,7 +117,7 @@ void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t hingeConstraint->setMaxMotorImpulse(p_value); break; default: - ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + ERR_EXPLAIN("The HingeJoint parameter " + itos(p_param) + " is deprecated."); WARN_DEPRECATED break; } @@ -143,7 +143,7 @@ real_t HingeJointBullet::get_param(PhysicsServer::HingeJointParam p_param) const case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: return hingeConstraint->getMaxMotorImpulse(); default: - ERR_EXPLAIN("This parameter " + itos(p_param) + " is deprecated"); + ERR_EXPLAIN("The HingeJoint parameter " + itos(p_param) + " is deprecated."); WARN_DEPRECATED; return 0; } @@ -159,6 +159,7 @@ void HingeJointBullet::set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_val case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR: hingeConstraint->enableMotor(p_value); break; + case PhysicsServer::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } } diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index f24c8670a3..988f3bc153 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -535,20 +535,18 @@ void RigidBodyBullet::set_mode(PhysicsServer::BodyMode p_mode) { reload_axis_lock(); _internal_set_mass(0); break; - case PhysicsServer::BODY_MODE_RIGID: { + case PhysicsServer::BODY_MODE_RIGID: mode = PhysicsServer::BODY_MODE_RIGID; reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); break; - } - case PhysicsServer::BODY_MODE_CHARACTER: { + case PhysicsServer::BODY_MODE_CHARACTER: mode = PhysicsServer::BODY_MODE_CHARACTER; reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); break; - } } btBody->setAngularVelocity(btVector3(0, 0, 0)); @@ -927,10 +925,10 @@ void RigidBodyBullet::reload_space_override_modificator() { } switch (currentArea->get_spOv_mode()) { - ///case PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED: - /// This area does not affect gravity/damp. These are generally areas - /// that exist only to detect collisions, and objects entering or exiting them. - /// break; + case PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED: + /// This area does not affect gravity/damp. These are generally areas + /// that exist only to detect collisions, and objects entering or exiting them. + break; case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE: /// This area adds its gravity/damp values to whatever has been /// calculated so far. This way, many overlapping areas can combine diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp index 9e1cd23989..9016ec3bf5 100644 --- a/modules/bullet/slider_joint_bullet.cpp +++ b/modules/bullet/slider_joint_bullet.cpp @@ -366,6 +366,7 @@ void SliderJointBullet::set_param(PhysicsServer::SliderJointParam p_param, real_ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoAng(p_value); break; case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoAng(p_value); break; case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: setDampingOrthoAng(p_value); break; + case PhysicsServer::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning } } diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index 17af6bff09..732b9cf733 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -118,7 +118,7 @@ static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const cvtt::Kernels::EncodeBC7(output_blocks, input_blocks_ldr, p_job_params.options); } - int num_real_blocks = ((w - x_start) + 3) / 4; + unsigned int num_real_blocks = ((w - x_start) + 3) / 4; if (num_real_blocks > cvtt::NumParallelBlocks) { num_real_blocks = cvtt::NumParallelBlocks; } @@ -131,7 +131,7 @@ static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const static void _digest_job_queue(void *p_job_queue) { CVTTCompressionJobQueue *job_queue = static_cast<CVTTCompressionJobQueue *>(p_job_queue); - for (int next_task = atomic_increment(&job_queue->current_task); next_task <= job_queue->num_tasks; next_task = atomic_increment(&job_queue->current_task)) { + for (uint32_t next_task = atomic_increment(&job_queue->current_task); next_task <= job_queue->num_tasks; next_task = atomic_increment(&job_queue->current_task)) { _digest_row_task(job_queue->job_params, job_queue->job_tasks[next_task - 1]); } } @@ -228,8 +228,6 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressS uint8_t *out_bytes = &wb[dst_ofs]; for (int y_start = 0; y_start < h; y_start += 4) { - int y_end = y_start + 4; - CVTTCompressionRowTask row_task; row_task.width = w; row_task.height = h; @@ -308,7 +306,6 @@ void image_decompress_cvtt(Image *p_image) { int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps()); int mm_count = p_image->get_mipmap_count(); data.resize(target_size); - int shift = Image::get_format_pixel_rshift(target_format); PoolVector<uint8_t>::Write wb = data.write(); @@ -335,7 +332,7 @@ void image_decompress_cvtt(Image *p_image) { uint8_t input_blocks[16 * cvtt::NumParallelBlocks]; memset(input_blocks, 0, sizeof(input_blocks)); - int num_real_blocks = ((w - x_start) + 3) / 4; + unsigned int num_real_blocks = ((w - x_start) + 3) / 4; if (num_real_blocks > cvtt::NumParallelBlocks) { num_real_blocks = cvtt::NumParallelBlocks; } diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index 0a1061f92e..7b5fd854ff 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -207,13 +207,13 @@ void NetworkedMultiplayerENet::poll() { _pop_current_packet(); ENetEvent event; - /* Wait up to 1000 milliseconds for an event. */ + /* Keep servicing until there are no available events left in queue. */ while (true) { if (!host || !active) // Might have been disconnected while emitting a notification return; - int ret = enet_host_service(host, &event, 1); + int ret = enet_host_service(host, &event, 0); if (ret < 0) { // Error, do something? @@ -293,7 +293,7 @@ void NetworkedMultiplayerENet::poll() { encode_uint32(*id, &packet->data[4]); enet_peer_send(E->get(), SYSCH_CONFIG, packet); } - } else if (!server) { + } else { emit_signal("server_disconnected"); close_connection(); return; diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_etc.cpp index a534aec11b..57f5b68c61 100644 --- a/modules/etc/image_etc.cpp +++ b/modules/etc/image_etc.cpp @@ -47,13 +47,14 @@ static Image::Format _get_etc2_mode(Image::DetectChannels format) { case Image::DETECTED_RGB: return Image::FORMAT_ETC2_RGB8; - default: + case Image::DETECTED_RGBA: return Image::FORMAT_ETC2_RGBA8; - // TODO: would be nice if we could use FORMAT_ETC2_RGB8A1 for FORMAT_RGBA5551 + // TODO: would be nice if we could use FORMAT_ETC2_RGB8A1 for FORMAT_RGBA5551 + default: + // TODO: Kept for compatibility, but should be investigated whether it's correct or if it should error out + return Image::FORMAT_ETC2_RGBA8; } - - ERR_FAIL_COND_V(true, Image::FORMAT_MAX); } static Etc::Image::Format _image_format_to_etc2comp_format(Image::Format format) { @@ -81,9 +82,10 @@ static Etc::Image::Format _image_format_to_etc2comp_format(Image::Format format) case Image::FORMAT_ETC2_RGB8A1: return Etc::Image::Format::RGB8A1; - } - ERR_FAIL_COND_V(true, Etc::Image::Format::UNKNOWN); + default: + ERR_FAIL_V(Etc::Image::Format::UNKNOWN); + } } static void _decompress_etc1(Image *p_img) { @@ -174,7 +176,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f PoolVector<uint8_t>::Read r = img->get_data().read(); - int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps()); + unsigned int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps()); int mmc = 1 + (p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0); PoolVector<uint8_t> dst_data; diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 48c0fc8aef..62e87c3651 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -29,19 +29,19 @@ /*************************************************************************/ #include "register_types.h" + #include "gdnative/gdnative.h" #include "gdnative.h" -#include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" - #include "arvr/register_types.h" #include "nativescript/register_types.h" #include "net/register_types.h" #include "pluginscript/register_types.h" #include "core/engine.h" +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" #include "core/os/os.h" #include "core/project_settings.h" @@ -148,7 +148,7 @@ protected: }; struct LibrarySymbol { - char *name; + const char *name; bool is_required; }; @@ -239,7 +239,7 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n" "extern void add_ios_init_callback(void (*cb)());\n"; String linker_flags = ""; - for (int i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) { + for (unsigned int i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) { String full_name = lib->get_symbol_prefix() + expected_symbols[i].name; String code = declare_pattern.replace("$name", full_name); code = code.replace("$weak", expected_symbols[i].is_required ? "" : " __attribute__((weak))"); @@ -255,7 +255,7 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty additional_code += String("void $prefixinit() {\n").replace("$prefix", lib->get_symbol_prefix()); String register_pattern = " if (&$name) register_dynamic_symbol((char *)\"$name\", (void *)$name);\n"; - for (int i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) { + for (unsigned int i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) { String full_name = lib->get_symbol_prefix() + expected_symbols[i].name; additional_code += register_pattern.replace("$name", full_name); } diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index b0d5422afe..48c1760662 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1981,6 +1981,7 @@ String GDScriptWarning::get_message() const { CHECK_SYMBOLS(2); return "The '" + symbols[0] + "' keyword is deprecated and will be removed in a future release, please replace its uses by '" + symbols[1] + "'."; } break; + case WARNING_MAX: break; // Can't happen, but silences warning } ERR_EXPLAIN("Invalid GDScript warning code: " + get_name_from_code(code)); ERR_FAIL_V(String()); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index d795500265..4a74b0712a 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -147,7 +147,7 @@ public: const Map<StringName, Variant> &get_constants() const { return constants; } const Set<StringName> &get_members() const { return members; } const GDScriptDataType &get_member_type(const StringName &p_member) const { - ERR_FAIL_COND_V(!member_indices.has(p_member), GDScriptDataType()); + CRASH_COND(!member_indices.has(p_member)); return member_indices[p_member].data_type; } const Map<StringName, GDScriptFunction *> &get_member_functions() const { return member_functions; } diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index a9b641de50..55bc3d2359 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -33,12 +33,9 @@ #include "core/engine.h" #include "core/global_constants.h" #include "core/os/file_access.h" -#include "editor/editor_settings.h" #include "gdscript_compiler.h" #ifdef TOOLS_ENABLED -#include "core/engine.h" -#include "core/reference.h" #include "editor/editor_file_system.h" #include "editor/editor_settings.h" #endif @@ -1113,6 +1110,7 @@ static bool _guess_expression_type(const GDScriptCompletionContext &p_context, c } break; } } break; + default: {} } // It may have found a null, but that's never useful @@ -3357,6 +3355,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol return OK; } } break; + default: {} } return ERR_CANT_RESOLVE; diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index abd08d13ff..b935861652 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -789,7 +789,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *()); GD_ERR_BREAK(!nc); - if (!src->get_type() != Variant::OBJECT && !src->get_type() != Variant::NIL) { + if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) { err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) + "' to a variable of type '" + nc->get_name() + "'."; OPCODE_BREAK; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index ea1287374b..5facfe7869 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -5079,7 +5079,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) { if (found) continue; if (p->constant_expressions.has(base)) { - if (!p->constant_expressions[base].expression->type == Node::TYPE_CONSTANT) { + if (p->constant_expressions[base].expression->type != Node::TYPE_CONSTANT) { _set_error("Could not resolve constant '" + base + "'.", p_class->line); return; } @@ -5219,6 +5219,8 @@ String GDScriptParser::DataType::to_string() const { } return class_type->name.operator String(); } break; + case UNRESOLVED: { + } break; } return "Unresolved"; @@ -5791,7 +5793,10 @@ bool GDScriptParser::_is_type_compatible(const DataType &p_container, const Data expr_native = base->base_type.native_type; expr_script = base->base_type.script_type; } - } + } break; + case DataType::BUILTIN: // Already handled above + case DataType::UNRESOLVED: // Not allowed, see above + break; } switch (p_container.kind) { @@ -5834,7 +5839,10 @@ bool GDScriptParser::_is_type_compatible(const DataType &p_container, const Data expr_class = expr_class->base_type.class_type; } return false; - } + } break; + case DataType::BUILTIN: // Already handled above + case DataType::UNRESOLVED: // Not allowed, see above + break; } return false; @@ -6228,6 +6236,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { case Variant::COLOR: { error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::STRING; } break; + default: {} } } if (error) { @@ -6345,6 +6354,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { } } } break; + default: {} } p_node->set_datatype(_resolve_type(node_type, p_node->line)); diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index cd68072499..c7813a2144 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -88,6 +88,8 @@ public: case CLASS: { return class_type == other.class_type; } break; + case UNRESOLVED: { + } break; } return false; } diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index a480c4183e..a8fdf8cf1f 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -29,37 +29,19 @@ /*************************************************************************/ #include "grid_map.h" -#include "core/message_queue.h" -#include "scene/3d/light.h" -#include "scene/resources/surface_tool.h" -#include "servers/visual_server.h" #include "core/io/marshalls.h" -#include "core/os/os.h" +#include "core/message_queue.h" +#include "scene/3d/light.h" #include "scene/resources/mesh_library.h" +#include "scene/resources/surface_tool.h" #include "scene/scene_string_names.h" +#include "servers/visual_server.h" bool GridMap::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; - /* } else if (name=="cells") { - PoolVector<int> cells = p_value; - int amount=cells.size(); - PoolVector<int>::Read r = cells.read(); - ERR_FAIL_COND_V(amount&1,false); // not even - cell_map.clear(); - for(int i=0;i<amount/3;i++) { - - - IndexKey ik; - ik.key=decode_uint64(&r[i*3]); - Cell cell; - cell.cell=uint32_t(r[i*+1]); - cell_map[ik]=cell; - - } - _recreate_octant_data();*/ if (name == "data") { Dictionary d = p_value; @@ -80,7 +62,9 @@ bool GridMap::_set(const StringName &p_name, const Variant &p_value) { cell_map[ik] = cell; } } + _recreate_octant_data(); + } else if (name == "baked_meshes") { clear_baked_meshes(); @@ -103,8 +87,9 @@ bool GridMap::_set(const StringName &p_name, const Variant &p_value) { _recreate_octant_data(); - } else + } else { return false; + } return true; } @@ -1081,8 +1066,6 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe } } - int ofs = 0; - for (Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool> > >::Element *E = surface_map.front(); E; E = E->next()) { Ref<ArrayMesh> mesh; diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 5fdb6a5196..fae88042af 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -597,29 +597,31 @@ bool GridMapEditor::forward_spatial_input_event(Camera *p_camera, const Ref<Inpu if (mb->get_button_index() == BUTTON_LEFT) { if (input_action == INPUT_DUPLICATE) { - //paste _duplicate_paste(); input_action = INPUT_NONE; _update_duplicate_indicator(); } else if (mb->get_shift()) { input_action = INPUT_SELECT; - } else if (mb->get_command()) + } else if (mb->get_command()) { input_action = INPUT_COPY; - else { + } else { input_action = INPUT_PAINT; set_items.clear(); } - } else if (mb->get_button_index() == BUTTON_RIGHT) + } else if (mb->get_button_index() == BUTTON_RIGHT) { if (input_action == INPUT_DUPLICATE) { - input_action = INPUT_NONE; _update_duplicate_indicator(); } else if (mb->get_shift()) { input_action = INPUT_ERASE; set_items.clear(); - } else + } else { return false; + } + } else { + return false; + } return do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true); } else { diff --git a/modules/mbedtls/stream_peer_mbed_tls.cpp b/modules/mbedtls/stream_peer_mbed_tls.cpp index e0cd67a810..5c81f32e9e 100755 --- a/modules/mbedtls/stream_peer_mbed_tls.cpp +++ b/modules/mbedtls/stream_peer_mbed_tls.cpp @@ -29,9 +29,11 @@ /*************************************************************************/ #include "stream_peer_mbed_tls.h" + #include "core/io/stream_peer_tcp.h" #include "core/os/file_access.h" -#include "mbedtls/platform_util.h" + +#include <mbedtls/platform_util.h> static void my_debug(void *ctx, int level, const char *file, int line, @@ -283,7 +285,7 @@ void StreamPeerMbedTLS::poll() { } Ref<StreamPeerTCP> tcp = base; - if (tcp.is_valid() && tcp->get_status() != STATUS_CONNECTED) { + if (tcp.is_valid() && tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) { disconnect_from_stream(); return; } @@ -310,7 +312,7 @@ void StreamPeerMbedTLS::disconnect_from_stream() { return; Ref<StreamPeerTCP> tcp = base; - if (tcp.is_valid() && tcp->get_status() == STATUS_CONNECTED) { + if (tcp.is_valid() && tcp->get_status() == StreamPeerTCP::STATUS_CONNECTED) { // We are still connected on the socket, try to send close notity. mbedtls_ssl_close_notify(&ssl); } diff --git a/modules/mbedtls/stream_peer_mbed_tls.h b/modules/mbedtls/stream_peer_mbed_tls.h index 0cf893eacf..abf87b79cc 100755 --- a/modules/mbedtls/stream_peer_mbed_tls.h +++ b/modules/mbedtls/stream_peer_mbed_tls.h @@ -33,12 +33,12 @@ #include "core/io/stream_peer_ssl.h" -#include "mbedtls/config.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/debug.h" -#include "mbedtls/entropy.h" -#include "mbedtls/net.h" -#include "mbedtls/ssl.h" +#include <mbedtls/config.h> +#include <mbedtls/ctr_drbg.h> +#include <mbedtls/debug.h> +#include <mbedtls/entropy.h> +#include <mbedtls/net.h> +#include <mbedtls/ssl.h> #include <stdio.h> #include <stdlib.h> diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index e2c630565f..2cabc7bd59 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -297,6 +297,7 @@ bool MobileVRInterface::initialize() { mag_current_min = Vector3(0, 0, 0); mag_current_max = Vector3(0, 0, 0); +#if !defined(SERVER_ENABLED) // build our shader if (lens_shader == NULL) { ///@TODO need to switch between GLES2 and GLES3 version, Reduz suggested moving this into our drivers and making this a core shader @@ -337,6 +338,7 @@ bool MobileVRInterface::initialize() { glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind } +#endif // reset our orientation orientation = Basis(); @@ -360,6 +362,7 @@ void MobileVRInterface::uninitialize() { arvr_server->clear_primary_interface_if(this); } +#if !defined(SERVER_ENABLED) // cleanup our shader and buffers if (lens_shader != NULL) { glDeleteVertexArrays(1, &half_screen_array); @@ -368,6 +371,7 @@ void MobileVRInterface::uninitialize() { delete lens_shader; lens_shader = NULL; } +#endif initialized = false; }; @@ -470,6 +474,7 @@ void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_t // get our render target RID eye_texture = VSG::storage->render_target_get_texture(p_render_target); uint32_t texid = VS::get_singleton()->texture_get_texid(eye_texture); +#if !defined(SERVER_ENABLED) glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texid); @@ -484,6 +489,7 @@ void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_t glBindVertexArray(half_screen_array); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindVertexArray(0); +#endif }; void MobileVRInterface::process() { diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h index cee0cca90e..63cad4c738 100644 --- a/modules/mobile_vr/mobile_vr_interface.h +++ b/modules/mobile_vr/mobile_vr_interface.h @@ -34,7 +34,9 @@ #include "servers/arvr/arvr_interface.h" #include "servers/arvr/arvr_positional_tracker.h" +#if !defined(SERVER_ENABLED) #include "shaders/lens_distorted.glsl.gen.h" +#endif /** @author Bastiaan Olij <mux213@gmail.com> @@ -58,9 +60,13 @@ private: float eye_height; uint64_t last_ticks; +#if !defined(SERVER_ENABLED) LensDistortedShaderGLES3 *lens_shader; GLuint half_screen_quad; GLuint half_screen_array; +#else + void *lens_shader; +#endif real_t intraocular_dist; real_t display_width; diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index c013c232d4..91fd482235 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1174,7 +1174,7 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { GDMonoProperty *property = script->script_class->get_property(p_name); if (property) { - property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value)); + property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value, property->get_type())); return true; } diff --git a/modules/mono/glue/Managed/Files/Array.cs b/modules/mono/glue/Managed/Files/Array.cs index c80cb7cc83..d5a35d7ae0 100644 --- a/modules/mono/glue/Managed/Files/Array.cs +++ b/modules/mono/glue/Managed/Files/Array.cs @@ -128,7 +128,7 @@ namespace Godot.Collections for (int i = 0; i < count; i++) { - yield return godot_icall_Array_At(GetPtr(), i); + yield return this[i]; } } @@ -167,6 +167,9 @@ namespace Godot.Collections internal extern static object godot_icall_Array_At(IntPtr ptr, int index); [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value); [MethodImpl(MethodImplOptions.InternalCall)] @@ -195,12 +198,23 @@ namespace Godot.Collections [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass); } public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T> { Array objectArray; + internal static int elemTypeEncoding; + internal static IntPtr elemTypeClass; + + static Array() + { + Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass); + } + public Array() { objectArray = new Array(); @@ -230,7 +244,7 @@ namespace Godot.Collections { get { - return (T)objectArray[index]; + return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); } set { @@ -287,7 +301,7 @@ namespace Godot.Collections for (int i = 0; i < count; i++) { - array[arrayIndex] = (T)objectArray[i]; + array[arrayIndex] = (T)this[i]; arrayIndex++; } } @@ -298,7 +312,7 @@ namespace Godot.Collections for (int i = 0; i < count; i++) { - yield return (T)objectArray[i]; + yield return (T)this[i]; } } diff --git a/modules/mono/glue/Managed/Files/Dictionary.cs b/modules/mono/glue/Managed/Files/Dictionary.cs index 523e48c31a..7695f03cd6 100644 --- a/modules/mono/glue/Managed/Files/Dictionary.cs +++ b/modules/mono/glue/Managed/Files/Dictionary.cs @@ -204,6 +204,9 @@ namespace Godot.Collections internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key); [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] @@ -235,6 +238,12 @@ namespace Godot.Collections [MethodImpl(MethodImplOptions.InternalCall)] internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass); } public class Dictionary<TKey, TValue> : @@ -244,6 +253,14 @@ namespace Godot.Collections { Dictionary objectDict; + internal static int valTypeEncoding; + internal static IntPtr valTypeClass; + + static Dictionary() + { + Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass); + } + public Dictionary() { objectDict = new Dictionary(); @@ -273,7 +290,7 @@ namespace Godot.Collections { get { - return (TValue)objectDict[key]; + return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); } set { @@ -382,7 +399,7 @@ namespace Godot.Collections public bool TryGetValue(TKey key, out TValue value) { object retValue; - bool found = objectDict.TryGetValue(key, out retValue); + bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass); value = found ? (TValue)retValue : default(TValue); return found; } diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index d9dba1c60d..059e2ff6de 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -53,6 +53,14 @@ MonoObject *godot_icall_Array_At(Array *ptr, int index) { return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index)); } +MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class) { + if (index < 0 || index > ptr->size()) { + GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); + return NULL; + } + return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class)); +} + void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) { if (index < 0 || index > ptr->size()) { GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); @@ -122,6 +130,14 @@ void godot_icall_Array_RemoveAt(Array *ptr, int index) { ptr->remove(index); } +void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) { + MonoType *elem_type = mono_reflection_type_get_type(refltype); + + *type_encoding = mono_type_get_type(elem_type); + MonoClass *type_class_raw = mono_class_from_mono_type(elem_type); + *type_class = GDMono::get_singleton()->get_class(type_class_raw); +} + Dictionary *godot_icall_Dictionary_Ctor() { return memnew(Dictionary); } @@ -144,6 +160,20 @@ MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) { return GDMonoMarshal::variant_to_mono_object(ret); } +MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class) { + Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); + if (ret == NULL) { + MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr()); +#ifdef DEBUG_ENABLED + CRASH_COND(!exc); +#endif + GDMonoUtils::runtime_object_init(exc); + GDMonoUtils::set_pending_exception((MonoException *)exc); + return NULL; + } + return GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class)); +} + void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) { ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value); } @@ -211,10 +241,29 @@ bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoOb return true; } +bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) { + Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); + if (ret == NULL) { + *value = NULL; + return false; + } + *value = GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class)); + return true; +} + +void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) { + MonoType *value_type = mono_reflection_type_get_type(refltype); + + *type_encoding = mono_type_get_type(value_type); + MonoClass *type_class_raw = mono_class_from_mono_type(value_type); + *type_class = GDMono::get_singleton()->get_class(type_class_raw); +} + void godot_register_collections_icalls() { mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At", (void *)godot_icall_Array_At); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", (void *)godot_icall_Array_At_Generic); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add); @@ -225,10 +274,12 @@ void godot_register_collections_icalls() { mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove); mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt); + mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", (void *)godot_icall_Array_Generic_GetElementTypeInfo); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", (void *)godot_icall_Dictionary_GetValue_Generic); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values); @@ -240,6 +291,8 @@ void godot_register_collections_icalls() { mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove); mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", (void *)godot_icall_Dictionary_TryGetValue_Generic); + mono_add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", (void *)godot_icall_Dictionary_Generic_GetValueTypeInfo); } #endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/collections_glue.h b/modules/mono/glue/collections_glue.h index fa8e4c28aa..b9b1338510 100644 --- a/modules/mono/glue/collections_glue.h +++ b/modules/mono/glue/collections_glue.h @@ -45,6 +45,8 @@ void godot_icall_Array_Dtor(Array *ptr); MonoObject *godot_icall_Array_At(Array *ptr, int index); +MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class); + void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value); int godot_icall_Array_Count(Array *ptr); @@ -65,6 +67,8 @@ bool godot_icall_Array_Remove(Array *ptr, MonoObject *item); void godot_icall_Array_RemoveAt(Array *ptr, int index); +void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class); + // Dictionary Dictionary *godot_icall_Dictionary_Ctor(); @@ -73,6 +77,8 @@ void godot_icall_Dictionary_Dtor(Dictionary *ptr); MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key); +MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class); + void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value); Array *godot_icall_Dictionary_Keys(Dictionary *ptr); @@ -95,6 +101,10 @@ bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value); +bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class); + +void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class); + // Register internal calls void godot_register_collections_icalls(); diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 2fed6064b7..9311aa3930 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -259,14 +259,15 @@ void GDMono::initialize() { // The following assemblies are not required at initialization #ifdef MONO_GLUE_ENABLED if (_load_api_assemblies()) { - if (!core_api_assembly_out_of_sync && !editor_api_assembly_out_of_sync && GDMonoUtils::mono_cache.godot_api_cache_updated) { - // Everything is fine with the api assemblies, load the project assembly - _load_project_assembly(); - } else { + // Everything is fine with the api assemblies, load the project assembly + _load_project_assembly(); + } else { + if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) || + (editor_api_assembly && editor_api_assembly_out_of_sync)) { #ifdef TOOLS_ENABLED // The assembly was successfully loaded, but the full api could not be cached. - // This is most likely an outdated assembly loaded because of an invalid version in the metadata, - // so we invalidate the version in the metadata and unload the script domain. + // This is most likely an outdated assembly loaded because of an invalid version in the + // metadata, so we invalidate the version in the metadata and unload the script domain. if (core_api_assembly_out_of_sync) { ERR_PRINT("The loaded Core API assembly is out of sync"); @@ -290,12 +291,12 @@ void GDMono::initialize() { #else ERR_PRINT("The loaded API assembly is invalid"); CRASH_NOW(); -#endif +#endif // TOOLS_ENABLED } } #else print_verbose("Mono: Glue disabled, ignoring script assemblies."); -#endif +#endif // MONO_GLUE_ENABLED print_verbose("Mono: INITIALIZED"); } @@ -448,8 +449,10 @@ bool GDMono::_load_core_api_assembly() { return true; #ifdef TOOLS_ENABLED - if (metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) + if (metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) { + print_verbose("Mono: Skipping loading of Core API assembly because it was invalidated"); return false; + } #endif bool success = load_assembly(API_ASSEMBLY_NAME, &core_api_assembly); @@ -460,8 +463,12 @@ bool GDMono::_load_core_api_assembly() { core_api_assembly_out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash || GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version || CS_GLUE_VERSION != api_assembly_ver.cs_glue_version; -#endif + if (!core_api_assembly_out_of_sync) { + GDMonoUtils::update_godot_api_cache(); + } +#else GDMonoUtils::update_godot_api_cache(); +#endif } return success; @@ -474,8 +481,10 @@ bool GDMono::_load_editor_api_assembly() { return true; #ifdef TOOLS_ENABLED - if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) + if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) { + print_verbose("Mono: Skipping loading of Editor API assembly because it was invalidated"); return false; + } #endif bool success = load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly); @@ -533,16 +542,22 @@ bool GDMono::_load_api_assemblies() { if (OS::get_singleton()->is_stdout_verbose()) print_error("Mono: Failed to load Core API assembly"); return false; - } else { + } + + if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated) + return false; + #ifdef TOOLS_ENABLED - if (!_load_editor_api_assembly()) { - if (OS::get_singleton()->is_stdout_verbose()) - print_error("Mono: Failed to load Editor API assembly"); - return false; - } -#endif + if (!_load_editor_api_assembly()) { + if (OS::get_singleton()->is_stdout_verbose()) + print_error("Mono: Failed to load Editor API assembly"); + return false; } + if (editor_api_assembly_out_of_sync) + return false; +#endif + return true; } @@ -708,43 +723,42 @@ Error GDMono::reload_scripts_domain() { #ifdef MONO_GLUE_ENABLED if (!_load_api_assemblies()) { - return ERR_CANT_OPEN; - } + if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) || + (editor_api_assembly && editor_api_assembly_out_of_sync)) { + // The assembly was successfully loaded, but the full api could not be cached. + // This is most likely an outdated assembly loaded because of an invalid version in the + // metadata, so we invalidate the version in the metadata and unload the script domain. - if (!core_api_assembly_out_of_sync && !editor_api_assembly_out_of_sync && GDMonoUtils::mono_cache.godot_api_cache_updated) { - // Everything is fine with the api assemblies, load the project assembly - _load_project_assembly(); - } else { - // The assembly was successfully loaded, but the full api could not be cached. - // This is most likely an outdated assembly loaded because of an invalid version in the metadata, - // so we invalidate the version in the metadata and unload the script domain. - - if (core_api_assembly_out_of_sync) { - ERR_PRINT("The loaded Core API assembly is out of sync"); - metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); - } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { - ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed"); - metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); - } + if (core_api_assembly_out_of_sync) { + ERR_PRINT("The loaded Core API assembly is out of sync"); + metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); + } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { + ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed"); + metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); + } - if (editor_api_assembly_out_of_sync) { - ERR_PRINT("The loaded Editor API assembly is out of sync"); - metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); - } + if (editor_api_assembly_out_of_sync) { + ERR_PRINT("The loaded Editor API assembly is out of sync"); + metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); + } - Error err = _unload_scripts_domain(); - if (err != OK) { - WARN_PRINT("Mono: Failed to unload scripts domain"); - } + Error err = _unload_scripts_domain(); + if (err != OK) { + WARN_PRINT("Mono: Failed to unload scripts domain"); + } - return ERR_CANT_RESOLVE; + return ERR_CANT_RESOLVE; + } else { + return ERR_CANT_OPEN; + } } - if (!_load_project_assembly()) + if (!_load_project_assembly()) { return ERR_CANT_OPEN; + } #else print_verbose("Mono: Glue disabled, ignoring script assemblies."); -#endif +#endif // MONO_GLUE_ENABLED return OK; } diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h index 2fe05006f1..4f2efc7b92 100644 --- a/modules/mono/mono_gd/gd_mono_header.h +++ b/modules/mono/mono_gd/gd_mono_header.h @@ -44,9 +44,14 @@ struct ManagedType { int type_encoding; GDMonoClass *type_class; - ManagedType() { - type_encoding = 0; - type_class = NULL; + ManagedType() : + type_encoding(0), + type_class(NULL) { + } + + ManagedType(int p_type_encoding, GDMonoClass *p_type_class) : + type_encoding(p_type_encoding), + type_class(p_type_class) { } }; diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 1ad0a4a6ea..cc0ab5fa05 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -97,10 +97,14 @@ _FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) { MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type); MonoObject *variant_to_mono_object(const Variant *p_var); -_FORCE_INLINE_ MonoObject *variant_to_mono_object(Variant p_var) { +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var) { return variant_to_mono_object(&p_var); } +_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) { + return variant_to_mono_object(&p_var, p_type); +} + Variant mono_object_to_variant(MonoObject *p_obj); // Array diff --git a/modules/opensimplex/simplex_noise.cpp b/modules/opensimplex/simplex_noise.cpp index e489b7f6f0..c99fd7b123 100644 --- a/modules/opensimplex/simplex_noise.cpp +++ b/modules/opensimplex/simplex_noise.cpp @@ -196,7 +196,7 @@ float SimplexNoise::get_noise_2d(float x, float y) { float max = 1.0; float sum = _get_octave_noise_2d(0, x, y); - unsigned int i = 0; + int i = 0; while (++i < octaves) { x *= lacunarity; y *= lacunarity; @@ -218,7 +218,7 @@ float SimplexNoise::get_noise_3d(float x, float y, float z) { float max = 1.0; float sum = _get_octave_noise_3d(0, x, y, z); - unsigned int i = 0; + int i = 0; while (++i < octaves) { x *= lacunarity; y *= lacunarity; @@ -242,7 +242,7 @@ float SimplexNoise::get_noise_4d(float x, float y, float z, float w) { float max = 1.0; float sum = _get_octave_noise_4d(0, x, y, z, w); - unsigned int i = 0; + int i = 0; while (++i < octaves) { x *= lacunarity; y *= lacunarity; diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 44052d473f..d72d74cf79 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -332,8 +332,8 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { int w; int h; - w = (ti.pic_x + ti.frame_width + 1 & ~1) - (ti.pic_x & ~1); - h = (ti.pic_y + ti.frame_height + 1 & ~1) - (ti.pic_y & ~1); + w = ((ti.pic_x + ti.frame_width + 1) & ~1) - (ti.pic_x & ~1); + h = ((ti.pic_y + ti.frame_height + 1) & ~1) - (ti.pic_y & ~1); size.x = w; size.y = h; @@ -439,7 +439,7 @@ void VideoStreamPlaybackTheora::update(float p_delta) { } } - int tr = vorbis_synthesis_read(&vd, ret - to_read); + vorbis_synthesis_read(&vd, ret - to_read); audio_frames_wrote += ret - to_read; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 1027c74f34..79f71535ad 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -2518,8 +2518,6 @@ void VisualScriptEditor::_port_action_menu(int p_option) { } ofs /= EDSCALE; - bool seq_connect = false; - Set<int> vn; switch (p_option) { @@ -2552,7 +2550,6 @@ void VisualScriptEditor::_port_action_menu(int p_option) { } } break; case CREATE_ACTION: { - seq_connect = true; VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); PropertyInfo property_info = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output); if (tg.type == Variant::OBJECT) { @@ -2603,7 +2600,6 @@ void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<Visua if (port >= value_count) { port = 0; } - int count = vnode_old->get_output_value_port_count() + vnode_old->get_output_sequence_port_count(); undo_redo->add_do_method(script.ptr(), "data_connect", edited_func, port_action_node, port, new_id, 0); undo_redo->add_undo_method(script.ptr(), "data_disconnect", edited_func, port_action_node, port, new_id, 0); undo_redo->commit_action(); @@ -2657,7 +2653,6 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri Ref<VisualScriptNode> vnode; - seq_connect = false; if (p_category == String("method")) { Ref<VisualScriptFunctionCall> n; @@ -2683,38 +2678,32 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri Ref<VisualScriptCondition> n; n.instance(); vnode = n; - seq_connect = true; } if (p_text == "VisualScriptSwitch") { Ref<VisualScriptSwitch> n; n.instance(); vnode = n; - seq_connect = true; } else if (p_text == "VisualScriptSequence") { Ref<VisualScriptSequence> n; n.instance(); vnode = n; - seq_connect = true; } else if (p_text == "VisualScriptIterator") { Ref<VisualScriptIterator> n; n.instance(); vnode = n; - seq_connect = true; } else if (p_text == "VisualScriptWhile") { Ref<VisualScriptWhile> n; n.instance(); vnode = n; - seq_connect = true; } else if (p_text == "VisualScriptReturn") { Ref<VisualScriptReturn> n; n.instance(); vnode = n; - seq_connect = true; } } @@ -2826,7 +2815,6 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri } void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id) { - int seq_count = vnode_old->get_output_sequence_port_count(); VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(vnode_new.ptr()); if (vnode_operator != NULL && vnode_operator->has_input_sequence_port() == false) { return; @@ -2841,7 +2829,7 @@ void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<Visual if (vnode_new->has_input_sequence_port() == false) { return; } - VisualScriptFunction *vnode_function = Object::cast_to<VisualScriptFunction>(vnode_old.ptr()); + undo_redo->create_action(TTR("Connect Node Sequence")); int pass_port = -vnode_old->get_output_sequence_port_count() + 1; int return_port = port_action_output - 1; @@ -3367,11 +3355,6 @@ void VisualScriptEditor::_member_option(int p_option) { undo_redo->add_undo_method(script.ptr(), "data_connect", name, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); } - /* - for(int i=0;i<script->function_get_argument_count(name);i++) { - undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i)); - } - */ undo_redo->add_do_method(this, "_update_members"); undo_redo->add_undo_method(this, "_update_members"); undo_redo->add_do_method(this, "_update_graph"); diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index b0bf971630..fb90e346a4 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -37,6 +37,7 @@ #include "scene/gui/graph_edit.h" #include "visual_script.h" #include "visual_script_property_selector.h" + class VisualScriptEditorSignalEdit; class VisualScriptEditorVariableEdit; @@ -159,8 +160,6 @@ class VisualScriptEditor : public ScriptEditorBase { MemberType member_type; String member_name; - bool seq_connect = false; - PortAction port_action; int port_action_node; int port_action_output; diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp index 9942d5baa6..e2e5cc77f5 100644 --- a/modules/visual_script/visual_script_property_selector.cpp +++ b/modules/visual_script/visual_script_property_selector.cpp @@ -190,15 +190,14 @@ void VisualScriptPropertySelector::_update_search() { if (type_filter.size() && type_filter.find(E->get().type) == -1) continue; + // capitalize() also converts underscore to space, we'll match again both possible styles String get_text_raw = String(vformat(TTR("Get %s"), E->get().name)); String get_text = get_text_raw.capitalize(); - String set_text_raw = String(vformat(TTR("Set %s"), E->get().name)); String set_text = set_text_raw.capitalize(); String input = search_box->get_text().capitalize(); - if (input == String() || - get_text_raw.findn(input) != -1 || - get_text.findn(input) != -1) { + + if (input == String() || get_text_raw.findn(input) != -1 || get_text.findn(input) != -1) { TreeItem *item = search_options->create_item(category ? category : root); item->set_text(0, get_text); item->set_metadata(0, E->get().name); @@ -211,9 +210,7 @@ void VisualScriptPropertySelector::_update_search() { item->set_metadata(2, connecting); } - if (input == String() || - set_text_raw.findn(input) != -1 && - set_text.findn(input) != -1) { + if (input == String() || set_text_raw.findn(input) != -1 || set_text.findn(input) != -1) { TreeItem *item = search_options->create_item(category ? category : root); item->set_text(0, set_text); item->set_metadata(0, E->get().name); @@ -389,8 +386,8 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt } Vector<String> path = E->get().split("/"); bool is_filter = false; - for (Set<String>::Element *E = filter.front(); E; E = E->next()) { - if (path.size() >= 2 && path[1].findn(E->get()) != -1) { + for (Set<String>::Element *F = filter.front(); F; F = F->next()) { + if (path.size() >= 2 && path[1].findn(F->get()) != -1) { is_filter = true; break; } @@ -721,6 +718,7 @@ VisualScriptPropertySelector::VisualScriptPropertySelector() { search_options->set_hide_root(true); search_options->set_hide_folding(true); virtuals_only = false; + seq_connect = false; help_bit = memnew(EditorHelpBit); vbc->add_margin_child(TTR("Description:"), help_bit); help_bit->connect("request_hide", this, "_closed"); diff --git a/modules/visual_script/visual_script_property_selector.h b/modules/visual_script/visual_script_property_selector.h index 917ef9ae6d..f974ee3355 100644 --- a/modules/visual_script/visual_script_property_selector.h +++ b/modules/visual_script/visual_script_property_selector.h @@ -63,8 +63,7 @@ class VisualScriptPropertySelector : public ConfirmationDialog { ObjectID script; Object *instance; bool virtuals_only; - - bool seq_connect = false; + bool seq_connect; void _item_selected(); diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub index 2daf8c282f..711000bd9f 100644 --- a/modules/webm/libvpx/SCsub +++ b/modules/webm/libvpx/SCsub @@ -349,7 +349,7 @@ if webm_multithread: env_libvpx.add_source_files(env.modules_sources, libvpx_sources_mt) if webm_cpu_x86: - is_clang_or_gcc = ('gcc' in env["CC"]) or ('clang' in env["CC"]) or ("OSXCROSS_ROOT" in os.environ) + is_clang_or_gcc = ('gcc' in os.path.basename(env["CC"])) or ('clang' in os.path.basename(env["CC"])) or ("OSXCROSS_ROOT" in os.environ) env_libvpx_mmx = env_libvpx.Clone() if cpu_bits == '32' and is_clang_or_gcc: diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml index 9241492623..b3ea535495 100644 --- a/modules/websocket/doc_classes/WebSocketClient.xml +++ b/modules/websocket/doc_classes/WebSocketClient.xml @@ -31,8 +31,12 @@ <method name="disconnect_from_host"> <return type="void"> </return> + <argument index="0" name="code" type="int" default="1000"> + </argument> + <argument index="1" name="reason" type="String" default=""""> + </argument> <description> - Disconnect from the server if currently connected. + Disconnect this client from the connected host. See [method WebSocketPeer.close] for more info. </description> </method> </methods> @@ -43,8 +47,10 @@ </members> <signals> <signal name="connection_closed"> + <argument index="0" name="was_clean_close" type="bool"> + </argument> <description> - Emitted when the connection to the server is closed. + Emitted when the connection to the server is closed. [code]was_clean_close[/code] will be [code]true[/code] if the connection was shutdown cleanly. </description> </signal> <signal name="connection_error"> @@ -64,6 +70,15 @@ Emitted when a WebSocket message is received. Note: This signal is NOT emitted when used as high level multiplayer peer. </description> </signal> + <signal name="server_close_request"> + <argument index="0" name="code" type="int"> + </argument> + <argument index="1" name="reason" type="String"> + </argument> + <description> + Emitted when the server requests a clean close. You should keep polling until you get a [signal connection_closed] signal to achieve the clean close. See [method WebSocketPeer.close] for more details. + </description> + </signal> </signals> <constants> </constants> diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml index 85a08e0c0b..cc59706916 100644 --- a/modules/websocket/doc_classes/WebSocketPeer.xml +++ b/modules/websocket/doc_classes/WebSocketPeer.xml @@ -15,8 +15,14 @@ <method name="close"> <return type="void"> </return> + <argument index="0" name="code" type="int" default="1000"> + </argument> + <argument index="1" name="reason" type="String" default=""""> + </argument> <description> - Close this WebSocket connection, actively disconnecting the peer. + Close this WebSocket connection. [code]code[/code] is the status code for the closure (see RFC6455 section 7.4 for a list of valid status codes). [reason] is the human readable reason for closing the connection (can be any UTF8 string, must be less than 123 bytes). + Note: To achieve a clean close, you will need to keep polling until either [signal WebSocketClient.connection_closed] or [signal WebSocketServer.client_disconnected] is received. + Note: HTML5 export might not support all status codes. Please refer to browsers-specific documentation for more details. </description> </method> <method name="get_connected_host" qualifiers="const"> diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml index a1061e446b..ba66fdd89b 100644 --- a/modules/websocket/doc_classes/WebSocketServer.xml +++ b/modules/websocket/doc_classes/WebSocketServer.xml @@ -18,8 +18,12 @@ </return> <argument index="0" name="id" type="int"> </argument> + <argument index="1" name="code" type="int" default="1000"> + </argument> + <argument index="2" name="reason" type="String" default=""""> + </argument> <description> - Disconnects the given peer. + Disconnects the peer identified by [code]id[/code] from the server. See [method WebSocketPeer.close] for more info. </description> </method> <method name="get_peer_address" qualifiers="const"> @@ -68,7 +72,7 @@ <description> Start listening on the given port. You can specify the desired subprotocols via the "protocols" array. If the list empty (default), "binary" will be used. - You can use this server as a network peer for [MultiplayerAPI] by passing true as "gd_mp_api". Note: [signal data_received] will not be fired and clients other than Godot will not work in this case. + You can use this server as a network peer for [MultiplayerAPI] by passing [code]true[/code] as [code]gd_mp_api[/code]. Note: [signal data_received] will not be fired and clients other than Godot will not work in this case. </description> </method> <method name="stop"> @@ -80,6 +84,17 @@ </method> </methods> <signals> + <signal name="client_close_request"> + <argument index="0" name="id" type="int"> + </argument> + <argument index="1" name="code" type="int"> + </argument> + <argument index="2" name="reason" type="String"> + </argument> + <description> + Emitted when a client requests a clean close. You should keep polling until you get a [signal client_disconnected] signal with the same [code]id[/code] to achieve the clean close. See [method WebSocketPeer.close] for more details. + </description> + </signal> <signal name="client_connected"> <argument index="0" name="id" type="int"> </argument> @@ -92,8 +107,10 @@ <signal name="client_disconnected"> <argument index="0" name="id" type="int"> </argument> + <argument index="1" name="was_clean_close" type="bool"> + </argument> <description> - Emitted when a client disconnects. + Emitted when a client disconnects. [code]was_clean_close[/code] will be [code]true[/code] if the connection was shutdown cleanly. </description> </signal> <signal name="data_received"> diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp index 836b564de8..8255ed7116 100644 --- a/modules/websocket/emws_client.cpp +++ b/modules/websocket/emws_client.cpp @@ -55,8 +55,9 @@ EMSCRIPTEN_KEEPALIVE void _esws_on_error(void *obj) { EMSCRIPTEN_KEEPALIVE void _esws_on_close(void *obj, int code, char *reason, int was_clean) { EMWSClient *client = static_cast<EMWSClient *>(obj); + client->_on_close_request(code, String(reason)); client->_is_connecting = false; - client->_on_disconnect(); + client->_on_disconnect(was_clean != 0); } } @@ -145,7 +146,7 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, if (!Module.IDHandler.has($0)) return; // Godot Object is gone! var was_clean = 0; - if (event.was_clean) + if (event.wasClean) was_clean = 1; ccall("_esws_on_close", "void", @@ -182,9 +183,9 @@ NetworkedMultiplayerPeer::ConnectionStatus EMWSClient::get_connection_status() c return CONNECTION_DISCONNECTED; }; -void EMWSClient::disconnect_from_host() { +void EMWSClient::disconnect_from_host(int p_code, String p_reason) { - _peer->close(); + _peer->close(p_code, p_reason); }; IP_Address EMWSClient::get_connected_host() const { diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h index 6c2fa23b53..b20633baff 100644 --- a/modules/websocket/emws_client.h +++ b/modules/websocket/emws_client.h @@ -48,7 +48,7 @@ public: Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>()); Ref<WebSocketPeer> get_peer(int p_peer_id) const; - void disconnect_from_host(); + void disconnect_from_host(int p_code = 1000, String p_reason = ""); IP_Address get_connected_host() const; uint16_t get_connected_port() const; virtual ConnectionStatus get_connection_status() const; diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp index e0b987b4d7..68f41165eb 100644 --- a/modules/websocket/emws_peer.cpp +++ b/modules/websocket/emws_peer.cpp @@ -130,15 +130,17 @@ bool EMWSPeer::is_connected_to_host() const { return peer_sock != -1; }; -void EMWSPeer::close() { +void EMWSPeer::close(int p_code, String p_reason) { if (peer_sock != -1) { /* clang-format off */ EM_ASM({ var sock = Module.IDHandler.get($0); - sock.close(); + var code = $1; + var reason = UTF8ToString($2); + sock.close(code, reason); Module.IDHandler.remove($0); - }, peer_sock); + }, peer_sock, p_code, p_reason.utf8().get_data()); /* clang-format on */ } peer_sock = -1; diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h index e06f725265..a4b2c8f50b 100644 --- a/modules/websocket/emws_peer.h +++ b/modules/websocket/emws_peer.h @@ -63,7 +63,7 @@ public: virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); virtual int get_max_packet_size() const { return PACKET_BUFFER_SIZE; }; - virtual void close(); + virtual void close(int p_code = 1000, String p_reason = ""); virtual bool is_connected_to_host() const; virtual IP_Address get_connected_host() const; virtual uint16_t get_connected_port() const; diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp index 3eb93e4152..ad4a758c0f 100644 --- a/modules/websocket/emws_server.cpp +++ b/modules/websocket/emws_server.cpp @@ -68,7 +68,7 @@ int EMWSServer::get_peer_port(int p_peer_id) const { return 0; } -void EMWSServer::disconnect_peer(int p_peer_id) { +void EMWSServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) { } EMWSServer::EMWSServer() { diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h index 9ec4ce72c8..74b689a29b 100644 --- a/modules/websocket/emws_server.h +++ b/modules/websocket/emws_server.h @@ -48,7 +48,7 @@ public: Ref<WebSocketPeer> get_peer(int p_id) const; IP_Address get_peer_address(int p_peer_id) const; int get_peer_port(int p_peer_id) const; - void disconnect_peer(int p_peer_id); + void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = ""); virtual void poll(); virtual PoolVector<String> get_protocols() const; diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp index 09f6422058..cd814760e6 100644 --- a/modules/websocket/lws_client.cpp +++ b/modules/websocket/lws_client.cpp @@ -129,6 +129,7 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi peer->set_wsi(wsi); peer_data->peer_id = 0; peer_data->force_close = false; + peer_data->clean_close = false; _on_connect(lws_get_protocol(wsi)->name); break; @@ -137,10 +138,18 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi destroy_context(); return -1; // We should close the connection (would probably happen anyway) + case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: { + int code; + String reason = peer->get_close_reason(in, len, code); + peer_data->clean_close = true; + _on_close_request(code, reason); + return 0; + } + case LWS_CALLBACK_CLIENT_CLOSED: peer->close(); destroy_context(); - _on_disconnect(); + _on_disconnect(peer_data->clean_close); return 0; // We can end here case LWS_CALLBACK_CLIENT_RECEIVE: @@ -150,8 +159,10 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi break; case LWS_CALLBACK_CLIENT_WRITEABLE: - if (peer_data->force_close) + if (peer_data->force_close) { + peer->send_close_status(wsi); return -1; + } peer->write_wsi(); break; @@ -179,13 +190,12 @@ NetworkedMultiplayerPeer::ConnectionStatus LWSClient::get_connection_status() co return CONNECTION_CONNECTING; } -void LWSClient::disconnect_from_host() { +void LWSClient::disconnect_from_host(int p_code, String p_reason) { if (context == NULL) return; - _peer->close(); - destroy_context(); + _peer->close(p_code, p_reason); }; IP_Address LWSClient::get_connected_host() const { @@ -208,6 +218,7 @@ LWSClient::~LWSClient() { invalidate_lws_ref(); // We do not want any more callback disconnect_from_host(); + destroy_context(); _peer = Ref<LWSPeer>(); }; diff --git a/modules/websocket/lws_client.h b/modules/websocket/lws_client.h index 8850683cb5..1bbc19f352 100644 --- a/modules/websocket/lws_client.h +++ b/modules/websocket/lws_client.h @@ -46,7 +46,7 @@ class LWSClient : public WebSocketClient { public: Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>()); Ref<WebSocketPeer> get_peer(int p_peer_id) const; - void disconnect_from_host(); + void disconnect_from_host(int p_code = 1000, String p_reason = ""); IP_Address get_connected_host() const; uint16_t get_connected_port() const; virtual ConnectionStatus get_connection_status() const; diff --git a/modules/websocket/lws_peer.cpp b/modules/websocket/lws_peer.cpp index 0989357258..b5c130b308 100644 --- a/modules/websocket/lws_peer.cpp +++ b/modules/websocket/lws_peer.cpp @@ -30,6 +30,7 @@ #ifndef JAVASCRIPT_ENABLED #include "lws_peer.h" + #include "core/io/ip.h" // Needed for socket_helpers on Android at least. UNIXes has it, just include if not windows @@ -38,7 +39,7 @@ #include <sys/socket.h> #endif -#include "drivers/unix/socket_helpers.h" +#include "drivers/unix/net_socket_posix.h" void LWSPeer::set_wsi(struct lws *p_wsi) { ERR_FAIL_COND(wsi != NULL); @@ -60,7 +61,6 @@ Error LWSPeer::read_wsi(void *in, size_t len) { ERR_FAIL_COND_V(!is_connected_to_host(), FAILED); - PeerData *peer_data = (PeerData *)(lws_wsi_user(wsi)); uint32_t size = in_size; uint8_t is_string = lws_frame_is_binary(wsi) ? 0 : 1; @@ -88,7 +88,6 @@ Error LWSPeer::write_wsi() { ERR_FAIL_COND_V(!is_connected_to_host(), FAILED); - PeerData *peer_data = (PeerData *)(lws_wsi_user(wsi)); PoolVector<uint8_t> tmp; int left = rbw.data_left(); uint32_t to_write = 0; @@ -119,7 +118,6 @@ Error LWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(!is_connected_to_host(), FAILED); - PeerData *peer_data = (PeerData *)lws_wsi_user(wsi); rbw.write((uint8_t *)&p_buffer_size, 4); rbw.write(p_buffer, MIN(p_buffer_size, rbw.space_left())); out_count++; @@ -132,8 +130,6 @@ Error LWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { ERR_FAIL_COND_V(!is_connected_to_host(), FAILED); - PeerData *peer_data = (PeerData *)lws_wsi_user(wsi); - if (in_count == 0) return ERR_UNAVAILABLE; @@ -178,11 +174,49 @@ bool LWSPeer::is_connected_to_host() const { return wsi != NULL; }; -void LWSPeer::close() { +String LWSPeer::get_close_reason(void *in, size_t len, int &r_code) { + String s; + r_code = 0; + if (len < 2) // From docs this should not happen + return s; + + const uint8_t *b = (const uint8_t *)in; + r_code = b[0] << 8 | b[1]; + + if (len > 2) { + const char *utf8 = (const char *)&b[2]; + s.parse_utf8(utf8, len - 2); + } + return s; +} + +void LWSPeer::send_close_status(struct lws *p_wsi) { + if (close_code == -1) + return; + + int len = close_reason.size(); + ERR_FAIL_COND(len > 123); // Maximum allowed reason size in bytes + + lws_close_status code = (lws_close_status)close_code; + unsigned char *reason = len > 0 ? (unsigned char *)close_reason.utf8().ptrw() : NULL; + + lws_close_reason(p_wsi, code, reason, len); + + close_code = -1; + close_reason = ""; +} + +void LWSPeer::close(int p_code, String p_reason) { if (wsi != NULL) { + close_code = p_code; + close_reason = p_reason; PeerData *data = ((PeerData *)lws_wsi_user(wsi)); data->force_close = true; - lws_callback_on_writable(wsi); // notify that we want to disconnect + data->clean_close = true; + lws_callback_on_writable(wsi); // Notify that we want to disconnect + } else { + close_code = -1; + close_reason = ""; } wsi = NULL; rbw.resize(0); @@ -198,7 +232,7 @@ IP_Address LWSPeer::get_connected_host() const { ERR_FAIL_COND_V(!is_connected_to_host(), IP_Address()); IP_Address ip; - int port = 0; + uint16_t port = 0; struct sockaddr_storage addr; socklen_t len = sizeof(addr); @@ -209,7 +243,7 @@ IP_Address LWSPeer::get_connected_host() const { int ret = getpeername(fd, (struct sockaddr *)&addr, &len); ERR_FAIL_COND_V(ret != 0, IP_Address()); - _set_ip_addr_port(ip, port, &addr); + NetSocketPosix::_set_ip_port(&addr, ip, port); return ip; }; @@ -219,7 +253,7 @@ uint16_t LWSPeer::get_connected_port() const { ERR_FAIL_COND_V(!is_connected_to_host(), 0); IP_Address ip; - int port = 0; + uint16_t port = 0; struct sockaddr_storage addr; socklen_t len = sizeof(addr); @@ -230,7 +264,7 @@ uint16_t LWSPeer::get_connected_port() const { int ret = getpeername(fd, (struct sockaddr *)&addr, &len); ERR_FAIL_COND_V(ret != 0, 0); - _set_ip_addr_port(ip, port, &addr); + NetSocketPosix::_set_ip_port(&addr, ip, port); return port; }; diff --git a/modules/websocket/lws_peer.h b/modules/websocket/lws_peer.h index d7d46e3076..571445db01 100644 --- a/modules/websocket/lws_peer.h +++ b/modules/websocket/lws_peer.h @@ -53,10 +53,14 @@ private: WriteMode write_mode; bool _was_string; + int close_code; + String close_reason; + public: struct PeerData { uint32_t peer_id; bool force_close; + bool clean_close; }; RingBuffer<uint8_t> rbw; @@ -71,7 +75,7 @@ public: virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); virtual int get_max_packet_size() const { return PACKET_BUFFER_SIZE; }; - virtual void close(); + virtual void close(int p_code = 1000, String p_reason = ""); virtual bool is_connected_to_host() const; virtual IP_Address get_connected_host() const; virtual uint16_t get_connected_port() const; @@ -83,6 +87,8 @@ public: void set_wsi(struct lws *wsi); Error read_wsi(void *in, size_t len); Error write_wsi(); + void send_close_status(struct lws *wsi); + String get_close_reason(void *in, size_t len, int &r_code); LWSPeer(); ~LWSPeer(); diff --git a/modules/websocket/lws_server.cpp b/modules/websocket/lws_server.cpp index 4a614f6933..58fa043346 100644 --- a/modules/websocket/lws_server.cpp +++ b/modules/websocket/lws_server.cpp @@ -90,20 +90,36 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi peer_data->peer_id = id; peer_data->force_close = false; - + peer_data->clean_close = false; _on_connect(id, lws_get_protocol(wsi)->name); break; } + case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: { + if (peer_data == NULL) + return 0; + + int32_t id = peer_data->peer_id; + if (_peer_map.has(id)) { + int code; + Ref<LWSPeer> peer = _peer_map[id]; + String reason = peer->get_close_reason(in, len, code); + peer_data->clean_close = true; + _on_close_request(id, code, reason); + } + return 0; + } + case LWS_CALLBACK_CLOSED: { if (peer_data == NULL) return 0; int32_t id = peer_data->peer_id; + bool clean = peer_data->clean_close; if (_peer_map.has(id)) { _peer_map[id]->close(); _peer_map.erase(id); } - _on_disconnect(id); + _on_disconnect(id, clean); return 0; // we can end here } @@ -118,10 +134,15 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi } case LWS_CALLBACK_SERVER_WRITEABLE: { - if (peer_data->force_close) + int id = peer_data->peer_id; + if (peer_data->force_close) { + if (_peer_map.has(id)) { + Ref<LWSPeer> peer = _peer_map[id]; + peer->send_close_status(wsi); + } return -1; + } - int id = peer_data->peer_id; if (_peer_map.has(id)) static_cast<Ref<LWSPeer> >(_peer_map[id])->write_wsi(); break; @@ -164,10 +185,10 @@ int LWSServer::get_peer_port(int p_peer_id) const { return _peer_map[p_peer_id]->get_connected_port(); } -void LWSServer::disconnect_peer(int p_peer_id) { +void LWSServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) { ERR_FAIL_COND(!has_peer(p_peer_id)); - get_peer(p_peer_id)->close(); + get_peer(p_peer_id)->close(p_code, p_reason); } LWSServer::LWSServer() { diff --git a/modules/websocket/lws_server.h b/modules/websocket/lws_server.h index 9e3fb9b775..346773ebc4 100644 --- a/modules/websocket/lws_server.h +++ b/modules/websocket/lws_server.h @@ -54,7 +54,7 @@ public: Ref<WebSocketPeer> get_peer(int p_id) const; IP_Address get_peer_address(int p_peer_id) const; int get_peer_port(int p_peer_id) const; - void disconnect_peer(int p_peer_id); + void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = ""); virtual void poll() { _lws_poll(); } LWSServer(); diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp index 7701163085..f9b94dc519 100644 --- a/modules/websocket/websocket_client.cpp +++ b/modules/websocket/websocket_client.cpp @@ -107,12 +107,17 @@ void WebSocketClient::_on_connect(String p_protocol) { } } -void WebSocketClient::_on_disconnect() { +void WebSocketClient::_on_close_request(int p_code, String p_reason) { + + emit_signal("server_close_request", p_code, p_reason); +} + +void WebSocketClient::_on_disconnect(bool p_was_clean) { if (_is_multiplayer) { emit_signal("connection_failed"); } else { - emit_signal("connection_closed"); + emit_signal("connection_closed", p_was_clean); } } @@ -127,7 +132,7 @@ void WebSocketClient::_on_error() { void WebSocketClient::_bind_methods() { ClassDB::bind_method(D_METHOD("connect_to_url", "url", "protocols", "gd_mp_api"), &WebSocketClient::connect_to_url, DEFVAL(PoolVector<String>()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("disconnect_from_host"), &WebSocketClient::disconnect_from_host); + ClassDB::bind_method(D_METHOD("disconnect_from_host", "code", "reason"), &WebSocketClient::disconnect_from_host, DEFVAL(1000), DEFVAL("")); ClassDB::bind_method(D_METHOD("set_verify_ssl_enabled", "enabled"), &WebSocketClient::set_verify_ssl_enabled); ClassDB::bind_method(D_METHOD("is_verify_ssl_enabled"), &WebSocketClient::is_verify_ssl_enabled); @@ -135,6 +140,7 @@ void WebSocketClient::_bind_methods() { ADD_SIGNAL(MethodInfo("data_received")); ADD_SIGNAL(MethodInfo("connection_established", PropertyInfo(Variant::STRING, "protocol"))); - ADD_SIGNAL(MethodInfo("connection_closed")); + ADD_SIGNAL(MethodInfo("server_close_request", PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason"))); + ADD_SIGNAL(MethodInfo("connection_closed", PropertyInfo(Variant::BOOL, "was_clean_close"))); ADD_SIGNAL(MethodInfo("connection_error")); } diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h index 6165f37d40..948f128e9f 100644 --- a/modules/websocket/websocket_client.h +++ b/modules/websocket/websocket_client.h @@ -53,7 +53,7 @@ public: virtual void poll() = 0; virtual Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocol = PoolVector<String>()) = 0; - virtual void disconnect_from_host() = 0; + virtual void disconnect_from_host(int p_code = 1000, String p_reason = "") = 0; virtual IP_Address get_connected_host() const = 0; virtual uint16_t get_connected_port() const = 0; @@ -62,7 +62,8 @@ public: void _on_peer_packet(); void _on_connect(String p_protocol); - void _on_disconnect(); + void _on_close_request(int p_code, String p_reason); + void _on_disconnect(bool p_was_clean); void _on_error(); WebSocketClient(); diff --git a/modules/websocket/websocket_peer.cpp b/modules/websocket/websocket_peer.cpp index 61f783e377..3ecb32ce19 100644 --- a/modules/websocket/websocket_peer.cpp +++ b/modules/websocket/websocket_peer.cpp @@ -42,7 +42,7 @@ void WebSocketPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_write_mode", "mode"), &WebSocketPeer::set_write_mode); ClassDB::bind_method(D_METHOD("is_connected_to_host"), &WebSocketPeer::is_connected_to_host); ClassDB::bind_method(D_METHOD("was_string_packet"), &WebSocketPeer::was_string_packet); - ClassDB::bind_method(D_METHOD("close"), &WebSocketPeer::close); + ClassDB::bind_method(D_METHOD("close", "code", "reason"), &WebSocketPeer::close, DEFVAL(1000), DEFVAL("")); ClassDB::bind_method(D_METHOD("get_connected_host"), &WebSocketPeer::get_connected_host); ClassDB::bind_method(D_METHOD("get_connected_port"), &WebSocketPeer::get_connected_port); diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h index ad451e9cc7..5918fda3c2 100644 --- a/modules/websocket/websocket_peer.h +++ b/modules/websocket/websocket_peer.h @@ -58,7 +58,7 @@ public: virtual WriteMode get_write_mode() const = 0; virtual void set_write_mode(WriteMode p_mode) = 0; - virtual void close() = 0; + virtual void close(int p_code = 1000, String p_reason = "") = 0; virtual bool is_connected_to_host() const = 0; virtual IP_Address get_connected_host() const = 0; diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp index 53dd7b51b7..c631ed70d5 100644 --- a/modules/websocket/websocket_server.cpp +++ b/modules/websocket/websocket_server.cpp @@ -46,9 +46,10 @@ void WebSocketServer::_bind_methods() { ClassDB::bind_method(D_METHOD("has_peer", "id"), &WebSocketServer::has_peer); ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &WebSocketServer::get_peer_address); ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &WebSocketServer::get_peer_port); - ClassDB::bind_method(D_METHOD("disconnect_peer", "id"), &WebSocketServer::disconnect_peer); + ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "code", "reason"), &WebSocketServer::disconnect_peer, DEFVAL(1000), DEFVAL("")); - ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("client_close_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason"))); + ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::BOOL, "was_clean_close"))); ADD_SIGNAL(MethodInfo("client_connected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "protocol"))); ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::INT, "id"))); } @@ -85,13 +86,18 @@ void WebSocketServer::_on_connect(int32_t p_peer_id, String p_protocol) { } } -void WebSocketServer::_on_disconnect(int32_t p_peer_id) { +void WebSocketServer::_on_disconnect(int32_t p_peer_id, bool p_was_clean) { if (_is_multiplayer) { // Send delete to clients _send_del(p_peer_id); emit_signal("peer_disconnected", p_peer_id); } else { - emit_signal("client_disconnected", p_peer_id); + emit_signal("client_disconnected", p_peer_id, p_was_clean); } } + +void WebSocketServer::_on_close_request(int32_t p_peer_id, int p_code, String p_reason) { + + emit_signal("client_close_request", p_peer_id, p_code, p_reason); +} diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h index 64935f8a58..156f25897c 100644 --- a/modules/websocket/websocket_server.h +++ b/modules/websocket/websocket_server.h @@ -54,11 +54,12 @@ public: virtual IP_Address get_peer_address(int p_peer_id) const = 0; virtual int get_peer_port(int p_peer_id) const = 0; - virtual void disconnect_peer(int p_peer_id) = 0; + virtual void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") = 0; void _on_peer_packet(int32_t p_peer_id); void _on_connect(int32_t p_peer_id, String p_protocol); - void _on_disconnect(int32_t p_peer_id); + void _on_disconnect(int32_t p_peer_id, bool p_was_clean); + void _on_close_request(int32_t p_peer_id, int p_code, String p_reason); WebSocketServer(); ~WebSocketServer(); diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 6ec7d27464..683dbfdc5a 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -194,8 +194,8 @@ static const char *android_perms[] = { }; struct LauncherIcon { - char *option_id; - char *export_path; + const char *option_id; + const char *export_path; }; static const LauncherIcon launcher_icons[] = { @@ -577,11 +577,11 @@ class EditorExportAndroid : public EditorExportPlatform { uint32_t ofs = 8; uint32_t string_count = 0; - uint32_t styles_count = 0; + //uint32_t styles_count = 0; uint32_t string_flags = 0; uint32_t string_data_offset = 0; - uint32_t styles_offset = 0; + //uint32_t styles_offset = 0; uint32_t string_table_begins = 0; uint32_t string_table_ends = 0; Vector<uint8_t> stable_extra; @@ -631,16 +631,16 @@ class EditorExportAndroid : public EditorExportPlatform { int iofs = ofs + 8; string_count = decode_uint32(&p_manifest[iofs]); - styles_count = decode_uint32(&p_manifest[iofs + 4]); + //styles_count = decode_uint32(&p_manifest[iofs + 4]); string_flags = decode_uint32(&p_manifest[iofs + 8]); string_data_offset = decode_uint32(&p_manifest[iofs + 12]); - styles_offset = decode_uint32(&p_manifest[iofs + 16]); + //styles_offset = decode_uint32(&p_manifest[iofs + 16]); /* printf("string count: %i\n",string_count); printf("flags: %i\n",string_flags); printf("sdata ofs: %i\n",string_data_offset); printf("styles ofs: %i\n",styles_offset); - */ + */ uint32_t st_offset = iofs + 20; string_table.resize(string_count); uint32_t string_end = 0; @@ -760,7 +760,6 @@ class EditorExportAndroid : public EditorExportPlatform { // save manifest ending so we can restore it Vector<uint8_t> manifest_end; uint32_t manifest_cur_size = p_manifest.size(); - uint32_t node_size = size; manifest_end.resize(p_manifest.size() - ofs); memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size()); @@ -1082,7 +1081,7 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_xlarge"), true)); - for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) { + for (unsigned int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) { r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icons[i].option_id, PROPERTY_HINT_FILE, "*.png"), "")); } @@ -1486,7 +1485,7 @@ public: if (file == "res/drawable/icon.png") { bool found = false; - for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) { + for (unsigned int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) { String icon_path = String(p_preset->get(launcher_icons[i].option_id)).strip_edges(); if (icon_path != "" && icon_path.ends_with(".png")) { FileAccess *f = FileAccess::open(icon_path, FileAccess::READ); @@ -1620,7 +1619,7 @@ public: APKExportData ed; ed.ep = &ep; ed.apk = unaligned_apk; - for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) { + for (unsigned int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) { String icon_path = String(p_preset->get(launcher_icons[i].option_id)).strip_edges(); if (icon_path != "" && icon_path.ends_with(".png") && FileAccess::exists(icon_path)) { Vector<uint8_t> data = FileAccess::get_file_as_array(icon_path); diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 92c9be5d43..c23037f3e0 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -184,6 +184,9 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC protected void onMainActivityResult(int requestCode, int resultCode, Intent data) { } + protected void onMainRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + } + protected void onMainPause() {} protected void onMainResume() {} protected void onMainDestroy() {} @@ -251,6 +254,13 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } }; + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + for (int i = 0; i < singleton_count; i++) { + singletons[i].onMainRequestPermissionsResult(requestCode, permissions, grantResults); + } + }; + public void onVideoInit() { boolean use_gl3 = getGLESVersionCode() >= 0x00030000; diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index aae9d97a28..63bc4a519b 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -203,7 +203,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with retina display - for (int i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { + for (unsigned int i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png"), "")); } @@ -353,7 +353,7 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr DirAccess *da = DirAccess::open(p_iconset_dir); ERR_FAIL_COND_V(!da, ERR_CANT_OPEN); - for (int i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { + for (unsigned int i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { IconInfo info = icon_infos[i]; String icon_path = p_preset->get(info.preset_key); if (icon_path.length() == 0) { @@ -403,7 +403,7 @@ Error EditorExportPlatformIOS::_export_loading_screens(const Ref<EditorExportPre DirAccess *da = DirAccess::open(p_dest_dir); ERR_FAIL_COND_V(!da, ERR_CANT_OPEN); - for (int i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { + for (unsigned int i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { LoadingScreenInfo info = loading_screen_infos[i]; String loading_screen_file = p_preset->get(info.preset_key); if (loading_screen_file.size() > 0) { @@ -490,7 +490,7 @@ private: static String _hex_pad(uint32_t num) { Vector<char> ret; ret.resize(sizeof(num) * 2); - for (int i = 0; i < sizeof(num) * 2; ++i) { + for (unsigned int i = 0; i < sizeof(num) * 2; ++i) { uint8_t four_bits = (num >> (sizeof(num) * 8 - (i + 1) * 4)) & 0xF; ret.write[i] = _hex_char(four_bits); } diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm index 9ad3437f0f..490155bb24 100644 --- a/platform/osx/crash_handler_osx.mm +++ b/platform/osx/crash_handler_osx.mm @@ -68,8 +68,9 @@ static uint64_t load_address() { } static void handle_crash(int sig) { - if (OS::get_singleton() == NULL) - return; + if (OS::get_singleton() == NULL) { + abort(); + } void *bt_buffer[256]; size_t size = backtrace(bt_buffer, 256); @@ -151,6 +152,7 @@ CrashHandler::CrashHandler() { } CrashHandler::~CrashHandler() { + disable(); } void CrashHandler::disable() { diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index b0232e2990..27b4fdc228 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -461,7 +461,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p fi.internal_fa = info.internal_fa; fi.external_fa = info.external_fa; - int zerr = zipOpenNewFileInZip(dst_pkg_zip, + zipOpenNewFileInZip(dst_pkg_zip, file.utf8().get_data(), &fi, NULL, @@ -472,7 +472,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p Z_DEFLATED, Z_DEFAULT_COMPRESSION); - zerr = zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size()); + zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size()); zipCloseFileInZip(dst_pkg_zip); } } diff --git a/platform/server/detect.py b/platform/server/detect.py index 266b0c5cc9..597a2ff6a0 100644 --- a/platform/server/detect.py +++ b/platform/server/detect.py @@ -29,9 +29,7 @@ def get_opts(): def get_flags(): - return [ - ("module_mobile_vr_enabled", False), - ] + return [] def configure(env): @@ -56,7 +54,7 @@ def configure(env): ## Compiler configuration if env['use_llvm']: - if ('clang++' not in env['CXX']): + if ('clang++' not in os.path.basename(env['CXX'])): env["CC"] = "clang" env["CXX"] = "clang++" env["LINK"] = "clang++" diff --git a/platform/x11/crash_handler_x11.cpp b/platform/x11/crash_handler_x11.cpp index ab9275e49f..79c3d9aece 100644 --- a/platform/x11/crash_handler_x11.cpp +++ b/platform/x11/crash_handler_x11.cpp @@ -45,8 +45,9 @@ #include <stdlib.h> static void handle_crash(int sig) { - if (OS::get_singleton() == NULL) - return; + if (OS::get_singleton() == NULL) { + abort(); + } void *bt_buffer[256]; size_t size = backtrace(bt_buffer, 256); @@ -119,6 +120,7 @@ CrashHandler::CrashHandler() { } CrashHandler::~CrashHandler() { + disable(); } void CrashHandler::disable() { diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 6a7a426804..905546e724 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -86,7 +86,7 @@ def configure(env): env.Prepend(CCFLAGS=['-O3', '-ffast-math']) else: #optimize for size env.Prepend(CCFLAGS=['-Os']) - + if (env["debug_symbols"] == "yes"): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): @@ -115,12 +115,12 @@ def configure(env): ## Compiler configuration - if 'CXX' in env and 'clang' in env['CXX']: + if 'CXX' in env and 'clang' in os.path.basename(env['CXX']): # Convenience check to enforce the use_llvm overrides when CXX is clang(++) env['use_llvm'] = True if env['use_llvm']: - if ('clang++' not in env['CXX']): + if ('clang++' not in os.path.basename(env['CXX'])): env["CC"] = "clang" env["CXX"] = "clang++" env["LINK"] = "clang++" diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 71bd51507e..5b8d10ea85 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -257,7 +257,6 @@ void TileMap::update_dirty_quadrants() { VisualServer *vs = VisualServer::get_singleton(); Physics2DServer *ps = Physics2DServer::get_singleton(); Vector2 tofs = get_cell_draw_offset(); - Vector2 tcenter = cell_size / 2; Transform2D nav_rel; if (navigation) nav_rel = get_relative_transform_to_parent(navigation); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 386f2a4348..b1f90b72e7 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -417,7 +417,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { } } - for (int k = 0; k < cc; k++) { + for (unsigned int k = 0; k < cc; k++) { output.vol[k] *= multiplier; } diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index d674958d33..7e1d60ab8e 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -163,6 +163,11 @@ void Light::_update_visibility() { if (!is_inside_tree()) return; + // FIXME: Since the call to VS::instance_light_set_enabled was disabled below, + // the whole logic became pointless so editor_ok triggers unused variable warnings. + // Commenting out for now but this should be fixed/reimplemented so that editor_only + // works as expected (GH-17989). + /* bool editor_ok = true; #ifdef TOOLS_ENABLED @@ -180,6 +185,7 @@ void Light::_update_visibility() { #endif //VS::get_singleton()->instance_light_set_enabled(get_instance(),is_visible_in_tree() && editor_ok); + */ _change_notify("geometry/visible"); } diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index 54f74c2df3..6e7b372647 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -563,7 +563,6 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Ve bool use_collision = p_use_collision; Vector3 closest_point; float closest_point_d = 1e20; - NavMesh *closest_navmesh = NULL; for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { @@ -582,12 +581,10 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Ve closest_point = inters; use_collision = true; closest_point_d = p_from.distance_to(inters); - closest_navmesh = p.owner; } else if (closest_point_d > inters.distance_to(p_from)) { closest_point = inters; closest_point_d = p_from.distance_to(inters); - closest_navmesh = p.owner; } } } @@ -605,7 +602,6 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Ve closest_point_d = d; closest_point = b; - closest_navmesh = p.owner; } } } diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index d7bd89625f..95a83bfc1f 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -2287,6 +2287,8 @@ void PhysicalBone::_reload_joint() { } } break; + case JOINT_TYPE_NONE: { + } break; } } @@ -2342,6 +2344,8 @@ void PhysicalBone::set_joint_type(JointType p_joint_type) { case JOINT_TYPE_6DOF: joint_data = memnew(SixDOFJointData); break; + case JOINT_TYPE_NONE: + break; } _reload_joint(); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 7d91703cf8..102f05a146 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1451,6 +1451,7 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) { case ANIMATION_PROCESS_PHYSICS: set_physics_process_internal(p_process && active); break; case ANIMATION_PROCESS_IDLE: set_process_internal(p_process && active); break; + case ANIMATION_PROCESS_MANUAL: break; } processing = p_process; diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 179f5d9698..524784df53 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -877,6 +877,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) { tr.track->object->call(method, args[0], args[1], args[2], args[3], args[4]); } } break; + default: {} } } } diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 82e2bb93e2..3521782417 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -277,7 +277,10 @@ Variant &Tween::_get_initial_val(InterpolateData &p_data) { ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, p_data.initial_val); } return initial_val; - } break; + } + + case INTER_CALLBACK: + break; } return p_data.delta_val; } @@ -313,7 +316,7 @@ Variant &Tween::_get_delta_val(InterpolateData &p_data) { if (final_val.get_type() == Variant::INT) final_val = final_val.operator real_t(); _calc_delta_val(p_data.initial_val, final_val, p_data.delta_val); return p_data.delta_val; - } break; + } case TARGETING_PROPERTY: case TARGETING_METHOD: { @@ -325,7 +328,10 @@ Variant &Tween::_get_delta_val(InterpolateData &p_data) { //_calc_delta_val(p_data.initial_val, p_data.final_val, p_data.delta_val); _calc_delta_val(initial_val, p_data.final_val, p_data.delta_val); return p_data.delta_val; - } break; + } + + case INTER_CALLBACK: + break; } return p_data.initial_val; } @@ -857,12 +863,8 @@ bool Tween::seek(real_t p_time) { data.finish = false; } - switch (data.type) { - case INTER_PROPERTY: - case INTER_METHOD: - break; - case INTER_CALLBACK: - continue; + if (data.type == INTER_CALLBACK) { + continue; } Variant result = _run_equation(data); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 12349e0983..dc18895298 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1993,7 +1993,7 @@ Control *Control::find_prev_valid_focus() const { if (!from) { - ERR_EXPLAIN("Prev focus node is not a control: " + n->get_name()); + ERR_EXPLAIN("Previous focus node is not a control: " + n->get_name()); ERR_FAIL_V(NULL); } } else { diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 283d66d8de..1e9f4df4a3 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -330,6 +330,10 @@ void FileDialog::deselect_items() { case MODE_OPEN_DIR: get_ok()->set_text(RTR("Select Current Folder")); break; + case MODE_OPEN_ANY: + case MODE_SAVE_FILE: + // FIXME: Implement, or refactor to avoid duplication with set_mode + break; } } } diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 125cf7dc75..e862743934 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -79,10 +79,11 @@ void Range::Shared::emit_changed(const char *p_what) { } void Range::set_value(double p_val) { + if (shared->step > 0) + p_val = Math::round(p_val / shared->step) * shared->step; - if (_rounded_values) { + if (_rounded_values) p_val = Math::round(p_val); - } if (!shared->allow_greater && p_val > shared->max - shared->page) p_val = shared->max - shared->page; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index fa5019a6f7..bb36852cf9 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -320,14 +320,17 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & Color color; Color font_color_shadow; bool underline = false; + bool strikethrough = false; if (p_mode == PROCESS_DRAW) { color = _find_color(text, p_base_color); font_color_shadow = _find_color(text, p_font_color_shadow); - underline = _find_underline(text); - if (_find_meta(text, &meta) && underline_meta) { + if (_find_underline(text) || (_find_meta(text, &meta) && underline_meta)) { underline = true; + } else if (_find_strikethrough(text)) { + + strikethrough = true; } } else if (p_mode == PROCESS_CACHE) { @@ -418,7 +421,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & int cw = 0; - bool visible = visible_characters < 0 || p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - line_descent - line_ascent, line_ascent + line_descent); + bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - line_descent - line_ascent, line_ascent + line_descent)); if (visible) line_is_blank = false; @@ -469,6 +472,15 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & underline_width *= EDSCALE; #endif VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, underline_width); + } else if (strikethrough) { + Color uc = color; + uc.a *= 0.5; + int uy = y + lh / 2 - line_descent + 2; + float strikethrough_width = 1.0; +#ifdef TOOLS_ENABLED + strikethrough_width *= EDSCALE; +#endif + VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, strikethrough_width); } } @@ -497,7 +509,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & ENSURE_WIDTH(img->image->get_width()); - bool visible = visible_characters < 0 || p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->image->get_height(), img->image->get_height()); + bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->image->get_height(), img->image->get_height())); if (visible) line_is_blank = false; @@ -835,8 +847,6 @@ void RichTextLabel::_notification(int p_what) { bool use_outline = get_constant("shadow_as_outline"); Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y")); - float x_ofs = 0; - visible_line_count = 0; while (y < size.height && from_line < main->lines.size()) { @@ -854,7 +864,6 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item if (r_click_item) *r_click_item = NULL; - Size2 size = get_size(); Rect2 text_rect = _get_text_rect(); int ofs = vscroll->get_value(); Color font_color_shadow = get_color("font_color_shadow"); @@ -1227,6 +1236,23 @@ bool RichTextLabel::_find_underline(Item *p_item) { return false; } +bool RichTextLabel::_find_strikethrough(Item *p_item) { + + Item *item = p_item; + + while (item) { + + if (item->type == ITEM_STRIKETHROUGH) { + + return true; + } + + item = item->parent; + } + + return false; +} + bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta) { Item *item = p_item; @@ -1458,6 +1484,7 @@ void RichTextLabel::push_font(const Ref<Font> &p_font) { item->font = p_font; _add_item(item, true); } + void RichTextLabel::push_color(const Color &p_color) { ERR_FAIL_COND(current->type == ITEM_TABLE); @@ -1466,6 +1493,7 @@ void RichTextLabel::push_color(const Color &p_color) { item->color = p_color; _add_item(item, true); } + void RichTextLabel::push_underline() { ERR_FAIL_COND(current->type == ITEM_TABLE); @@ -1474,6 +1502,14 @@ void RichTextLabel::push_underline() { _add_item(item, true); } +void RichTextLabel::push_strikethrough() { + + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemStrikethrough *item = memnew(ItemStrikethrough); + + _add_item(item, true); +} + void RichTextLabel::push_align(Align p_align) { ERR_FAIL_COND(current->type == ITEM_TABLE); @@ -1683,7 +1719,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { } if (brk_pos == p_bbcode.length()) - break; //nothing else o add + break; //nothing else to add int brk_end = p_bbcode.find("]", brk_pos + 1); @@ -1749,7 +1785,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { int columns = tag.substr(6, tag.length()).to_int(); if (columns < 1) columns = 1; - //use monospace font + push_table(columns); pos = brk_end + 1; tag_stack.push_front("table"); @@ -1763,7 +1799,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { int ratio = tag.substr(5, tag.length()).to_int(); if (ratio < 1) ratio = 1; - //use monospace font + set_table_column_expand(get_current_table_column(), true, ratio); push_cell(); pos = brk_end + 1; @@ -1776,43 +1812,37 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { tag_stack.push_front(tag); } else if (tag == "s") { - //use strikethrough (not supported underline instead) - push_underline(); + //use strikethrough + push_strikethrough(); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "center") { - //use underline push_align(ALIGN_CENTER); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "fill") { - //use underline push_align(ALIGN_FILL); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "right") { - //use underline push_align(ALIGN_RIGHT); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "ul") { - //use underline push_list(LIST_DOTS); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "ol") { - //use underline push_list(LIST_NUMBERS); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "indent") { - //use underline indent_level++; push_indent(indent_level); pos = brk_end + 1; @@ -1820,7 +1850,6 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { } else if (tag == "url") { - //use strikethrough (not supported underline instead) int end = p_bbcode.find("[", brk_end); if (end == -1) end = p_bbcode.length(); @@ -1838,7 +1867,6 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { tag_stack.push_front("url"); } else if (tag == "img") { - //use strikethrough (not supported underline instead) int end = p_bbcode.find("[", brk_end); if (end == -1) end = p_bbcode.length(); @@ -2145,6 +2173,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("push_list", "type"), &RichTextLabel::push_list); ClassDB::bind_method(D_METHOD("push_meta", "data"), &RichTextLabel::push_meta); ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline); + ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough); ClassDB::bind_method(D_METHOD("push_table", "columns"), &RichTextLabel::push_table); ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand); ClassDB::bind_method(D_METHOD("push_cell"), &RichTextLabel::push_cell); @@ -2205,7 +2234,7 @@ void RichTextLabel::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_underlined"), "set_meta_underline", "is_meta_underlined"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_size", PROPERTY_HINT_RANGE, "0,24,1"), "set_tab_size", "get_tab_size"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_active"), "set_scroll_active", "is_scroll_active"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_following"), "set_scroll_follow", "is_scroll_following"); @@ -2233,6 +2262,7 @@ void RichTextLabel::_bind_methods() { BIND_ENUM_CONSTANT(ITEM_FONT); BIND_ENUM_CONSTANT(ITEM_COLOR); BIND_ENUM_CONSTANT(ITEM_UNDERLINE); + BIND_ENUM_CONSTANT(ITEM_STRIKETHROUGH); BIND_ENUM_CONSTANT(ITEM_ALIGN); BIND_ENUM_CONSTANT(ITEM_INDENT); BIND_ENUM_CONSTANT(ITEM_LIST); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 06e9b8efe3..c2e5712b9d 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -62,6 +62,7 @@ public: ITEM_FONT, ITEM_COLOR, ITEM_UNDERLINE, + ITEM_STRIKETHROUGH, ITEM_ALIGN, ITEM_INDENT, ITEM_LIST, @@ -164,6 +165,11 @@ private: ItemUnderline() { type = ITEM_UNDERLINE; } }; + struct ItemStrikethrough : public Item { + + ItemStrikethrough() { type = ITEM_STRIKETHROUGH; } + }; + struct ItemMeta : public Item { Variant meta; @@ -277,6 +283,7 @@ private: Align _find_align(Item *p_item); Color _find_color(Item *p_item, const Color &p_default_color); bool _find_underline(Item *p_item); + bool _find_strikethrough(Item *p_item); bool _find_meta(Item *p_item, Variant *r_meta); void _update_scroll(); @@ -307,6 +314,7 @@ public: void push_font(const Ref<Font> &p_font); void push_color(const Color &p_color); void push_underline(); + void push_strikethrough(); void push_align(Align p_align); void push_indent(int p_level); void push_list(ListType p_list); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index e3fb602065..26da16569a 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -30,6 +30,7 @@ #include "scroll_container.h" #include "core/os/os.h" + bool ScrollContainer::clips_input() const { return true; @@ -170,7 +171,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y); drag_accum -= motion; - if (beyond_deadzone || scroll_h && Math::abs(drag_accum.x) > deadzone || scroll_v && Math::abs(drag_accum.y) > deadzone) { + if (beyond_deadzone || (scroll_h && Math::abs(drag_accum.x) > deadzone) || (scroll_v && Math::abs(drag_accum.y) > deadzone)) { if (!beyond_deadzone) { propagate_notification(NOTIFICATION_SCROLL_BEGIN); emit_signal("scroll_started"); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index a9566d9387..632a686256 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -650,8 +650,6 @@ void TextEdit::_notification(int p_what) { int visible_rows = get_visible_rows() + 1; - int tab_w = cache.font->get_char_size(' ').width * indent_size; - Color color = cache.font_color; color.a *= readonly_alpha; @@ -3796,7 +3794,7 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const { int tab_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width; while (col < line_text.length()) { - char c = line_text[col]; + CharType c = line_text[col]; int w = text.get_char_width(c, line_text[col + 1], px + word_px); int indent_ofs = (cur_wrap_index != 0 ? tab_offset_px : 0); @@ -4402,7 +4400,7 @@ int TextEdit::_is_line_in_region(int p_line) { // if not find the closest line we have int previous_line = p_line - 1; - for (previous_line; previous_line > -1; previous_line--) { + for (; previous_line > -1; previous_line--) { if (color_region_cache.has(p_line)) { break; } @@ -5866,7 +5864,7 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { if (select_word(s, col, beg, end)) { bool inside_quotes = false; - char selected_quote = '\0'; + CharType selected_quote = '\0'; int qbegin = 0, qend = 0; for (int i = 0; i < s.length(); i++) { if (s[i] == '"' || s[i] == '\'') { diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 6bd3b26280..a6a57b010f 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -88,6 +88,9 @@ bool TextureButton::has_point(const Point2 &p_point) const { scale.y = min; ofs -= _texture_region.position / min; } break; + default: { + // FIXME: Why a switch if we only handle one enum value? + } } // offset and scale the new point position to adjust it to the bitmask size diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index 8188d1dcf8..d28b4065fb 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -229,6 +229,17 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, F first_section_size = topleft.y; last_section_size = bottomright.y; } break; + case FILL_BILINEAR_LEFT_AND_RIGHT: { + // TODO: Implement + } break; + case FILL_BILINEAR_TOP_AND_BOTTOM: { + // TODO: Implement + } break; + case FILL_CLOCKWISE: + case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: + case FILL_COUNTER_CLOCKWISE: { + // Those modes are circular, not relevant for nine patch + } break; } double width_filled = width_total * p_ratio; @@ -263,6 +274,17 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, F dst_rect.size.y = width_filled; topleft.y = last_section_size; } break; + case FILL_BILINEAR_LEFT_AND_RIGHT: { + // TODO: Implement + } break; + case FILL_BILINEAR_TOP_AND_BOTTOM: { + // TODO: Implement + } break; + case FILL_CLOCKWISE: + case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: + case FILL_COUNTER_CLOCKWISE: { + // Those modes are circular, not relevant for nine patch + } break; } } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 23e4c26695..3a540d187b 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1254,13 +1254,13 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 String s = RTR("(Other)"); Vector<String> strings = p_item->cells[i].text.split(","); - for (int i = 0; i < strings.size(); i++) { - int value = i; - if (!strings[i].get_slicec(':', 1).empty()) { - value = strings[i].get_slicec(':', 1).to_int(); + for (int j = 0; j < strings.size(); j++) { + int value = j; + if (!strings[j].get_slicec(':', 1).empty()) { + value = strings[j].get_slicec(':', 1).to_int(); } if (option == value) { - s = strings[i].get_slicec(':', 0); + s = strings[j].get_slicec(':', 0); break; } } @@ -1416,7 +1416,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 while (c) { - if (cache.draw_relationship_lines == 1 && (c->get_parent() != root || c->get_parent() == root && !hide_root)) { + if (cache.draw_relationship_lines == 1 && (c->get_parent() != root || !hide_root)) { int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 551600109e..34138acb85 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -53,7 +53,6 @@ public: CELL_MODE_STRING, ///< just a string CELL_MODE_CHECK, ///< string + check CELL_MODE_RANGE, ///< Contains a range - CELL_MODE_RANGE_EXPRESSION, ///< Contains a range CELL_MODE_ICON, ///< Contains an icon, not editable CELL_MODE_CUSTOM, ///< Contains a custom value, show a string, and an edit button }; diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index 17ab234551..39e7c73390 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -102,6 +102,10 @@ void VideoPlayer::_mix_audio() { } } break; + case AudioServer::SPEAKER_SURROUND_31: { + + // FIXME: Implement + } break; case AudioServer::SPEAKER_SURROUND_51: { AudioFrame *targets[2] = { diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index aebc96aad7..fdbe3b57f0 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1197,6 +1197,9 @@ void SceneTree::_update_root_rect() { } switch (stretch_mode) { + case STRETCH_MODE_DISABLED: { + // Already handled above + } break; case STRETCH_MODE_2D: { root->set_size((screen_size / stretch_shrink).floor()); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 487ca2b009..bb379ff4af 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -701,15 +701,6 @@ void Viewport::set_canvas_transform(const Transform2D &p_transform) { canvas_transform = p_transform; VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform); - - Transform2D xform = (global_canvas_transform * canvas_transform).affine_inverse(); - Size2 ss = get_visible_rect().size; - /*SpatialSound2DServer::get_singleton()->listener_set_transform(internal_listener_2d, Transform2D(0, xform.xform(ss*0.5))); - Vector2 ss2 = ss*xform.get_scale(); - float panrange = MAX(ss2.x,ss2.y); - - SpatialSound2DServer::get_singleton()->listener_set_param(internal_listener_2d, SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE, panrange); -*/ } Transform2D Viewport::get_canvas_transform() const { @@ -722,15 +713,6 @@ void Viewport::_update_global_transform() { Transform2D sxform = stretch_transform * global_canvas_transform; VisualServer::get_singleton()->viewport_set_global_canvas_transform(viewport, sxform); - - Transform2D xform = (sxform * canvas_transform).affine_inverse(); - Size2 ss = get_visible_rect().size; - /*SpatialSound2DServer::get_singleton()->listener_set_transform(internal_listener_2d, Transform2D(0, xform.xform(ss*0.5))); - Vector2 ss2 = ss*xform.get_scale(); - float panrange = MAX(ss2.x,ss2.y); - - SpatialSound2DServer::get_singleton()->listener_set_param(internal_listener_2d, SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE, panrange); -*/ } void Viewport::set_global_canvas_transform(const Transform2D &p_transform) { diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index 57d0deeb78..9ee85b64b6 100644 --- a/scene/resources/audio_stream_sample.cpp +++ b/scene/resources/audio_stream_sample.cpp @@ -562,13 +562,13 @@ void AudioStreamSample::save_to_wav(String p_path) { PoolVector<uint8_t>::Read read_data = get_data().read(); switch (format) { case AudioStreamSample::FORMAT_8_BITS: - for (int i = 0; i < data_bytes; i++) { + for (unsigned int i = 0; i < data_bytes; i++) { uint8_t data_point = (read_data[i] + 128); file->store_8(data_point); } break; case AudioStreamSample::FORMAT_16_BITS: - for (int i = 0; i < data_bytes / 2; i++) { + for (unsigned int i = 0; i < data_bytes / 2; i++) { uint16_t data_point = decode_uint16(&read_data[i * 2]); file->store_16(data_point); } diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp index d670161afd..56b236d03b 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_mask.cpp @@ -183,7 +183,6 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) unsigned int count = 0; Set<Point2i> case9s; Set<Point2i> case6s; - int i; Vector<Vector2> _points; do { int sv = 0; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 2cf802a2da..ce801c8763 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -427,10 +427,8 @@ void SpatialMaterial::_update_shader() { if (flags[FLAG_USE_VERTEX_LIGHTING]) { code += ",vertex_lighting"; } - bool using_world = false; if (flags[FLAG_TRIPLANAR_USE_WORLD] && (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR])) { code += ",world_vertex_coords"; - using_world = true; } if (flags[FLAG_DONT_RECEIVE_SHADOWS]) { code += ",shadows_disabled"; @@ -562,7 +560,9 @@ void SpatialMaterial::_update_shader() { if (flags[FLAG_SRGB_VERTEX_COLOR]) { - code += "\tCOLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );\n"; + code += "\tif (!OUTPUT_IS_SRGB) {\n"; + code += "\t\tCOLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );\n"; + code += "\t}\n"; } if (flags[FLAG_USE_POINT_SIZE]) { diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 6426689397..fa87623e38 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -546,19 +546,6 @@ void Mesh::clear_cache() const { Mesh::Mesh() { } -static const char *_array_name[] = { - "vertex_array", - "normal_array", - "tangent_array", - "color_array", - "tex_uv_array", - "tex_uv2_array", - "bone_array", - "weights_array", - "index_array", - NULL -}; - static const ArrayMesh::ArrayType _array_types[] = { ArrayMesh::ARRAY_VERTEX, diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 364ec9bb19..6f67ba8af1 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -691,6 +691,7 @@ void ParticlesMaterial::set_param(Parameter p_param, float p_value) { case PARAM_ANIM_OFFSET: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value); } break; + case PARAM_MAX: break; // Can't happen, but silences warning } } float ParticlesMaterial::get_param(Parameter p_param) const { @@ -743,6 +744,7 @@ void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) { case PARAM_ANIM_OFFSET: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value); } break; + case PARAM_MAX: break; // Can't happen, but silences warning } } float ParticlesMaterial::get_param_randomness(Parameter p_param) const { @@ -819,6 +821,7 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> case PARAM_ANIM_OFFSET: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture); } break; + case PARAM_MAX: break; // Can't happen, but silences warning } _queue_shader_change(); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index f12ea8f2bb..96b9cfa137 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -796,10 +796,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui val.basis.transpose(); inputs[i] = "n_in" + itos(node) + "p" + itos(i); Array values; - for (int i = 0; i < 3; i++) { - values.push_back(val.basis[i].x); - values.push_back(val.basis[i].y); - values.push_back(val.basis[i].z); + for (int j = 0; j < 3; j++) { + values.push_back(val.basis[j].x); + values.push_back(val.basis[j].y); + values.push_back(val.basis[j].z); } values.push_back(val.origin.x); values.push_back(val.origin.y); diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp index 3ae897c299..84a87de2e2 100644 --- a/servers/audio/audio_rb_resampler.cpp +++ b/servers/audio/audio_rb_resampler.cpp @@ -82,19 +82,28 @@ uint32_t AudioRBResampler::_resample(AudioFrame *p_dest, int p_todo, int32_t p_i // For now, channels higher than stereo are almost ignored if (C == 4) { + // FIXME: v2 and v3 are not being used (thus were commented out to prevent + // compilation warnings, but they should likely be uncommented *and* used). + // See also C == 6 with similar issues. float v0 = rb[(pos << 2) + 0]; float v1 = rb[(pos << 2) + 1]; + /* float v2 = rb[(pos << 2) + 2]; float v3 = rb[(pos << 2) + 3]; + */ float v0n = rb[(pos_next << 2) + 0]; float v1n = rb[(pos_next << 2) + 1]; + /* float v2n = rb[(pos_next << 2) + 2]; float v3n = rb[(pos_next << 2) + 3]; + */ v0 += (v0n - v0) * frac; v1 += (v1n - v1) * frac; + /* v2 += (v2n - v2) * frac; v3 += (v3n - v3) * frac; + */ p_dest[i] = AudioFrame(v0, v1); } @@ -104,6 +113,7 @@ uint32_t AudioRBResampler::_resample(AudioFrame *p_dest, int p_todo, int32_t p_i // should be done as for C == 2 (C == 4 also has some unused assignments). float v0 = rb[(pos * 6) + 0]; float v1 = rb[(pos * 6) + 1]; + /* float v2 = rb[(pos * 6) + 2]; float v3 = rb[(pos * 6) + 3]; float v4 = rb[(pos * 6) + 4]; @@ -114,6 +124,7 @@ uint32_t AudioRBResampler::_resample(AudioFrame *p_dest, int p_todo, int32_t p_i float v3n = rb[(pos_next * 6) + 3]; float v4n = rb[(pos_next * 6) + 4]; float v5n = rb[(pos_next * 6) + 5]; + */ p_dest[i] = AudioFrame(v0, v1); } @@ -153,7 +164,7 @@ bool AudioRBResampler::mix(AudioFrame *p_dest, int p_frames) { } // Fill zeros (silence) for the rest of frames - for (uint32_t i = target_todo; i < p_frames; i++) { + for (int i = target_todo; i < p_frames; i++) { p_dest[i] = AudioFrame(0, 0); } } diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index c7763890fc..2740f86d55 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -122,7 +122,7 @@ class AudioStreamPlaybackMicrophone : public AudioStreamPlaybackResampled { GDCLASS(AudioStreamPlaybackMicrophone, AudioStreamPlayback) friend class AudioStreamMicrophone; - const int MICROPHONE_PLAYBACK_DELAY = 256; + static const int MICROPHONE_PLAYBACK_DELAY = 256; bool active; unsigned int input_ofs; diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h index 5f5c7802b4..edf8565c06 100644 --- a/servers/audio/effects/audio_effect_record.h +++ b/servers/audio/effects/audio_effect_record.h @@ -49,7 +49,7 @@ class AudioEffectRecordInstance : public AudioEffectInstance { bool is_recording; Thread *io_thread; - bool thread_active = false; + bool thread_active; Vector<AudioFrame> ring_buffer; Vector<float> recording_data; @@ -67,6 +67,9 @@ public: void init(); virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count); virtual bool process_silence(); + + AudioEffectRecordInstance() : + thread_active(false) {} }; class AudioEffectRecord : public AudioEffect { diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 070099a3d8..fead2f54da 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -189,7 +189,7 @@ void AudioDriverManager::initialize(int p_driver) { } } - if (driver_count > 1 && AudioDriver::get_singleton()->get_name() == "Dummy") { + if (driver_count > 1 && String(AudioDriver::get_singleton()->get_name()) == "Dummy") { WARN_PRINT("All audio drivers failed, falling back to the dummy driver."); } } diff --git a/servers/physics/joints/cone_twist_joint_sw.cpp b/servers/physics/joints/cone_twist_joint_sw.cpp index c06f27cc57..37fcde4b76 100644 --- a/servers/physics/joints/cone_twist_joint_sw.cpp +++ b/servers/physics/joints/cone_twist_joint_sw.cpp @@ -332,6 +332,7 @@ void ConeTwistJointSW::set_param(PhysicsServer::ConeTwistJointParam p_param, rea m_relaxationFactor = p_value; } break; + case PhysicsServer::CONE_TWIST_MAX: break; // Can't happen, but silences warning } } @@ -358,6 +359,7 @@ real_t ConeTwistJointSW::get_param(PhysicsServer::ConeTwistJointParam p_param) c return m_relaxationFactor; } break; + case PhysicsServer::CONE_TWIST_MAX: break; // Can't happen, but silences warning } return 0; diff --git a/servers/physics/joints/generic_6dof_joint_sw.cpp b/servers/physics/joints/generic_6dof_joint_sw.cpp index c95e5cef32..9b1a41e80d 100644 --- a/servers/physics/joints/generic_6dof_joint_sw.cpp +++ b/servers/physics/joints/generic_6dof_joint_sw.cpp @@ -497,6 +497,13 @@ void Generic6DOFJointSW::set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJoi m_angularLimits[p_axis].m_maxLimitForce = p_value; } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning } } @@ -572,6 +579,13 @@ real_t Generic6DOFJointSW::get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJ return m_angularLimits[p_axis].m_maxMotorForce; } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning } return 0; } @@ -593,6 +607,10 @@ void Generic6DOFJointSW::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJoin m_angularLimits[p_axis].m_enableMotor = p_value; } break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } } bool Generic6DOFJointSW::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const { @@ -611,6 +629,10 @@ bool Generic6DOFJointSW::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJoin return m_angularLimits[p_axis].m_enableMotor; } break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } return 0; diff --git a/servers/physics/joints/hinge_joint_sw.cpp b/servers/physics/joints/hinge_joint_sw.cpp index 368a349632..50de0e871e 100644 --- a/servers/physics/joints/hinge_joint_sw.cpp +++ b/servers/physics/joints/hinge_joint_sw.cpp @@ -409,6 +409,7 @@ void HingeJointSW::set_param(PhysicsServer::HingeJointParam p_param, real_t p_va case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION: m_relaxationFactor = p_value; break; case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY: m_motorTargetVelocity = p_value; break; case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: m_maxMotorImpulse = p_value; break; + case PhysicsServer::HINGE_JOINT_MAX: break; // Can't happen, but silences warning } } @@ -424,6 +425,7 @@ real_t HingeJointSW::get_param(PhysicsServer::HingeJointParam p_param) const { case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION: return m_relaxationFactor; case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY: return m_motorTargetVelocity; case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: return m_maxMotorImpulse; + case PhysicsServer::HINGE_JOINT_MAX: break; // Can't happen, but silences warning } return 0; @@ -434,6 +436,7 @@ void HingeJointSW::set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value) switch (p_flag) { case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT: m_useLimit = p_value; break; case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR: m_enableAngularMotor = p_value; break; + case PhysicsServer::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } } bool HingeJointSW::get_flag(PhysicsServer::HingeJointFlag p_flag) const { @@ -441,6 +444,7 @@ bool HingeJointSW::get_flag(PhysicsServer::HingeJointFlag p_flag) const { switch (p_flag) { case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT: return m_useLimit; case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR: return m_enableAngularMotor; + case PhysicsServer::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } return false; diff --git a/servers/physics/joints/slider_joint_sw.cpp b/servers/physics/joints/slider_joint_sw.cpp index c0e9660b22..30700d45f1 100644 --- a/servers/physics/joints/slider_joint_sw.cpp +++ b/servers/physics/joints/slider_joint_sw.cpp @@ -404,6 +404,8 @@ void SliderJointSW::set_param(PhysicsServer::SliderJointParam p_param, real_t p_ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: m_softnessOrthoAng = p_value; break; case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: m_restitutionOrthoAng = p_value; break; case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: m_dampingOrthoAng = p_value; break; + + case PhysicsServer::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning } } @@ -433,6 +435,8 @@ real_t SliderJointSW::get_param(PhysicsServer::SliderJointParam p_param) const { case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: return m_softnessOrthoAng; case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: return m_restitutionOrthoAng; case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: return m_dampingOrthoAng; + + case PhysicsServer::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning } return 0; diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index c3b9e4b713..f2b2363499 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -112,23 +112,23 @@ public: _FORCE_INLINE_ int get_shape_count() const { return shapes.size(); } _FORCE_INLINE_ Shape2DSW *get_shape(int p_index) const { - ERR_FAIL_INDEX_V(p_index, shapes.size(), NULL); + CRASH_BAD_INDEX(p_index, shapes.size()); return shapes[p_index].shape; } _FORCE_INLINE_ const Transform2D &get_shape_transform(int p_index) const { - ERR_FAIL_INDEX_V(p_index, shapes.size(), Transform2D()); + CRASH_BAD_INDEX(p_index, shapes.size()); return shapes[p_index].xform; } _FORCE_INLINE_ const Transform2D &get_shape_inv_transform(int p_index) const { - ERR_FAIL_INDEX_V(p_index, shapes.size(), Transform2D()); + CRASH_BAD_INDEX(p_index, shapes.size()); return shapes[p_index].xform_inv; } _FORCE_INLINE_ const Rect2 &get_shape_aabb(int p_index) const { - ERR_FAIL_INDEX_V(p_index, shapes.size(), Rect2()); + CRASH_BAD_INDEX(p_index, shapes.size()); return shapes[p_index].aabb_cache; } _FORCE_INLINE_ const Variant &get_shape_metadata(int p_index) const { - ERR_FAIL_INDEX_V(p_index, shapes.size(), Variant()); + CRASH_BAD_INDEX(p_index, shapes.size()); return shapes[p_index].metadata; } @@ -138,16 +138,16 @@ public: void set_shape_as_disabled(int p_idx, bool p_disabled); _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, shapes.size(), false); + CRASH_BAD_INDEX(p_idx, shapes.size()); return shapes[p_idx].disabled; } _FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision) { - ERR_FAIL_INDEX(p_idx, shapes.size()); + CRASH_BAD_INDEX(p_idx, shapes.size()); shapes.write[p_idx].one_way_collision = p_one_way_collision; } _FORCE_INLINE_ bool is_shape_set_as_one_way_collision(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, shapes.size(), false); + CRASH_BAD_INDEX(p_idx, shapes.size()); return shapes[p_idx].one_way_collision; } diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index fc2a228723..7c23fcdaea 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -372,7 +372,6 @@ public: BODY_MODE_KINEMATIC, BODY_MODE_RIGID, BODY_MODE_CHARACTER - //BODY_MODE_SOFT ?? }; virtual RID body_create() = 0; @@ -581,9 +580,7 @@ public: INFO_ACTIVE_OBJECTS, INFO_COLLISION_PAIRS, - INFO_ISLAND_COUNT, - INFO_STEP_TIME, - INFO_BROAD_PHASE_TIME + INFO_ISLAND_COUNT }; virtual int get_process_info(ProcessInfo p_info) = 0; diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index 0660c84d09..888e16e0c3 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -678,7 +678,6 @@ void PhysicsServer::_bind_methods() { BIND_ENUM_CONSTANT(BODY_MODE_STATIC); BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC); BIND_ENUM_CONSTANT(BODY_MODE_RIGID); - BIND_ENUM_CONSTANT(BODY_MODE_SOFT); BIND_ENUM_CONSTANT(BODY_MODE_CHARACTER); BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE); diff --git a/servers/physics_server.h b/servers/physics_server.h index d0d2ec16f0..d80d76305a 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -360,7 +360,6 @@ public: BODY_MODE_STATIC, BODY_MODE_KINEMATIC, BODY_MODE_RIGID, - BODY_MODE_SOFT, BODY_MODE_CHARACTER }; diff --git a/servers/visual/default_mouse_cursor.xpm b/servers/visual/default_mouse_cursor.xpm deleted file mode 100644 index 37d437dd15..0000000000 --- a/servers/visual/default_mouse_cursor.xpm +++ /dev/null @@ -1,23 +0,0 @@ -/* XPM */ -static const char * default_mouse_cursor_xpm[] = { -"16 16 4 1", -" c None", -". c #000000", -"+ c #FF00FF", -"@ c #FFFFFF", -"...+++++++++++++", -".@...+++++++++++", -".@@@...+++++++++", -".@@@@@....++++++", -".@@@@@@@@...++++", -".@@@@@@@@@@...++", -".@@@@@@@@@@@@..+", -".@@@@@@@@@@@@@..", -".@@@@@@@@@@@@..+", -".@@@@@@@@@@@..++", -".@@@@@@@@@...+++", -".@@@.....@@..+++", -".....+++.@@@..++", -"++++++++..@@@..+", -"+++++++++..@@@.+", -"++++++++++.....+"}; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 417617fa5b..67a810bf1c 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2023,10 +2023,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p StringName name = static_cast<VariableNode *>(p_func->arguments[0])->name.operator String(); - bool all_const = true; for (int i = 1; i < p_func->arguments.size(); i++) { - if (p_func->arguments[i]->type != Node::TYPE_CONSTANT) - all_const = false; args.push_back(p_func->arguments[i]->get_datatype()); } @@ -2369,6 +2366,21 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C value = Variant(t); break; } + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER2D: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2D: + case ShaderLanguage::TYPE_USAMPLER3D: + case ShaderLanguage::TYPE_SAMPLERCUBE: { + // Texture types, likely not relevant here. + break; + } + case ShaderLanguage::TYPE_VOID: + break; } return value; } @@ -3008,6 +3020,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons case TYPE_IVEC2: member_type = TYPE_INT; break; case TYPE_UVEC2: member_type = TYPE_UINT; break; case TYPE_MAT2: member_type = TYPE_VEC2; break; + default: break; } break; @@ -3033,6 +3046,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons case TYPE_IVEC3: member_type = TYPE_INT; break; case TYPE_UVEC3: member_type = TYPE_UINT; break; case TYPE_MAT3: member_type = TYPE_VEC3; break; + default: break; } break; case TYPE_BVEC4: @@ -3057,6 +3071,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons case TYPE_IVEC4: member_type = TYPE_INT; break; case TYPE_UVEC4: member_type = TYPE_UINT; break; case TYPE_MAT4: member_type = TYPE_VEC4; break; + default: break; } break; default: { diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index caa454b98e..57e8d86468 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -78,6 +78,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4; shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); @@ -112,6 +113,8 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_SCISSOR"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); @@ -138,6 +141,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ROUGHNESS"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3; + shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[VS::SHADER_SPATIAL].functions["light"].can_discard = true; diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index ea63ae5013..6e41197e21 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -34,7 +34,6 @@ #include "core/os/os.h" #include "core/project_settings.h" #include "core/sort.h" -#include "default_mouse_cursor.xpm" #include "visual_server_canvas.h" #include "visual_server_global.h" #include "visual_server_scene.h" diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index eacb5f671c..a82b426f0d 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -398,6 +398,7 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { VSG::scene_render->free(gi_probe->probe_instance); } break; + default: {} } if (instance->base_data) { @@ -471,6 +472,7 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { gi_probe->probe_instance = VSG::scene_render->gi_probe_instance_create(); } break; + default: {} } VSG::storage->instance_add_dependency(p_base, instance); @@ -518,6 +520,7 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) { gi_probe_update_list.remove(&gi_probe->update_element); } } break; + default: {} } instance->scenario = NULL; @@ -549,6 +552,7 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) { gi_probe_update_list.add(&gi_probe->update_element); } } break; + default: {} } _instance_queue_update(instance, true, true); @@ -649,6 +653,7 @@ void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) { } } break; + default: {} } } inline bool is_geometry_instance(VisualServer::InstanceType p_type) { @@ -825,6 +830,7 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF instance->redraw_if_visible = p_enabled; } break; + default: {} } } void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting) { @@ -902,7 +908,7 @@ void VisualServerScene::_update_instance(Instance *p_instance) { _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->lightmap_capture_data.resize(0); //not in use, clear capture data } } } @@ -1016,7 +1022,6 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { new_aabb = VSG::storage->lightmap_capture_get_bounds(p_instance->base); } break; - default: {} } @@ -1378,9 +1383,12 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons float y_min = 0.f, y_max = 0.f; float z_min = 0.f, z_max = 0.f; + // FIXME: z_max_cam is defined, computed, but not used below when setting up + // ortho_camera. Commented out for now to fix warnings but should be investigated. float x_min_cam = 0.f, x_max_cam = 0.f; float y_min_cam = 0.f, y_max_cam = 0.f; - float z_min_cam = 0.f, z_max_cam = 0.f; + float z_min_cam = 0.f; + //float z_max_cam = 0.f; float bias_scale = 1.0; @@ -1442,7 +1450,7 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons x_min_cam = x_vec.dot(center) - radius; y_max_cam = y_vec.dot(center) + radius; y_min_cam = y_vec.dot(center) - radius; - z_max_cam = z_vec.dot(center) + radius; + //z_max_cam = z_vec.dot(center) + radius; z_min_cam = z_vec.dot(center) - radius; if (depth_range_mode == VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 7240266133..18a239b019 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -2393,6 +2393,10 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/quality/shading/force_vertex_shading", false); GLOBAL_DEF("rendering/quality/shading/force_vertex_shading.mobile", true); + GLOBAL_DEF("rendering/quality/shading/force_lambert_over_burley", false); + GLOBAL_DEF("rendering/quality/shading/force_lambert_over_burley.mobile", true); + GLOBAL_DEF("rendering/quality/shading/force_blinn_over_ggx", false); + GLOBAL_DEF("rendering/quality/shading/force_blinn_over_ggx.mobile", true); GLOBAL_DEF("rendering/quality/depth_prepass/enable", true); GLOBAL_DEF("rendering/quality/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno"); |