diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index e3360a23d20..fd6a91d125f 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -4,6 +4,7 @@ #include "io/marshalls.h" #include "io/base64.h" #include "core/globals.h" +#include "io/file_access_encrypted.h" _ResourceLoader *_ResourceLoader::singleton=NULL; @@ -812,6 +813,44 @@ _Geometry::_Geometry() { ///////////////////////// FILE + +Error _File::open_encrypted(const String& p_path, int p_mode_flags,const Vector& p_key) { + + Error err = open(p_path,p_mode_flags); + if (err) + return err; + + FileAccessEncrypted *fae = memnew( FileAccessEncrypted ); + err = fae->open_and_parse(f,p_key,(p_mode_flags==WRITE)?FileAccessEncrypted::MODE_WRITE_AES256:FileAccessEncrypted::MODE_READ); + if (err) { + memdelete(fae); + close(); + return err; + } + f=fae; + return OK; +} + +Error _File::open_encrypted_pass(const String& p_path, int p_mode_flags,const String& p_pass) { + + Error err = open(p_path,p_mode_flags); + if (err) + return err; + + FileAccessEncrypted *fae = memnew( FileAccessEncrypted ); + err = fae->open_and_parse_password(f,p_pass,(p_mode_flags==WRITE)?FileAccessEncrypted::MODE_WRITE_AES256:FileAccessEncrypted::MODE_READ); + if (err) { + memdelete(fae); + close(); + return err; + } + + f=fae; + return OK; + +} + + Error _File::open(const String& p_path, int p_mode_flags) { close(); @@ -1113,6 +1152,10 @@ Variant _File::get_var() const { void _File::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("open_encrypted","path","mode_flags","key"),&_File::open_encrypted); + ObjectTypeDB::bind_method(_MD("open_encrypted_with_pass","path","mode_flags","pass"),&_File::open_encrypted_pass); + ObjectTypeDB::bind_method(_MD("open","path","flags"),&_File::open); ObjectTypeDB::bind_method(_MD("close"),&_File::close); ObjectTypeDB::bind_method(_MD("is_open"),&_File::is_open); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 0084726547d..f5c94dcf06b 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -243,6 +243,10 @@ public: READ_WRITE=3, }; + Error open_encrypted(const String& p_path, int p_mode_flags,const Vector& p_key); + Error open_encrypted_pass(const String& p_path, int p_mode_flags,const String& p_pass); + + Error open(const String& p_path, int p_mode_flags); ///< open a file void close(); ///< close a file bool is_open() const; ///< true when file is open diff --git a/demos/2d/platformer/engine.cfg b/demos/2d/platformer/engine.cfg index 5fc2c3b2bae..a377bf89836 100644 --- a/demos/2d/platformer/engine.cfg +++ b/demos/2d/platformer/engine.cfg @@ -10,6 +10,8 @@ name_es="Plataformero" width=800 height=480 stretch_2d=true +stretch_mode="viewport" +stretch_aspect="keep" [input] diff --git a/doc/base/classes.xml b/doc/base/classes.xml index 6e4d97c4131..e5330925a9e 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -50,6 +50,7 @@ + Hyperbolic cosine. @@ -281,13 +282,18 @@ + Reset the seed of the random number generator with a + new, different one. - + - Random value (integer). + Random 32 bits value (integer). To obtain a value + from 0 to N, you can use remainder, like (for random + from 0 to 19): randi() % + 20. @@ -305,7 +311,8 @@ - Random range. + Random range, any floating point value between + 'from' and 'to' @@ -314,7 +321,7 @@ - random from seed, pass a seed and an array with both number and new seed is returned. + Random from seed, pass a seed and an array with both number and new seed is returned. @@ -406,6 +413,16 @@ Return a weak reference to an object. + + + + + + + + + + @@ -491,12 +508,24 @@ Return an array with the given range. Range can be 1 argument N (0 to N-1), two arguments (initial, final-1) or three arguments (initial,final-1,increment). + + + + + + + Load a resource from the filesystem, pass a valid + path as argument. + + + Convert a script class instance to a dictionary + (useful for serializing). @@ -505,16 +534,24 @@ + Convert a previously converted instances to dictionary + back into an instance. Useful for deserializing. + Print a stack track at code location, only works when + running with debugger turned on. + + Constant that represents how many times the diameter of a + circumference fits around it's perimeter. + @@ -531,54 +568,79 @@ + The file engine.cfg is read into this singleton. + Global IP protocol functions (like hostname resolution). + Geometry helpers. + Singleton that loads resources (load() calls this) + Singleton that saves resources. + Uset to setup remaps for the filesystem. + Operating system functions. + Used to serialize and deserialize, helpers. + Server that takes care of translating between different + languages. + Short version for TranslationServer. + Global input variables and functions. + Deprecaed. + Server that handles anything visual at low level. + Short for VisualServer. + Server that handles anything audio at low level. + Short for AudioServer. + Server that handles anything 3D physics at low level. + Short for PhysicsServer. + Server that handles anything 2D physics at low level. + Short for Physics2DServer. + Server that handles spatial audio positioning in 3D at low + level. + Short for SpatialSoundServer. + Server that handles spatial audio positioning in 2D at low + level. - - + Short for SpatialSound2DServer. @@ -1493,16 +1555,6 @@ - - - - - - - - - - Axis-Aligned Bounding Box. @@ -1692,6 +1744,7 @@ + Same as pos+size. @@ -1794,92 +1847,114 @@ + Sprite node that can use multiple textures for animation. + Sprite node that can use multiple textures for animation. + Set the [SpriteFrames] resource, which contains all + frames. + Get the [SpriteFrames] resource, which contains all + frames. + When turned on, offset at (0,0) is the center of the + sprite, when off, the top-left corner is. + Return true when centered. See [set_centered]. + Set the offset of the sprite in the node origin. + Position varies depending on whether it is centered + or not. + Return the offset of the sprite in the node origin. + If true, sprite is flipped horizontally. + Return true if sprite is flipped horizontally. + If true, sprite is flipped vertically. + Return true if sprite is flipped vertically. + Set the visible sprite frame index (from the list of + frames inside the [SpriteFrames] resource). + Return the visible frame index. + Change the color modulation (multiplication) for this sprite. + Return the color modulation for this sprite. @@ -2361,22 +2436,27 @@ + Play a given animation by the animation name. Custom + speed and blend times can be set. If custom speed is + negative (-1), 'from_end' being true can play the + animation backwards. + Stop the currently played animation. - Stop playback on all animation channels. + Stop playback of animations (deprecated). - Return wether an animation chanel is playing (or channel 0 if none is provided). + Return wether an animation is playing. @@ -2390,7 +2470,7 @@ - Return the name of the animation being played in a channel (or channel 0 if none is provided). + Return the name of the animation being played. @@ -2402,13 +2482,15 @@ + If animations are queued to play, clear them. - Set the player as active (playing) + Set the player as active (playing). If false, it + will do nothing. @@ -2450,12 +2532,16 @@ + AnimationPlayer resolves animation track paths from + this node (which is relative to itself), by + default root is "..", but it can be changed.. + Return path to root node (see [set_root]). @@ -2464,7 +2550,10 @@ - Seek the animation in an animation channel (or channel 0 if none is provided) to a specific position (in seconds). + Seek the animation to a given position in time (in + seconds). If 'update' + is true, the animation will be updated too, + otherwise it will be updated at process time. @@ -2506,12 +2595,16 @@ + Get the position (in seconds) of the currently being + played animation. + Get the length (in seconds) of the currently being + played animation. @@ -2522,24 +2615,35 @@ + If the currently being played animation changes, + this signal will notify of such change. + Notifies when an animation finished playing. + Process animation on fixed process. This is specially useful + when animating kinematic bodies. + Process animation on idle process. + Animation Player that uses a node graph for the blending. + Animation Player that uses a node graph for the blending. This kind + of player is very useful when animating character or other skeleton + based rigs, because it can combine several animations to form a + desired pose. @@ -2548,6 +2652,8 @@ + Add a node of a given type in the graph with given + id. @@ -2556,6 +2662,7 @@ + Check if a node exists (by name). @@ -2566,6 +2673,7 @@ + Rename a node in the graph. @@ -2574,6 +2682,7 @@ + Get the node type, will return from NODE_* enum. @@ -2582,6 +2691,8 @@ + Return the input count for a given node. Different + types of nodes have different amount of inputs. @@ -2592,6 +2703,7 @@ + Return the input source for a given node input. @@ -2600,6 +2712,7 @@ + Set the animation for an animation node. @@ -4887,6 +5000,18 @@ Return true if the camera is at the center of the screen (default: true). + + + + + + + + + + + + Make this the current 2D camera for the scene (viewport and layer), in case there's many cameras in the scene. @@ -5168,18 +5293,16 @@ Set canvas item self-opacity. This does not affect the opacity of children items. - - + + - Set canvas item as drawing over the parent canvas item (default: true). - + - Return if the canvas item is drawing over the parent canvas item (default: true). @@ -8229,6 +8352,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8809,6 +8958,18 @@ + + + + + + + + + + + + @@ -9124,38 +9285,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9532,6 +9661,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -10827,7 +11004,13 @@ - + + + + + + + @@ -11038,6 +11221,12 @@ + + + + + + @@ -11595,6 +11784,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -11651,6 +11860,16 @@ + + + + + + + + + + @@ -11847,6 +12066,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Control that displays formatted text. @@ -13580,16 +13923,6 @@ - - - - - - - - - - @@ -14433,13 +14766,6 @@ -Command Line - - - - - Return the mouse pos. - - @@ -14706,11 +15032,10 @@ Return true if the engine was executed with -v (verbose stdout). - - + + - Return the state of the mouse buttons (each button in each bit). @@ -14775,6 +15100,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -16804,6 +17155,20 @@ Intersect a given shape (RID or [Shape2D]) against the space, the intersected shapes are returned in a special result object. + + + + + + + + + + + + + + @@ -17006,19 +17371,21 @@ - + + + - - - + + + @@ -17103,8 +17470,6 @@ - - @@ -17216,16 +17581,16 @@ - + - + - - + + @@ -17252,14 +17617,6 @@ - - - - - - - - @@ -17532,6 +17889,12 @@ + + + + + + @@ -21032,18 +21395,16 @@ Return wether contact monitoring is enabled. - - + + - Enable continuos collision detection. This prevents very fast-moving bodies (such as bullets) to not go through objects. - - + + - Return true if continuous collision detection is in use. @@ -21157,6 +21518,12 @@ Character body, can move but not rotate. + + + + + + @@ -22610,6 +22977,54 @@ Return the custom solver bias. No need to change this unless you really know what you are doing. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -23694,20 +24109,6 @@ Alternatively, a constant linear or angular velocity can be set for the static body, so even if it doesn't move, it affects other bodies as if it was moving (this is useful for simulating conveyor belts or conveyor wheels). - - - - - Enable or disable simulated motion mode. - - - - - - - Return true if simulated motion mode is enabled. - - @@ -25881,6 +26282,18 @@ + + + + + + + + + + + + @@ -26133,22 +26546,36 @@ Return the texture of the tile. - + - + - Set the offset to draw the tile. - + + + + + + + + + + + + + + + + + - Return the offset to draw the tile. @@ -26231,6 +26658,12 @@ Find the first tile with the given name. + + + + + + @@ -27466,6 +27899,14 @@ Returns a normalized vector to unit length. + + + + + + + + @@ -27474,6 +27915,14 @@ + + + + + + + + @@ -28077,6 +28526,24 @@ + + + + + + + + + + + + + + + + + + @@ -28088,6 +28555,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -28096,6 +28587,14 @@ + + + + + + + + @@ -30133,7 +30632,15 @@ - + + + + + + + + + diff --git a/drivers/gles1/rasterizer_gles1.cpp b/drivers/gles1/rasterizer_gles1.cpp index f763a60abbb..3ffebd47038 100644 --- a/drivers/gles1/rasterizer_gles1.cpp +++ b/drivers/gles1/rasterizer_gles1.cpp @@ -4602,6 +4602,12 @@ void RasterizerGLES1::canvas_begin() { } + +void RasterizerGLES1::canvas_disable_blending() { + + glDisable(GL_BLEND); +} + void RasterizerGLES1::canvas_set_opacity(float p_opacity) { canvas_opacity = p_opacity; diff --git a/drivers/gles1/rasterizer_gles1.h b/drivers/gles1/rasterizer_gles1.h index a20477eced6..e7e3200bbc3 100644 --- a/drivers/gles1/rasterizer_gles1.h +++ b/drivers/gles1/rasterizer_gles1.h @@ -1126,6 +1126,7 @@ public: /* CANVAS API */ virtual void canvas_begin(); + virtual void canvas_disable_blending(); virtual void canvas_set_opacity(float p_opacity); virtual void canvas_set_blend_mode(VS::MaterialBlendMode p_mode); virtual void canvas_begin_rect(const Matrix32& p_transform); diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 20505875ead..7d732f19680 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -6302,6 +6302,12 @@ void RasterizerGLES2::canvas_begin() { } + +void RasterizerGLES2::canvas_disable_blending() { + + glDisable(GL_BLEND); +} + void RasterizerGLES2::canvas_set_opacity(float p_opacity) { canvas_opacity = p_opacity; diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index ce6ba1770cd..f18bdd1ff7a 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -1373,6 +1373,8 @@ public: /* CANVAS API */ virtual void canvas_begin(); + virtual void canvas_disable_blending(); + virtual void canvas_set_opacity(float p_opacity); virtual void canvas_set_blend_mode(VS::MaterialBlendMode p_mode); virtual void canvas_begin_rect(const Matrix32& p_transform); diff --git a/drivers/openssl/stream_peer_ssl.cpp b/drivers/openssl/stream_peer_ssl.cpp index aaedd7dde98..19a17ea0cd8 100644 --- a/drivers/openssl/stream_peer_ssl.cpp +++ b/drivers/openssl/stream_peer_ssl.cpp @@ -1,111 +1,97 @@ #include "stream_peer_ssl.h" -int StreamPeerSSL::bio_create( BIO *b ) { - b->init = 1; - b->num = 0; - b->ptr = NULL; - b->flags = 0; - return 1; -} +Error StreamPeerSSL::connect(const String &p_host,int p_port,int p_flags) { -int StreamPeerSSL::bio_destroy( BIO *b ) { + // Set up a SSL_CTX object, which will tell our BIO object how to do its work + ctx = SSL_CTX_new(SSLv23_client_method()); + // Create our BIO object for SSL connections. + BIO* bio = BIO_new_ssl_connect(ctx); + // Failure? + if (bio == NULL) { - if ( b == NULL ) return 0; - b->ptr = NULL; /* sb_tls_remove() will free it */ - b->init = 0; - b->flags = 0; - return 1; -} + // We need to free up the SSL_CTX before we leave. + ERR_FAIL_COND_V(bio==NULL,ERR_CANT_CREATE); + } + // Makes ssl point to bio's SSL object. + BIO_get_ssl(bio, &ssl); + // Set the SSL to automatically retry on failure. + SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); + // We're connection to google.com on port 443. + BIO_set_conn_hostname(bio, (p_host+":"+itos(p_port)).utf8().get_data()); -int StreamPeerSSL::bio_read( BIO *b, char *buf, int len ) { + // Same as before, try to connect. + if (BIO_do_connect(bio) <= 0) { - if ( buf == NULL || len <= 0 ) return 0; + ERR_EXPLAIN("Failed to connect to '"+p_host+"'' port "+itos(p_port)); + BIO_free_all(bio); + SSL_CTX_free(ctx); + ERR_FAIL_V(ERR_CANT_CONNECT); + } - StreamPeerSSL * sp = (StreamPeerSSL*)b->ptr; - - if (sp->base.is_null()) - return 0; + // Now we need to do the SSL handshake, so we can communicate. + if (BIO_do_handshake(bio) <= 0) { + ERR_EXPLAIN("Failed to handshake to '"+p_host+"'' port "+itos(p_port)); + BIO_free_all(bio); + SSL_CTX_free(ctx); + ERR_FAIL_V(ERR_CANT_CONNECT); + } - - BIO_clear_retry_flags( b ); - - Error err; - int ret=0; - if (sp->block) { - err = sp->base->get_data((const uint8_t*)buf,len); - if (err==OK) - ret=len; - } else { - - err = sp->base->get_partial_data((const uint8_t*)buf,len,ret); - if (err==OK && ret!=len) { - BIO_set_retry_write( b ); + // Create a buffer for grabbing information from the page. + char buf[1024]; + memset(buf, 0, sizeof(buf)); + // Create a buffer for the reqest we'll send to the server + char send[1024]; + memset(send, 0, sizeof(send)); + // Create our GET request. + strcat(send, "GET / HTTP/1.1\nHost:google.com\nUser Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)\nConnection: Close\n\n"); + // BIO_puts sends a null-terminated string to the server. In this case it's our GET request. + BIO_puts(bio, send); + // Loop while there's information to be read. + while (1) { + // BIO_read() reads data from the server into a buffer. It returns the number of characters read in. + int x = BIO_read(bio, buf, sizeof(buf) - 1); + // If we haven't read in anything, assume there's nothing more to be sent since we used Connection: Close. + if (x == 0) { + break; } - - } - - return ret; -} - -int StreamPeerSSL::bio_write( BIO *b, const char *buf, int len ) { - - if ( buf == NULL || len <= 0 ) return 0; - - StreamPeerSSL * sp = (StreamPeerSSL*)b->ptr; - - if (sp->base.is_null()) - return 0; - - BIO_clear_retry_flags( b ); - - Error err; - int wrote=0; - if (sp->block) { - err = sp->base->put_data((const uint8_t*)buf,len); - if (err==OK) - wrote=len; - } else { - - err = sp->base->put_partial_data((const uint8_t*)buf,len,wrote); - if (err==OK && wrote!=len) { - BIO_set_retry_write( b ); + // If BIO_read() returns a negative number, there was an error + else if (x < 0) { + // BIO_should_retry lets us know if we should keep trying to read data or not. + if (!BIO_should_retry(bio)) { + printf("\nRead Failed!\n"); + BIO_free_all(bio); + SSL_CTX_free(ctx); + return; + } + } + // We actually got some data, without errors! + else { + // Null-terminate our buffer, just in case + buf[x] = 0; + // Echo what the server sent to the screen + printf("%s", buf); } - } + // Free up that BIO object we created. + BIO_free_all(bio); + // Remember, we also need to free up that SSL_CTX object! + SSL_CTX_free(ctx); + // Return. - return wrote; } -long StreamPeerSSL::bio_ctrl( BIO *b, int cmd, long num, void *ptr ) { - if ( cmd == BIO_CTRL_FLUSH ) { - /* The OpenSSL library needs this */ - return 1; - } - return 0; +void StreamPeerSSL::initialize_ssl() { + + CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use + SSL_library_init(); // Initialize OpenSSL's SSL libraries + SSL_load_error_strings(); // Load SSL error strings + ERR_load_BIO_strings(); // Load BIO error strings + OpenSSL_add_all_algorithms(); // Load all available encryption algorithms } -int StreamPeerSSL::bio_gets( BIO *b, char *buf, int len ) { - return -1; -} +void StreamPeerSSL::finalize_ssl(){ -int StreamPeerSSL::bio_puts( BIO *b, const char *str ) { - return StreamPeerSSL::bio_write( b, str, strlen( str ) ); -} -BIO_METHOD StreamPeerSSL::bio_methods = -{ - ( 100 | 0x400 ), /* it's a source/sink BIO */ - "sockbuf glue", - StreamPeerSSL::bio_write, - StreamPeerSSL::bio_read, - StreamPeerSSL::bio_puts, - StreamPeerSSL::bio_gets, - StreamPeerSSL::bio_ctrl, - StreamPeerSSL::bio_create, - StreamPeerSSL::bio_destroy -}; - -StreamPeerSSL::StreamPeerSSL() { } diff --git a/drivers/openssl/stream_peer_ssl.h b/drivers/openssl/stream_peer_ssl.h index a126f6122cb..74866c2da4e 100644 --- a/drivers/openssl/stream_peer_ssl.h +++ b/drivers/openssl/stream_peer_ssl.h @@ -1,26 +1,43 @@ #ifndef STREAM_PEER_SSL_H #define STREAM_PEER_SSL_H -#include "io/stream_peer.h" +#ifdef OPENSSL_ENABLED +#include "io/stream_peer.h" +#include // To prevent crashing (see the OpenSSL FAQ) +#include // BIO objects for I/O +#include // SSL and SSL_CTX for SSL connections +#include // Error reporting + +#include // If you don't know what this is for stop reading now. class StreamPeerSSL : public StreamPeer { OBJ_TYPE(StreamPeerSSL,StreamPeer); +public: - Ref base; - bool block; - static BIO_METHOD bio_methods; + enum ConnectFlags { + + CONNECT_FLAG_BUG_WORKAROUNDS=1, + CONNECT_FLAG_NO_SSLV2=2, + CONNECT_FLAG_NO_SSLV3=4, + CONNECT_FLAG_NO_TLSV1=8, + CONNECT_FLAG_NO_COMPRESSION=16, + }; + + SSL_CTX* ctx; + SSL* ssl; + BIO* bio; - static int bio_create( BIO *b ); - static int bio_destroy( BIO *b ); - static int bio_read( BIO *b, char *buf, int len ); - static int bio_write( BIO *b, const char *buf, int len ); - static long bio_ctrl( BIO *b, int cmd, long num, void *ptr ); - static int bio_gets( BIO *b, char *buf, int len ); - static int bio_puts( BIO *b, const char *str ); public: + + + Error connect(const String &p_host,int p_port); + static void initialize_ssl(); + static void finalize_ssl(); + StreamPeerSSL(); }; +#endif #endif // STREAM_PEER_SSL_H diff --git a/main/main.cpp b/main/main.cpp index 19dbbe52039..0d9e94346e0 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1008,11 +1008,25 @@ bool Main::start() { if (!editor) { //standard helpers that can be changed from main config - if (GLOBAL_DEF("display/stretch_2d",false).operator bool()) { + String stretch_mode = GLOBAL_DEF("display/stretch_mode","disabled"); + String stretch_aspect = GLOBAL_DEF("display/stretch_aspect","ignore"); + Size2i stretch_size = Size2(GLOBAL_DEF("display/width",0),GLOBAL_DEF("display/height",0)); - sml->get_root()->set_size_override(true,Size2(Globals::get_singleton()->get("display/width"),Globals::get_singleton()->get("display/height"))); - sml->get_root()->set_size_override_stretch(true); - } + SceneMainLoop::StretchMode sml_sm=SceneMainLoop::STRETCH_MODE_DISABLED; + if (stretch_mode=="2d") + sml_sm=SceneMainLoop::STRETCH_MODE_2D; + else if (stretch_mode=="viewport") + sml_sm=SceneMainLoop::STRETCH_MODE_VIEWPORT; + + SceneMainLoop::StretchAspect sml_aspect=SceneMainLoop::STRETCH_ASPECT_IGNORE; + if (stretch_aspect=="keep") + sml_aspect=SceneMainLoop::STRETCH_ASPECT_KEEP; + else if (stretch_aspect=="keep_width") + sml_aspect=SceneMainLoop::STRETCH_ASPECT_KEEP_WIDTH; + else if (stretch_aspect=="keep_height") + sml_aspect=SceneMainLoop::STRETCH_ASPECT_KEEP_HEIGHT; + + sml->set_screen_stretch(sml_sm,sml_aspect,stretch_size); sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true)); String appname = Globals::get_singleton()->get("application/name"); @@ -1021,7 +1035,10 @@ bool Main::start() { } else { - GLOBAL_DEF("display/stretch_2d",false); + GLOBAL_DEF("display/stretch_mode","disabled"); + Globals::get_singleton()->set_custom_property_info("display/stretch_mode",PropertyInfo(Variant::STRING,"display/stretch_mode",PROPERTY_HINT_ENUM,"disabled,2d,viewport")); + GLOBAL_DEF("display/stretch_aspect","ignore"); + Globals::get_singleton()->set_custom_property_info("display/stretch_aspect",PropertyInfo(Variant::STRING,"display/stretch_aspect",PROPERTY_HINT_ENUM,"ignore,keep,keep_width,keep_height")); sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true)); diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template index 99c3650efa0..e723b693d87 100644 --- a/platform/android/AndroidManifest.xml.template +++ b/platform/android/AndroidManifest.xml.template @@ -5,6 +5,11 @@ android:versionName="1.0" android:installLocation="preferExternal" > + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/android/detect.py b/platform/android/detect.py index 17e97fae0f6..72a16ab59a1 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -57,6 +57,7 @@ def configure(env): env['SPAWN'] = methods.win32_spawn env.android_source_modules.append("../libs/apk_expansion") + env.android_source_modules.append("../libs/google_play_services") ndk_platform="" ndk_platform="android-15" diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index a9b96a116bf..51db77595b5 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -10,10 +10,169 @@ #include "os/os.h" #include "platform/android/logo.h" + +static const char* android_perms[]={ +"ACCESS_CHECKIN_PROPERTIES", +"ACCESS_COARSE_LOCATION", +"ACCESS_FINE_LOCATION", +"ACCESS_LOCATION_EXTRA_COMMANDS", +"ACCESS_MOCK_LOCATION", +"ACCESS_NETWORK_STATE", +"ACCESS_SURFACE_FLINGER", +"ACCESS_WIFI_STATE", +"ACCOUNT_MANAGER", +"ADD_VOICEMAIL", +"AUTHENTICATE_ACCOUNTS", +"BATTERY_STATS", +"BIND_ACCESSIBILITY_SERVICE", +"BIND_APPWIDGET", +"BIND_DEVICE_ADMIN", +"BIND_INPUT_METHOD", +"BIND_NFC_SERVICE", +"BIND_NOTIFICATION_LISTENER_SERVICE", +"BIND_PRINT_SERVICE", +"BIND_REMOTEVIEWS", +"BIND_TEXT_SERVICE", +"BIND_VPN_SERVICE", +"BIND_WALLPAPER", +"BLUETOOTH", +"BLUETOOTH_ADMIN", +"BLUETOOTH_PRIVILEGED", +"BRICK", +"BROADCAST_PACKAGE_REMOVED", +"BROADCAST_SMS", +"BROADCAST_STICKY", +"BROADCAST_WAP_PUSH", +"CALL_PHONE", +"CALL_PRIVILEGED", +"CAMERA", +"CAPTURE_AUDIO_OUTPUT", +"CAPTURE_SECURE_VIDEO_OUTPUT", +"CAPTURE_VIDEO_OUTPUT", +"CHANGE_COMPONENT_ENABLED_STATE", +"CHANGE_CONFIGURATION", +"CHANGE_NETWORK_STATE", +"CHANGE_WIFI_MULTICAST_STATE", +"CHANGE_WIFI_STATE", +"CLEAR_APP_CACHE", +"CLEAR_APP_USER_DATA", +"CONTROL_LOCATION_UPDATES", +"DELETE_CACHE_FILES", +"DELETE_PACKAGES", +"DEVICE_POWER", +"DIAGNOSTIC", +"DISABLE_KEYGUARD", +"DUMP", +"EXPAND_STATUS_BAR", +"FACTORY_TEST", +"FLASHLIGHT", +"FORCE_BACK", +"GET_ACCOUNTS", +"GET_PACKAGE_SIZE", +"GET_TASKS", +"GET_TOP_ACTIVITY_INFO", +"GLOBAL_SEARCH", +"HARDWARE_TEST", +"INJECT_EVENTS", +"INSTALL_LOCATION_PROVIDER", +"INSTALL_PACKAGES", +"INSTALL_SHORTCUT", +"INTERNAL_SYSTEM_WINDOW", +"INTERNET", +"KILL_BACKGROUND_PROCESSES", +"LOCATION_HARDWARE", +"MANAGE_ACCOUNTS", +"MANAGE_APP_TOKENS", +"MANAGE_DOCUMENTS", +"MASTER_CLEAR", +"MEDIA_CONTENT_CONTROL", +"MODIFY_AUDIO_SETTINGS", +"MODIFY_PHONE_STATE", +"MOUNT_FORMAT_FILESYSTEMS", +"MOUNT_UNMOUNT_FILESYSTEMS", +"NFC", +"PERSISTENT_ACTIVITY", +"PROCESS_OUTGOING_CALLS", +"READ_CALENDAR", +"READ_CALL_LOG", +"READ_CONTACTS", +"READ_EXTERNAL_STORAGE", +"READ_FRAME_BUFFER", +"READ_HISTORY_BOOKMARKS", +"READ_INPUT_STATE", +"READ_LOGS", +"READ_PHONE_STATE", +"READ_PROFILE", +"READ_SMS", +"READ_SOCIAL_STREAM", +"READ_SYNC_SETTINGS", +"READ_SYNC_STATS", +"READ_USER_DICTIONARY", +"REBOOT", +"RECEIVE_BOOT_COMPLETED", +"RECEIVE_MMS", +"RECEIVE_SMS", +"RECEIVE_WAP_PUSH", +"RECORD_AUDIO", +"REORDER_TASKS", +"RESTART_PACKAGES", +"SEND_RESPOND_VIA_MESSAGE", +"SEND_SMS", +"SET_ACTIVITY_WATCHER", +"SET_ALARM", +"SET_ALWAYS_FINISH", +"SET_ANIMATION_SCALE", +"SET_DEBUG_APP", +"SET_ORIENTATION", +"SET_POINTER_SPEED", +"SET_PREFERRED_APPLICATIONS", +"SET_PROCESS_LIMIT", +"SET_TIME", +"SET_TIME_ZONE", +"SET_WALLPAPER", +"SET_WALLPAPER_HINTS", +"SIGNAL_PERSISTENT_PROCESSES", +"STATUS_BAR", +"SUBSCRIBED_FEEDS_READ", +"SUBSCRIBED_FEEDS_WRITE", +"SYSTEM_ALERT_WINDOW", +"TRANSMIT_IR", +"UNINSTALL_SHORTCUT", +"UPDATE_DEVICE_STATS", +"USE_CREDENTIALS", +"USE_SIP", +"VIBRATE", +"WAKE_LOCK", +"WRITE_APN_SETTINGS", +"WRITE_CALENDAR", +"WRITE_CALL_LOG", +"WRITE_CONTACTS", +"WRITE_EXTERNAL_STORAGE", +"WRITE_GSERVICES", +"WRITE_HISTORY_BOOKMARKS", +"WRITE_PROFILE", +"WRITE_SECURE_SETTINGS", +"WRITE_SETTINGS", +"WRITE_SMS", +"WRITE_SOCIAL_STREAM", +"WRITE_SYNC_SETTINGS", +"WRITE_USER_DICTIONARY", +NULL}; + class EditorExportPlatformAndroid : public EditorExportPlatform { OBJ_TYPE( EditorExportPlatformAndroid,EditorExportPlatform ); + + enum { + MAX_USER_PERMISSIONS=20, + SCREEN_SMALL=0, + SCREEN_NORMAL=1, + SCREEN_LARGE=2, + SCREEN_XLARGE=3, + SCREEN_MAX=4 + }; + String custom_release_package; String custom_debug_package; @@ -47,6 +206,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { Thread *device_thread; Ref logo; + Set perms; + String user_perms[MAX_USER_PERMISSIONS]; + bool screen_support[SCREEN_MAX]; + volatile bool quit_request; @@ -104,11 +267,33 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant& _signed=p_value; else if (n=="screen/orientation") orientation=p_value; + else if (n=="screen/support_small") + screen_support[SCREEN_SMALL]=p_value; + else if (n=="screen/support_normal") + screen_support[SCREEN_NORMAL]=p_value; + else if (n=="screen/support_large") + screen_support[SCREEN_LARGE]=p_value; + else if (n=="screen/support_xlarge") + screen_support[SCREEN_XLARGE]=p_value; else if (n=="keystore/release") release_keystore=p_value; else if (n=="keystore/release_user") release_username=p_value; - else + else if (n.begins_with("permissions/")) { + + String what = n.get_slice("/",1).to_upper(); + bool state = p_value; + if (state) + perms.insert(what); + else + perms.erase(what); + } else if (n.begins_with("user_permissions/")) { + + int which = n.get_slice("/",1).to_int(); + ERR_FAIL_INDEX_V(which,MAX_USER_PERMISSIONS,false); + user_perms[which]=p_value; + + } else return false; return true; @@ -132,15 +317,33 @@ bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret) r_ret=_signed; else if (n=="screen/orientation") r_ret=orientation; + else if (n=="screen/support_small") + r_ret=screen_support[SCREEN_SMALL]; + else if (n=="screen/support_normal") + r_ret=screen_support[SCREEN_NORMAL]; + else if (n=="screen/support_large") + r_ret=screen_support[SCREEN_LARGE]; + else if (n=="screen/support_xlarge") + r_ret=screen_support[SCREEN_XLARGE]; else if (n=="keystore/release") r_ret=release_keystore; else if (n=="keystore/release_user") r_ret=release_username; - else + else if (n.begins_with("permissions/")) { + + String what = n.get_slice("/",1).to_upper(); + r_ret = perms.has(what); + } else if (n.begins_with("user_permissions/")) { + + int which = n.get_slice("/",1).to_int(); + ERR_FAIL_INDEX_V(which,MAX_USER_PERMISSIONS,false); + r_ret=user_perms[which]; + } else return false; return true; } + void EditorExportPlatformAndroid::_get_property_list( List *p_list) const{ p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_FILE,"apk")); @@ -152,9 +355,25 @@ void EditorExportPlatformAndroid::_get_property_list( List *p_list p_list->push_back( PropertyInfo( Variant::STRING, "package/icon",PROPERTY_HINT_FILE,"png") ); p_list->push_back( PropertyInfo( Variant::BOOL, "package/signed") ); p_list->push_back( PropertyInfo( Variant::INT, "screen/orientation",PROPERTY_HINT_ENUM,"Landscape,Portrait") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "screen/support_small") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "screen/support_normal") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "screen/support_large") ); + p_list->push_back( PropertyInfo( Variant::BOOL, "screen/support_xlarge") ); p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release",PROPERTY_HINT_FILE,"keystore") ); p_list->push_back( PropertyInfo( Variant::STRING, "keystore/release_user" ) ); + const char **perms = android_perms; + while(*perms) { + + p_list->push_back( PropertyInfo( Variant::BOOL, "permissions/"+String(*perms).to_lower())); + perms++; + } + + for(int i=0;ipush_back( PropertyInfo( Variant::STRING, "user_permissions/"+itos(i))); + } + //p_list->push_back( PropertyInfo( Variant::INT, "resources/pack_mode", PROPERTY_HINT_ENUM,"Copy,Single Exec.,Pack (.pck),Bundles (Optical)")); } @@ -536,6 +755,53 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector& p_manifest) { } } + if (tname=="uses-permission" && /*nspace=="android" &&*/ attrname=="name") { + + if (value.begins_with("godot.custom")) { + + int which = value.get_slice(".",2).to_int(); + if (which>=0 && which( memnew( ImageTexture )); logo->create_from_image(img); + + for(int i=0;i<4;i++) + screen_support[i]=true; } bool EditorExportPlatformAndroid::can_export(String *r_error) const { diff --git a/platform/android/java/src/com/android/godot/GodotPaymentV3.java b/platform/android/java/src/com/android/godot/GodotPaymentV3.java index 9d2893cde6a..23f5bf34d32 100644 --- a/platform/android/java/src/com/android/godot/GodotPaymentV3.java +++ b/platform/android/java/src/com/android/godot/GodotPaymentV3.java @@ -24,8 +24,12 @@ public class GodotPaymentV3 extends Godot.SingletonBase { } }); }; + +/* public string requestPurchasedTicket(){ + activity.getPaymentsManager() + } - +*/ static public Godot.SingletonBase initialize(Activity p_activity) { return new GodotPaymentV3(p_activity); @@ -40,8 +44,8 @@ public class GodotPaymentV3 extends Godot.SingletonBase { - public void callbackSuccess(){ - GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{}); + public void callbackSuccess(String ticket){ + GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket}); } public void callbackFail(){ diff --git a/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java b/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java index 08fc4051839..531a786dc9b 100644 --- a/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java +++ b/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java @@ -61,7 +61,7 @@ abstract public class HandlePurchaseTask { pc.setConsumableFlag("block", productId, true); pc.setConsumableValue("token", productId, purchaseToken); - success(purchaseToken, productId); + success(purchaseData); return; } catch (JSONException e) { error(e.getMessage()); @@ -71,7 +71,7 @@ abstract public class HandlePurchaseTask { } } - abstract protected void success(String purchaseToken, String sku); + abstract protected void success(String ticket); abstract protected void error(String message); abstract protected void canceled(); diff --git a/platform/android/java/src/com/android/godot/payments/PaymentsManager.java b/platform/android/java/src/com/android/godot/payments/PaymentsManager.java index 325e3a07514..983f655c350 100644 --- a/platform/android/java/src/com/android/godot/payments/PaymentsManager.java +++ b/platform/android/java/src/com/android/godot/payments/PaymentsManager.java @@ -84,8 +84,9 @@ public class PaymentsManager { new HandlePurchaseTask(activity){ @Override - protected void success(String purchaseToken, String sku) { - validatePurchase(purchaseToken, sku); + protected void success(String ticket) { + godotPaymentV3.callbackSuccess(ticket); + //validatePurchase(purchaseToken, sku); } @Override @@ -112,7 +113,7 @@ public class PaymentsManager { @Override protected void success() { - godotPaymentV3.callbackSuccess(); + godotPaymentV3.callbackSuccess(""); } @@ -145,7 +146,5 @@ public class PaymentsManager { this.godotPaymentV3 = godotPaymentV3; } - - } diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 8eb5c9dfc82..b9cddfa572f 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -821,6 +821,17 @@ void CanvasItem::_bind_methods() { } +Matrix32 CanvasItem::get_canvas_transform() const { + + ERR_FAIL_COND_V(!is_inside_scene(),Matrix32()); + + if (canvas_layer) + return canvas_layer->get_transform(); + else + return get_viewport()->get_canvas_transform(); + +} + Matrix32 CanvasItem::get_viewport_transform() const { ERR_FAIL_COND_V(!is_inside_scene(),Matrix32()); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 397b206677e..1c104c5fc25 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -195,6 +195,8 @@ public: void set_block_transform_notify(bool p_enable); bool is_block_transform_notify_enabled() const; + + Matrix32 get_canvas_transform() const; Matrix32 get_viewport_transform() const; Rect2 get_viewport_rect() const; RID get_viewport_rid() const; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 9e0faac7168..e0604b7cb87 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -955,7 +955,7 @@ void Control::_window_input_event(InputEvent p_event) { window->key_event_accepted=false; - Point2 mpos =(get_viewport_transform()).affine_inverse().xform(Point2(p_event.mouse_button.x,p_event.mouse_button.y)); + Point2 mpos =(get_canvas_transform()).affine_inverse().xform(Point2(p_event.mouse_button.x,p_event.mouse_button.y)); if (p_event.mouse_button.pressed) { @@ -1102,7 +1102,7 @@ void Control::_window_input_event(InputEvent p_event) { window->key_event_accepted=false; - Matrix32 localizer = (get_viewport_transform()).affine_inverse(); + Matrix32 localizer = (get_canvas_transform()).affine_inverse(); Size2 pos = localizer.xform(Size2(p_event.mouse_motion.x,p_event.mouse_motion.y)) - _window_get_pos(); Vector2 speed = localizer.basis_xform(Point2(p_event.mouse_motion.speed_x,p_event.mouse_motion.speed_y)); Vector2 rel = localizer.basis_xform(Point2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y)); diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index 32bc4b3e16e..5ec416fb477 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -516,7 +516,8 @@ bool SceneMainLoop::idle(float p_time){ last_screen_size=win_size; - root->set_rect(Rect2(Point2(),last_screen_size)); + _update_root_rect(); + emit_signal("screen_resized"); @@ -849,6 +850,120 @@ int SceneMainLoop::get_node_count() const { return node_count; } + +void SceneMainLoop::_update_root_rect() { + + + if (stretch_mode==STRETCH_MODE_DISABLED) { + root->set_rect(Rect2(Point2(),last_screen_size)); + return; //user will take care + } + + //actual screen video mode + Size2 video_mode = Size2(OS::get_singleton()->get_video_mode().width,OS::get_singleton()->get_video_mode().height); + Size2 desired_res = stretch_min; + + Size2 viewport_size; + Size2 screen_size; + + float viewport_aspect = desired_res.get_aspect(); + float video_mode_aspect = video_mode.get_aspect(); + + if (stretch_aspect==STRETCH_ASPECT_IGNORE || ABS(viewport_aspect - video_mode_aspect)black_bars_set_margins(margin.x,0,margin.x,0); + offset.x = Math::round(margin.x * viewport_size.y / screen_size.y); + } else if (screen_size.y < video_mode.y) { + + margin.y = Math::round((video_mode.y - screen_size.y)/2.0); + VisualServer::get_singleton()->black_bars_set_margins(0,margin.y,0,margin.y); + offset.y = Math::round(margin.y * viewport_size.x / screen_size.x); + } else { + VisualServer::get_singleton()->black_bars_set_margins(0,0,0,0); + } + +// print_line("VP SIZE: "+viewport_size+" OFFSET: "+offset+" = "+(offset*2+viewport_size)); +// print_line("SS: "+video_mode); + switch (stretch_mode) { + case STRETCH_MODE_2D: { + +// root->set_rect(Rect2(Point2(),video_mode)); + root->set_as_render_target(false); + root->set_rect(Rect2(margin,screen_size)); + root->set_size_override_stretch(true); + root->set_size_override(true,viewport_size); + + } break; + case STRETCH_MODE_VIEWPORT: { + + print_line("VP SIZE: "+viewport_size); + root->set_rect(Rect2(Point2(),viewport_size)); + root->set_size_override_stretch(false); + root->set_size_override(false,Size2()); + root->set_as_render_target(true); + root->set_render_target_update_mode(Viewport::RENDER_TARGET_UPDATE_ALWAYS); + root->set_render_target_to_screen_rect(Rect2(margin,screen_size)); + + } break; + + + } + +} + +void SceneMainLoop::set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize) { + + stretch_mode=p_mode; + stretch_aspect=p_aspect; + stretch_min=p_minsize; + _update_root_rect(); +} + + void SceneMainLoop::_bind_methods() { @@ -874,6 +989,9 @@ void SceneMainLoop::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_frame"),&SceneMainLoop::get_frame); ObjectTypeDB::bind_method(_MD("quit"),&SceneMainLoop::quit); + ObjectTypeDB::bind_method(_MD("set_screen_stretch","mode","aspect","minsize"),&SceneMainLoop::set_screen_stretch); + + ObjectTypeDB::bind_method(_MD("queue_delete","obj"),&SceneMainLoop::queue_delete); @@ -899,6 +1017,14 @@ void SceneMainLoop::_bind_methods() { BIND_CONSTANT( GROUP_CALL_REALTIME ); BIND_CONSTANT( GROUP_CALL_UNIQUE ); + BIND_CONSTANT( STRETCH_MODE_DISABLED ); + BIND_CONSTANT( STRETCH_MODE_2D ); + BIND_CONSTANT( STRETCH_MODE_VIEWPORT ); + BIND_CONSTANT( STRETCH_ASPECT_IGNORE ); + BIND_CONSTANT( STRETCH_ASPECT_KEEP ); + BIND_CONSTANT( STRETCH_ASPECT_KEEP_WIDTH ); + BIND_CONSTANT( STRETCH_ASPECT_KEEP_HEIGHT ); + } SceneMainLoop::SceneMainLoop() { @@ -927,6 +1053,9 @@ SceneMainLoop::SceneMainLoop() { root->set_as_audio_listener(true); root->set_as_audio_listener_2d(true); + stretch_mode=STRETCH_MODE_DISABLED; + stretch_aspect=STRETCH_ASPECT_IGNORE; + last_screen_size=Size2( OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height ); root->set_rect(Rect2(Point2(),last_screen_size)); @@ -934,7 +1063,6 @@ SceneMainLoop::SceneMainLoop() { ScriptDebugger::get_singleton()->set_request_scene_tree_message_func(_debugger_request_tree,this); } - } diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index 1c8e0c90aee..8b9ea0b585c 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -50,6 +50,25 @@ class SceneMainLoop : public MainLoop { _THREAD_SAFE_CLASS_ OBJ_TYPE( SceneMainLoop, MainLoop ); +public: + + + enum StretchMode { + + STRETCH_MODE_DISABLED, + STRETCH_MODE_2D, + STRETCH_MODE_VIEWPORT, + }; + + enum StretchAspect { + + STRETCH_ASPECT_IGNORE, + STRETCH_ASPECT_KEEP, + STRETCH_ASPECT_KEEP_WIDTH, + STRETCH_ASPECT_KEEP_HEIGHT, + }; +private: + struct Group { @@ -95,6 +114,12 @@ class SceneMainLoop : public MainLoop { Set call_skip; //skip erased nodes + StretchMode stretch_mode; + StretchAspect stretch_aspect; + Size2i stretch_min; + + void _update_root_rect(); + List delete_queue; Map > unique_group_calls; @@ -152,7 +177,6 @@ public: GROUP_CALL_MULIILEVEL=8, }; - _FORCE_INLINE_ Viewport *get_root() const { return root; } uint32_t get_last_event_id() const; @@ -196,10 +220,18 @@ public: void get_nodes_in_group(const StringName& p_group,List *p_list); + void set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize); + + SceneMainLoop(); ~SceneMainLoop(); }; +VARIANT_ENUM_CAST( SceneMainLoop::StretchMode ); +VARIANT_ENUM_CAST( SceneMainLoop::StretchAspect ); + + + #endif diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 56d0544abdb..0e32fd006dc 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -86,8 +86,9 @@ void Viewport::_update_stretch_transform() { if (size_override_stretch && size_override) { stretch_transform=Matrix32(); - stretch_transform.scale(rect.size/(size_override_size+size_override_margin*2)); - stretch_transform.elements[2]=size_override_margin; + Size2 scale = rect.size/(size_override_size+size_override_margin*2); + stretch_transform.scale(scale); + stretch_transform.elements[2]=size_override_margin*scale; } else { @@ -629,7 +630,9 @@ Ref Viewport::get_world() const{ Ref Viewport::find_world() const{ - if (world.is_valid()) + if (own_world.is_valid()) + return own_world; + else if (world.is_valid()) return world; else if (parent) return parent->find_world(); @@ -863,6 +866,60 @@ void Viewport::unhandled_input(const InputEvent& p_event) { } } +void Viewport::set_use_own_world(bool p_world) { + + if (p_world==own_world.is_valid()) + return; + + + if (is_inside_scene()) + _propagate_exit_world(this); + +#ifndef _3D_DISABLED + if (find_world().is_valid() && camera) + camera->notification(Camera::NOTIFICATION_LOST_CURRENT); +#endif + + if (!p_world) + own_world=Ref(); + else + own_world=Ref( memnew( World )); + + if (is_inside_scene()) + _propagate_enter_world(this); + +#ifndef _3D_DISABLED + if (find_world().is_valid() && camera) + camera->notification(Camera::NOTIFICATION_BECAME_CURRENT); +#endif + + //propagate exit + + if (is_inside_scene()) { + VisualServer::get_singleton()->viewport_set_scenario(viewport,find_world()->get_scenario()); + } + + _update_listener(); + + +} + +bool Viewport::is_using_own_world() const { + + return own_world.is_valid(); +} + +void Viewport::set_render_target_to_screen_rect(const Rect2& p_rect) { + + to_screen_rect=p_rect; + VisualServer::get_singleton()->viewport_set_render_target_to_screen_rect(viewport,to_screen_rect); +} + +Rect2 Viewport::get_render_target_to_screen_rect() const{ + + return to_screen_rect; +} + void Viewport::_bind_methods() { @@ -918,15 +975,20 @@ void Viewport::_bind_methods() { ObjectTypeDB::bind_method(_MD("update_worlds"), &Viewport::update_worlds); + ObjectTypeDB::bind_method(_MD("set_use_own_world","enable"), &Viewport::set_use_own_world); + ObjectTypeDB::bind_method(_MD("is_using_own_world"), &Viewport::is_using_own_world); + ObjectTypeDB::bind_method(_MD("set_as_audio_listener","enable"), &Viewport::set_as_audio_listener); ObjectTypeDB::bind_method(_MD("is_audio_listener","enable"), &Viewport::is_audio_listener); ObjectTypeDB::bind_method(_MD("set_as_audio_listener_2d","enable"), &Viewport::set_as_audio_listener_2d); ObjectTypeDB::bind_method(_MD("is_audio_listener_2d","enable"), &Viewport::is_audio_listener_2d); + ObjectTypeDB::bind_method(_MD("set_render_target_to_screen_rect"), &Viewport::set_render_target_to_screen_rect); ADD_PROPERTY( PropertyInfo(Variant::RECT2,"rect"), _SCS("set_rect"), _SCS("get_rect") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"own_world"), _SCS("set_use_own_world"), _SCS("is_using_own_world") ); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world",PROPERTY_HINT_RESOURCE_TYPE,"World"), _SCS("set_world"), _SCS("get_world") ); // ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world_2d",PROPERTY_HINT_RESOURCE_TYPE,"World2D"), _SCS("set_world_2d"), _SCS("get_world_2d") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transparent_bg"), _SCS("set_transparent_background"), _SCS("has_transparent_background") ); @@ -969,6 +1031,7 @@ Viewport::Viewport() { render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE; render_target_texture = Ref( memnew( RenderTargetTexture(this) ) ); + String id=itos(get_instance_ID()); input_group = "_vp_input"+id; gui_input_group = "_vp_gui_input"+id; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 8ba84651f8d..33e1f27b932 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -101,6 +101,7 @@ friend class RenderTargetTexture; Matrix32 stretch_transform; Rect2 rect; + Rect2 to_screen_rect; bool size_override; @@ -120,6 +121,7 @@ friend class RenderTargetTexture; Ref world_2d; Ref world; + Ref own_world; StringName input_group; StringName gui_input_group; @@ -213,9 +215,15 @@ public: void queue_screen_capture(); Image get_screen_capture() const; + void set_use_own_world(bool p_world); + bool is_using_own_world() const; + void input(const InputEvent& p_event); void unhandled_input(const InputEvent& p_event); + void set_render_target_to_screen_rect(const Rect2& p_rect); + Rect2 get_render_target_to_screen_rect() const; + Viewport(); ~Viewport(); diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index fd1ea579f0f..ee29d3aeff2 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -770,7 +770,7 @@ void Physics2DServerSW::body_remove_collision_exception(RID p_body, RID p_body_b Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); - body->remove_exception(p_body); + body->remove_exception(p_body_b); }; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 37a846ca72a..0b54fec8590 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -494,6 +494,7 @@ public: }; virtual void canvas_begin()=0; + virtual void canvas_disable_blending()=0; virtual void canvas_set_opacity(float p_opacity)=0; virtual void canvas_set_blend_mode(VS::MaterialBlendMode p_mode)=0; virtual void canvas_begin_rect(const Matrix32& p_transform)=0;; diff --git a/servers/visual/rasterizer_dummy.cpp b/servers/visual/rasterizer_dummy.cpp index 4fc8f1da8f7..bfb427f2e85 100644 --- a/servers/visual/rasterizer_dummy.cpp +++ b/servers/visual/rasterizer_dummy.cpp @@ -1384,7 +1384,7 @@ void RasterizerDummy::set_viewport(const VS::ViewportRect& p_viewport) { } -void RasterizerDummy::set_render_target(RID p_render_target,bool p_transparent_bg) { +void RasterizerDummy::set_render_target(RID p_render_target, bool p_transparent_bg, bool p_vflip) { } @@ -1455,6 +1455,12 @@ void RasterizerDummy::canvas_begin() { } +void RasterizerDummy::canvas_disable_blending() { + + + +} + void RasterizerDummy::canvas_set_opacity(float p_opacity) { diff --git a/servers/visual/rasterizer_dummy.h b/servers/visual/rasterizer_dummy.h index 07a78549f70..e1fa521284f 100644 --- a/servers/visual/rasterizer_dummy.h +++ b/servers/visual/rasterizer_dummy.h @@ -627,7 +627,7 @@ public: virtual void begin_frame(); virtual void set_viewport(const VS::ViewportRect& p_viewport); - virtual void set_render_target(RID p_render_target,bool p_transparent_bg=false); + virtual void set_render_target(RID p_render_target,bool p_transparent_bg=false,bool p_vflip=false); virtual void clear_viewport(const Color& p_color); virtual void capture_viewport(Image* r_capture); @@ -652,6 +652,7 @@ public: /* CANVAS API */ virtual void canvas_begin(); + virtual void canvas_disable_blending(); virtual void canvas_set_opacity(float p_opacity); virtual void canvas_set_blend_mode(VS::MaterialBlendMode p_mode); virtual void canvas_begin_rect(const Matrix32& p_transform); diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index a189fff2464..18fd4c99220 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -1145,6 +1145,15 @@ void VisualServerRaster::viewport_set_render_target_vflip(RID p_viewport,bool p_ } +void VisualServerRaster::viewport_set_render_target_to_screen_rect(RID p_viewport,const Rect2& p_rect) { + + Viewport *viewport = viewport_owner.get( p_viewport ); + ERR_FAIL_COND(!viewport); + + viewport->rt_to_screen_rect=p_rect; + +} + bool VisualServerRaster::viewport_get_render_target_vflip(RID p_viewport) const{ const Viewport *viewport = viewport_owner.get( p_viewport ); @@ -5458,6 +5467,8 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_ void VisualServerRaster::_draw_viewports() { //draw viewports for render targets + + List to_blit; List to_disable; for(SelfList *E=viewport_update_list.first();E;E=E->next()) { @@ -5472,6 +5483,9 @@ void VisualServerRaster::_draw_viewports() { continue; } + if (vp->rt_to_screen_rect!=Rect2()) + to_blit.push_back(vp); + rasterizer->set_render_target(vp->render_target,vp->transparent_bg,vp->render_target_vflip); _draw_viewport(vp,0,0,vp->rect.width,vp->rect.height); @@ -5491,6 +5505,38 @@ void VisualServerRaster::_draw_viewports() { to_disable.pop_front(); } + + //draw RTs directly to screen when requested + + for (List::Element *E=to_blit.front();E;E=E->next()) { + + int window_w = OS::get_singleton()->get_video_mode().width; + int window_h = OS::get_singleton()->get_video_mode().height; + + ViewportRect desired_rect; + desired_rect.x = desired_rect.y = 0; + desired_rect.width = window_w; + desired_rect.height = window_h; + + if ( viewport_rect.x != desired_rect.x || + viewport_rect.y != desired_rect.y || + viewport_rect.width != desired_rect.width || + viewport_rect.height != desired_rect.height ) { + + viewport_rect=desired_rect; + + rasterizer->set_viewport(viewport_rect); + } + + rasterizer->canvas_begin(); + rasterizer->canvas_disable_blending(); + rasterizer->canvas_begin_rect(Matrix32()); + rasterizer->canvas_draw_rect(E->get()->rt_to_screen_rect,0,Rect2(Point2(),E->get()->rt_to_screen_rect.size),E->get()->render_target_texture,Color(1,1,1)); + + } + + + //draw viewports attached to screen for(Map::Element *E=screen_viewports.front();E;E=E->next()) { diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index d8d72b63ea3..d3d504a7c65 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -481,6 +481,8 @@ class VisualServerRaster : public VisualServer { RID render_target; RID render_target_texture; + Rect2 rt_to_screen_rect; + bool hide_scenario; bool hide_canvas; bool transparent_bg; @@ -913,6 +915,7 @@ public: virtual RID viewport_get_render_target_texture(RID p_viewport) const; virtual void viewport_set_render_target_vflip(RID p_viewport,bool p_enable); virtual bool viewport_get_render_target_vflip(RID p_viewport) const; + virtual void viewport_set_render_target_to_screen_rect(RID p_viewport,const Rect2& p_rect); virtual void viewport_queue_screen_capture(RID p_viewport); virtual Image viewport_get_screen_capture(RID p_viewport) const; diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 4e1094a3a26..c8f00c37866 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -891,6 +891,7 @@ public: FUNC2(viewport_set_render_target_vflip,RID,bool); FUNC1RC(bool,viewport_get_render_target_vflip,RID); + FUNC2(viewport_set_render_target_to_screen_rect,RID,const Rect2&); FUNC1(viewport_queue_screen_capture,RID); FUNC1RC(Image,viewport_get_screen_capture,RID); diff --git a/servers/visual_server.h b/servers/visual_server.h index d2c2046e54a..4cf0c962288 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -592,6 +592,7 @@ public: virtual void viewport_attach_to_screen(RID p_viewport,int p_screen=0)=0; virtual void viewport_detach(RID p_viewport)=0; + virtual void viewport_set_render_target_to_screen_rect(RID p_viewport,const Rect2& p_rect)=0; enum RenderTargetUpdateMode { RENDER_TARGET_UPDATE_DISABLED, @@ -611,6 +612,8 @@ public: virtual void viewport_queue_screen_capture(RID p_viewport)=0; virtual Image viewport_get_screen_capture(RID p_viewport) const=0; + + struct ViewportRect { int x,y,width,height; diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 9429c161827..e799c103d07 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -3927,7 +3927,7 @@ EditorNode::EditorNode() { file_templates->set_mode(FileDialog::MODE_OPEN_FILE); file_templates->set_access(FileDialog::ACCESS_FILESYSTEM); file_templates->clear_filters(); - file_templates->add_filter("*.zip ; Zip Template Package"); + file_templates->add_filter("*.tpz ; Template Package"); file = memnew( FileDialog );