summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Choi <code.kchoi@gmail.com>2015-05-31 01:37:56 -0400
committerKevin Choi <code.kchoi@gmail.com>2015-05-31 01:37:56 -0400
commit6813a1f1e1104c62f9cd4f3848ca0030855911ba (patch)
tree2ce9353b114574d40465129b7e3afd4117bbb008
parentec93668f8d652f826b6e89861746bf655ec29234 (diff)
parentd5348eebdc7228f7836582cd9bd4ed4f5fd59348 (diff)
Merge pull request #2 from okamstudio/master
pull
-rw-r--r--core/globals.cpp3
-rw-r--r--core/image.cpp10
-rw-r--r--core/image.h5
-rw-r--r--core/io/file_access_memory.cpp8
-rw-r--r--core/io/file_access_memory.h1
-rw-r--r--core/io/file_access_zip.cpp21
-rw-r--r--core/object.cpp2
-rw-r--r--core/variant.cpp8
-rw-r--r--demos/2d/motion/engine.cfg7
-rw-r--r--drivers/png/image_loader_png.cpp22
-rw-r--r--drivers/png/image_loader_png.h3
-rw-r--r--main/main.cpp2
-rw-r--r--platform/android/os_android.cpp3
-rw-r--r--platform/android/os_android.h1
-rw-r--r--platform/iphone/game_center.h6
-rw-r--r--platform/iphone/game_center.mm228
-rw-r--r--platform/iphone/in_app_store.mm2
-rw-r--r--platform/iphone/os_iphone.cpp3
-rw-r--r--platform/iphone/os_iphone.h1
-rw-r--r--platform/iphone/view_controller.h3
-rw-r--r--platform/iphone/view_controller.mm7
-rw-r--r--platform/osx/os_osx.h1
-rw-r--r--platform/osx/os_osx.mm3
-rw-r--r--platform/windows/os_windows.cpp7
-rw-r--r--platform/windows/os_windows.h1
-rw-r--r--platform/x11/os_x11.cpp4
-rw-r--r--platform/x11/os_x11.h1
-rw-r--r--scene/io/resource_format_wav.cpp4
-rw-r--r--scene/resources/default_theme/default_theme.cpp1
-rw-r--r--servers/audio/sample_manager_sw.cpp2
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp18
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h9
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.cpp169
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h297
-rw-r--r--servers/physics_2d_server.cpp2
-rw-r--r--servers/physics_2d_server.h5
-rw-r--r--servers/server_wrap_mt_common.h700
-rw-r--r--servers/visual/visual_server_wrap_mt.cpp4
-rw-r--r--servers/visual/visual_server_wrap_mt.h560
-rw-r--r--tools/editor/animation_editor.cpp10
-rw-r--r--tools/editor/editor_file_dialog.cpp874
-rw-r--r--tools/editor/editor_file_dialog.h198
-rw-r--r--tools/editor/editor_node.cpp153
-rw-r--r--tools/editor/editor_node.h12
-rw-r--r--tools/editor/editor_resource_preview.cpp260
-rw-r--r--tools/editor/editor_resource_preview.h95
-rw-r--r--tools/editor/editor_settings.cpp2
-rw-r--r--tools/editor/icons/icon_wait_no_preview.pngbin0 -> 1041 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_1.pngbin0 -> 1208 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_2.pngbin0 -> 1270 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_3.pngbin0 -> 1190 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_4.pngbin0 -> 1269 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_5.pngbin0 -> 1191 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_6.pngbin0 -> 1278 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_7.pngbin0 -> 1192 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_8.pngbin0 -> 1341 bytes
-rw-r--r--tools/editor/plugins/editor_preview_plugins.cpp664
-rw-r--r--tools/editor/plugins/editor_preview_plugins.h69
-rw-r--r--tools/editor/plugins/sample_editor_plugin.cpp119
-rw-r--r--tools/editor/plugins/spatial_editor_plugin.h8
-rw-r--r--tools/editor/resources_dock.cpp4
-rw-r--r--tools/editor/resources_dock.h3
-rw-r--r--tools/pck/pck_packer.h6
63 files changed, 3982 insertions, 629 deletions
diff --git a/core/globals.cpp b/core/globals.cpp
index 23d8c16ace..0315ff0c24 100644
--- a/core/globals.cpp
+++ b/core/globals.cpp
@@ -339,7 +339,7 @@ Error Globals::setup(const String& p_path,const String & p_main_pack) {
//try to load settings in ascending through dirs shape!
//tries to open pack, but only first time
- if (first_time && _load_resource_pack(current_dir+"/data.pck")) {
+ if (first_time && (_load_resource_pack(current_dir+"/data.pck") || _load_resource_pack(current_dir+"/data.pcz") )) {
if (_load_settings("res://engine.cfg")==OK || _load_settings_binary("res://engine.cfb")==OK) {
_load_settings("res://override.cfg");
@@ -1460,6 +1460,7 @@ Globals::Globals() {
custom_prop_info["display/orientation"]=PropertyInfo(Variant::STRING,"display/orientation",PROPERTY_HINT_ENUM,"landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");
custom_prop_info["render/mipmap_policy"]=PropertyInfo(Variant::INT,"render/mipmap_policy",PROPERTY_HINT_ENUM,"Allow,Allow For Po2,Disallow");
custom_prop_info["render/thread_model"]=PropertyInfo(Variant::INT,"render/thread_model",PROPERTY_HINT_ENUM,"Single-Unsafe,Single-Safe,Multi-Threaded");
+ custom_prop_info["physics_2d/thread_model"]=PropertyInfo(Variant::INT,"physics_2d/thread_model",PROPERTY_HINT_ENUM,"Single-Unsafe,Single-Safe,Multi-Threaded");
set("display/emulate_touchscreen",false);
using_datapack=false;
diff --git a/core/image.cpp b/core/image.cpp
index 04b3905489..b516790494 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -1746,6 +1746,10 @@ Error Image::_decompress_bc() {
return OK;
}
+bool Image::is_compressed() const {
+ return format>=FORMAT_BC1;
+}
+
Image Image::decompressed() const {
@@ -1998,7 +2002,7 @@ void Image::blit_rect(const Image& p_src, const Rect2& p_src_rect,const Point2&
}
-Image (*Image::_png_mem_loader_func)(const uint8_t*)=NULL;
+Image (*Image::_png_mem_loader_func)(const uint8_t*,int)=NULL;
void (*Image::_image_compress_bc_func)(Image *)=NULL;
void (*Image::_image_compress_pvrtc2_func)(Image *)=NULL;
void (*Image::_image_compress_pvrtc4_func)(Image *)=NULL;
@@ -2167,7 +2171,7 @@ void Image::fix_alpha_edges() {
}
-Image::Image(const uint8_t* p_png) {
+Image::Image(const uint8_t* p_png,int p_len) {
width=0;
height=0;
@@ -2175,7 +2179,7 @@ Image::Image(const uint8_t* p_png) {
format=FORMAT_GRAYSCALE;
if (_png_mem_loader_func) {
- *this = _png_mem_loader_func(p_png);
+ *this = _png_mem_loader_func(p_png,p_len);
}
}
diff --git a/core/image.h b/core/image.h
index ddb5e88ebf..a9eb8fd769 100644
--- a/core/image.h
+++ b/core/image.h
@@ -94,7 +94,7 @@ public:
/* INTERPOLATE GAUSS */
};
- static Image (*_png_mem_loader_func)(const uint8_t* p_png);
+ static Image (*_png_mem_loader_func)(const uint8_t* p_png,int p_size);
static void (*_image_compress_bc_func)(Image *);
static void (*_image_compress_pvrtc2_func)(Image *);
static void (*_image_compress_pvrtc4_func)(Image *);
@@ -335,6 +335,7 @@ public:
Image compressed(int p_mode); /* from the Image::CompressMode enum */
Error decompress();
Image decompressed() const;
+ bool is_compressed() const;
void fix_alpha_edges();
void premultiply_alpha();
@@ -349,7 +350,7 @@ public:
Image get_rect(const Rect2& p_area) const;
static void set_compress_bc_func(void (*p_compress_func)(Image *));
- Image(const uint8_t* p_mem_png);
+ Image(const uint8_t* p_mem_png, int p_len=-1);
Image(const char **p_xpm);
~Image();
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 2880c4ebda..83da55fc61 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -74,6 +74,14 @@ bool FileAccessMemory::file_exists(const String& p_name) {
}
+Error FileAccessMemory::open_custom(const uint8_t* p_data, int p_len) {
+
+ data=(uint8_t*)p_data;
+ length=p_len;
+ pos=0;
+ return OK;
+}
+
Error FileAccessMemory::_open(const String& p_path, int p_mode_flags) {
ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND);
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 5a9ec2b3c6..8c58a8a8ce 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -44,6 +44,7 @@ public:
static void register_file(String p_name, Vector<uint8_t> p_data);
static void cleanup();
+ virtual Error open_custom(const uint8_t* p_data, int p_len); ///< open a file
virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 7a1b6454bd..ab2eb3b3f2 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -31,6 +31,7 @@
#include "file_access_zip.h"
#include "core/os/file_access.h"
+#include "core/os/copymem.h"
ZipArchive* ZipArchive::instance = NULL;
@@ -103,9 +104,17 @@ static int godot_testerror(voidpf opaque, voidpf stream) {
return f->get_error()!=OK?1:0;
};
+static voidpf godot_alloc(voidpf opaque, uInt items, uInt size) {
+ return memalloc(items * size);
};
+static void godot_free(voidpf opaque, voidpf address) {
+
+ memfree(address);
+};
+
+}; // extern "C"
void ZipArchive::close_handle(unzFile p_file) const {
@@ -125,6 +134,7 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
ERR_FAIL_COND_V(!f, NULL);
zlib_filefunc_def io;
+ zeromem(&io, sizeof(io));
io.opaque = f;
io.zopen_file = godot_open;
@@ -136,9 +146,13 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
io.zclose_file = godot_close;
io.zerror_file = godot_testerror;
+ io.alloc_mem = godot_alloc;
+ io.free_mem = godot_free;
+
unzFile pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io);
ERR_FAIL_COND_V(!pkg, NULL);
- unzGoToFilePos(pkg, &file.file_pos);
+ int unz_err = unzGoToFilePos(pkg, &file.file_pos);
+ ERR_FAIL_COND_V(unz_err != UNZ_OK, NULL);
if (unzOpenCurrentFile(pkg) != UNZ_OK) {
unzClose(pkg);
@@ -150,7 +164,7 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
bool ZipArchive::try_open_pack(const String& p_name) {
- //printf("opening pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
+ //printf("opening zip pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
if (p_name.extension().nocasecmp_to("zip") != 0 && p_name.extension().nocasecmp_to("pcz") != 0)
return false;
@@ -198,7 +212,8 @@ bool ZipArchive::try_open_pack(const String& p_name) {
files[fname] = f;
uint8_t md5[16]={0,0,0,0,0,0,0,0 , 0,0,0,0,0,0,0,0};
- PackedData::get_singleton()->add_path(p_name, fname, 0, 0, md5, this);
+ PackedData::get_singleton()->add_path(p_name, fname, 1, 0, md5, this);
+ //printf("packed data add path %ls, %ls\n", p_name.c_str(), fname.c_str());
if ((i+1)<gi.number_entry) {
unzGoToNextFile(zfile);
diff --git a/core/object.cpp b/core/object.cpp
index 84786df8d4..83a6dada80 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -1351,7 +1351,7 @@ Error Object::connect(const StringName& p_signal, Object *p_to_object, const Str
if (!s) {
bool signal_is_valid = ObjectTypeDB::has_signal(get_type_name(),p_signal);
if (!signal_is_valid) {
- ERR_EXPLAIN("Attempt to connect to nonexistent signal: "+p_signal);
+ ERR_EXPLAIN("Attempt to connect nonexistent signal '"+p_signal+"' to method '"+p_to_method+"'");
ERR_FAIL_COND_V(!signal_is_valid,ERR_INVALID_PARAMETER);
}
signal_map[p_signal]=Signal();
diff --git a/core/variant.cpp b/core/variant.cpp
index d7817ac268..034dc2b4fc 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -302,8 +302,8 @@ bool Variant::can_convert(Variant::Type p_type_from,Variant::Type p_type_to) {
case COLOR: {
static const Type valid[] = {
- //STRING,
- //INT,
+ STRING,
+ INT,
NIL,
};
@@ -1653,6 +1653,10 @@ Variant::operator Color() const {
if (type==COLOR)
return *reinterpret_cast<const Color*>(_data._mem);
+ else if (type==STRING)
+ return Color::html( operator String() );
+ else if (type==INT)
+ return Color::hex( operator int() );
else
return Color();
}
diff --git a/demos/2d/motion/engine.cfg b/demos/2d/motion/engine.cfg
index 064de6b331..261111904c 100644
--- a/demos/2d/motion/engine.cfg
+++ b/demos/2d/motion/engine.cfg
@@ -2,3 +2,10 @@
name="Motion Test"
main_scene="res://motion.scn"
+
+[display]
+
+width=800
+height=600
+stretch_mode="2d"
+stretch_aspect="keep"
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 2e1488ff9d..2a4720b07b 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -31,6 +31,8 @@
#include "print_string.h"
#include "os/os.h"
+
+
void ImageLoaderPNG::_read_png_data(png_structp png_ptr,png_bytep data, png_size_t p_length) {
FileAccess *f = (FileAccess*)png_get_io_ptr(png_ptr);
@@ -253,6 +255,7 @@ void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const
struct PNGReadStatus {
int offset;
+ int size;
const unsigned char *image;
};
@@ -261,17 +264,26 @@ static void user_read_data(png_structp png_ptr,png_bytep data, png_size_t p_leng
PNGReadStatus *rstatus;
rstatus=(PNGReadStatus*)png_get_io_ptr(png_ptr);
- memcpy(data,&rstatus->image[rstatus->offset],p_length);
- rstatus->offset+=p_length;
+ int to_read=p_length;
+ if (rstatus->size>=0) {
+ to_read = MIN( p_length, rstatus->size - rstatus->offset);
+ }
+ memcpy(data,&rstatus->image[rstatus->offset],to_read);
+ rstatus->offset+=to_read;
+
+ if (to_read<p_length) {
+ memset(&data[to_read],0,p_length-to_read);
+ }
}
-static Image _load_mem_png(const uint8_t* p_png) {
+static Image _load_mem_png(const uint8_t* p_png,int p_size) {
PNGReadStatus prs;
prs.image=p_png;
prs.offset=0;
+ prs.size=p_size;
Image img;
Error err = ImageLoaderPNG::_load_image(&prs,user_read_data,&img);
@@ -283,9 +295,10 @@ static Image _load_mem_png(const uint8_t* p_png) {
static Image _lossless_unpack_png(const DVector<uint8_t>& p_data) {
+ int len = p_data.size();
DVector<uint8_t>::Read r = p_data.read();
ERR_FAIL_COND_V(r[0]!='P' || r[1]!='N' || r[2]!='G' || r[3]!=' ',Image());
- return _load_mem_png(&r[4]);
+ return _load_mem_png(&r[4],len-4);
}
@@ -424,6 +437,7 @@ static DVector<uint8_t> _lossless_pack_png(const Image& p_image) {
ImageLoaderPNG::ImageLoaderPNG() {
+
Image::_png_mem_loader_func=_load_mem_png;
Image::lossless_unpacker=_lossless_unpack_png;
Image::lossless_packer=_lossless_pack_png;
diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h
index 7acfd041ee..8413a7eae1 100644
--- a/drivers/png/image_loader_png.h
+++ b/drivers/png/image_loader_png.h
@@ -40,7 +40,10 @@ class ImageLoaderPNG : public ImageFormatLoader {
static void _read_png_data(png_structp png_ptr,png_bytep data, png_size_t p_length);
+
public:
+
+
static Error _load_image(void *rf_up,png_rw_ptr p_func,Image *p_image);
virtual Error load_image(Image *p_image,FileAccess *f);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
diff --git a/main/main.cpp b/main/main.cpp
index f826b36212..531d7cfbdc 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1356,6 +1356,8 @@ bool Main::iteration() {
message_queue->flush();
PhysicsServer::get_singleton()->step(frame_slice*time_scale);
+
+ Physics2DServer::get_singleton()->end_sync();
Physics2DServer::get_singleton()->step(frame_slice*time_scale);
time_accum-=frame_slice;
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 80953df85f..612148418b 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -163,7 +163,8 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_
//
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ //physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
input = memnew( InputDefault );
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 41892d23b4..7a5a55653f 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -37,6 +37,7 @@
#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
#include "servers/audio/audio_server_sw.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include "servers/visual/rasterizer.h"
diff --git a/platform/iphone/game_center.h b/platform/iphone/game_center.h
index 1f4820a3c2..8f180d1638 100644
--- a/platform/iphone/game_center.h
+++ b/platform/iphone/game_center.h
@@ -51,6 +51,12 @@ public:
Error post_score(Variant p_score);
Error award_achievement(Variant p_params);
+ void reset_achievements();
+ void request_achievements();
+ void request_achievement_descriptions();
+ Error show_game_center(Variant p_params);
+
+ void game_center_closed();
int get_pending_event_count();
Variant pop_pending_event();
diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm
index fd1e5f3be7..79c056776d 100644
--- a/platform/iphone/game_center.mm
+++ b/platform/iphone/game_center.mm
@@ -32,6 +32,7 @@
extern "C" {
#import <GameKit/GameKit.h>
+#import "app_delegate.h"
};
GameCenter* GameCenter::instance = NULL;
@@ -42,6 +43,10 @@ void GameCenter::_bind_methods() {
ObjectTypeDB::bind_method(_MD("post_score"),&GameCenter::post_score);
ObjectTypeDB::bind_method(_MD("award_achievement"),&GameCenter::award_achievement);
+ ObjectTypeDB::bind_method(_MD("reset_achievements"),&GameCenter::reset_achievements);
+ ObjectTypeDB::bind_method(_MD("request_achievements"),&GameCenter::request_achievements);
+ ObjectTypeDB::bind_method(_MD("request_achievement_descriptions"),&GameCenter::request_achievement_descriptions);
+ ObjectTypeDB::bind_method(_MD("show_game_center"),&GameCenter::show_game_center);
ObjectTypeDB::bind_method(_MD("get_pending_event_count"),&GameCenter::get_pending_event_count);
ObjectTypeDB::bind_method(_MD("pop_pending_event"),&GameCenter::pop_pending_event);
@@ -50,23 +55,41 @@ void GameCenter::_bind_methods() {
Error GameCenter::connect() {
- GKLocalPlayer* player = [GKLocalPlayer localPlayer];
- [player authenticateWithCompletionHandler:^(NSError* error) {
+ //if this class isn't available, game center isn't implemented
+ if ((NSClassFromString(@"GKLocalPlayer")) == nil) {
+ GameCenter::get_singleton()->connected = false;
+ return ERR_UNAVAILABLE;
+ }
- Dictionary ret;
- ret["type"] = "authentication";
- if (player.isAuthenticated) {
- ret["result"] = "ok";
- GameCenter::get_singleton()->connected = true;
- } else {
- ret["result"] = "error";
- ret["error_code"] = error.code;
- ret["error_description"] = [error.localizedDescription UTF8String];
- GameCenter::get_singleton()->connected = false;
- };
+ GKLocalPlayer* player = [GKLocalPlayer localPlayer];
+ ERR_FAIL_COND_V(![player respondsToSelector:@selector(authenticateHandler)], ERR_UNAVAILABLE);
+
+ ViewController *root_controller=(ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController;
+ ERR_FAIL_COND_V(!root_controller, FAILED);
+
+ //this handler is called serveral times. first when the view needs to be shown, then again after the view is cancelled or the user logs in. or if the user's already logged in, it's called just once to confirm they're authenticated. This is why no result needs to be specified in the presentViewController phase. in this case, more calls to this function will follow.
+ player.authenticateHandler = (^(UIViewController *controller, NSError *error) {
+ if (controller) {
+ [root_controller presentViewController:controller animated:YES completion:nil];
+ }
+ else {
+ Dictionary ret;
+ ret["type"] = "authentication";
+ if (player.isAuthenticated) {
+ ret["result"] = "ok";
+ GameCenter::get_singleton()->connected = true;
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ ret["error_description"] = [error.localizedDescription UTF8String];
+ GameCenter::get_singleton()->connected = false;
+ };
+
+ pending_events.push_back(ret);
+ };
+
+ });
- pending_events.push_back(ret);
- }];
return OK;
};
@@ -85,7 +108,9 @@ Error GameCenter::post_score(Variant p_score) {
GKScore* reporter = [[[GKScore alloc] initWithCategory:cat_str] autorelease];
reporter.value = score;
- [reporter reportScoreWithCompletionHandler:^(NSError* error) {
+ ERR_FAIL_COND_V([GKScore respondsToSelector:@selector(reportScores)], ERR_UNAVAILABLE);
+
+ [GKScore reportScores:@[reporter] withCompletionHandler:^(NSError* error) {
Dictionary ret;
ret["type"] = "post_score";
@@ -114,8 +139,15 @@ Error GameCenter::award_achievement(Variant p_params) {
GKAchievement* achievement = [[[GKAchievement alloc] initWithIdentifier: name_str] autorelease];
ERR_FAIL_COND_V(!achievement, FAILED);
+ ERR_FAIL_COND_V([GKAchievement respondsToSelector:@selector(reportAchievements)], ERR_UNAVAILABLE);
+
achievement.percentComplete = progress;
- [achievement reportAchievementWithCompletionHandler:^(NSError* error) {
+ achievement.showsCompletionBanner = NO;
+ if (params.has("show_completion_banner")) {
+ achievement.showsCompletionBanner = params["show_completion_banner"] ? YES : NO;
+ }
+
+ [GKAchievement reportAchievements:@[achievement] withCompletionHandler:^(NSError *error) {
Dictionary ret;
ret["type"] = "award_achievement";
@@ -132,6 +164,168 @@ Error GameCenter::award_achievement(Variant p_params) {
return OK;
};
+void GameCenter::request_achievement_descriptions() {
+
+ [GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:^(NSArray *descriptions, NSError *error) {
+
+ Dictionary ret;
+ ret["type"] = "achievement_descriptions";
+ if (error == nil) {
+ ret["result"] = "ok";
+ StringArray names;
+ StringArray titles;
+ StringArray unachieved_descriptions;
+ StringArray achieved_descriptions;
+ IntArray maximum_points;
+ Array hidden;
+ Array replayable;
+
+ for (int i=0; i<[descriptions count]; i++) {
+
+ GKAchievementDescription* description = [descriptions objectAtIndex:i];
+
+ const char* str = [description.identifier UTF8String];
+ names.push_back(String::utf8(str != NULL ? str : ""));
+
+ str = [description.title UTF8String];
+ titles.push_back(String::utf8(str != NULL ? str : ""));
+
+ str = [description.unachievedDescription UTF8String];
+ unachieved_descriptions.push_back(String::utf8(str != NULL ? str : ""));
+
+ str = [description.achievedDescription UTF8String];
+ achieved_descriptions.push_back(String::utf8(str != NULL ? str : ""));
+
+ maximum_points.push_back(description.maximumPoints);
+
+ hidden.push_back(description.hidden == YES);
+
+ replayable.push_back(description.replayable == YES);
+ }
+
+ ret["names"] = names;
+ ret["titles"] = titles;
+ ret["unachieved_descriptions"] = unachieved_descriptions;
+ ret["achieved_descriptions"] = achieved_descriptions;
+ ret["maximum_points"] = maximum_points;
+ ret["hidden"] = hidden;
+ ret["replayable"] = replayable;
+
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ };
+
+ pending_events.push_back(ret);
+ }];
+};
+
+
+void GameCenter::request_achievements() {
+
+ [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
+
+ Dictionary ret;
+ ret["type"] = "achievements";
+ if (error == nil) {
+ ret["result"] = "ok";
+ StringArray names;
+ RealArray percentages;
+
+ for (int i=0; i<[achievements count]; i++) {
+
+ GKAchievement* achievement = [achievements objectAtIndex:i];
+ const char* str = [achievement.identifier UTF8String];
+ names.push_back(String::utf8(str != NULL ? str : ""));
+
+ percentages.push_back(achievement.percentComplete);
+ }
+
+ ret["names"] = names;
+ ret["progress"] = percentages;
+
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ };
+
+ pending_events.push_back(ret);
+ }];
+};
+
+void GameCenter::reset_achievements() {
+
+ [GKAchievement resetAchievementsWithCompletionHandler:^(NSError *error)
+ {
+ Dictionary ret;
+ ret["type"] = "reset_achievements";
+ if (error == nil) {
+ ret["result"] = "ok";
+ } else {
+ ret["result"] = "error";
+ ret["error_code"] = error.code;
+ };
+
+ pending_events.push_back(ret);
+ }];
+};
+
+Error GameCenter::show_game_center(Variant p_params) {
+
+ ERR_FAIL_COND_V(!NSProtocolFromString(@"GKGameCenterControllerDelegate"), FAILED);
+
+ Dictionary params = p_params;
+
+ GKGameCenterViewControllerState view_state = GKGameCenterViewControllerStateDefault;
+ if (params.has("view")) {
+ String view_name = params["view"];
+ if (view_name == "default") {
+ view_state = GKGameCenterViewControllerStateDefault;
+ }
+ else if (view_name == "leaderboards") {
+ view_state = GKGameCenterViewControllerStateLeaderboards;
+ }
+ else if (view_name == "achievements") {
+ view_state = GKGameCenterViewControllerStateAchievements;
+ }
+ else if (view_name == "challenges") {
+ view_state = GKGameCenterViewControllerStateChallenges;
+ }
+ else {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ GKGameCenterViewController *controller = [[GKGameCenterViewController alloc] init];
+ ERR_FAIL_COND_V(!controller, FAILED);
+
+ ViewController *root_controller=(ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController;
+ ERR_FAIL_COND_V(!root_controller, FAILED);
+
+ controller.gameCenterDelegate = root_controller;
+ controller.viewState = view_state;
+ if (view_state == GKGameCenterViewControllerStateLeaderboards) {
+ controller.leaderboardIdentifier = nil;
+ if (params.has("leaderboard_name")) {
+ String name = params["leaderboard_name"];
+ NSString* name_str = [[[NSString alloc] initWithUTF8String:name.utf8().get_data()] autorelease];
+ controller.leaderboardIdentifier = name_str;
+ }
+ }
+
+ [root_controller presentViewController: controller animated: YES completion:nil];
+
+ return OK;
+};
+
+void GameCenter::game_center_closed() {
+
+ Dictionary ret;
+ ret["type"] = "show_game_center";
+ ret["result"] = "ok";
+ pending_events.push_back(ret);
+}
+
int GameCenter::get_pending_event_count() {
return pending_events.size();
diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm
index 1d40b1762e..e3ba6bbd73 100644
--- a/platform/iphone/in_app_store.mm
+++ b/platform/iphone/in_app_store.mm
@@ -210,7 +210,7 @@ Error InAppStore::request_product_info(Variant p_params) {
receipt_to_send = [receipt description];
}
Dictionary receipt_ret;
- receipt_ret["receipt"] = String::utf8([receipt_to_send UTF8String]);
+ receipt_ret["receipt"] = String::utf8(receipt_to_send != nil ? [receipt_to_send UTF8String] : "");
receipt_ret["sdk"] = sdk_version;
ret["receipt"] = receipt_ret;
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index bf85ecc9dd..ade1c292a4 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -136,7 +136,8 @@ void OSIPhone::initialize(const VideoMode& p_desired,int p_video_driver,int p_au
//
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ //physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
input = memnew( InputDefault );
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 721db36f41..844f067552 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -38,6 +38,7 @@
#include "servers/visual/rasterizer.h"
#include "servers/physics/physics_server_sw.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include "servers/audio/audio_server_sw.h"
#include "servers/audio/sample_manager_sw.h"
#include "servers/spatial_sound/spatial_sound_server_sw.h"
diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h
index 9432aebd97..0cee2f6fbf 100644
--- a/platform/iphone/view_controller.h
+++ b/platform/iphone/view_controller.h
@@ -27,8 +27,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#import <UIKit/UIKit.h>
+#import <GameKit/GameKit.h>
-@interface ViewController : UIViewController {
+@interface ViewController : UIViewController <GKGameCenterControllerDelegate> {
};
diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm
index a5ca689e61..bc9950979e 100644
--- a/platform/iphone/view_controller.mm
+++ b/platform/iphone/view_controller.mm
@@ -124,10 +124,15 @@ int add_cmdline(int p_argc, char** p_args) {
}
};
-
- (BOOL)prefersStatusBarHidden
{
return YES;
}
+- (void) gameCenterViewControllerDidFinish:(GKGameCenterViewController*) gameCenterViewController {
+ //[gameCenterViewController dismissViewControllerAnimated:YES completion:^{GameCenter::get_singleton()->game_center_closed();}];//version for signaling when overlay is completely gone
+ GameCenter::get_singleton()->game_center_closed();
+ [gameCenterViewController dismissViewControllerAnimated:YES completion:nil];
+}
+
@end
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 1e9a7e89e8..144037b1cb 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -44,6 +44,7 @@
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include "platform/osx/audio_driver_osx.h"
#include <ApplicationServices/ApplicationServices.h>
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index eb2a12cdef..e2ff8d1116 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -1015,7 +1015,8 @@ void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
//
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ //physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
input = memnew( InputDefault );
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 1350719778..4e8f9fcd9b 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -1177,7 +1177,7 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
if (!is_no_window_mode_enabled()) {
@@ -1375,6 +1375,9 @@ void OS_Windows::finalize() {
physics_2d_server->finish();
memdelete(physics_2d_server);
+ joystick_change_queue.clear();
+ monitor_info.clear();
+
}
void OS_Windows::finalize_core() {
@@ -2052,7 +2055,7 @@ String OS_Windows::get_executable_path() const {
wchar_t bufname[4096];
GetModuleFileNameW(NULL,bufname,4096);
String s= bufname;
- print_line("EXEC PATHP¨®: "+s);
+ print_line("EXEC PATHP??: "+s);
return s;
}
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 2e3700da6a..64fbbf23c0 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -45,6 +45,7 @@
#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
#include "drivers/unix/ip_unix.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include <windows.h>
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 28427fa2f0..f8c570a5c0 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -35,6 +35,7 @@
#include "print_string.h"
#include "servers/physics/physics_server_sw.h"
+
#include "X11/Xutil.h"
#include "X11/Xatom.h"
@@ -426,7 +427,8 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
//
physics_server = memnew( PhysicsServerSW );
physics_server->init();
- physics_2d_server = memnew( Physics2DServerSW );
+ //physics_2d_server = memnew( Physics2DServerSW );
+ physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
input = memnew( InputDefault );
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 0036485f3f..261a54dd25 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -45,6 +45,7 @@
#include "drivers/alsa/audio_driver_alsa.h"
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include <X11/keysym.h>
#include <X11/Xlib.h>
diff --git a/scene/io/resource_format_wav.cpp b/scene/io/resource_format_wav.cpp
index b246eb66f5..7c90a4b3cd 100644
--- a/scene/io/resource_format_wav.cpp
+++ b/scene/io/resource_format_wav.cpp
@@ -150,10 +150,10 @@ RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_
frames/=format_channels;
frames/=(format_bits>>3);
- print_line("chunksize: "+itos(chunksize));
+ /*print_line("chunksize: "+itos(chunksize));
print_line("channels: "+itos(format_channels));
print_line("bits: "+itos(format_bits));
-
+*/
sample->create(
(format_bits==8) ? Sample::FORMAT_PCM8 : Sample::FORMAT_PCM16,
(format_channels==2)?true:false,
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 2fddafc07b..d43ffd2130 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -692,7 +692,6 @@ void make_default_theme() {
// FileDialog
t->set_icon("folder","FileDialog",make_icon(icon_folder_png));
-
t->set_color("files_disabled","FileDialog",Color(0,0,0,0.7));
diff --git a/servers/audio/sample_manager_sw.cpp b/servers/audio/sample_manager_sw.cpp
index 49ca5369ae..9195136a5d 100644
--- a/servers/audio/sample_manager_sw.cpp
+++ b/servers/audio/sample_manager_sw.cpp
@@ -135,7 +135,7 @@ void SampleManagerMallocSW::sample_set_data(RID p_sample, const DVector<uint8_t>
ERR_EXPLAIN("Sample buffer size does not match sample size.");
- print_line("len bytes: "+itos(s->length_bytes)+" bufsize: "+itos(buff_size));
+ //print_line("len bytes: "+itos(s->length_bytes)+" bufsize: "+itos(buff_size));
ERR_FAIL_COND(s->length_bytes!=buff_size);
DVector<uint8_t>::Read buffer_r=p_buffer.read();
const uint8_t *src = buffer_r.ptr();
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
index 08d871be69..b446f4928a 100644
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ b/servers/physics_2d/physics_2d_server_sw.cpp
@@ -30,7 +30,7 @@
#include "broad_phase_2d_basic.h"
#include "broad_phase_2d_hash_grid.h"
#include "collision_solver_2d_sw.h"
-
+#include "globals.h"
RID Physics2DServerSW::shape_create(ShapeType p_shape) {
Shape2DSW *shape=NULL;
@@ -261,7 +261,7 @@ Physics2DDirectSpaceState* Physics2DServerSW::space_get_direct_state(RID p_space
Space2DSW *space = space_owner.get(p_space);
ERR_FAIL_COND_V(!space,NULL);
- if (/*doing_sync ||*/ space->is_locked()) {
+ if ((using_threads && !doing_sync) || space->is_locked()) {
ERR_EXPLAIN("Space state is inaccesible right now, wait for iteration or fixed process notification.");
ERR_FAIL_V(NULL);
@@ -733,7 +733,7 @@ void Physics2DServerSW::body_set_layer_mask(RID p_body, uint32_t p_flags) {
};
-uint32_t Physics2DServerSW::body_get_layer_mask(RID p_body, uint32_t p_flags) const {
+uint32_t Physics2DServerSW::body_get_layer_mask(RID p_body) const {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND_V(!body,0);
@@ -750,7 +750,7 @@ void Physics2DServerSW::body_set_collision_mask(RID p_body, uint32_t p_flags) {
};
-uint32_t Physics2DServerSW::body_get_collision_mask(RID p_body, uint32_t p_flags) const {
+uint32_t Physics2DServerSW::body_get_collision_mask(RID p_body) const {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND_V(!body,0);
@@ -1196,7 +1196,7 @@ void Physics2DServerSW::set_active(bool p_active) {
void Physics2DServerSW::init() {
- doing_sync=true;
+ doing_sync=false;
last_step=0.001;
iterations=8;// 8?
stepper = memnew( Step2DSW );
@@ -1228,6 +1228,7 @@ void Physics2DServerSW::step(float p_step) {
void Physics2DServerSW::sync() {
+ doing_sync=true;
};
void Physics2DServerSW::flush_queries() {
@@ -1235,7 +1236,7 @@ void Physics2DServerSW::flush_queries() {
if (!active)
return;
- doing_sync=true;
+
for( Set<const Space2DSW*>::Element *E=active_spaces.front();E;E=E->next()) {
Space2DSW *space=(Space2DSW *)E->get();
@@ -1244,6 +1245,10 @@ void Physics2DServerSW::flush_queries() {
};
+void Physics2DServerSW::end_sync() {
+ doing_sync=false;
+}
+
void Physics2DServerSW::finish() {
@@ -1283,6 +1288,7 @@ Physics2DServerSW::Physics2DServerSW() {
island_count=0;
active_objects=0;
collision_pairs=0;
+ using_threads=int(Globals::get_singleton()->get("physics_2d/thread_model"))==2;
};
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
index 341df2fdc9..6e875701b8 100644
--- a/servers/physics_2d/physics_2d_server_sw.h
+++ b/servers/physics_2d/physics_2d_server_sw.h
@@ -51,6 +51,8 @@ friend class Physics2DDirectSpaceStateSW;
int active_objects;
int collision_pairs;
+ bool using_threads;
+
Step2DSW *stepper;
Set<const Space2DSW*> active_spaces;
@@ -179,10 +181,10 @@ public:
virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const;
virtual void body_set_layer_mask(RID p_body, uint32_t p_mask);
- virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const;
+ virtual uint32_t body_get_layer_mask(RID p_body) const;
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask);
- virtual uint32_t body_get_collision_mask(RID p_body, uint32_t p_mask) const;
+ virtual uint32_t body_get_collision_mask(RID p_) const;
virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value);
virtual float body_get_param(RID p_body, BodyParameter p_param) const;
@@ -248,8 +250,9 @@ public:
virtual void set_active(bool p_active);
virtual void init();
virtual void step(float p_step);
- virtual void sync();
+ virtual void sync();
virtual void flush_queries();
+ virtual void end_sync();
virtual void finish();
int get_process_info(ProcessInfo p_info);
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.cpp b/servers/physics_2d/physics_2d_server_wrap_mt.cpp
new file mode 100644
index 0000000000..c5f023f162
--- /dev/null
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.cpp
@@ -0,0 +1,169 @@
+#include "physics_2d_server_wrap_mt.h"
+
+#include "os/os.h"
+
+void Physics2DServerWrapMT::thread_exit() {
+
+ exit=true;
+}
+
+void Physics2DServerWrapMT::thread_step(float p_delta) {
+
+ physics_2d_server->step(p_delta);
+ step_sem->post();
+
+}
+
+void Physics2DServerWrapMT::_thread_callback(void *_instance) {
+
+ Physics2DServerWrapMT *vsmt = reinterpret_cast<Physics2DServerWrapMT*>(_instance);
+
+
+ vsmt->thread_loop();
+}
+
+void Physics2DServerWrapMT::thread_loop() {
+
+ server_thread=Thread::get_caller_ID();
+
+ OS::get_singleton()->make_rendering_thread();
+
+ physics_2d_server->init();
+
+ exit=false;
+ step_thread_up=true;
+ while(!exit) {
+ // flush commands one by one, until exit is requested
+ command_queue.wait_and_flush_one();
+ }
+
+ command_queue.flush_all(); // flush all
+
+ physics_2d_server->finish();
+
+}
+
+
+/* EVENT QUEUING */
+
+
+void Physics2DServerWrapMT::step(float p_step) {
+
+ if (create_thread) {
+
+ command_queue.push( this, &Physics2DServerWrapMT::thread_step,p_step);
+ } else {
+
+ command_queue.flush_all(); //flush all pending from other threads
+ physics_2d_server->step(p_step);
+ }
+}
+
+void Physics2DServerWrapMT::sync() {
+
+ if (step_sem) {
+ if (first_frame)
+ first_frame=false;
+ else
+ step_sem->wait(); //must not wait if a step was not issued
+ }
+ physics_2d_server->sync();;
+}
+
+void Physics2DServerWrapMT::flush_queries(){
+
+ physics_2d_server->flush_queries();
+}
+
+void Physics2DServerWrapMT::end_sync() {
+
+ physics_2d_server->end_sync();;
+}
+
+void Physics2DServerWrapMT::init() {
+
+ if (create_thread) {
+
+ step_sem = Semaphore::create();
+ print_line("CREATING PHYSICS 2D THREAD");
+ //OS::get_singleton()->release_rendering_thread();
+ if (create_thread) {
+ thread = Thread::create( _thread_callback, this );
+ print_line("STARTING PHYISICS 2D THREAD");
+ }
+ while(!step_thread_up) {
+ OS::get_singleton()->delay_usec(1000);
+ }
+ print_line("DONE PHYSICS 2D THREAD");
+ } else {
+
+ physics_2d_server->init();
+ }
+
+}
+
+void Physics2DServerWrapMT::finish() {
+
+
+ if (thread) {
+
+ command_queue.push( this, &Physics2DServerWrapMT::thread_exit);
+ Thread::wait_to_finish( thread );
+ memdelete(thread);
+
+/*
+ shape_free_cached_ids();
+ area_free_cached_ids();
+ body_free_cached_ids();
+ pin_joint_free_cached_ids();
+ groove_joint_free_cached_ids();
+ damped_string_free_cached_ids();
+*/
+ thread=NULL;
+ } else {
+ physics_2d_server->finish();
+ }
+
+ if (step_sem)
+ memdelete(step_sem);
+
+}
+
+
+Physics2DServerWrapMT::Physics2DServerWrapMT(Physics2DServer* p_contained,bool p_create_thread) : command_queue(p_create_thread) {
+
+ physics_2d_server=p_contained;
+ create_thread=p_create_thread;
+ thread=NULL;
+ step_sem=NULL;
+ step_pending=0;
+ step_thread_up=false;
+ alloc_mutex=Mutex::create();
+
+ shape_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ area_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ body_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ pin_joint_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ groove_joint_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+ damped_spring_joint_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20);
+
+ if (!p_create_thread) {
+ server_thread=Thread::get_caller_ID();
+ } else {
+ server_thread=0;
+ }
+
+ main_thread = Thread::get_caller_ID();
+ first_frame=true;
+}
+
+
+Physics2DServerWrapMT::~Physics2DServerWrapMT() {
+
+ memdelete(physics_2d_server);
+ memdelete(alloc_mutex);
+ //finish();
+
+}
+
+
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h
new file mode 100644
index 0000000000..0ddc8f16ec
--- /dev/null
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.h
@@ -0,0 +1,297 @@
+#ifndef PHYSICS2DSERVERWRAPMT_H
+#define PHYSICS2DSERVERWRAPMT_H
+
+
+#include "servers/physics_2d_server.h"
+#include "command_queue_mt.h"
+#include "os/thread.h"
+#include "globals.h"
+
+#ifdef DEBUG_SYNC
+#define SYNC_DEBUG print_line("sync on: "+String(__FUNCTION__));
+#else
+#define SYNC_DEBUG
+#endif
+
+
+class Physics2DServerWrapMT : public Physics2DServer {
+
+ mutable Physics2DServer *physics_2d_server;
+
+ mutable CommandQueueMT command_queue;
+
+ static void _thread_callback(void *_instance);
+ void thread_loop();
+
+ Thread::ID server_thread;
+ Thread::ID main_thread;
+ volatile bool exit;
+ Thread *thread;
+ volatile bool step_thread_up;
+ bool create_thread;
+
+ Semaphore *step_sem;
+ int step_pending;
+ void thread_step(float p_delta);
+ void thread_flush();
+
+ void thread_exit();
+
+ Mutex*alloc_mutex;
+ bool first_frame;
+
+ int shape_pool_max_size;
+ List<RID> shape_id_pool;
+ int area_pool_max_size;
+ List<RID> area_id_pool;
+ int body_pool_max_size;
+ List<RID> body_id_pool;
+ int pin_joint_pool_max_size;
+ List<RID> pin_joint_id_pool;
+ int groove_joint_pool_max_size;
+ List<RID> groove_joint_id_pool;
+ int damped_spring_joint_pool_max_size;
+ List<RID> damped_spring_joint_id_pool;
+
+
+public:
+
+#define ServerName Physics2DServer
+#define ServerNameWrapMT Physics2DServerWrapMT
+#define server_name physics_2d_server
+#include "servers/server_wrap_mt_common.h"
+
+ //FUNC1RID(shape,ShapeType); todo fix
+ FUNC1R(RID,shape_create,ShapeType);
+ FUNC2(shape_set_data,RID,const Variant& );
+ FUNC2(shape_set_custom_solver_bias,RID,real_t );
+
+ FUNC1RC(ShapeType,shape_get_type,RID );
+ FUNC1RC(Variant,shape_get_data,RID);
+ FUNC1RC(real_t,shape_get_custom_solver_bias,RID);
+
+
+ //these work well, but should be used from the main thread only
+ bool shape_collide(RID p_shape_A, const Matrix32& p_xform_A,const Vector2& p_motion_A,RID p_shape_B, const Matrix32& p_xform_B, const Vector2& p_motion_B,Vector2 *r_results,int p_result_max,int &r_result_count) {
+
+ ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),false);
+ return physics_2d_server->shape_collide(p_shape_A,p_xform_A,p_motion_A,p_shape_B,p_xform_B,p_motion_B,r_results,p_result_max,r_result_count);
+ }
+
+ /* SPACE API */
+
+ FUNC0R(RID,space_create);
+ FUNC2(space_set_active,RID,bool);
+ FUNC1RC(bool,space_is_active,RID);
+
+ FUNC3(space_set_param,RID,SpaceParameter,real_t);
+ FUNC2RC(real_t,space_get_param,RID,SpaceParameter);
+
+ // this function only works on fixed process, errors and returns null otherwise
+ Physics2DDirectSpaceState* space_get_direct_state(RID p_space) {
+
+ ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),NULL);
+ return physics_2d_server->space_get_direct_state(p_space);
+ }
+
+
+ /* AREA API */
+
+ //FUNC0RID(area);
+ FUNC0R(RID,area_create);
+
+ FUNC2(area_set_space,RID,RID);
+ FUNC1RC(RID,area_get_space,RID);
+
+ FUNC2(area_set_space_override_mode,RID,AreaSpaceOverrideMode);
+ FUNC1RC(AreaSpaceOverrideMode,area_get_space_override_mode,RID);
+
+ FUNC3(area_add_shape,RID,RID,const Matrix32&);
+ FUNC3(area_set_shape,RID,int,RID);
+ FUNC3(area_set_shape_transform,RID,int,const Matrix32&);
+
+ FUNC1RC(int,area_get_shape_count,RID);
+ FUNC2RC(RID,area_get_shape,RID,int);
+ FUNC2RC(Matrix32,area_get_shape_transform,RID,int);
+ FUNC2(area_remove_shape,RID,int);
+ FUNC1(area_clear_shapes,RID);
+
+ FUNC2(area_attach_object_instance_ID,RID,ObjectID);
+ FUNC1RC(ObjectID,area_get_object_instance_ID,RID);
+
+ FUNC3(area_set_param,RID,AreaParameter,const Variant&);
+ FUNC2(area_set_transform,RID,const Matrix32&);
+
+ FUNC2RC(Variant,area_get_param,RID,AreaParameter);
+ FUNC1RC(Matrix32,area_get_transform,RID);
+
+ FUNC2(area_set_collision_mask,RID,uint32_t);
+ FUNC2(area_set_layer_mask,RID,uint32_t);
+
+ FUNC2(area_set_monitorable,RID,bool);
+ FUNC2(area_set_pickable,RID,bool);
+
+ FUNC3(area_set_monitor_callback,RID,Object*,const StringName&);
+ FUNC3(area_set_area_monitor_callback,RID,Object*,const StringName&);
+
+
+ /* BODY API */
+
+ //FUNC2RID(body,BodyMode,bool);
+ FUNC2R(RID,body_create,BodyMode,bool)
+
+ FUNC2(body_set_space,RID,RID);
+ FUNC1RC(RID,body_get_space,RID);
+
+ FUNC2(body_set_mode,RID,BodyMode);
+ FUNC1RC(BodyMode,body_get_mode,RID);
+
+
+ FUNC3(body_add_shape,RID,RID,const Matrix32&);
+ FUNC3(body_set_shape,RID,int,RID);
+ FUNC3(body_set_shape_transform,RID,int,const Matrix32&);
+ FUNC3(body_set_shape_metadata,RID,int,const Variant&);
+
+ FUNC1RC(int,body_get_shape_count,RID);
+ FUNC2RC(Matrix32,body_get_shape_transform,RID,int);
+ FUNC2RC(Variant,body_get_shape_metadata,RID,int);
+ FUNC2RC(RID,body_get_shape,RID,int);
+
+ FUNC3(body_set_shape_as_trigger,RID,int,bool);
+ FUNC2RC(bool,body_is_shape_set_as_trigger,RID,int);
+
+ FUNC2(body_remove_shape,RID,int);
+ FUNC1(body_clear_shapes,RID);
+
+ FUNC2(body_attach_object_instance_ID,RID,uint32_t);
+ FUNC1RC(uint32_t,body_get_object_instance_ID,RID);
+
+ FUNC2(body_set_continuous_collision_detection_mode,RID,CCDMode);
+ FUNC1RC(CCDMode,body_get_continuous_collision_detection_mode,RID);
+
+ FUNC2(body_set_layer_mask,RID,uint32_t);
+ FUNC1RC(uint32_t,body_get_layer_mask,RID);
+
+ FUNC2(body_set_collision_mask,RID,uint32_t);
+ FUNC1RC(uint32_t,body_get_collision_mask,RID);
+
+
+ FUNC3(body_set_param,RID,BodyParameter,float);
+ FUNC2RC(float,body_get_param,RID,BodyParameter);
+
+
+ FUNC3(body_set_state,RID,BodyState,const Variant&);
+ FUNC2RC(Variant,body_get_state,RID,BodyState);
+
+ FUNC2(body_set_applied_force,RID,const Vector2&);
+ FUNC1RC(Vector2,body_get_applied_force,RID);
+
+ FUNC2(body_set_applied_torque,RID,float);
+ FUNC1RC(float,body_get_applied_torque,RID);
+
+ FUNC3(body_apply_impulse,RID,const Vector2&,const Vector2&);
+ FUNC2(body_set_axis_velocity,RID,const Vector2&);
+
+ FUNC2(body_add_collision_exception,RID,RID);
+ FUNC2(body_remove_collision_exception,RID,RID);
+ FUNC2S(body_get_collision_exceptions,RID,List<RID>*);
+
+ FUNC2(body_set_max_contacts_reported,RID,int);
+ FUNC1RC(int,body_get_max_contacts_reported,RID);
+
+ FUNC2(body_set_one_way_collision_direction,RID,const Vector2&);
+ FUNC1RC(Vector2,body_get_one_way_collision_direction,RID);
+
+ FUNC2(body_set_one_way_collision_max_depth,RID,float);
+ FUNC1RC(float,body_get_one_way_collision_max_depth,RID);
+
+
+ FUNC2(body_set_contacts_reported_depth_treshold,RID,float);
+ FUNC1RC(float,body_get_contacts_reported_depth_treshold,RID);
+
+ FUNC2(body_set_omit_force_integration,RID,bool);
+ FUNC1RC(bool,body_is_omitting_force_integration,RID);
+
+ FUNC4(body_set_force_integration_callback,RID ,Object *,const StringName& ,const Variant& );
+
+
+ bool body_collide_shape(RID p_body, int p_body_shape,RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,Vector2 *r_results,int p_result_max,int &r_result_count) {
+ return physics_2d_server->body_collide_shape(p_body,p_body_shape,p_shape,p_shape_xform,p_motion,r_results,p_result_max,r_result_count);
+ }
+
+ FUNC2(body_set_pickable,RID,bool);
+
+ bool body_test_motion(RID p_body,const Vector2& p_motion,float p_margin=0.001,MotionResult *r_result=NULL) {
+
+ ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),false);
+ return physics_2d_server->body_test_motion(p_body,p_motion,p_margin,r_result);
+ }
+
+ /* JOINT API */
+
+
+ FUNC3(joint_set_param,RID,JointParam,real_t);
+ FUNC2RC(real_t,joint_get_param,RID,JointParam);
+
+
+ ///FUNC3RID(pin_joint,const Vector2&,RID,RID);
+ ///FUNC5RID(groove_joint,const Vector2&,const Vector2&,const Vector2&,RID,RID);
+ ///FUNC4RID(damped_spring_joint,const Vector2&,const Vector2&,RID,RID);
+
+ FUNC3R(RID,pin_joint_create,const Vector2&,RID,RID);
+ FUNC5R(RID,groove_joint_create,const Vector2&,const Vector2&,const Vector2&,RID,RID);
+ FUNC4R(RID,damped_spring_joint_create,const Vector2&,const Vector2&,RID,RID);
+
+ FUNC3(damped_string_joint_set_param,RID,DampedStringParam,real_t);
+ FUNC2RC(real_t,damped_string_joint_get_param,RID,DampedStringParam);
+
+ FUNC1RC(JointType,joint_get_type,RID);
+
+
+ /* MISC */
+
+
+ FUNC1(free,RID);
+ FUNC1(set_active,bool);
+
+ virtual void init();
+ virtual void step(float p_step);
+ virtual void sync();
+ virtual void end_sync();
+ virtual void flush_queries();
+ virtual void finish();
+
+ int get_process_info(ProcessInfo p_info) {
+ return physics_2d_server->get_process_info(p_info);
+ }
+
+ Physics2DServerWrapMT(Physics2DServer* p_contained,bool p_create_thread);
+ ~Physics2DServerWrapMT();
+
+
+ template<class T>
+ static Physics2DServer* init_server() {
+
+ int tm = GLOBAL_DEF("physics_2d/thread_model",1);
+ if (tm==0) //single unsafe
+ return memnew( T );
+ else if (tm==1) //single saef
+ return memnew( Physics2DServerWrapMT( memnew( T ), false ));
+ else //single unsafe
+ return memnew( Physics2DServerWrapMT( memnew( T ), true ));
+
+
+ }
+
+#undef ServerNameWrapMT
+#undef ServerName
+#undef server_name
+
+};
+
+#ifdef DEBUG_SYNC
+#undef DEBUG_SYNC
+#endif
+#undef SYNC_DEBUG
+
+#endif // PHYSICS2DSERVERWRAPMT_H
diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp
index 279ad0d742..c2ad7b2165 100644
--- a/servers/physics_2d_server.cpp
+++ b/servers/physics_2d_server.cpp
@@ -713,7 +713,7 @@ void Physics2DServer::_bind_methods() {
Physics2DServer::Physics2DServer() {
- ERR_FAIL_COND( singleton!=NULL );
+ //ERR_FAIL_COND( singleton!=NULL );
singleton=this;
}
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index 5411228c0f..9922d2e345 100644
--- a/servers/physics_2d_server.h
+++ b/servers/physics_2d_server.h
@@ -405,10 +405,10 @@ public:
virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const=0;
virtual void body_set_layer_mask(RID p_body, uint32_t p_mask)=0;
- virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const=0;
+ virtual uint32_t body_get_layer_mask(RID p_body) const=0;
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask)=0;
- virtual uint32_t body_get_collision_mask(RID p_body, uint32_t p_mask) const=0;
+ virtual uint32_t body_get_collision_mask(RID p_body) const=0;
// common body variables
enum BodyParameter {
@@ -539,6 +539,7 @@ public:
virtual void step(float p_step)=0;
virtual void sync()=0;
virtual void flush_queries()=0;
+ virtual void end_sync()=0;
virtual void finish()=0;
enum ProcessInfo {
diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h
new file mode 100644
index 0000000000..cbb75129d0
--- /dev/null
+++ b/servers/server_wrap_mt_common.h
@@ -0,0 +1,700 @@
+
+#define FUNC0R(m_r,m_type)\
+ virtual m_r m_type() { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type();\
+ }\
+ }
+
+
+#define FUNCRID(m_type)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create() { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create();\
+ }\
+ }
+
+#define FUNC1RID(m_type,m_arg1)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1);\
+ }\
+ }
+
+#define FUNC2RID(m_type,m_arg1,m_arg2)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1,m_arg2 p2) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1,p2);\
+ }\
+ }
+
+#define FUNC3RID(m_type,m_arg1,m_arg2,m_arg3)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1,m_arg2 p2,m_arg3 p3) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,p3,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1,p2,p3);\
+ }\
+ }
+
+
+#define FUNC4RID(m_type,m_arg1,m_arg2,m_arg3,m_arg4)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1,m_arg2 p2,m_arg3 p3,m_arg4 p4) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,p3,p4,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1,p2,p3,p4);\
+ }\
+ }
+
+
+#define FUNC5RID(m_type,m_arg1,m_arg2,m_arg3,m_arg4,m_arg5)\
+ int m_type##allocn() {\
+ for(int i=0;i<m_type##_pool_max_size;i++) {\
+ m_type##_id_pool.push_back( server_name->m_type##_create() );\
+ }\
+ return 0;\
+ }\
+ void m_type##_free_cached_ids() {\
+ while (m_type##_id_pool.size()) {\
+ free(m_type##_id_pool.front()->get());\
+ m_type##_id_pool.pop_front();\
+ }\
+ }\
+ virtual RID m_type##_create(m_arg1 p1,m_arg2 p2,m_arg3 p3,m_arg4 p4,m_arg5 p5) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ RID rid;\
+ alloc_mutex->lock();\
+ if (m_type##_id_pool.size()==0) {\
+ int ret;\
+ command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,p3,p4,p5,&ret);\
+ }\
+ rid=m_type##_id_pool.front()->get();\
+ m_type##_id_pool.pop_front();\
+ alloc_mutex->unlock();\
+ return rid;\
+ } else {\
+ return server_name->m_type##_create(p1,p2,p3,p4,p5);\
+ }\
+ }
+
+#define FUNC0RC(m_r,m_type)\
+ virtual m_r m_type() const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type();\
+ }\
+ }
+
+
+#define FUNC0(m_type)\
+ virtual void m_type() { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type);\
+ } else {\
+ server_name->m_type();\
+ }\
+ }
+
+#define FUNC0C(m_type)\
+ virtual void m_type() const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type);\
+ } else {\
+ server_name->m_type();\
+ }\
+ }
+
+
+#define FUNC0S(m_type)\
+ virtual void m_type() { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type);\
+ } else {\
+ server_name->m_type();\
+ }\
+ }
+
+#define FUNC0SC(m_type)\
+ virtual void m_type() const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type);\
+ } else {\
+ server_name->m_type();\
+ }\
+ }
+
+
+///////////////////////////////////////////////
+
+
+#define FUNC1R(m_r,m_type,m_arg1)\
+ virtual m_r m_type(m_arg1 p1) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1);\
+ }\
+ }
+
+#define FUNC1RC(m_r,m_type,m_arg1)\
+ virtual m_r m_type(m_arg1 p1) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1);\
+ }\
+ }
+
+
+#define FUNC1S(m_type,m_arg1)\
+ virtual void m_type(m_arg1 p1) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1);\
+ } else {\
+ server_name->m_type(p1);\
+ }\
+ }
+
+#define FUNC1SC(m_type,m_arg1)\
+ virtual void m_type(m_arg1 p1) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1);\
+ } else {\
+ server_name->m_type(p1);\
+ }\
+ }
+
+
+#define FUNC1(m_type,m_arg1)\
+ virtual void m_type(m_arg1 p1) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1);\
+ } else {\
+ server_name->m_type(p1);\
+ }\
+ }
+
+#define FUNC1C(m_type,m_arg1)\
+ virtual void m_type(m_arg1 p1) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1);\
+ } else {\
+ server_name->m_type(p1);\
+ }\
+ }
+
+
+
+
+#define FUNC2R(m_r,m_type,m_arg1, m_arg2)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2);\
+ }\
+ }
+
+#define FUNC2RC(m_r,m_type,m_arg1, m_arg2)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2);\
+ }\
+ }
+
+
+#define FUNC2S(m_type,m_arg1, m_arg2)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2);\
+ } else {\
+ server_name->m_type(p1, p2);\
+ }\
+ }
+
+#define FUNC2SC(m_type,m_arg1, m_arg2)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2);\
+ } else {\
+ server_name->m_type(p1, p2);\
+ }\
+ }
+
+
+#define FUNC2(m_type,m_arg1, m_arg2)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2);\
+ } else {\
+ server_name->m_type(p1, p2);\
+ }\
+ }
+
+#define FUNC2C(m_type,m_arg1, m_arg2)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2);\
+ } else {\
+ server_name->m_type(p1, p2);\
+ }\
+ }
+
+
+
+
+#define FUNC3R(m_r,m_type,m_arg1, m_arg2, m_arg3)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+#define FUNC3RC(m_r,m_type,m_arg1, m_arg2, m_arg3)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3,&ret);\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+
+#define FUNC3S(m_type,m_arg1, m_arg2, m_arg3)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3);\
+ } else {\
+ server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+#define FUNC3SC(m_type,m_arg1, m_arg2, m_arg3)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3);\
+ } else {\
+ server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+
+#define FUNC3(m_type,m_arg1, m_arg2, m_arg3)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3);\
+ } else {\
+ server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+#define FUNC3C(m_type,m_arg1, m_arg2, m_arg3)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3);\
+ } else {\
+ server_name->m_type(p1, p2, p3);\
+ }\
+ }
+
+
+
+
+#define FUNC4R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+#define FUNC4RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+
+#define FUNC4S(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+#define FUNC4SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+
+#define FUNC4(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+#define FUNC4C(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4);\
+ }\
+ }
+
+
+
+
+#define FUNC5R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+#define FUNC5RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+
+#define FUNC5S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+#define FUNC5SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+
+#define FUNC5(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+#define FUNC5C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5);\
+ }\
+ }
+
+
+
+
+#define FUNC6R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+#define FUNC6RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6,&ret);\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+
+#define FUNC6S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+#define FUNC6SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+
+#define FUNC6(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+#define FUNC6C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6);\
+ }\
+ }
+
+
+
+
+#define FUNC7R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+#define FUNC7RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ m_r ret;\
+ command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\
+ SYNC_DEBUG\
+ return ret;\
+ } else {\
+ return server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+
+#define FUNC7S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+#define FUNC7SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+
+#define FUNC7(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
+#define FUNC7C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
+ if (Thread::get_caller_ID()!=server_thread) {\
+ command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\
+ } else {\
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\
+ }\
+ }
+
diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp
index a044981bbb..44a41a93da 100644
--- a/servers/visual/visual_server_wrap_mt.cpp
+++ b/servers/visual/visual_server_wrap_mt.cpp
@@ -187,8 +187,8 @@ VisualServerWrapMT::VisualServerWrapMT(VisualServer* p_contained,bool p_create_t
draw_pending=0;
draw_thread_up=false;
alloc_mutex=Mutex::create();
- texture_pool_max_size=GLOBAL_DEF("render/thread_textures_prealloc",20);
- mesh_pool_max_size=GLOBAL_DEF("render/thread_meshes_prealloc",20);
+ texture_pool_max_size=GLOBAL_DEF("render/thread_textures_prealloc",5);
+ mesh_pool_max_size=GLOBAL_DEF("core/rid_pool_prealloc",20);
if (!p_create_thread) {
server_thread=Thread::get_caller_ID();
} else {
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index 3d97243827..d07e1940d7 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -79,554 +79,10 @@ class VisualServerWrapMT : public VisualServer {
public:
-#define FUNC0R(m_r,m_type)\
- virtual m_r m_type() { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type();\
- }\
- }
-
-#define FUNCRID(m_type)\
- int m_type##allocn() {\
- for(int i=0;i<m_type##_pool_max_size;i++) {\
- m_type##_id_pool.push_back( visual_server->m_type##_create() );\
- }\
- return 0;\
- }\
- void m_type##_free_cached_ids() {\
- while (m_type##_id_pool.size()) {\
- free(m_type##_id_pool.front()->get());\
- m_type##_id_pool.pop_front();\
- }\
- }\
- virtual RID m_type##_create() { \
- if (Thread::get_caller_ID()!=server_thread) {\
- RID rid;\
- alloc_mutex->lock();\
- if (m_type##_id_pool.size()==0) {\
- int ret;\
- command_queue.push_and_ret( this, &VisualServerWrapMT::m_type##allocn,&ret);\
- }\
- rid=m_type##_id_pool.front()->get();\
- m_type##_id_pool.pop_front();\
- alloc_mutex->unlock();\
- return rid;\
- } else {\
- return visual_server->m_type##_create();\
- }\
- }
-
-#define FUNC0RC(m_r,m_type)\
- virtual m_r m_type() const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type();\
- }\
- }
-
-
-#define FUNC0(m_type)\
- virtual void m_type() { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type);\
- } else {\
- visual_server->m_type();\
- }\
- }
-
-#define FUNC0C(m_type)\
- virtual void m_type() const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type);\
- } else {\
- visual_server->m_type();\
- }\
- }
-
-
-#define FUNC0S(m_type)\
- virtual void m_type() { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type);\
- } else {\
- visual_server->m_type();\
- }\
- }
-
-#define FUNC0SC(m_type)\
- virtual void m_type() const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type);\
- } else {\
- visual_server->m_type();\
- }\
- }
-
-
-///////////////////////////////////////////////
-
-
-#define FUNC1R(m_r,m_type,m_arg1)\
- virtual m_r m_type(m_arg1 p1) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1);\
- }\
- }
-
-#define FUNC1RC(m_r,m_type,m_arg1)\
- virtual m_r m_type(m_arg1 p1) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1);\
- }\
- }
-
-
-#define FUNC1S(m_type,m_arg1)\
- virtual void m_type(m_arg1 p1) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1);\
- } else {\
- visual_server->m_type(p1);\
- }\
- }
-
-#define FUNC1SC(m_type,m_arg1)\
- virtual void m_type(m_arg1 p1) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1);\
- } else {\
- visual_server->m_type(p1);\
- }\
- }
-
-
-#define FUNC1(m_type,m_arg1)\
- virtual void m_type(m_arg1 p1) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1);\
- } else {\
- visual_server->m_type(p1);\
- }\
- }
-
-#define FUNC1C(m_type,m_arg1)\
- virtual void m_type(m_arg1 p1) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1);\
- } else {\
- visual_server->m_type(p1);\
- }\
- }
-
-
-
-
-#define FUNC2R(m_r,m_type,m_arg1, m_arg2)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2);\
- }\
- }
-
-#define FUNC2RC(m_r,m_type,m_arg1, m_arg2)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2);\
- }\
- }
-
-
-#define FUNC2S(m_type,m_arg1, m_arg2)\
- virtual void m_type(m_arg1 p1, m_arg2 p2) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2);\
- } else {\
- visual_server->m_type(p1, p2);\
- }\
- }
-
-#define FUNC2SC(m_type,m_arg1, m_arg2)\
- virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2);\
- } else {\
- visual_server->m_type(p1, p2);\
- }\
- }
-
-
-#define FUNC2(m_type,m_arg1, m_arg2)\
- virtual void m_type(m_arg1 p1, m_arg2 p2) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2);\
- } else {\
- visual_server->m_type(p1, p2);\
- }\
- }
-
-#define FUNC2C(m_type,m_arg1, m_arg2)\
- virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2);\
- } else {\
- visual_server->m_type(p1, p2);\
- }\
- }
-
-
-
-
-#define FUNC3R(m_r,m_type,m_arg1, m_arg2, m_arg3)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-#define FUNC3RC(m_r,m_type,m_arg1, m_arg2, m_arg3)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3,&ret);\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-
-#define FUNC3S(m_type,m_arg1, m_arg2, m_arg3)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3);\
- } else {\
- visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-#define FUNC3SC(m_type,m_arg1, m_arg2, m_arg3)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3);\
- } else {\
- visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-
-#define FUNC3(m_type,m_arg1, m_arg2, m_arg3)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3);\
- } else {\
- visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-#define FUNC3C(m_type,m_arg1, m_arg2, m_arg3)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3);\
- } else {\
- visual_server->m_type(p1, p2, p3);\
- }\
- }
-
-
-
-
-#define FUNC4R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-#define FUNC4RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-
-#define FUNC4S(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-#define FUNC4SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-
-#define FUNC4(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-#define FUNC4C(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4);\
- }\
- }
-
-
-
-
-#define FUNC5R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-#define FUNC5RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-
-#define FUNC5S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-#define FUNC5SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-
-#define FUNC5(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-#define FUNC5C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5);\
- }\
- }
-
-
-
-
-#define FUNC6R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-#define FUNC6RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6,&ret);\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-
-#define FUNC6S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-#define FUNC6SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-
-#define FUNC6(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-#define FUNC6C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6);\
- }\
- }
-
-
-
-
-#define FUNC7R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-#define FUNC7RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- m_r ret;\
- command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\
- SYNC_DEBUG\
- return ret;\
- } else {\
- return visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-
-#define FUNC7S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-#define FUNC7SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-
-#define FUNC7(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-#define FUNC7C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
- if (Thread::get_caller_ID()!=server_thread) {\
- command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\
- } else {\
- visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\
- }\
- }
-
-
-
+#define ServerName VisualServer
+#define ServerNameWrapMT VisualServerWrapMT
+#define server_name visual_server
+#include "servers/server_wrap_mt_common.h"
//FUNC0R(RID,texture_create);
FUNCRID(texture);
@@ -1242,7 +698,15 @@ public:
VisualServerWrapMT(VisualServer* p_contained,bool p_create_thread);
~VisualServerWrapMT();
+#undef ServerName
+#undef ServerNameWrapMT
+#undef server_name
+
};
+#ifdef DEBUG_SYNC
+#undef DEBUG_SYNC
+#endif
+#undef SYNC_DEBUG
#endif
diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp
index 36fb6fb5f8..bb6f7e9a6f 100644
--- a/tools/editor/animation_editor.cpp
+++ b/tools/editor/animation_editor.cpp
@@ -1327,8 +1327,16 @@ void AnimationKeyEditor::_track_editor_draw() {
float time = animation->track_get_key_time(idx,i);
if (time<keys_from)
continue;
- if (time>keys_to)
+ if (time>keys_to) {
+
+ if (first && i>0 && animation->track_get_key_value(idx,i)==animation->track_get_key_value(idx,i-1)) {
+ //draw whole line
+ te->draw_line(ofs+Vector2(name_limit,y+h/2),ofs+Point2(settings_limit,y+h/2),color);
+ }
+
break;
+ }
+
float x = key_hofs + name_limit + (time-keys_from)*zoom_scale;
Ref<Texture> tex = type_icon[tt];
diff --git a/tools/editor/editor_file_dialog.cpp b/tools/editor/editor_file_dialog.cpp
new file mode 100644
index 0000000000..359f807ae4
--- /dev/null
+++ b/tools/editor/editor_file_dialog.cpp
@@ -0,0 +1,874 @@
+#include "editor_file_dialog.h"
+#include "scene/gui/label.h"
+#include "scene/gui/center_container.h"
+#include "print_string.h"
+#include "os/keyboard.h"
+#include "editor_resource_preview.h"
+
+
+EditorFileDialog::GetIconFunc EditorFileDialog::get_icon_func=NULL;
+EditorFileDialog::GetIconFunc EditorFileDialog::get_large_icon_func=NULL;
+
+EditorFileDialog::RegisterFunc EditorFileDialog::register_func=NULL;
+EditorFileDialog::RegisterFunc EditorFileDialog::unregister_func=NULL;
+
+
+VBoxContainer *EditorFileDialog::get_vbox() {
+ return vbox;
+
+}
+
+void EditorFileDialog::_notification(int p_what) {
+ if (p_what==NOTIFICATION_PROCESS) {
+
+ if (preview_waiting) {
+ preview_wheel_timeout-=get_process_delta_time();
+ if (preview_wheel_timeout<=0) {
+ preview_wheel_index++;
+ if (preview_wheel_index>=8)
+ preview_wheel_index=0;
+ Ref<Texture> frame = get_icon("WaitPreview"+itos(preview_wheel_index+1),"EditorIcons");
+ preview->set_texture(frame);
+ preview_wheel_timeout=0.1;
+ }
+ }
+ }
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ //RID ci = get_canvas_item();
+ //get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
+ }
+}
+
+void EditorFileDialog::set_enable_multiple_selection(bool p_enable) {
+
+ tree->set_select_mode(p_enable?Tree::SELECT_MULTI : Tree::SELECT_SINGLE);
+};
+
+Vector<String> EditorFileDialog::get_selected_files() const {
+
+ Vector<String> list;
+
+ TreeItem* item = tree->get_root();
+ while ( (item = tree->get_next_selected(item)) ) {
+
+ list.push_back(dir_access->get_current_dir().plus_file(item->get_text(0)));
+ };
+
+ return list;
+};
+
+void EditorFileDialog::update_dir() {
+
+ dir->set_text(dir_access->get_current_dir());
+}
+
+void EditorFileDialog::_dir_entered(String p_dir) {
+
+
+ dir_access->change_dir(p_dir);
+ file->set_text("");
+ invalidate();
+ update_dir();
+}
+
+void EditorFileDialog::_file_entered(const String& p_file) {
+
+ _action_pressed();
+}
+
+void EditorFileDialog::_save_confirm_pressed() {
+ String f=dir_access->get_current_dir().plus_file(file->get_text());
+ emit_signal("file_selected",f);
+ hide();
+}
+
+void EditorFileDialog::_post_popup() {
+
+ ConfirmationDialog::_post_popup();
+ if (invalidated) {
+ update_file_list();
+ invalidated=false;
+ }
+ if (mode==MODE_SAVE_FILE)
+ file->grab_focus();
+ else
+ tree->grab_focus();
+
+ if (is_visible() && get_current_file()!="")
+ _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+
+}
+
+void EditorFileDialog::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) {
+
+ set_process(false);
+ preview_waiting=false;
+
+ if (p_preview.is_valid() && get_current_path()==p_path) {
+
+ preview->set_texture(p_preview);
+ preview_vb->show();
+
+ } else {
+ preview_vb->hide();
+ preview->set_texture(Ref<Texture>());
+
+ }
+
+}
+
+void EditorFileDialog::_request_single_thumbnail(const String& p_path) {
+
+ EditorResourcePreview::get_singleton()->queue_resource_preview(p_path,this,"_thumbnail_done",p_path);
+ print_line("want file "+p_path);
+ set_process(true);
+ preview_waiting=true;
+ preview_wheel_timeout=0;
+
+}
+
+void EditorFileDialog::_action_pressed() {
+
+ if (mode==MODE_OPEN_FILES) {
+
+ TreeItem *ti=tree->get_next_selected(NULL);
+ String fbase=dir_access->get_current_dir();
+
+ DVector<String> files;
+ while(ti) {
+
+ files.push_back( fbase.plus_file(ti->get_text(0)) );
+ ti=tree->get_next_selected(ti);
+ }
+
+ if (files.size()) {
+ emit_signal("files_selected",files);
+ hide();
+ }
+
+ return;
+ }
+
+ String f=dir_access->get_current_dir().plus_file(file->get_text());
+
+ if (mode==MODE_OPEN_FILE && dir_access->file_exists(f)) {
+ emit_signal("file_selected",f);
+ hide();
+ }
+
+ if (mode==MODE_OPEN_DIR) {
+
+
+ String path=dir_access->get_current_dir();
+ /*if (tree->get_selected()) {
+ Dictionary d = tree->get_selected()->get_metadata(0);
+ if (d["dir"]) {
+ path=path+"/"+String(d["name"]);
+ }
+ }*/
+ path=path.replace("\\","/");
+ emit_signal("dir_selected",path);
+ hide();
+ }
+
+ if (mode==MODE_SAVE_FILE) {
+
+ bool valid=false;
+
+ if (filter->get_selected()==filter->get_item_count()-1) {
+ valid=true; //match none
+ } else if (filters.size()>1 && filter->get_selected()==0) {
+ // match all filters
+ for (int i=0;i<filters.size();i++) {
+
+ String flt=filters[i].get_slice(";",0);
+ for (int j=0;j<flt.get_slice_count(",");j++) {
+
+ String str = flt.get_slice(",",j).strip_edges();
+ if (f.match(str)) {
+ valid=true;
+ break;
+ }
+ }
+ if (valid)
+ break;
+ }
+ } else {
+ int idx=filter->get_selected();
+ if (filters.size()>1)
+ idx--;
+ if (idx>=0 && idx<filters.size()) {
+
+ String flt=filters[idx].get_slice(";",0);
+ int filterSliceCount=flt.get_slice_count(",");
+ for (int j=0;j<filterSliceCount;j++) {
+
+ String str = (flt.get_slice(",",j).strip_edges());
+ if (f.match(str)) {
+ valid=true;
+ break;
+ }
+ }
+
+ if (!valid && filterSliceCount>0) {
+ String str = (flt.get_slice(",",0).strip_edges());
+ f+=str.substr(1, str.length()-1);
+ _request_single_thumbnail(get_current_dir().plus_file(f.get_file()));
+ file->set_text(f.get_file());
+ valid=true;
+ }
+ } else {
+ valid=true;
+ }
+ }
+
+
+ if (!valid) {
+
+ exterr->popup_centered_minsize(Size2(250,80));
+ return;
+
+ }
+
+ if (dir_access->file_exists(f)) {
+ confirm_save->set_text("File Exists, Overwrite?");
+ confirm_save->popup_centered(Size2(200,80));
+ } else {
+
+
+ emit_signal("file_selected",f);
+ hide();
+ }
+ }
+}
+
+void EditorFileDialog::_cancel_pressed() {
+
+ file->set_text("");
+ invalidate();
+ hide();
+}
+
+void EditorFileDialog::_tree_selected() {
+
+ TreeItem *ti=tree->get_selected();
+ if (!ti)
+ return;
+ Dictionary d=ti->get_metadata(0);
+
+ if (!d["dir"]) {
+
+ file->set_text(d["name"]);
+ _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ }
+}
+
+void EditorFileDialog::_tree_dc_selected() {
+
+
+ TreeItem *ti=tree->get_selected();
+ if (!ti)
+ return;
+
+ Dictionary d=ti->get_metadata(0);
+
+ if (d["dir"]) {
+
+ dir_access->change_dir(d["name"]);
+ if (mode==MODE_OPEN_FILE || mode==MODE_OPEN_FILES || mode==MODE_OPEN_DIR)
+ file->set_text("");
+ call_deferred("_update_file_list");
+ call_deferred("_update_dir");
+ } else {
+
+ _action_pressed();
+ }
+}
+
+void EditorFileDialog::update_file_list() {
+
+ tree->clear();
+ dir_access->list_dir_begin();
+
+ TreeItem *root = tree->create_item();
+ Ref<Texture> folder = get_icon("folder","FileDialog");
+ List<String> files;
+ List<String> dirs;
+
+ bool isdir;
+ bool ishidden;
+ bool show_hidden = show_hidden_files;
+ String item;
+
+ while ((item=dir_access->get_next(&isdir))!="") {
+
+ ishidden = dir_access->current_is_hidden();
+
+ if (show_hidden || !ishidden) {
+ if (!isdir)
+ files.push_back(item);
+ else
+ dirs.push_back(item);
+ }
+ }
+
+ dirs.sort_custom<NoCaseComparator>();
+ files.sort_custom<NoCaseComparator>();
+
+ while(!dirs.empty()) {
+
+ if (dirs.front()->get()!=".") {
+ TreeItem *ti=tree->create_item(root);
+ ti->set_text(0,dirs.front()->get()+"/");
+ ti->set_icon(0,folder);
+ Dictionary d;
+ d["name"]=dirs.front()->get();
+ d["dir"]=true;
+ ti->set_metadata(0,d);
+ }
+ dirs.pop_front();
+
+ }
+
+ dirs.clear();
+
+ List<String> patterns;
+ // build filter
+ if (filter->get_selected()==filter->get_item_count()-1) {
+
+ // match all
+ } else if (filters.size()>1 && filter->get_selected()==0) {
+ // match all filters
+ for (int i=0;i<filters.size();i++) {
+
+ String f=filters[i].get_slice(";",0);
+ for (int j=0;j<f.get_slice_count(",");j++) {
+
+ patterns.push_back(f.get_slice(",",j).strip_edges());
+ }
+ }
+ } else {
+ int idx=filter->get_selected();
+ if (filters.size()>1)
+ idx--;
+
+ if (idx>=0 && idx<filters.size()) {
+
+ String f=filters[idx].get_slice(";",0);
+ for (int j=0;j<f.get_slice_count(",");j++) {
+
+ patterns.push_back(f.get_slice(",",j).strip_edges());
+ }
+ }
+ }
+
+
+ String base_dir = dir_access->get_current_dir();
+
+
+ while(!files.empty()) {
+
+ bool match=patterns.empty();
+
+ for(List<String>::Element *E=patterns.front();E;E=E->next()) {
+
+ if (files.front()->get().matchn(E->get())) {
+
+ match=true;
+ break;
+ }
+ }
+
+ if (match) {
+ TreeItem *ti=tree->create_item(root);
+ ti->set_text(0,files.front()->get());
+
+ if (get_icon_func) {
+
+ Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get()));
+ ti->set_icon(0,icon);
+ }
+
+ if (mode==MODE_OPEN_DIR) {
+ ti->set_custom_color(0,get_color("files_disabled"));
+ ti->set_selectable(0,false);
+ }
+ Dictionary d;
+ d["name"]=files.front()->get();
+ d["dir"]=false;
+ ti->set_metadata(0,d);
+
+ if (file->get_text()==files.front()->get())
+ ti->select(0);
+ }
+
+ files.pop_front();
+ }
+
+ if (tree->get_root() && tree->get_root()->get_children())
+ tree->get_root()->get_children()->select(0);
+
+ files.clear();
+
+}
+
+void EditorFileDialog::_filter_selected(int) {
+
+ update_file_list();
+}
+
+void EditorFileDialog::update_filters() {
+
+ filter->clear();
+
+ if (filters.size()>1) {
+ String all_filters;
+
+ const int max_filters=5;
+
+ for(int i=0;i<MIN( max_filters, filters.size()) ;i++) {
+ String flt=filters[i].get_slice(";",0);
+ if (i>0)
+ all_filters+=",";
+ all_filters+=flt;
+ }
+
+ if (max_filters<filters.size())
+ all_filters+=", ...";
+
+ filter->add_item("All Recognized ( "+all_filters+" )");
+ }
+ for(int i=0;i<filters.size();i++) {
+
+ String flt=filters[i].get_slice(";",0).strip_edges();
+ String desc=filters[i].get_slice(";",1).strip_edges();
+ if (desc.length())
+ filter->add_item(desc+" ( "+flt+" )");
+ else
+ filter->add_item("( "+flt+" )");
+ }
+
+ filter->add_item("All Files (*)");
+
+}
+
+void EditorFileDialog::clear_filters() {
+
+ filters.clear();
+ update_filters();
+ invalidate();
+}
+void EditorFileDialog::add_filter(const String& p_filter) {
+
+ filters.push_back(p_filter);
+ update_filters();
+ invalidate();
+
+}
+
+String EditorFileDialog::get_current_dir() const {
+
+ return dir->get_text();
+}
+String EditorFileDialog::get_current_file() const {
+
+ return file->get_text();
+}
+String EditorFileDialog::get_current_path() const {
+
+ return dir->get_text().plus_file(file->get_text());
+}
+void EditorFileDialog::set_current_dir(const String& p_dir) {
+
+ dir_access->change_dir(p_dir);
+ update_dir();
+ invalidate();
+
+}
+void EditorFileDialog::set_current_file(const String& p_file) {
+
+ file->set_text(p_file);
+ update_dir();
+ invalidate();
+ int lp = p_file.find_last(".");
+ if (lp!=-1) {
+ file->select(0,lp);
+ file->grab_focus();
+ }
+
+ if (is_visible())
+ _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+
+
+}
+void EditorFileDialog::set_current_path(const String& p_path) {
+
+ if (!p_path.size())
+ return;
+ int pos=MAX( p_path.find_last("/"), p_path.find_last("\\") );
+ if (pos==-1) {
+
+ set_current_file(p_path);
+ } else {
+
+ String dir=p_path.substr(0,pos);
+ String file=p_path.substr(pos+1,p_path.length());
+ set_current_dir(dir);
+ set_current_file(file);
+ }
+}
+
+
+void EditorFileDialog::set_mode(Mode p_mode) {
+
+ mode=p_mode;
+ switch(mode) {
+
+ case MODE_OPEN_FILE: get_ok()->set_text("Open"); set_title("Open a File"); makedir->hide(); break;
+ case MODE_OPEN_FILES: get_ok()->set_text("Open"); set_title("Open File(s)"); makedir->hide(); break;
+ case MODE_SAVE_FILE: get_ok()->set_text("Save"); set_title("Save a File"); makedir->show(); break;
+ case MODE_OPEN_DIR: get_ok()->set_text("Open"); set_title("Open a Directory"); makedir->show(); break;
+ }
+
+ if (mode==MODE_OPEN_FILES) {
+ tree->set_select_mode(Tree::SELECT_MULTI);
+ } else {
+ tree->set_select_mode(Tree::SELECT_SINGLE);
+
+ }
+}
+
+EditorFileDialog::Mode EditorFileDialog::get_mode() const {
+
+ return mode;
+}
+
+void EditorFileDialog::set_access(Access p_access) {
+
+ ERR_FAIL_INDEX(p_access,3);
+ if (access==p_access)
+ return;
+ memdelete( dir_access );
+ switch(p_access) {
+ case ACCESS_FILESYSTEM: {
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ } break;
+ case ACCESS_RESOURCES: {
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ } break;
+ case ACCESS_USERDATA: {
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_USERDATA);
+ } break;
+ }
+ access=p_access;
+ _update_drives();
+ invalidate();
+ update_filters();
+ update_dir();
+}
+
+void EditorFileDialog::invalidate() {
+
+ if (is_visible()) {
+ update_file_list();
+ invalidated=false;
+ } else {
+ invalidated=true;
+ }
+
+}
+
+EditorFileDialog::Access EditorFileDialog::get_access() const{
+
+ return access;
+}
+
+void EditorFileDialog::_make_dir_confirm() {
+
+
+ Error err = dir_access->make_dir( makedirname->get_text() );
+ if (err==OK) {
+ dir_access->change_dir(makedirname->get_text());
+ invalidate();
+ update_filters();
+ update_dir();
+ } else {
+ mkdirerr->popup_centered_minsize(Size2(250,50));
+ }
+}
+
+
+void EditorFileDialog::_make_dir() {
+
+ makedialog->popup_centered_minsize(Size2(250,80));
+ makedirname->grab_focus();
+
+}
+
+void EditorFileDialog::_select_drive(int p_idx) {
+
+ String d = drives->get_item_text(p_idx);
+ dir_access->change_dir(d);
+ file->set_text("");
+ invalidate();
+ update_dir();
+
+}
+
+void EditorFileDialog::_update_drives() {
+
+
+ int dc = dir_access->get_drive_count();
+ if (dc==0 || access!=ACCESS_FILESYSTEM) {
+ drives->hide();
+ } else {
+ drives->clear();
+ drives->show();
+
+ for(int i=0;i<dir_access->get_drive_count();i++) {
+ String d = dir_access->get_drive(i);
+ drives->add_item(dir_access->get_drive(i));
+ }
+
+ drives->select(dir_access->get_current_drive());
+
+ }
+}
+
+bool EditorFileDialog::default_show_hidden_files=true;
+
+
+void EditorFileDialog::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_tree_selected"),&EditorFileDialog::_tree_selected);
+ ObjectTypeDB::bind_method(_MD("_tree_db_selected"),&EditorFileDialog::_tree_dc_selected);
+ ObjectTypeDB::bind_method(_MD("_dir_entered"),&EditorFileDialog::_dir_entered);
+ ObjectTypeDB::bind_method(_MD("_file_entered"),&EditorFileDialog::_file_entered);
+ ObjectTypeDB::bind_method(_MD("_action_pressed"),&EditorFileDialog::_action_pressed);
+ ObjectTypeDB::bind_method(_MD("_cancel_pressed"),&EditorFileDialog::_cancel_pressed);
+ ObjectTypeDB::bind_method(_MD("_filter_selected"),&EditorFileDialog::_filter_selected);
+ ObjectTypeDB::bind_method(_MD("_save_confirm_pressed"),&EditorFileDialog::_save_confirm_pressed);
+
+ ObjectTypeDB::bind_method(_MD("clear_filters"),&EditorFileDialog::clear_filters);
+ ObjectTypeDB::bind_method(_MD("add_filter","filter"),&EditorFileDialog::add_filter);
+ ObjectTypeDB::bind_method(_MD("get_current_dir"),&EditorFileDialog::get_current_dir);
+ ObjectTypeDB::bind_method(_MD("get_current_file"),&EditorFileDialog::get_current_file);
+ ObjectTypeDB::bind_method(_MD("get_current_path"),&EditorFileDialog::get_current_path);
+ ObjectTypeDB::bind_method(_MD("set_current_dir","dir"),&EditorFileDialog::set_current_dir);
+ ObjectTypeDB::bind_method(_MD("set_current_file","file"),&EditorFileDialog::set_current_file);
+ ObjectTypeDB::bind_method(_MD("set_current_path","path"),&EditorFileDialog::set_current_path);
+ ObjectTypeDB::bind_method(_MD("set_mode","mode"),&EditorFileDialog::set_mode);
+ ObjectTypeDB::bind_method(_MD("get_mode"),&EditorFileDialog::get_mode);
+ ObjectTypeDB::bind_method(_MD("get_vbox:VBoxContainer"),&EditorFileDialog::get_vbox);
+ ObjectTypeDB::bind_method(_MD("set_access","access"),&EditorFileDialog::set_access);
+ ObjectTypeDB::bind_method(_MD("get_access"),&EditorFileDialog::get_access);
+ ObjectTypeDB::bind_method(_MD("set_show_hidden_files"),&EditorFileDialog::set_show_hidden_files);
+ ObjectTypeDB::bind_method(_MD("is_showing_hidden_files"),&EditorFileDialog::is_showing_hidden_files);
+ ObjectTypeDB::bind_method(_MD("_select_drive"),&EditorFileDialog::_select_drive);
+ ObjectTypeDB::bind_method(_MD("_make_dir"),&EditorFileDialog::_make_dir);
+ ObjectTypeDB::bind_method(_MD("_make_dir_confirm"),&EditorFileDialog::_make_dir_confirm);
+ ObjectTypeDB::bind_method(_MD("_update_file_list"),&EditorFileDialog::update_file_list);
+ ObjectTypeDB::bind_method(_MD("_update_dir"),&EditorFileDialog::update_dir);
+ ObjectTypeDB::bind_method(_MD("_thumbnail_done"),&EditorFileDialog::_thumbnail_done);
+
+ ObjectTypeDB::bind_method(_MD("invalidate"),&EditorFileDialog::invalidate);
+
+ ADD_SIGNAL(MethodInfo("file_selected",PropertyInfo( Variant::STRING,"path")));
+ ADD_SIGNAL(MethodInfo("files_selected",PropertyInfo( Variant::STRING_ARRAY,"paths")));
+ ADD_SIGNAL(MethodInfo("dir_selected",PropertyInfo( Variant::STRING,"dir")));
+
+ BIND_CONSTANT( MODE_OPEN_FILE );
+ BIND_CONSTANT( MODE_OPEN_FILES );
+ BIND_CONSTANT( MODE_OPEN_DIR );
+ BIND_CONSTANT( MODE_SAVE_FILE );
+
+ BIND_CONSTANT( ACCESS_RESOURCES );
+ BIND_CONSTANT( ACCESS_USERDATA );
+ BIND_CONSTANT( ACCESS_FILESYSTEM );
+
+}
+
+
+void EditorFileDialog::set_show_hidden_files(bool p_show) {
+ show_hidden_files=p_show;
+ invalidate();
+}
+
+bool EditorFileDialog::is_showing_hidden_files() const {
+ return show_hidden_files;
+}
+
+void EditorFileDialog::set_default_show_hidden_files(bool p_show) {
+ default_show_hidden_files=p_show;
+}
+
+EditorFileDialog::EditorFileDialog() {
+
+ show_hidden_files=true;
+
+ VBoxContainer *vbc = memnew( VBoxContainer );
+ add_child(vbc);
+ set_child_rect(vbc);
+
+ mode=MODE_SAVE_FILE;
+ set_title("Save a File");
+
+ dir = memnew(LineEdit);
+ HBoxContainer *pathhb = memnew( HBoxContainer );
+ pathhb->add_child(dir);
+ dir->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ drives = memnew( OptionButton );
+ pathhb->add_child(drives);
+ drives->connect("item_selected",this,"_select_drive");
+
+ makedir = memnew( Button );
+ makedir->set_text("Create Folder");
+ makedir->connect("pressed",this,"_make_dir");
+ pathhb->add_child(makedir);
+
+ vbc->add_margin_child("Path:",pathhb);
+
+ list_hb = memnew( HBoxContainer );
+ vbc->add_margin_child("Directories & Files:",list_hb,true);
+
+ tree = memnew(Tree);
+ tree->set_hide_root(true);
+ tree->set_h_size_flags(SIZE_EXPAND_FILL);
+ list_hb->add_child(tree);
+
+ HBoxContainer* filter_hb = memnew( HBoxContainer );
+ vbc->add_child(filter_hb);
+
+ VBoxContainer *filter_vb = memnew( VBoxContainer );
+ filter_hb->add_child(filter_vb);
+ filter_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ preview_vb = memnew( VBoxContainer );
+ filter_hb->add_child(preview_vb);
+ CenterContainer *prev_cc = memnew( CenterContainer );
+ preview_vb->add_margin_child("Preview:",prev_cc);
+ preview = memnew( TextureFrame );
+ prev_cc->add_child(preview);
+ preview_vb->hide();
+
+
+ file = memnew(LineEdit);
+ //add_child(file);
+ filter_vb->add_margin_child("File:",file);
+
+
+ filter = memnew( OptionButton );
+ //add_child(filter);
+ filter_vb->add_margin_child("Filter:",filter);
+ filter->set_clip_text(true);//too many extensions overflow it
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ access=ACCESS_RESOURCES;
+ _update_drives();
+
+
+ connect("confirmed", this,"_action_pressed");
+ //cancel->connect("pressed", this,"_cancel_pressed");
+ tree->connect("cell_selected", this,"_tree_selected",varray(),CONNECT_DEFERRED);
+ tree->connect("item_activated", this,"_tree_db_selected",varray());
+ dir->connect("text_entered", this,"_dir_entered");
+ file->connect("text_entered", this,"_file_entered");
+ filter->connect("item_selected", this,"_filter_selected");
+
+
+ confirm_save = memnew( ConfirmationDialog );
+ confirm_save->set_as_toplevel(true);
+ add_child(confirm_save);
+
+
+ confirm_save->connect("confirmed", this,"_save_confirm_pressed");
+
+ makedialog = memnew( ConfirmationDialog );
+ makedialog->set_title("Create Folder");
+ VBoxContainer *makevb= memnew( VBoxContainer );
+ makedialog->add_child(makevb);
+ makedialog->set_child_rect(makevb);
+ makedirname = memnew( LineEdit );
+ makevb->add_margin_child("Name:",makedirname);
+ add_child(makedialog);
+ makedialog->register_text_enter(makedirname);
+ makedialog->connect("confirmed",this,"_make_dir_confirm");
+ mkdirerr = memnew( AcceptDialog );
+ mkdirerr->set_text("Could not create folder.");
+ add_child(mkdirerr);
+
+ exterr = memnew( AcceptDialog );
+ exterr->set_text("Must use a valid extension.");
+ add_child(exterr);
+
+
+ //update_file_list();
+ update_filters();
+ update_dir();
+
+ set_hide_on_ok(false);
+ vbox=vbc;
+
+
+ invalidated=true;
+ if (register_func)
+ register_func(this);
+
+ preview_wheel_timeout=0;
+ preview_wheel_index=0;
+ preview_waiting=false;
+
+}
+
+
+EditorFileDialog::~EditorFileDialog() {
+
+ if (unregister_func)
+ unregister_func(this);
+ memdelete(dir_access);
+}
+
+
+void EditorLineEditFileChooser::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_browse"),&EditorLineEditFileChooser::_browse);
+ ObjectTypeDB::bind_method(_MD("_chosen"),&EditorLineEditFileChooser::_chosen);
+ ObjectTypeDB::bind_method(_MD("get_button:Button"),&EditorLineEditFileChooser::get_button);
+ ObjectTypeDB::bind_method(_MD("get_line_edit:LineEdit"),&EditorLineEditFileChooser::get_line_edit);
+ ObjectTypeDB::bind_method(_MD("get_file_dialog:EditorFileDialog"),&EditorLineEditFileChooser::get_file_dialog);
+
+}
+
+void EditorLineEditFileChooser::_chosen(const String& p_text){
+
+ line_edit->set_text(p_text);
+ line_edit->emit_signal("text_entered",p_text);
+}
+
+void EditorLineEditFileChooser::_browse() {
+
+ dialog->popup_centered_ratio();
+}
+
+EditorLineEditFileChooser::EditorLineEditFileChooser() {
+
+ line_edit = memnew( LineEdit );
+ add_child(line_edit);
+ line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ button = memnew( Button );
+ button->set_text(" .. ");
+ add_child(button);
+ button->connect("pressed",this,"_browse");
+ dialog = memnew( EditorFileDialog);
+ add_child(dialog);
+ dialog->connect("file_selected",this,"_chosen");
+ dialog->connect("dir_selected",this,"_chosen");
+ dialog->connect("files_selected",this,"_chosen");
+
+}
diff --git a/tools/editor/editor_file_dialog.h b/tools/editor/editor_file_dialog.h
new file mode 100644
index 0000000000..72b8848788
--- /dev/null
+++ b/tools/editor/editor_file_dialog.h
@@ -0,0 +1,198 @@
+/*************************************************************************/
+/* file_dialog.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 EDITORFILEDIALOG_H
+#define EDITORFILEDIALOG_H
+
+#include "scene/gui/dialogs.h"
+#include "scene/gui/tree.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/dialogs.h"
+#include "os/dir_access.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/texture_frame.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class EditorFileDialog : public ConfirmationDialog {
+
+ OBJ_TYPE( EditorFileDialog, ConfirmationDialog );
+
+public:
+
+ enum Access {
+ ACCESS_RESOURCES,
+ ACCESS_USERDATA,
+ ACCESS_FILESYSTEM
+ };
+
+
+ enum Mode {
+ MODE_OPEN_FILE,
+ MODE_OPEN_FILES,
+ MODE_OPEN_DIR,
+ MODE_SAVE_FILE,
+ };
+
+ typedef Ref<Texture> (*GetIconFunc)(const String&);
+ typedef void (*RegisterFunc)(EditorFileDialog*);
+
+ static GetIconFunc get_icon_func;
+ static GetIconFunc get_large_icon_func;
+ static RegisterFunc register_func;
+ static RegisterFunc unregister_func;
+
+private:
+
+ ConfirmationDialog *makedialog;
+ LineEdit *makedirname;
+
+ Button *makedir;
+ Access access;
+ //Button *action;
+ VBoxContainer *vbox;
+ Mode mode;
+ LineEdit *dir;
+ OptionButton *drives;
+ Tree *tree;
+ TextureFrame *preview;
+ VBoxContainer *preview_vb;
+ HBoxContainer *list_hb;
+ LineEdit *file;
+ AcceptDialog *mkdirerr;
+ AcceptDialog *exterr;
+ OptionButton *filter;
+ DirAccess *dir_access;
+ ConfirmationDialog *confirm_save;
+
+ Vector<String> filters;
+
+ bool preview_waiting;
+ int preview_wheel_index;
+ float preview_wheel_timeout;
+ static bool default_show_hidden_files;
+ bool show_hidden_files;
+
+ bool invalidated;
+
+ void update_dir();
+ void update_file_list();
+ void update_filters();
+
+ void _tree_selected();
+
+ void _select_drive(int p_idx);
+ void _tree_dc_selected();
+ void _dir_entered(String p_dir);
+ void _file_entered(const String& p_file);
+ void _action_pressed();
+ void _save_confirm_pressed();
+ void _cancel_pressed();
+ void _filter_selected(int);
+ void _make_dir();
+ void _make_dir_confirm();
+
+ void _update_drives();
+
+ virtual void _post_popup();
+
+
+ //callback funtion is callback(String p_path,Ref<Texture> preview,Variant udata) preview null if could not load
+
+ void _thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata);
+ void _request_single_thumbnail(const String& p_path);
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+ //bind helpers
+public:
+
+ void clear_filters();
+ void add_filter(const String& p_filter);
+
+ void set_enable_multiple_selection(bool p_enable);
+ Vector<String> get_selected_files() const;
+
+ String get_current_dir() const;
+ String get_current_file() const;
+ String get_current_path() const;
+ void set_current_dir(const String& p_dir);
+ void set_current_file(const String& p_file);
+ void set_current_path(const String& p_path);
+
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
+ VBoxContainer *get_vbox();
+ LineEdit *get_line_edit() { return file; }
+
+ void set_access(Access p_access);
+ Access get_access() const;
+
+ void set_show_hidden_files(bool p_show);
+ bool is_showing_hidden_files() const;
+
+ static void set_default_show_hidden_files(bool p_show);
+
+ void invalidate();
+
+ EditorFileDialog();
+ ~EditorFileDialog();
+
+};
+
+class EditorLineEditFileChooser : public HBoxContainer {
+
+ OBJ_TYPE( EditorLineEditFileChooser, HBoxContainer );
+ Button *button;
+ LineEdit *line_edit;
+ EditorFileDialog *dialog;
+
+ void _chosen(const String& p_text);
+ void _browse();
+protected:
+ static void _bind_methods();
+public:
+
+ Button *get_button() { return button; }
+ LineEdit *get_line_edit() { return line_edit; }
+ EditorFileDialog *get_file_dialog() { return dialog; }
+
+ EditorLineEditFileChooser();
+};
+
+VARIANT_ENUM_CAST( EditorFileDialog::Mode );
+VARIANT_ENUM_CAST( EditorFileDialog::Access );
+
+#endif // EDITORFILEDIALOG_H
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp
index 7157dbda96..500f8d232e 100644
--- a/tools/editor/editor_node.cpp
+++ b/tools/editor/editor_node.cpp
@@ -99,6 +99,7 @@
#include "tools/editor/io_plugins/editor_translation_import_plugin.h"
#include "tools/editor/io_plugins/editor_mesh_import_plugin.h"
+#include "plugins/editor_preview_plugins.h"
EditorNode *EditorNode::singleton=NULL;
@@ -320,6 +321,11 @@ void EditorNode::_fs_changed() {
E->get()->invalidate();
}
+
+ for(Set<EditorFileDialog*>::Element *E=editor_file_dialogs.front();E;E=E->next()) {
+
+ E->get()->invalidate();
+ }
}
void EditorNode::_sources_changed(bool p_exist) {
@@ -386,7 +392,7 @@ void EditorNode::edit_node(Node *p_node) {
void EditorNode::open_resource(const String& p_type) {
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type(p_type,&extensions);
@@ -718,6 +724,96 @@ void EditorNode::_save_edited_subresources(Node* scene,Map<RES,bool>& processed,
}
+void EditorNode::_find_node_types(Node* p_node, int&count_2d, int&count_3d) {
+
+ if (p_node->is_type("Viewport") || (p_node!=get_edited_scene() && p_node->get_owner()!=get_edited_scene()))
+ return;
+
+ if (p_node->is_type("CanvasItem"))
+ count_2d++;
+ else if (p_node->is_type("Spatial"))
+ count_3d++;
+
+ for(int i=0;i<p_node->get_child_count();i++)
+ _find_node_types(p_node->get_child(i),count_2d,count_3d);
+
+}
+
+
+void EditorNode::_save_scene_with_preview(String p_file) {
+
+ int c2d=0;
+ int c3d=0;
+
+ EditorProgress save("save","Saving Scene",4);
+ save.step("Analyzing",0);
+ _find_node_types(get_edited_scene(),c2d,c3d);
+
+ RID viewport;
+ bool is2d;
+ if (c3d<c2d) {
+ viewport=scene_root->get_viewport();
+ is2d=true;
+ } else {
+ viewport=SpatialEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_viewport();
+ is2d=false;
+
+ }
+ save.step("Creating Thumbnail",1);
+ //current view?
+ int screen =-1;
+ for(int i=0;i<editor_table.size();i++) {
+ if (editor_plugin_screen==editor_table[i]) {
+ screen=i;
+ break;
+ }
+ }
+
+ _editor_select(is2d?0:1);
+
+ VS::get_singleton()->viewport_queue_screen_capture(viewport);
+ save.step("Creating Thumbnail",2);
+ save.step("Creating Thumbnail",3);
+ Image img = VS::get_singleton()->viewport_get_screen_capture(viewport);
+ int preview_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");;
+ int width,height;
+ if (img.get_width() > preview_size && img.get_width() >= img.get_height()) {
+
+ width=preview_size;
+ height = img.get_height() * preview_size / img.get_width();
+ } else if (img.get_height() > preview_size && img.get_height() >= img.get_width()) {
+
+ height=preview_size;
+ width = img.get_width() * preview_size / img.get_height();
+ } else {
+
+ width=img.get_width();
+ height=img.get_height();
+ }
+
+ img.convert(Image::FORMAT_RGB);
+ img.resize(width,height);
+
+ String pfile = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/last_scene_preview.png");
+ img.save_png(pfile);
+ Vector<uint8_t> imgdata = FileAccess::get_file_as_array(pfile);
+
+ print_line("img data is "+itos(imgdata.size()));
+
+ if (scene_import_metadata.is_null())
+ scene_import_metadata = Ref<ResourceImportMetadata>( memnew( ResourceImportMetadata ) );
+ scene_import_metadata->set_option("thumbnail",imgdata);
+
+ //tamanio tel thumbnail
+ if (screen!=-1) {
+ _editor_select(screen);
+ }
+ save.step("Saving Scene",4);
+ _save_scene(p_file);
+
+}
+
+
void EditorNode::_save_scene(String p_file) {
Node *scene = edited_scene;
@@ -1016,7 +1112,9 @@ void EditorNode::_dialog_action(String p_file) {
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
- _save_scene(p_file);
+ //_save_scene(p_file);
+ _save_scene_with_preview(p_file);
+
}
} break;
@@ -1024,7 +1122,8 @@ void EditorNode::_dialog_action(String p_file) {
case FILE_SAVE_AND_RUN: {
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
- _save_scene(p_file);
+ //_save_scene(p_file);
+ _save_scene_with_preview(p_file);
_run(false);
}
} break;
@@ -1177,7 +1276,8 @@ void EditorNode::_dialog_action(String p_file) {
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
- _save_scene(p_file);
+ //_save_scene(p_file);
+ _save_scene_with_preview(p_file);
}
} break;
@@ -1505,7 +1605,8 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
return;
}
- _save_scene(scene->get_filename());
+ //_save_scene(scene->get_filename());
+ _save_scene_with_preview(scene->get_filename());
}
}
@@ -1608,7 +1709,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//print_tree();
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
//not for now?
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene",&extensions);
@@ -1659,7 +1760,8 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
Node *scene = edited_scene;
if (scene && scene->get_filename()!="") {
- _save_scene(scene->get_filename());
+ //_save_scene(scene->get_filename());
+ _save_scene_with_preview(scene->get_filename());
return;
};
// fallthrough to save_as
@@ -1678,7 +1780,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
break;
}
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
bool relpaths = (scene->has_meta("__editor_relpaths__") && scene->get_meta("__editor_relpaths__").operator bool());
@@ -1761,7 +1863,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
bool relpaths = (scene->has_meta("__editor_relpaths__") && scene->get_meta("__editor_relpaths__").operator bool());
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
file->set_current_path(cpath);
file->set_title("Save Translatable Strings");
@@ -1810,7 +1912,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
break;
}
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
List<String> extensions;
Ref<PackedScene> sd = memnew( PackedScene );
@@ -3132,6 +3234,7 @@ void EditorNode::register_editor_types() {
ObjectTypeDB::register_type<EditorImportPlugin>();
ObjectTypeDB::register_type<EditorScenePostImport>();
ObjectTypeDB::register_type<EditorScript>();
+ ObjectTypeDB::register_type<EditorFileDialog>();
//ObjectTypeDB::register_type<EditorImporter>();
@@ -3282,6 +3385,16 @@ void EditorNode::_file_dialog_unregister(FileDialog *p_dialog){
singleton->file_dialogs.erase(p_dialog);
}
+void EditorNode::_editor_file_dialog_register(EditorFileDialog *p_dialog) {
+
+ singleton->editor_file_dialogs.insert(p_dialog);
+}
+
+void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog){
+
+ singleton->editor_file_dialogs.erase(p_dialog);
+}
+
Vector<EditorNodeInitCallback> EditorNode::_init_callbacks;
Error EditorNode::export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after) {
@@ -3334,6 +3447,11 @@ EditorNode::EditorNode() {
FileDialog::register_func=_file_dialog_register;
FileDialog::unregister_func=_file_dialog_unregister;
+ EditorFileDialog::get_icon_func=_file_dialog_get_icon;
+ EditorFileDialog::register_func=_editor_file_dialog_register;
+ EditorFileDialog::unregister_func=_editor_file_dialog_unregister;
+
+
editor_import_export = memnew( EditorImportExport );
add_child(editor_import_export);
@@ -3358,6 +3476,9 @@ EditorNode::EditorNode() {
editor_register_icons(theme);
editor_register_fonts(theme);
+ //theme->set_icon("folder","EditorFileDialog",Theme::get_default()->get_icon("folder","EditorFileDialog"));
+ //theme->set_color("files_disabled","EditorFileDialog",Color(0,0,0,0.7));
+
String global_font = EditorSettings::get_singleton()->get("global/font");
if (global_font!="") {
Ref<Font> fnt = ResourceLoader::load(global_font);
@@ -3376,6 +3497,8 @@ EditorNode::EditorNode() {
theme->set_stylebox("EditorFocus","EditorStyles",focus_sbt);
+ resource_preview = memnew( EditorResourcePreview );
+ add_child(resource_preview);
progress_dialog = memnew( ProgressDialog );
gui_base->add_child(progress_dialog);
@@ -3473,6 +3596,7 @@ EditorNode::EditorNode() {
animation_panel=pc;
animation_panel->hide();
+
HBoxContainer *animation_hb = memnew( HBoxContainer);
animation_vb->add_child(animation_hb);
@@ -4031,7 +4155,7 @@ EditorNode::EditorNode() {
file_templates->add_filter("*.tpz ; Template Package");
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
gui_base->add_child(file);
file->set_current_dir("res://");
@@ -4161,6 +4285,13 @@ EditorNode::EditorNode() {
for(int i=0;i<EditorPlugins::get_plugin_count();i++)
add_editor_plugin( EditorPlugins::create(i,this) );
+
+ resource_preview->add_preview_generator( Ref<EditorTexturePreviewPlugin>( memnew(EditorTexturePreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorPackedScenePreviewPlugin>( memnew(EditorPackedScenePreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorMaterialPreviewPlugin>( memnew(EditorMaterialPreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorScriptPreviewPlugin>( memnew(EditorScriptPreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorSamplePreviewPlugin>( memnew(EditorSamplePreviewPlugin )));
+
circle_step_msec=OS::get_singleton()->get_ticks_msec();
circle_step_frame=OS::get_singleton()->get_frames_drawn();;
circle_step=0;
diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h
index 614cec5bcc..365dff84ee 100644
--- a/tools/editor/editor_node.h
+++ b/tools/editor/editor_node.h
@@ -78,7 +78,7 @@
#include "tools/editor/editor_plugin.h"
#include "fileserver/editor_file_server.h"
-
+#include "editor_resource_preview.h"
@@ -238,7 +238,7 @@ class EditorNode : public Node {
EditorSettingsDialog *settings_config_dialog;
RunSettingsDialog *run_settings_dialog;
ProjectSettings *project_settings;
- FileDialog *file;
+ EditorFileDialog *file;
FileDialog *file_templates;
FileDialog *file_export;
FileDialog *file_export_lib;
@@ -304,6 +304,7 @@ class EditorNode : public Node {
EditorSelection *editor_selection;
ProjectExport *project_export;
ProjectExportDialog *project_export_settings;
+ EditorResourcePreview *resource_preview;
EditorFileServer *file_server;
@@ -381,11 +382,15 @@ class EditorNode : public Node {
String import_reload_fn;
Set<FileDialog*> file_dialogs;
+ Set<EditorFileDialog*> editor_file_dialogs;
+
Map<String,Ref<Texture> > icon_type_cache;
static Ref<Texture> _file_dialog_get_icon(const String& p_path);
static void _file_dialog_register(FileDialog *p_dialog);
static void _file_dialog_unregister(FileDialog *p_dialog);
+ static void _editor_file_dialog_register(EditorFileDialog *p_dialog);
+ static void _editor_file_dialog_unregister(EditorFileDialog *p_dialog);
void _cleanup_scene();
@@ -394,6 +399,9 @@ class EditorNode : public Node {
bool _find_and_save_edited_subresources(Object *obj,Map<RES,bool>& processed,int32_t flags);
void _save_edited_subresources(Node* scene,Map<RES,bool>& processed,int32_t flags);
+ void _find_node_types(Node* p_node, int&count_2d, int&count_3d);
+ void _save_scene_with_preview(String p_file);
+
struct ExportDefer {
String platform;
diff --git a/tools/editor/editor_resource_preview.cpp b/tools/editor/editor_resource_preview.cpp
new file mode 100644
index 0000000000..9b7d8d227e
--- /dev/null
+++ b/tools/editor/editor_resource_preview.cpp
@@ -0,0 +1,260 @@
+#include "editor_resource_preview.h"
+#include "editor_settings.h"
+#include "os/file_access.h"
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "globals.h"
+
+
+Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String& p_path) {
+
+ RES res = ResourceLoader::load(p_path);
+ if (!res.is_valid())
+ return res;
+ return generate(res);
+}
+
+EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() {
+
+
+}
+
+
+EditorResourcePreview* EditorResourcePreview::singleton=NULL;
+
+
+void EditorResourcePreview::_thread_func(void *ud) {
+
+ EditorResourcePreview *erp=(EditorResourcePreview*)ud;
+ erp->_thread();
+
+}
+
+
+void EditorResourcePreview::_preview_ready(const String& p_str,const Ref<Texture>& p_texture,ObjectID id,const StringName& p_func,const Variant& p_ud) {
+
+ print_line("preview is ready");
+ preview_mutex->lock();
+
+ Item item;
+ item.order=order++;
+ item.preview=p_texture;
+ cache[p_str]=item;
+
+ Object *recv = ObjectDB::get_instance(id);
+ if (recv) {
+ recv->call_deferred(p_func,p_str,p_texture,p_ud);
+ }
+
+ preview_mutex->unlock();
+}
+
+Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem& p_item,const String& cache_base) {
+
+ String type = ResourceLoader::get_resource_type(p_item.path);
+ print_line("resource type is: "+type);
+
+ if (type=="")
+ return Ref<Texture>(); //could not guess type
+
+ Ref<Texture> generated;
+
+ for(int i=0;i<preview_generators.size();i++) {
+ if (!preview_generators[i]->handles(type))
+ continue;
+ generated = preview_generators[i]->generate_from_path(p_item.path);
+
+ break;
+ }
+
+ if (generated.is_valid()) {
+ print_line("was generated");
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ //wow it generated a preview... save cache
+ ResourceSaver::save(cache_base+".png",generated);
+ FileAccess *f=FileAccess::open(cache_base+".txt",FileAccess::WRITE);
+ f->store_line(itos(thumbnail_size));
+ f->store_line(itos(FileAccess::get_modified_time(p_item.path)));
+ f->store_line(FileAccess::get_md5(p_item.path));
+ memdelete(f);
+ } else {
+ print_line("was not generated");
+
+ }
+
+ return generated;
+}
+
+void EditorResourcePreview::_thread() {
+
+ print_line("begin thread");
+ while(!exit) {
+
+ print_line("wait for semaphore");
+ preview_sem->wait();
+ preview_mutex->lock();
+
+ print_line("blue team go");
+
+ if (queue.size()) {
+
+ print_line("pop from queue");
+
+ QueueItem item = queue.front()->get();
+ queue.pop_front();
+ preview_mutex->unlock();
+
+ Ref<Texture> texture;
+
+
+ uint64_t modtime = FileAccess::get_modified_time(item.path);
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+
+ if (cache.has(item.path)) {
+ //already has it because someone loaded it, just let it know it's ready
+ call_deferred("_preview_ready",item.path,cache[item.path].preview,item.id,item.function,item.userdata);
+
+ } else {
+
+
+ String temp_path=EditorSettings::get_singleton()->get_settings_path().plus_file("tmp");
+ String cache_base = Globals::get_singleton()->globalize_path(item.path).md5_text();
+ cache_base = temp_path.plus_file("resthumb-"+cache_base);
+
+ //does not have it, try to load a cached thumbnail
+
+ String file = cache_base+".txt";
+ print_line("cachetxt at "+file);
+ FileAccess *f=FileAccess::open(file,FileAccess::READ);
+ if (!f) {
+
+ print_line("generate because not cached");
+
+ //generate
+ texture=_generate_preview(item,cache_base);
+ } else {
+
+ int tsize = f->get_line().to_int64();
+ uint64_t last_modtime = f->get_line().to_int64();
+
+ bool cache_valid = true;
+
+ if (tsize!=thumbnail_size) {
+ cache_valid=false;
+ memdelete(f);
+ } else if (last_modtime!=modtime) {
+
+ String last_md5 = f->get_line();
+ String md5 = FileAccess::get_md5(item.path);
+ memdelete(f);
+
+ if (last_md5!=md5) {
+
+ cache_valid=false;
+ } else {
+ //update modified time
+
+ f=FileAccess::open(file,FileAccess::WRITE);
+ f->store_line(itos(modtime));
+ f->store_line(md5);
+ memdelete(f);
+ }
+ } else {
+ memdelete(f);
+ }
+
+ if (cache_valid) {
+
+ texture = ResourceLoader::load(cache_base+".png","ImageTexture",true);
+ if (!texture.is_valid()) {
+ //well fuck
+ cache_valid=false;
+ }
+ }
+
+ if (!cache_valid) {
+
+ texture=_generate_preview(item,cache_base);
+ }
+
+ }
+
+ print_line("notify of preview ready");
+ call_deferred("_preview_ready",item.path,texture,item.id,item.function,item.userdata);
+
+ }
+
+ } else {
+ preview_mutex->unlock();
+ }
+
+ }
+}
+
+
+
+
+void EditorResourcePreview::queue_resource_preview(const String& p_path, Object* p_receiver, const StringName& p_receiver_func, const Variant& p_userdata) {
+
+ ERR_FAIL_NULL(p_receiver);
+ preview_mutex->lock();
+ if (cache.has(p_path)) {
+ cache[p_path].order=order++;
+ p_receiver->call_deferred(p_receiver_func,p_path,cache[p_path].preview,p_userdata);
+ preview_mutex->unlock();
+ return;
+
+ }
+
+ print_line("send to thread");
+ QueueItem item;
+ item.function=p_receiver_func;
+ item.id=p_receiver->get_instance_ID();
+ item.path=p_path;
+ item.userdata=p_userdata;
+
+ queue.push_back(item);
+ preview_mutex->unlock();
+ preview_sem->post();
+
+}
+
+void EditorResourcePreview::add_preview_generator(const Ref<EditorResourcePreviewGenerator>& p_generator) {
+
+ preview_generators.push_back(p_generator);
+}
+
+EditorResourcePreview* EditorResourcePreview::get_singleton() {
+
+ return singleton;
+}
+
+void EditorResourcePreview::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_preview_ready",&EditorResourcePreview::_preview_ready);
+}
+
+EditorResourcePreview::EditorResourcePreview() {
+ singleton=this;
+ preview_mutex = Mutex::create();
+ preview_sem = Semaphore::create();
+ order=0;
+ exit=false;
+
+ thread = Thread::create(_thread_func,this);
+}
+
+
+EditorResourcePreview::~EditorResourcePreview()
+{
+
+ exit=true;
+ preview_sem->post();
+ Thread::wait_to_finish(thread);
+ memdelete(thread);
+ memdelete(preview_mutex);
+ memdelete(preview_sem);
+
+
+}
+
diff --git a/tools/editor/editor_resource_preview.h b/tools/editor/editor_resource_preview.h
new file mode 100644
index 0000000000..f8b96eca22
--- /dev/null
+++ b/tools/editor/editor_resource_preview.h
@@ -0,0 +1,95 @@
+#ifndef EDITORRESOURCEPREVIEW_H
+#define EDITORRESOURCEPREVIEW_H
+
+#include "scene/main/node.h"
+#include "os/semaphore.h"
+#include "os/thread.h"
+#include "scene/resources/texture.h"
+
+/* make previews for:
+*packdscene
+-wav
+*image
+-mesh
+-font
+*script
+*material
+-shader
+-shader graph?
+-navigation mesh
+-collision?
+-occluder polygon
+-navigation polygon
+-tileset
+-curve and curve2D
+*/
+
+
+class EditorResourcePreviewGenerator : public Reference {
+
+ OBJ_TYPE(EditorResourcePreviewGenerator,Reference );
+
+public:
+
+ virtual bool handles(const String& p_type) const=0;
+ virtual Ref<Texture> generate(const RES& p_from)=0;
+ virtual Ref<Texture> generate_from_path(const String& p_path);
+
+ EditorResourcePreviewGenerator();
+};
+
+
+class EditorResourcePreview : public Node {
+
+ OBJ_TYPE(EditorResourcePreview,Node);
+
+
+ static EditorResourcePreview* singleton;
+
+ struct QueueItem {
+ String path;
+ ObjectID id;
+ StringName function;
+ Variant userdata;
+ };
+
+ List<QueueItem> queue;
+
+ Mutex *preview_mutex;
+ Semaphore *preview_sem;
+ Thread *thread;
+ bool exit;
+
+ struct Item {
+ Ref<Texture> preview;
+ int order;
+ };
+
+ int order;
+
+ Map<String,Item> cache;
+
+ void _preview_ready(const String& p_str,const Ref<Texture>& p_texture, ObjectID id, const StringName &p_func, const Variant &p_ud);
+ Ref<Texture> _generate_preview(const QueueItem& p_item, const String &cache_base);
+
+ static void _thread_func(void *ud);
+ void _thread();
+
+ Vector<Ref<EditorResourcePreviewGenerator> > preview_generators;
+protected:
+
+ static void _bind_methods();
+public:
+
+ static EditorResourcePreview* get_singleton();
+
+ //callback funtion is callback(String p_path,Ref<Texture> preview,Variant udata) preview null if could not load
+ void queue_resource_preview(const String& p_path, Object* p_receiver, const StringName& p_receiver_func, const Variant& p_userdata);
+
+ void add_preview_generator(const Ref<EditorResourcePreviewGenerator>& p_generator);
+
+ EditorResourcePreview();
+ ~EditorResourcePreview();
+};
+
+#endif // EDITORRESOURCEPREVIEW_H
diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp
index f49d3b496d..2fac05753a 100644
--- a/tools/editor/editor_settings.cpp
+++ b/tools/editor/editor_settings.cpp
@@ -448,6 +448,8 @@ void EditorSettings::_load_defaults() {
set("text_editor/create_signal_callbacks",true);
set("file_dialog/show_hidden_files", false);
+ set("file_dialog/thumbnail_size", 64);
+ hints["file_dialog/thumbnail_size"]=PropertyInfo(Variant::INT,"file_dialog/thumbnail_size",PROPERTY_HINT_RANGE,"32,128,16");
set("animation/autorename_animation_tracks",true);
set("animation/confirm_insert_track",true);
diff --git a/tools/editor/icons/icon_wait_no_preview.png b/tools/editor/icons/icon_wait_no_preview.png
new file mode 100644
index 0000000000..5d20cd99ec
--- /dev/null
+++ b/tools/editor/icons/icon_wait_no_preview.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_1.png b/tools/editor/icons/icon_wait_preview_1.png
new file mode 100644
index 0000000000..0aab42e04a
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_1.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_2.png b/tools/editor/icons/icon_wait_preview_2.png
new file mode 100644
index 0000000000..f476b9ce1f
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_2.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_3.png b/tools/editor/icons/icon_wait_preview_3.png
new file mode 100644
index 0000000000..2775d1ef43
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_3.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_4.png b/tools/editor/icons/icon_wait_preview_4.png
new file mode 100644
index 0000000000..2eaa86fec9
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_4.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_5.png b/tools/editor/icons/icon_wait_preview_5.png
new file mode 100644
index 0000000000..6590644bc1
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_5.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_6.png b/tools/editor/icons/icon_wait_preview_6.png
new file mode 100644
index 0000000000..307e412310
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_6.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_7.png b/tools/editor/icons/icon_wait_preview_7.png
new file mode 100644
index 0000000000..b0edc94d93
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_7.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_8.png b/tools/editor/icons/icon_wait_preview_8.png
new file mode 100644
index 0000000000..67a2f48ec3
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_8.png
Binary files differ
diff --git a/tools/editor/plugins/editor_preview_plugins.cpp b/tools/editor/plugins/editor_preview_plugins.cpp
new file mode 100644
index 0000000000..64814cce6a
--- /dev/null
+++ b/tools/editor/plugins/editor_preview_plugins.cpp
@@ -0,0 +1,664 @@
+#include "editor_preview_plugins.h"
+#include "io/resource_loader.h"
+#include "tools/editor/editor_settings.h"
+#include "io/file_access_memory.h"
+#include "os/os.h"
+#include "scene/resources/material.h"
+#include "scene/resources/sample.h"
+
+bool EditorTexturePreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"ImageTexture");
+}
+
+Ref<Texture> EditorTexturePreviewPlugin::generate(const RES& p_from) {
+
+ Ref<ImageTexture> tex =p_from;
+ Image img = tex->get_data();
+ if (img.empty())
+ return Ref<Texture>();
+
+ img.clear_mipmaps();
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ if (img.is_compressed()) {
+ if (img.decompress()!=OK)
+ return Ref<Texture>();
+ } else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGB) {
+ img.convert(Image::FORMAT_RGBA);
+ }
+
+ int width,height;
+ if (img.get_width() > thumbnail_size && img.get_width() >= img.get_height()) {
+
+ width=thumbnail_size;
+ height = img.get_height() * thumbnail_size / img.get_width();
+ } else if (img.get_height() > thumbnail_size && img.get_height() >= img.get_width()) {
+
+ height=thumbnail_size;
+ width = img.get_width() * thumbnail_size / img.get_height();
+ } else {
+
+ width=img.get_width();
+ height=img.get_height();
+ }
+
+ img.resize(width,height);
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+
+ ptex->create_from_image(img,0);
+ return ptex;
+
+}
+
+EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() {
+
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+
+Ref<Texture> EditorPackedScenePreviewPlugin::_gen_from_imd(Ref<ResourceImportMetadata> p_imd) {
+
+ if (p_imd.is_null())
+ return Ref<Texture>();
+
+ if (!p_imd->has_option("thumbnail"))
+ return Ref<Texture>();
+
+ Variant tn = p_imd->get_option("thumbnail");
+ print_line(Variant::get_type_name(tn.get_type()));
+ DVector<uint8_t> thumbnail = tn;
+
+ int len = thumbnail.size();
+ if (len==0)
+ return Ref<Texture>();
+
+
+ DVector<uint8_t>::Read r = thumbnail.read();
+
+ Image img(r.ptr(),len);
+ if (img.empty())
+ return Ref<Texture>();
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+ ptex->create_from_image(img,0);
+ return ptex;
+
+}
+
+bool EditorPackedScenePreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"PackedScene");
+}
+Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES& p_from) {
+
+ Ref<ResourceImportMetadata> imd = p_from->get_import_metadata();
+ return _gen_from_imd(imd);
+}
+
+Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String& p_path) {
+
+ Ref<ResourceImportMetadata> imd = ResourceLoader::load_import_metadata(p_path);
+ return _gen_from_imd(imd);
+}
+
+EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
+
+}
+
+//////////////////////////////////////////////////////////////////
+
+bool EditorMaterialPreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Material"); //any material
+}
+
+Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES& p_from) {
+
+ Ref<Material> material = p_from;
+ ERR_FAIL_COND_V(material.is_null(),Ref<Texture>());
+
+ VS::get_singleton()->mesh_surface_set_material(sphere,0,material->get_rid());
+
+ VS::get_singleton()->viewport_queue_screen_capture(viewport);
+ VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_ONCE); //once used for capture
+// print_line("queue capture!");
+ Image img;
+
+ int timeout=1000;
+ while(timeout) {
+ //print_line("try capture?");
+ OS::get_singleton()->delay_usec(10);
+ img = VS::get_singleton()->viewport_get_screen_capture(viewport);
+ if (!img.empty())
+ break;
+ timeout--;
+ }
+
+ //print_line("captured!");
+ VS::get_singleton()->mesh_surface_set_material(sphere,0,RID());
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ img.resize(thumbnail_size,thumbnail_size);
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+ ptex->create_from_image(img,0);
+ return ptex;
+}
+
+EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
+
+ scenario = VS::get_singleton()->scenario_create();
+
+ viewport = VS::get_singleton()->viewport_create();
+ VS::get_singleton()->viewport_set_as_render_target(viewport,true);
+ VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_DISABLED);
+ VS::get_singleton()->viewport_set_scenario(viewport,scenario);
+ VS::ViewportRect vr;
+ vr.x=0;
+ vr.y=0;
+ vr.width=128;
+ vr.height=128;
+ VS::get_singleton()->viewport_set_rect(viewport,vr);
+
+ camera = VS::get_singleton()->camera_create();
+ VS::get_singleton()->viewport_attach_camera(viewport,camera);
+ VS::get_singleton()->camera_set_transform(camera,Transform(Matrix3(),Vector3(0,0,3)));
+ VS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
+
+ light = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
+ light_instance = VS::get_singleton()->instance_create2(light,scenario);
+ VS::get_singleton()->instance_set_transform(light_instance,Transform().looking_at(Vector3(-1,-1,-1),Vector3(0,1,0)));
+
+ light2 = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
+ VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_DIFFUSE,Color(0.7,0.7,0.7));
+ VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_SPECULAR,Color(0.0,0.0,0.0));
+ light_instance2 = VS::get_singleton()->instance_create2(light2,scenario);
+
+ VS::get_singleton()->instance_set_transform(light_instance2,Transform().looking_at(Vector3(0,1,0),Vector3(0,0,1)));
+
+ sphere = VS::get_singleton()->mesh_create();
+ sphere_instance = VS::get_singleton()->instance_create2(sphere,scenario);
+
+ int lats=32;
+ int lons=32;
+ float radius=1.0;
+
+ DVector<Vector3> vertices;
+ DVector<Vector3> normals;
+ DVector<Vector2> uvs;
+ DVector<float> tangents;
+ Matrix3 tt = Matrix3(Vector3(0,1,0),Math_PI*0.5);
+
+ for(int i = 1; i <= lats; i++) {
+ double lat0 = Math_PI * (-0.5 + (double) (i - 1) / lats);
+ double z0 = Math::sin(lat0);
+ double zr0 = Math::cos(lat0);
+
+ double lat1 = Math_PI * (-0.5 + (double) i / lats);
+ double z1 = Math::sin(lat1);
+ double zr1 = Math::cos(lat1);
+
+ for(int j = lons; j >= 1; j--) {
+
+ double lng0 = 2 * Math_PI * (double) (j - 1) / lons;
+ double x0 = Math::cos(lng0);
+ double y0 = Math::sin(lng0);
+
+ double lng1 = 2 * Math_PI * (double) (j) / lons;
+ double x1 = Math::cos(lng1);
+ double y1 = Math::sin(lng1);
+
+
+ Vector3 v[4]={
+ Vector3(x1 * zr0, z0, y1 *zr0),
+ Vector3(x1 * zr1, z1, y1 *zr1),
+ Vector3(x0 * zr1, z1, y0 *zr1),
+ Vector3(x0 * zr0, z0, y0 *zr0)
+ };
+
+#define ADD_POINT(m_idx) \
+ normals.push_back(v[m_idx]);\
+ vertices.push_back(v[m_idx]*radius);\
+ { Vector2 uv(Math::atan2(v[m_idx].x,v[m_idx].z),Math::atan2(-v[m_idx].y,v[m_idx].z));\
+ uv/=Math_PI;\
+ uv*=4.0;\
+ uv=uv*0.5+Vector2(0.5,0.5);\
+ uvs.push_back(uv);\
+ }\
+ { Vector3 t = tt.xform(v[m_idx]);\
+ tangents.push_back(t.x);\
+ tangents.push_back(t.y);\
+ tangents.push_back(t.z);\
+ tangents.push_back(1.0);\
+ }
+
+
+
+ ADD_POINT(0);
+ ADD_POINT(1);
+ ADD_POINT(2);
+
+ ADD_POINT(2);
+ ADD_POINT(3);
+ ADD_POINT(0);
+ }
+ }
+
+ Array arr;
+ arr.resize(VS::ARRAY_MAX);
+ arr[VS::ARRAY_VERTEX]=vertices;
+ arr[VS::ARRAY_NORMAL]=normals;
+ arr[VS::ARRAY_TANGENT]=tangents;
+ arr[VS::ARRAY_TEX_UV]=uvs;
+ VS::get_singleton()->mesh_add_surface(sphere,VS::PRIMITIVE_TRIANGLES,arr);
+
+}
+
+EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
+
+ VS::get_singleton()->free(sphere);
+ VS::get_singleton()->free(sphere_instance);
+ VS::get_singleton()->free(viewport);
+ VS::get_singleton()->free(light);
+ VS::get_singleton()->free(light_instance);
+ VS::get_singleton()->free(light2);
+ VS::get_singleton()->free(light_instance2);
+ VS::get_singleton()->free(camera);
+ VS::get_singleton()->free(scenario);
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static bool _is_text_char(CharType c) {
+
+ return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
+}
+
+bool EditorScriptPreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Script");
+}
+
+Ref<Texture> EditorScriptPreviewPlugin::generate(const RES& p_from) {
+
+
+ Ref<Script> scr = p_from;
+ if (scr.is_null())
+ return Ref<Texture>();
+
+ String code = scr->get_source_code().strip_edges();
+ if (code=="")
+ return Ref<Texture>();
+
+ List<String> kwors;
+ scr->get_language()->get_reserved_words(&kwors);
+
+ Set<String> keywords;
+
+ for(List<String>::Element *E=kwors.front();E;E=E->next()) {
+
+ keywords.insert(E->get());
+
+ }
+
+
+ int line = 0;
+ int col=0;
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ Image img(thumbnail_size,thumbnail_size,0,Image::FORMAT_RGBA);
+
+
+
+ Color bg_color = EditorSettings::get_singleton()->get("text_editor/background_color");
+ bg_color.a=1.0;
+ Color keyword_color = EditorSettings::get_singleton()->get("text_editor/keyword_color");
+ Color text_color = EditorSettings::get_singleton()->get("text_editor/text_color");
+ Color symbol_color = EditorSettings::get_singleton()->get("text_editor/symbol_color");
+ Color comment_color = EditorSettings::get_singleton()->get("text_editor/comment_color");
+
+
+ for(int i=0;i<thumbnail_size;i++) {
+ for(int j=0;j<thumbnail_size;j++) {
+ img.put_pixel(i,j,bg_color);
+ }
+
+ }
+
+ bool prev_is_text=false;
+ bool in_keyword=false;
+ for(int i=0;i<code.length();i++) {
+
+ CharType c = code[i];
+ if (c>32) {
+ if (col<thumbnail_size) {
+ Color color = text_color;
+
+ if (c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t')) {
+ //make symbol a little visible
+ color=symbol_color;
+ in_keyword=false;
+ } else if (!prev_is_text && _is_text_char(c)) {
+ int pos = i;
+
+ while(_is_text_char(code[pos])) {
+ pos++;
+ }
+ ///print_line("from "+itos(i)+" to "+itos(pos));
+ String word = code.substr(i,pos-i);
+ //print_line("found word: "+word);
+ if (keywords.has(word))
+ in_keyword=true;
+
+ } else if (!_is_text_char(c)) {
+ in_keyword=false;
+ }
+
+ if (in_keyword)
+ color=keyword_color;
+
+ Color ul=color;
+ ul.a*=0.5;
+ img.put_pixel(col,line*2,bg_color.blend(ul));
+ img.put_pixel(col,line*2+1,color);
+
+ prev_is_text=_is_text_char(c);
+ }
+ } else {
+
+ prev_is_text=false;
+ in_keyword=false;
+
+ if (c=='\n') {
+ col=0;
+ line++;
+ if (line>=thumbnail_size/2)
+ break;
+ } else if (c=='\t') {
+ col+=3;
+ }
+ }
+ col++;
+ }
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture));
+
+ ptex->create_from_image(img,0);
+ return ptex;
+
+}
+
+EditorScriptPreviewPlugin::EditorScriptPreviewPlugin() {
+
+
+}
+///////////////////////////////////////////////////////////////////
+
+bool EditorSamplePreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Sample");
+}
+
+Ref<Texture> EditorSamplePreviewPlugin::generate(const RES& p_from) {
+
+ Ref<Sample> smp =p_from;
+ ERR_FAIL_COND_V(smp.is_null(),Ref<Texture>());
+
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+
+ DVector<uint8_t> img;
+ int w = thumbnail_size;
+ int h = thumbnail_size;
+ img.resize(w*h*3);
+
+ DVector<uint8_t>::Write imgdata = img.write();
+ uint8_t * imgw = imgdata.ptr();
+ DVector<uint8_t> data = smp->get_data();
+ DVector<uint8_t>::Read sampledata = data.read();
+ const uint8_t *sdata=sampledata.ptr();
+
+ bool stereo = smp->is_stereo();
+ bool _16=smp->get_format()==Sample::FORMAT_PCM16;
+ int len = smp->get_length();
+
+ if (len<1)
+ return Ref<Texture>();
+
+ if (smp->get_format()==Sample::FORMAT_IMA_ADPCM) {
+
+ struct IMA_ADPCM_State {
+
+ int16_t step_index;
+ int32_t predictor;
+ /* values at loop point */
+ int16_t loop_step_index;
+ int32_t loop_predictor;
+ int32_t last_nibble;
+ int32_t loop_pos;
+ int32_t window_ofs;
+ const uint8_t *ptr;
+ } ima_adpcm;
+
+ ima_adpcm.step_index=0;
+ ima_adpcm.predictor=0;
+ ima_adpcm.loop_step_index=0;
+ ima_adpcm.loop_predictor=0;
+ ima_adpcm.last_nibble=-1;
+ ima_adpcm.loop_pos=0x7FFFFFFF;
+ ima_adpcm.window_ofs=0;
+ ima_adpcm.ptr=NULL;
+
+
+ for(int i=0;i<w;i++) {
+
+ float max[2]={-1e10,-1e10};
+ float min[2]={1e10,1e10};
+ int from = i*len/w;
+ int to = (i+1)*len/w;
+ if (to>=len)
+ to=len-1;
+
+ for(int j=from;j<to;j++) {
+
+ while(j>ima_adpcm.last_nibble) {
+
+ static const int16_t _ima_adpcm_step_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+ };
+
+ static const int8_t _ima_adpcm_index_table[16] = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+ };
+
+ int16_t nibble,signed_nibble,diff,step;
+
+ ima_adpcm.last_nibble++;
+ const uint8_t *src_ptr=sdata;
+
+ nibble = (ima_adpcm.last_nibble&1)?
+ (src_ptr[ima_adpcm.last_nibble>>1]>>4):(src_ptr[ima_adpcm.last_nibble>>1]&0xF);
+ step=_ima_adpcm_step_table[ima_adpcm.step_index];
+
+ ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
+ if (ima_adpcm.step_index<0)
+ ima_adpcm.step_index=0;
+ if (ima_adpcm.step_index>88)
+ ima_adpcm.step_index=88;
+
+ /*
+ signed_nibble = (nibble&7) * ((nibble&8)?-1:1);
+ diff = (2 * signed_nibble + 1) * step / 4; */
+
+ diff = step >> 3 ;
+ if (nibble & 1)
+ diff += step >> 2 ;
+ if (nibble & 2)
+ diff += step >> 1 ;
+ if (nibble & 4)
+ diff += step ;
+ if (nibble & 8)
+ diff = -diff ;
+
+ ima_adpcm.predictor+=diff;
+ if (ima_adpcm.predictor<-0x8000)
+ ima_adpcm.predictor=-0x8000;
+ else if (ima_adpcm.predictor>0x7FFF)
+ ima_adpcm.predictor=0x7FFF;
+
+
+ /* store loop if there */
+ if (ima_adpcm.last_nibble==ima_adpcm.loop_pos) {
+
+ ima_adpcm.loop_step_index = ima_adpcm.step_index;
+ ima_adpcm.loop_predictor = ima_adpcm.predictor;
+ }
+
+ }
+
+ float v=ima_adpcm.predictor/32767.0;
+ if (v>max[0])
+ max[0]=v;
+ if (v<min[0])
+ min[0]=v;
+ }
+ max[0]*=0.8;
+ min[0]*=0.8;
+
+ for(int j=0;j<h;j++) {
+ float v = (j/(float)h) * 2.0 - 1.0;
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[0] && v<max[0]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+ }
+ } else {
+ for(int i=0;i<w;i++) {
+ // i trust gcc will optimize this loop
+ float max[2]={-1e10,-1e10};
+ float min[2]={1e10,1e10};
+ int c=stereo?2:1;
+ int from = i*len/w;
+ int to = (i+1)*len/w;
+ if (to>=len)
+ to=len-1;
+
+ if (_16) {
+ const int16_t*src =(const int16_t*)sdata;
+
+ for(int j=0;j<c;j++) {
+
+ for(int k=from;k<=to;k++) {
+
+ float v = src[k*c+j]/32768.0;
+ if (v>max[j])
+ max[j]=v;
+ if (v<min[j])
+ min[j]=v;
+ }
+
+ }
+ } else {
+
+ const int8_t*src =(const int8_t*)sdata;
+
+ for(int j=0;j<c;j++) {
+
+ for(int k=from;k<=to;k++) {
+
+ float v = src[k*c+j]/128.0;
+ if (v>max[j])
+ max[j]=v;
+ if (v<min[j])
+ min[j]=v;
+ }
+
+ }
+ }
+
+ max[0]*=0.8;
+ max[1]*=0.8;
+ min[0]*=0.8;
+ min[1]*=0.8;
+
+ if (!stereo) {
+ for(int j=0;j<h;j++) {
+ float v = (j/(float)h) * 2.0 - 1.0;
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[0] && v<max[0]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+ } else {
+
+ for(int j=0;j<h;j++) {
+
+ int half,ofs;
+ float v;
+ if (j<(h/2)) {
+ half=0;
+ ofs=0;
+ v = (j/(float)(h/2)) * 2.0 - 1.0;
+ } else {
+ half=1;
+ ofs=h/2;
+ v = ((j-(h/2))/(float)(h/2)) * 2.0 - 1.0;
+ }
+
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[half] && v<max[half]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+
+ }
+
+ }
+ }
+
+ imgdata = DVector<uint8_t>::Write();
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture));
+ ptex->create_from_image(Image(w,h,0,Image::FORMAT_RGB,img),0);
+ return ptex;
+
+}
+
+EditorSamplePreviewPlugin::EditorSamplePreviewPlugin() {
+
+
+}
+
+///////////////////////////////////////////////////////////////////////////
diff --git a/tools/editor/plugins/editor_preview_plugins.h b/tools/editor/plugins/editor_preview_plugins.h
new file mode 100644
index 0000000000..fc42ebfc0e
--- /dev/null
+++ b/tools/editor/plugins/editor_preview_plugins.h
@@ -0,0 +1,69 @@
+#ifndef EDITORPREVIEWPLUGINS_H
+#define EDITORPREVIEWPLUGINS_H
+
+#include "tools/editor/editor_resource_preview.h"
+
+class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorTexturePreviewPlugin();
+};
+
+
+class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator {
+
+ Ref<Texture> _gen_from_imd(Ref<ResourceImportMetadata> p_imd);
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+ virtual Ref<Texture> generate_from_path(const String& p_path);
+
+ EditorPackedScenePreviewPlugin();
+};
+
+class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
+
+ RID scenario;
+ RID sphere;
+ RID sphere_instance;
+ RID viewport;
+ RID light;
+ RID light_instance;
+ RID light2;
+ RID light_instance2;
+ RID camera;
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorMaterialPreviewPlugin();
+ ~EditorMaterialPreviewPlugin();
+};
+
+class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorScriptPreviewPlugin();
+};
+
+
+class EditorSamplePreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorSamplePreviewPlugin();
+};
+
+
+
+#endif // EDITORPREVIEWPLUGINS_H
diff --git a/tools/editor/plugins/sample_editor_plugin.cpp b/tools/editor/plugins/sample_editor_plugin.cpp
index 3219935688..31fa7246ae 100644
--- a/tools/editor/plugins/sample_editor_plugin.cpp
+++ b/tools/editor/plugins/sample_editor_plugin.cpp
@@ -98,6 +98,125 @@ void SampleEditor::generate_preview_texture(const Ref<Sample>& p_sample,Ref<Imag
if (p_sample->get_format()==Sample::FORMAT_IMA_ADPCM) {
+ struct IMA_ADPCM_State {
+
+ int16_t step_index;
+ int32_t predictor;
+ /* values at loop point */
+ int16_t loop_step_index;
+ int32_t loop_predictor;
+ int32_t last_nibble;
+ int32_t loop_pos;
+ int32_t window_ofs;
+ const uint8_t *ptr;
+ } ima_adpcm;
+
+ ima_adpcm.step_index=0;
+ ima_adpcm.predictor=0;
+ ima_adpcm.loop_step_index=0;
+ ima_adpcm.loop_predictor=0;
+ ima_adpcm.last_nibble=-1;
+ ima_adpcm.loop_pos=0x7FFFFFFF;
+ ima_adpcm.window_ofs=0;
+ ima_adpcm.ptr=NULL;
+
+
+ for(int i=0;i<w;i++) {
+
+ float max[2]={-1e10,-1e10};
+ float min[2]={1e10,1e10};
+ int from = i*len/w;
+ int to = (i+1)*len/w;
+ if (to>=len)
+ to=len-1;
+
+ for(int j=from;j<to;j++) {
+
+ while(j>ima_adpcm.last_nibble) {
+
+ static const int16_t _ima_adpcm_step_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+ };
+
+ static const int8_t _ima_adpcm_index_table[16] = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+ };
+
+ int16_t nibble,signed_nibble,diff,step;
+
+ ima_adpcm.last_nibble++;
+ const uint8_t *src_ptr=sdata;
+
+ nibble = (ima_adpcm.last_nibble&1)?
+ (src_ptr[ima_adpcm.last_nibble>>1]>>4):(src_ptr[ima_adpcm.last_nibble>>1]&0xF);
+ step=_ima_adpcm_step_table[ima_adpcm.step_index];
+
+ ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
+ if (ima_adpcm.step_index<0)
+ ima_adpcm.step_index=0;
+ if (ima_adpcm.step_index>88)
+ ima_adpcm.step_index=88;
+
+ /*
+ signed_nibble = (nibble&7) * ((nibble&8)?-1:1);
+ diff = (2 * signed_nibble + 1) * step / 4; */
+
+ diff = step >> 3 ;
+ if (nibble & 1)
+ diff += step >> 2 ;
+ if (nibble & 2)
+ diff += step >> 1 ;
+ if (nibble & 4)
+ diff += step ;
+ if (nibble & 8)
+ diff = -diff ;
+
+ ima_adpcm.predictor+=diff;
+ if (ima_adpcm.predictor<-0x8000)
+ ima_adpcm.predictor=-0x8000;
+ else if (ima_adpcm.predictor>0x7FFF)
+ ima_adpcm.predictor=0x7FFF;
+
+
+ /* store loop if there */
+ if (ima_adpcm.last_nibble==ima_adpcm.loop_pos) {
+
+ ima_adpcm.loop_step_index = ima_adpcm.step_index;
+ ima_adpcm.loop_predictor = ima_adpcm.predictor;
+ }
+
+ }
+
+ float v=ima_adpcm.predictor/32767.0;
+ if (v>max[0])
+ max[0]=v;
+ if (v<min[0])
+ min[0]=v;
+ }
+
+ for(int j=0;j<h;j++) {
+ float v = (j/(float)h) * 2.0 - 1.0;
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[0] && v<max[0]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+ }
} else {
for(int i=0;i<w;i++) {
// i trust gcc will optimize this loop
diff --git a/tools/editor/plugins/spatial_editor_plugin.h b/tools/editor/plugins/spatial_editor_plugin.h
index b890f285ee..ff8912fca8 100644
--- a/tools/editor/plugins/spatial_editor_plugin.h
+++ b/tools/editor/plugins/spatial_editor_plugin.h
@@ -239,7 +239,7 @@ public:
void set_state(const Dictionary& p_state);
Dictionary get_state() const;
void reset();
-
+ Viewport *get_viewport_node() { return viewport; }
SpatialEditorViewport(SpatialEditor *p_spatial_editor,EditorNode *p_editor,int p_index);
@@ -422,6 +422,7 @@ private:
HBoxContainer *hbc_menu;
+
//
//
void _generate_selection_box();
@@ -514,6 +515,11 @@ public:
void set_can_preview(Camera* p_preview);
+ SpatialEditorViewport *get_editor_viewport(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx,4,NULL);
+ return viewports[p_idx];
+ }
+
Camera *get_camera() { return NULL; }
void edit(Spatial *p_spatial);
void clear();
diff --git a/tools/editor/resources_dock.cpp b/tools/editor/resources_dock.cpp
index 33ec1f2054..b69eec4a51 100644
--- a/tools/editor/resources_dock.cpp
+++ b/tools/editor/resources_dock.cpp
@@ -152,7 +152,7 @@ void ResourcesDock::save_resource_as(const Ref<Resource>& p_resource) {
List<String> extensions;
ResourceSaver::get_recognized_extensions(res,&extensions);
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
if (p_resource->get_path()!="" && p_resource->get_path().find("::")==-1) {
@@ -396,7 +396,7 @@ ResourcesDock::ResourcesDock(EditorNode *p_editor) {
accept = memnew (AcceptDialog);
add_child(accept);
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
add_child(file);
file->connect("file_selected",this,"_file_action");
diff --git a/tools/editor/resources_dock.h b/tools/editor/resources_dock.h
index a94579240e..933b457b29 100644
--- a/tools/editor/resources_dock.h
+++ b/tools/editor/resources_dock.h
@@ -38,6 +38,7 @@
#include "scene/gui/menu_button.h"
#include "scene/gui/file_dialog.h"
#include "create_dialog.h"
+#include "editor_file_dialog.h"
class EditorNode;
@@ -68,7 +69,7 @@ class ResourcesDock : public VBoxContainer {
CreateDialog *create_dialog;
AcceptDialog *accept;
- FileDialog *file;
+ EditorFileDialog *file;
Tree *resources;
bool block_add;
int current_action;
diff --git a/tools/pck/pck_packer.h b/tools/pck/pck_packer.h
index 76752a6170..2bb51128e9 100644
--- a/tools/pck/pck_packer.h
+++ b/tools/pck/pck_packer.h
@@ -1,10 +1,10 @@
-#include "core/object.h"
+#include "core/reference.h"
class FileAccess;
-class PCKPacker : public Object {
+class PCKPacker : public Reference {
- OBJ_TYPE(PCKPacker, Object);
+ OBJ_TYPE(PCKPacker, Reference);
FileAccess* file;
int alignment;