diff options
187 files changed, 3100 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 09d8664240..e862743934 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -30,6 +30,19 @@  #include "range.h" +String Range::get_configuration_warning() const { +	String warning = Control::get_configuration_warning(); + +	if (shared->exp_ratio && shared->min <= 0) { +		if (warning != String()) { +			warning += "\n"; +		} +		warning += TTR("If exp_edit is true min_value must be > 0."); +	} + +	return warning; +} +  void Range::_value_changed_notify() {  	_value_changed(shared->val); @@ -66,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; @@ -90,6 +104,8 @@ void Range::set_min(double p_min) {  	set_value(shared->val);  	shared->emit_changed("min"); + +	update_configuration_warning();  }  void Range::set_max(double p_max) { @@ -277,6 +293,8 @@ bool Range::is_using_rounded_values() const {  void Range::set_exp_ratio(bool p_enable) {  	shared->exp_ratio = p_enable; + +	update_configuration_warning();  }  bool Range::is_ratio_exp() const { diff --git a/scene/gui/range.h b/scene/gui/range.h index 125f559248..58f15c8aa8 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -97,6 +97,8 @@ public:  	void share(Range *p_range);  	void unshare(); +	virtual String get_configuration_warning() const; +  	Range();  	~Range();  }; 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");  |