summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2014-11-12 11:23:23 -0300
committerJuan Linietsky <reduzio@gmail.com>2014-11-12 11:23:23 -0300
commit6dd8768811cfca5bb831619d93cf870e5d20667f (patch)
tree9e8837b7c8334855a1bce1bd79ab441edde28129
parentc8cd5222a7fa931f072e02b23c5b9d826d0ef548 (diff)
3D Import Import & UDP
-=-=-=-=-=-=-=-=-=-=- -Animation Import filter support -Animation Clip import support -Animation Optimizer Fixes, Improvements and Visibile Options -Extremely Experimental UDP support.
-rw-r--r--core/io/packet_peer.cpp2
-rw-r--r--core/io/packet_peer_udp.cpp48
-rw-r--r--core/io/packet_peer_udp.h35
-rw-r--r--core/register_core_types.cpp2
-rw-r--r--demos/2d/shower_of_bullets/bullets.gd4
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp5
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraVideoClip.h2
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraVideoManager.h4
-rw-r--r--drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.mm3
-rw-r--r--drivers/theoraplayer/src/TheoraVideoClip.cpp2
-rw-r--r--drivers/theoraplayer/src/TheoraVideoManager.cpp14
-rw-r--r--drivers/theoraplayer/video_stream_theoraplayer.cpp51
-rw-r--r--drivers/theoraplayer/video_stream_theoraplayer.h3
-rw-r--r--drivers/unix/os_unix.cpp2
-rw-r--r--drivers/unix/packet_peer_udp_posix.cpp188
-rw-r--r--drivers/unix/packet_peer_udp_posix.h56
-rw-r--r--platform/android/export/export.cpp2
-rw-r--r--platform/windows/SCsub1
-rw-r--r--platform/windows/os_windows.cpp2
-rw-r--r--platform/windows/packet_peer_udp_winsock.cpp167
-rw-r--r--platform/windows/packet_peer_udp_winsock.h51
-rw-r--r--scene/gui/base_button.cpp35
-rw-r--r--scene/gui/video_player.cpp4
-rw-r--r--scene/gui/video_player.h2
-rw-r--r--scene/resources/animation.cpp283
-rw-r--r--scene/resources/animation.h1
-rw-r--r--scene/resources/video_stream.cpp1
-rw-r--r--scene/resources/video_stream.h2
-rw-r--r--servers/audio/audio_server_sw.cpp8
-rw-r--r--servers/audio/audio_server_sw.h5
-rw-r--r--servers/audio_server.h1
-rw-r--r--servers/physics_2d_server.cpp2
-rw-r--r--servers/physics_server.cpp2
-rw-r--r--tools/editor/animation_editor.cpp53
-rw-r--r--tools/editor/animation_editor.h6
-rw-r--r--tools/editor/editor_file_system.cpp29
-rw-r--r--tools/editor/editor_file_system.h3
-rw-r--r--tools/editor/io_plugins/editor_import_collada.cpp13
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.cpp138
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.h1
-rw-r--r--tools/export/blender25/io_scene_dae/export_dae.py2
41 files changed, 1050 insertions, 185 deletions
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 37fc9c4a0a..b566ce4b7b 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -111,7 +111,7 @@ Variant PacketPeer::_bnd_get_var() const {
void PacketPeer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_var"),&PacketPeer::_bnd_get_var);
- ObjectTypeDB::bind_method(_MD("put_var", "var:Variant"),&PacketPeer::put_var);
+ ObjectTypeDB::bind_method(_MD("put_var", "var:var"),&PacketPeer::put_var);
ObjectTypeDB::bind_method(_MD("get_available_packet_count"),&PacketPeer::get_available_packet_count);
};
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
new file mode 100644
index 0000000000..60f56ed28a
--- /dev/null
+++ b/core/io/packet_peer_udp.cpp
@@ -0,0 +1,48 @@
+#include "packet_peer_udp.h"
+
+
+
+PacketPeerUDP* (*PacketPeerUDP::_create)()=NULL;
+
+int PacketPeerUDP::_get_packet_address() const {
+
+ IP_Address ip = get_packet_address();
+ return ip.host;
+}
+
+String PacketPeerUDP::_get_packet_ip() const {
+
+ return get_packet_address();
+}
+
+
+void PacketPeerUDP::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("listen:Error","port","recv_buf_size"),&PacketPeerUDP::listen,DEFVAL(65536));
+ ObjectTypeDB::bind_method(_MD("close"),&PacketPeerUDP::close);
+ ObjectTypeDB::bind_method(_MD("poll:Error"),&PacketPeerUDP::poll);
+ ObjectTypeDB::bind_method(_MD("is_listening"),&PacketPeerUDP::is_listening);
+ ObjectTypeDB::bind_method(_MD("get_packet_ip"),&PacketPeerUDP::_get_packet_ip);
+ ObjectTypeDB::bind_method(_MD("get_packet_address"),&PacketPeerUDP::_get_packet_address);
+ ObjectTypeDB::bind_method(_MD("set_send_address","address","port"),&PacketPeerUDP::set_send_address);
+
+
+}
+
+Ref<PacketPeerUDP> PacketPeerUDP::create_ref() {
+
+ if (!_create)
+ return Ref<PacketPeerUDP>();
+ return Ref<PacketPeerUDP>(_create());
+}
+
+PacketPeerUDP* PacketPeerUDP::create() {
+
+ if (!_create)
+ return NULL;
+ return _create();
+}
+
+PacketPeerUDP::PacketPeerUDP()
+{
+}
diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h
new file mode 100644
index 0000000000..049ac0132f
--- /dev/null
+++ b/core/io/packet_peer_udp.h
@@ -0,0 +1,35 @@
+#ifndef PACKET_PEER_UDP_H
+#define PACKET_PEER_UDP_H
+
+
+#include "io/packet_peer.h"
+
+class PacketPeerUDP : public PacketPeer {
+ OBJ_TYPE(PacketPeerUDP,PacketPeer);
+
+protected:
+
+ static PacketPeerUDP* (*_create)();
+ static void _bind_methods();
+
+ int _get_packet_address() const;
+ String _get_packet_ip() const;
+
+public:
+
+ virtual Error listen(int p_port,int p_recv_buffer_size=65536)=0;
+ virtual void close()=0;
+ virtual Error poll()=0;
+ virtual bool is_listening() const=0;
+ virtual IP_Address get_packet_address() const=0;
+ virtual int get_packet_port() const=0;
+ virtual void set_send_address(const IP_Address& p_address,int p_port)=0;
+
+
+ static Ref<PacketPeerUDP> create_ref();
+ static PacketPeerUDP* create();
+
+ PacketPeerUDP();
+};
+
+#endif // PACKET_PEER_UDP_H
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 492068f604..2f16e31de6 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -29,6 +29,7 @@
#include "register_core_types.h"
#include "io/tcp_server.h"
+#include "io/packet_peer_udp.h"
#include "io/config_file.h"
#include "os/main_loop.h"
#include "io/packet_peer.h"
@@ -115,6 +116,7 @@ void register_core_types() {
ObjectTypeDB::register_virtual_type<StreamPeer>();
ObjectTypeDB::register_create_type<StreamPeerTCP>();
ObjectTypeDB::register_create_type<TCP_Server>();
+ ObjectTypeDB::register_create_type<PacketPeerUDP>();
ObjectTypeDB::register_create_type<StreamPeerSSL>();
ObjectTypeDB::register_virtual_type<IP>();
ObjectTypeDB::register_virtual_type<PacketPeer>();
diff --git a/demos/2d/shower_of_bullets/bullets.gd b/demos/2d/shower_of_bullets/bullets.gd
index f76fcc38ba..79f4faaae6 100644
--- a/demos/2d/shower_of_bullets/bullets.gd
+++ b/demos/2d/shower_of_bullets/bullets.gd
@@ -65,9 +65,9 @@ func _ready():
func _exit_tree():
for b in bullets:
- Physics2DServer.free(b.body)
+ Physics2DServer.free_rid(b.body)
- Physics2DServer.free(shape)
+ Physics2DServer.free_rid(shape)
# Initalization here
bullets.clear()
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 4044496953..bc1b17eade 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -4173,6 +4173,9 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) {
pixels.resize(viewport.width*viewport.height*4);
DVector<uint8_t>::Write w = pixels.write();
glPixelStorei(GL_PACK_ALIGNMENT, 4);
+
+ uint64_t time = OS::get_singleton()->get_ticks_usec();
+
if (current_rt) {
#ifdef GLEW_ENABLED
glReadBuffer(GL_COLOR_ATTACHMENT0);
@@ -4182,11 +4185,13 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) {
// back?
glReadPixels( viewport.x, window_size.height-(viewport.height+viewport.y), viewport.width,viewport.height,GL_RGBA,GL_UNSIGNED_BYTE,w.ptr());
}
+ printf("readpixels time %i\n", (int)(OS::get_singleton()->get_ticks_usec() - time));
w=DVector<uint8_t>::Write();
r_capture->create(viewport.width,viewport.height,0,Image::FORMAT_RGBA,pixels);
r_capture->flip_y();
+ printf("total time %i\n", (int)(OS::get_singleton()->get_ticks_usec() - time));
#endif
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraVideoClip.h b/drivers/theoraplayer/include/theoraplayer/TheoraVideoClip.h
index b2987c01c4..fe71cf8566 100644
--- a/drivers/theoraplayer/include/theoraplayer/TheoraVideoClip.h
+++ b/drivers/theoraplayer/include/theoraplayer/TheoraVideoClip.h
@@ -87,6 +87,7 @@ protected:
std::string mName;
int mWidth, mHeight, mStride;
int mNumFrames;
+ int audio_track;
int mSubFrameWidth, mSubFrameHeight, mSubFrameOffsetX, mSubFrameOffsetY;
float mAudioGain; //! multiplier for audio samples. between 0 and 1
@@ -233,6 +234,7 @@ public:
bool getAutoRestart() { return mAutoRestart; }
+ void set_audio_track(int p_track) { audio_track=p_track; }
/**
TODO: user priority. Useful only when more than one video is being decoded
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraVideoManager.h b/drivers/theoraplayer/include/theoraplayer/TheoraVideoManager.h
index 3ff9b217cd..d94c51b4d4 100644
--- a/drivers/theoraplayer/include/theoraplayer/TheoraVideoManager.h
+++ b/drivers/theoraplayer/include/theoraplayer/TheoraVideoManager.h
@@ -67,8 +67,8 @@ public:
//! search registered clips by name
TheoraVideoClip* getVideoClipByName(std::string name);
- TheoraVideoClip* createVideoClip(std::string filename,TheoraOutputMode output_mode=TH_RGB,int numPrecachedOverride=0,bool usePower2Stride=0);
- TheoraVideoClip* createVideoClip(TheoraDataSource* data_source,TheoraOutputMode output_mode=TH_RGB,int numPrecachedOverride=0,bool usePower2Stride=0);
+ TheoraVideoClip* createVideoClip(std::string filename,TheoraOutputMode output_mode=TH_RGB,int numPrecachedOverride=0,bool usePower2Stride=0, int p_track=0);
+ TheoraVideoClip* createVideoClip(TheoraDataSource* data_source,TheoraOutputMode output_mode=TH_RGB,int numPrecachedOverride=0,bool usePower2Stride=0, int p_audio_track=0);
void update(float timeDelta);
diff --git a/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.mm b/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.mm
index 8c3d2cc3b9..72e3dfc9fa 100644
--- a/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.mm
+++ b/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.mm
@@ -271,7 +271,8 @@ void TheoraVideoClip_AVFoundation::load(TheoraDataSource* source)
AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
NSArray* audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
- AVAssetTrack *audioTrack = audioTracks.count > 0 ? [audioTracks objectAtIndex:0] : NULL;
+ AVAssetTrack *audioTrack = audioTracks.count > 0 ? [audioTracks objectAtIndex:audio_track] : NULL;
+ printf("*********** using audio track %i\n", audio_track);
#ifdef _AVFOUNDATION_BGRX
bool yuv_output = (mOutputMode != TH_BGRX && mOutputMode != TH_RGBA);
diff --git a/drivers/theoraplayer/src/TheoraVideoClip.cpp b/drivers/theoraplayer/src/TheoraVideoClip.cpp
index b71319e6a1..ed9f2c22da 100644
--- a/drivers/theoraplayer/src/TheoraVideoClip.cpp
+++ b/drivers/theoraplayer/src/TheoraVideoClip.cpp
@@ -51,6 +51,8 @@ TheoraVideoClip::TheoraVideoClip(TheoraDataSource* data_source,
mWaitingForCache(false),
mOutputMode(TH_UNDEFINED)
{
+
+ audio_track=0;
mAudioMutex = NULL;
mThreadAccessMutex = new TheoraMutex();
mTimer = mDefaultTimer = new TheoraTimer();
diff --git a/drivers/theoraplayer/src/TheoraVideoManager.cpp b/drivers/theoraplayer/src/TheoraVideoManager.cpp
index 87696d12a9..53b211374a 100644
--- a/drivers/theoraplayer/src/TheoraVideoManager.cpp
+++ b/drivers/theoraplayer/src/TheoraVideoManager.cpp
@@ -35,6 +35,8 @@ extern "C"
void initYUVConversionModule();
}
+#include "core/os/memory.h"
+
//#define _DECODING_BENCHMARK //uncomment to test average decoding time on a given device
@@ -184,16 +186,18 @@ TheoraAudioInterfaceFactory* TheoraVideoManager::getAudioInterfaceFactory()
TheoraVideoClip* TheoraVideoManager::createVideoClip(std::string filename,
TheoraOutputMode output_mode,
int numPrecachedOverride,
- bool usePower2Stride)
+ bool usePower2Stride,
+ int p_track)
{
- TheoraDataSource* src=new TheoraFileDataSource(filename);
- return createVideoClip(src,output_mode,numPrecachedOverride,usePower2Stride);
+ TheoraDataSource* src=memnew(TheoraFileDataSource(filename));
+ return createVideoClip(src,output_mode,numPrecachedOverride,usePower2Stride, p_track);
}
TheoraVideoClip* TheoraVideoManager::createVideoClip(TheoraDataSource* data_source,
TheoraOutputMode output_mode,
int numPrecachedOverride,
- bool usePower2Stride)
+ bool usePower2Stride,
+ int p_audio_track)
{
mWorkMutex->lock();
@@ -226,6 +230,8 @@ TheoraVideoClip* TheoraVideoManager::createVideoClip(TheoraDataSource* data_sour
#ifdef __FFMPEG
clip = new TheoraVideoClip_FFmpeg(data_source, output_mode, nPrecached, usePower2Stride);
#endif
+
+ clip->set_audio_track(p_audio_track);
clip->load(data_source);
clip->decodeNextFrame(); // ensure the first frame is always preloaded and have the main thread do it to prevent potential thread starvatio
diff --git a/drivers/theoraplayer/video_stream_theoraplayer.cpp b/drivers/theoraplayer/video_stream_theoraplayer.cpp
index fdf612ff0f..643899aaed 100644
--- a/drivers/theoraplayer/video_stream_theoraplayer.cpp
+++ b/drivers/theoraplayer/video_stream_theoraplayer.cpp
@@ -39,6 +39,8 @@
#include "core/ring_buffer.h"
#include "core/os/thread_safe.h"
+#include "core/globals.h"
+
static TheoraVideoManager* mgr = NULL;
class TPDataFA : public TheoraDataSource {
@@ -141,6 +143,7 @@ public:
playing=false;
_clear();
};
+
virtual bool is_playing() const { return true; };
virtual void set_paused(bool p_paused) {};
@@ -164,12 +167,16 @@ public:
void input(float* p_data, int p_samples) {
+
_THREAD_SAFE_METHOD_;
+ //printf("input %i samples from %p\n", p_samples, p_data);
if (rb.space_left() < p_samples) {
rb_power += 1;
rb.resize(rb_power);
}
rb.write(p_data, p_samples);
+
+ update(); //update too here for less latency
};
void update() {
@@ -177,15 +184,16 @@ public:
_THREAD_SAFE_METHOD_;
int todo = get_todo();
int16_t* buffer = get_write_buffer();
- int samples = rb.data_left();
- const int to_write = MIN(todo, samples);
+ int frames = rb.data_left()/channels;
+ const int to_write = MIN(todo, frames);
- for (int i=0; i<to_write; i++) {
+ for (int i=0; i<to_write*channels; i++) {
- uint16_t sample = uint16_t(rb.read() * 32767);
+ int v = rb.read() * 32767;
+ int16_t sample = CLAMP(v,-32768,32767);
buffer[i] = sample;
};
- write(to_write/channels);
+ write(to_write);
total_wrote += to_write;
};
@@ -231,7 +239,7 @@ public:
TPAudioGodot(TheoraVideoClip* owner, int nChannels, int p_freq)
: TheoraAudioInterface(owner, nChannels, p_freq), TheoraTimer() {
- printf("***************** audio interface constructor\n");
+ printf("***************** audio interface constructor freq %i\n", p_freq);
channels = nChannels;
freq = p_freq;
stream = Ref<AudioStreamInput>(memnew(AudioStreamInput(nChannels, p_freq)));
@@ -247,12 +255,13 @@ public:
void update(float time_increase)
{
- mTime = (float)(stream->get_total_wrote() / channels) / freq;
+ //mTime = (float)(stream->get_total_wrote()) / freq;
+ //mTime = MAX(0,mTime-AudioServer::get_singleton()->get_output_delay());
//mTime = (float)sample_count / channels / freq;
- //mTime += time_increase;
+ mTime += time_increase;
//float duration=mClip->getDuration();
//if (mTime > duration) mTime=duration;
- //printf("time at timer is %f, samples %i\n", mTime, sample_count);
+ //printf("time at timer is %f, %f, samples %i\n", mTime, time_increase, sample_count);
}
};
@@ -358,13 +367,15 @@ void VideoStreamTheoraplayer::pop_frame(Ref<ImageTexture> p_tex) {
#endif
float w=clip->getWidth(),h=clip->getHeight();
- int imgsize = w * h * f->mBpp;
+ int imgsize = w * h * f->mBpp;
int size = f->getStride() * f->getHeight() * f->mBpp;
data.resize(imgsize);
- DVector<uint8_t>::Write wr = data.write();
- uint8_t* ptr = wr.ptr();
- copymem(ptr, f->getBuffer(), imgsize);
+ {
+ DVector<uint8_t>::Write wr = data.write();
+ uint8_t* ptr = wr.ptr();
+ memcpy(ptr, f->getBuffer(), imgsize);
+ }
/*
for (int i=0; i<h; i++) {
int dstofs = i * w * f->mBpp;
@@ -421,6 +432,13 @@ void VideoStreamTheoraplayer::update(float p_time) {
mgr->update(p_time);
};
+
+void VideoStreamTheoraplayer::set_audio_track(int p_idx) {
+ audio_track=p_idx;
+ if (clip)
+ clip->set_audio_track(audio_track);
+}
+
void VideoStreamTheoraplayer::set_file(const String& p_file) {
FileAccess* f = FileAccess::open(p_file, FileAccess::READ);
@@ -436,10 +454,13 @@ void VideoStreamTheoraplayer::set_file(const String& p_file) {
mgr->setAudioInterfaceFactory(audio_factory);
};
+ int track = GLOBAL_DEF("theora/audio_track", 0); // hack
+
if (p_file.find(".mp4") != -1) {
std::string file = p_file.replace("res://", "").utf8().get_data();
- clip = mgr->createVideoClip(file, TH_BGRX, 16);
+ clip = mgr->createVideoClip(file, TH_RGBX, 2, false, track);
+ //clip->set_audio_track(audio_track);
memdelete(f);
} else {
@@ -448,6 +469,7 @@ void VideoStreamTheoraplayer::set_file(const String& p_file) {
try {
clip = mgr->createVideoClip(ds);
+ clip->set_audio_track(audio_track);
} catch (_TheoraGenericException e) {
printf("exception ocurred! %s\n", e.repr().c_str());
clip = NULL;
@@ -478,6 +500,7 @@ VideoStreamTheoraplayer::VideoStreamTheoraplayer() {
started = false;
playing = false;
loop = false;
+ audio_track=0;
};
diff --git a/drivers/theoraplayer/video_stream_theoraplayer.h b/drivers/theoraplayer/video_stream_theoraplayer.h
index d88f495032..f926dfdaf5 100644
--- a/drivers/theoraplayer/video_stream_theoraplayer.h
+++ b/drivers/theoraplayer/video_stream_theoraplayer.h
@@ -18,6 +18,8 @@ class VideoStreamTheoraplayer : public VideoStream {
bool playing;
bool loop;
+ int audio_track;
+
public:
virtual void stop();
@@ -43,6 +45,7 @@ public:
void update(float p_time);
void set_file(const String& p_file);
+ void set_audio_track(int p_idx);
~VideoStreamTheoraplayer();
VideoStreamTheoraplayer();
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index ef4cf644fd..e6458068ea 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -42,6 +42,7 @@
#include "dir_access_unix.h"
#include "tcp_server_posix.h"
#include "stream_peer_tcp_posix.h"
+#include "packet_peer_udp_posix.h"
#include <stdarg.h>
@@ -115,6 +116,7 @@ void OS_Unix::initialize_core() {
#ifndef NO_NETWORK
TCPServerPosix::make_default();
StreamPeerTCPPosix::make_default();
+ PacketPeerUDPPosix::make_default();
IP_Unix::make_default();
#endif
mempool_static = new MemoryPoolStaticMalloc;
diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp
new file mode 100644
index 0000000000..d951524d3a
--- /dev/null
+++ b/drivers/unix/packet_peer_udp_posix.cpp
@@ -0,0 +1,188 @@
+#include "packet_peer_udp_posix.h"
+
+#ifdef UNIX_ENABLED
+
+
+#include <errno.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <stdio.h>
+
+#ifndef NO_FCNTL
+#include <sys/fcntl.h>
+#else
+#include <sys/ioctl.h>
+#endif
+
+#ifdef JAVASCRIPT_ENABLED
+#include <arpa/inet.h>
+#endif
+
+
+int PacketPeerUDPPosix::get_available_packet_count() const {
+
+ Error err = const_cast<PacketPeerUDPPosix*>(this)->poll();
+ if (err!=OK)
+ return 0;
+
+ return queue_count;
+}
+
+Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer,int &r_buffer_size) const{
+
+ Error err = const_cast<PacketPeerUDPPosix*>(this)->poll();
+ if (err!=OK)
+ return err;
+ if (queue_count==0)
+ return ERR_UNAVAILABLE;
+
+ uint32_t size;
+ rb.read((uint8_t*)&size,4,true);
+ rb.read((uint8_t*)&packet_ip.host,4,true);
+ rb.read((uint8_t*)&packet_port,4,true);
+ rb.read(packet_buffer,size,true);
+ --queue_count;
+ *r_buffer=packet_buffer;
+ r_buffer_size=size;
+ return OK;
+
+}
+Error PacketPeerUDPPosix::put_packet(const uint8_t *p_buffer,int p_buffer_size){
+
+ int sock = _get_socket();
+ ERR_FAIL_COND_V( sock == -1, FAILED );
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(peer_port);
+ addr.sin_addr = *((struct in_addr*)&peer_addr.host);
+
+ errno = 0;
+ int err;
+ while ( (err = sendto(sock, p_buffer, p_buffer_size, 0, (struct sockaddr*)&addr, sizeof(addr))) != p_buffer_size) {
+
+ if (errno != EAGAIN) {
+ return FAILED;
+ }
+ }
+
+ return OK;
+}
+
+int PacketPeerUDPPosix::get_max_packet_size() const{
+
+ return 512; // uhm maybe not
+}
+
+Error PacketPeerUDPPosix::listen(int p_port, int p_recv_buffer_size){
+
+ close();
+ int sock = _get_socket();
+ if (sock == -1 )
+ return ERR_CANT_CREATE;
+ sockaddr_in addr = {0};
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(p_port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == -1 ) {
+ close();
+ return ERR_UNAVAILABLE;
+ }
+ printf("UDP Connection listening on port %i\n", p_port);
+ rb.resize(nearest_power_of_2(p_recv_buffer_size));
+ return OK;
+}
+
+void PacketPeerUDPPosix::close(){
+
+ if (sockfd != -1)
+ ::close(sockfd);
+ sockfd=-1;
+ rb.resize(8);
+ queue_count=0;
+}
+
+Error PacketPeerUDPPosix::poll() {
+
+ struct sockaddr_in from = {0};
+ socklen_t len = sizeof(struct sockaddr_in);
+ int ret;
+ while ( (ret = recvfrom(sockfd, recv_buffer, MIN(sizeof(recv_buffer),rb.data_left()-12), MSG_DONTWAIT, (struct sockaddr*)&from, &len)) > 0) {
+ rb.write((uint8_t*)&from.sin_addr, 4);
+ uint32_t port = ntohs(from.sin_port);
+ rb.write((uint8_t*)&port, 4);
+ rb.write((uint8_t*)&ret, 4);
+ rb.write(recv_buffer, ret);
+
+ len = sizeof(struct sockaddr_in);
+ ++queue_count;
+ };
+
+ if (ret == 0 || (ret == -1 && errno != EAGAIN) ) {
+ close();
+ return FAILED;
+ };
+
+ return OK;
+}
+bool PacketPeerUDPPosix::is_listening() const{
+
+ return sockfd!=-1;
+}
+
+IP_Address PacketPeerUDPPosix::get_packet_address() const {
+
+ return packet_ip;
+}
+
+int PacketPeerUDPPosix::get_packet_port() const{
+
+ return packet_port;
+}
+
+int PacketPeerUDPPosix::_get_socket() {
+
+ if (sockfd != -1)
+ return sockfd;
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ ERR_FAIL_COND_V( sockfd == -1, -1 );
+ //fcntl(sockfd, F_SETFL, O_NONBLOCK);
+
+ return sockfd;
+}
+
+
+void PacketPeerUDPPosix::set_send_address(const IP_Address& p_address,int p_port) {
+
+ peer_addr=p_address;
+ peer_port=p_port;
+}
+
+PacketPeerUDP* PacketPeerUDPPosix::_create() {
+
+ return memnew(PacketPeerUDPPosix);
+};
+
+void PacketPeerUDPPosix::make_default() {
+
+ PacketPeerUDP::_create = PacketPeerUDPPosix::_create;
+};
+
+
+PacketPeerUDPPosix::PacketPeerUDPPosix() {
+
+ sockfd=-1;
+ packet_port=0;
+ queue_count=0;
+ peer_port=0;
+}
+
+PacketPeerUDPPosix::~PacketPeerUDPPosix() {
+
+ close();
+}
+#endif
diff --git a/drivers/unix/packet_peer_udp_posix.h b/drivers/unix/packet_peer_udp_posix.h
new file mode 100644
index 0000000000..428c3ac37e
--- /dev/null
+++ b/drivers/unix/packet_peer_udp_posix.h
@@ -0,0 +1,56 @@
+#ifndef PACKET_PEER_UDP_POSIX_H
+#define PACKET_PEER_UDP_POSIX_H
+
+#ifdef UNIX_ENABLED
+
+#include "io/packet_peer_udp.h"
+#include "ring_buffer.h"
+
+class PacketPeerUDPPosix : public PacketPeerUDP {
+
+
+ enum {
+ PACKET_BUFFER_SIZE=65536
+ };
+
+ mutable RingBuffer<uint8_t> rb;
+ uint8_t recv_buffer[PACKET_BUFFER_SIZE];
+ mutable uint8_t packet_buffer[PACKET_BUFFER_SIZE];
+ IP_Address packet_ip;
+ int packet_port;
+ mutable int queue_count;
+ int sockfd;
+
+ IP_Address peer_addr;
+ int peer_port;
+
+ _FORCE_INLINE_ int _get_socket();
+
+ static PacketPeerUDP* _create();
+
+public:
+
+ virtual int get_available_packet_count() const;
+ virtual Error get_packet(const uint8_t **r_buffer,int &r_buffer_size) const;
+ virtual Error put_packet(const uint8_t *p_buffer,int p_buffer_size);
+
+ virtual int get_max_packet_size() const;
+
+ virtual Error listen(int p_port,int p_recv_buffer_size=65536);
+ virtual void close();
+ virtual Error poll();
+ virtual bool is_listening() const;
+
+ virtual IP_Address get_packet_address() const;
+ virtual int get_packet_port() const;
+
+ virtual void set_send_address(const IP_Address& p_address,int p_port);
+
+ static void make_default();
+
+ PacketPeerUDPPosix();
+ ~PacketPeerUDPPosix();
+};
+
+#endif // PACKET_PEER_UDP_POSIX_H
+#endif
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index bcc818dac8..89f121c3f6 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -1533,7 +1533,7 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
device_lock = Mutex::create();
quit_request=false;
orientation=0;
- remove_prev=false;
+ remove_prev=true;
device_thread=Thread::create(_device_poll_thread,this);
devices_changed=true;
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 08a775e689..a77428e954 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -7,6 +7,7 @@ common_win=[
"ctxgl_procaddr.cpp",
"key_mapping_win.cpp",
"tcp_server_winsock.cpp",
+ "packet_peer_udp_winsock.cpp",
"stream_peer_winsock.cpp",
]
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index be53d2d46a..19bf324916 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -45,6 +45,7 @@
#include "servers/visual/visual_server_wrap_mt.h"
#include "tcp_server_winsock.h"
+#include "packet_peer_udp_winsock.h"
#include "stream_peer_winsock.h"
#include "os/pc_joystick_map.h"
#include "lang_table.h"
@@ -173,6 +174,7 @@ void OS_Windows::initialize_core() {
TCPServerWinsock::make_default();
StreamPeerWinsock::make_default();
+ PacketPeerUDPWinsock::make_default();
mempool_static = new MemoryPoolStaticMalloc;
#if 1
diff --git a/platform/windows/packet_peer_udp_winsock.cpp b/platform/windows/packet_peer_udp_winsock.cpp
new file mode 100644
index 0000000000..25851c0d73
--- /dev/null
+++ b/platform/windows/packet_peer_udp_winsock.cpp
@@ -0,0 +1,167 @@
+#include "packet_peer_udp_winsock.h"
+
+#include <winsock2.h>
+
+int PacketPeerUDPWinsock::get_available_packet_count() const {
+
+ Error err = const_cast<PacketPeerUDPWinsock*>(this)->poll();
+ if (err!=OK)
+ return 0;
+
+ return queue_count;
+}
+
+Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer,int &r_buffer_size) const{
+
+ Error err = const_cast<PacketPeerUDPWinsock*>(this)->poll();
+ if (err!=OK)
+ return err;
+ if (queue_count==0)
+ return ERR_UNAVAILABLE;
+
+ uint32_t size;
+ rb.read((uint8_t*)&size,4,true);
+ rb.read((uint8_t*)&packet_ip.host,4,true);
+ rb.read((uint8_t*)&packet_port,4,true);
+ rb.read(packet_buffer,size,true);
+ --queue_count;
+ *r_buffer=packet_buffer;
+ r_buffer_size=size;
+ return OK;
+
+}
+Error PacketPeerUDPWinsock::put_packet(const uint8_t *p_buffer,int p_buffer_size){
+
+ int sock = _get_socket();
+ ERR_FAIL_COND_V( sock == -1, FAILED );
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(peer_port);
+ addr.sin_addr = *((struct in_addr*)&peer_addr.host);
+
+ errno = 0;
+ int err;
+ while ( (err = sendto(sock, (const char*)p_buffer, p_buffer_size, 0, (struct sockaddr*)&addr, sizeof(addr))) != p_buffer_size) {
+
+ if (WSAGetLastError() != WSAEWOULDBLOCK) {
+ return FAILED;
+ };
+ }
+
+ return OK;
+}
+
+int PacketPeerUDPWinsock::get_max_packet_size() const{
+
+ return 512; // uhm maybe not
+}
+
+Error PacketPeerUDPWinsock::listen(int p_port, int p_recv_buffer_size){
+
+ close();
+ int sock = _get_socket();
+ if (sock == -1 )
+ return ERR_CANT_CREATE;
+ sockaddr_in addr = {0};
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(p_port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == -1 ) {
+ close();
+ return ERR_UNAVAILABLE;
+ }
+ printf("UDP Connection listening on port %i\n", p_port);
+ rb.resize(nearest_power_of_2(p_recv_buffer_size));
+ return OK;
+}
+
+void PacketPeerUDPWinsock::close(){
+
+ if (sockfd != -1)
+ ::closesocket(sockfd);
+ sockfd=-1;
+ rb.resize(8);
+ queue_count=0;
+}
+
+Error PacketPeerUDPWinsock::poll() {
+
+ struct sockaddr_in from = {0};
+ int len = sizeof(struct sockaddr_in);
+ int ret;
+ while ( (ret = recvfrom(sockfd, (char*)recv_buffer, MIN(sizeof(recv_buffer),rb.data_left()-12), 0, (struct sockaddr*)&from, &len)) > 0) {
+ rb.write((uint8_t*)&from.sin_addr, 4);
+ uint32_t port = ntohs(from.sin_port);
+ rb.write((uint8_t*)&port, 4);
+ rb.write((uint8_t*)&ret, 4);
+ rb.write(recv_buffer, ret);
+
+ len = sizeof(struct sockaddr_in);
+ ++queue_count;
+ };
+
+ if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) ) {
+ close();
+ return FAILED;
+ };
+
+ return OK;
+}
+bool PacketPeerUDPWinsock::is_listening() const{
+
+ return sockfd!=-1;
+}
+
+IP_Address PacketPeerUDPWinsock::get_packet_address() const {
+
+ return packet_ip;
+}
+
+int PacketPeerUDPWinsock::get_packet_port() const{
+
+ return packet_port;
+}
+
+int PacketPeerUDPWinsock::_get_socket() {
+
+ if (sockfd != -1)
+ return sockfd;
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ ERR_FAIL_COND_V( sockfd == -1, -1 );
+ //fcntl(sockfd, F_SETFL, O_NONBLOCK);
+
+ return sockfd;
+}
+
+
+void PacketPeerUDPWinsock::set_send_address(const IP_Address& p_address,int p_port) {
+
+ peer_addr=p_address;
+ peer_port=p_port;
+}
+
+void PacketPeerUDPWinsock::make_default() {
+
+ PacketPeerUDP::_create = PacketPeerUDPWinsock::_create;
+};
+
+
+PacketPeerUDP* PacketPeerUDPWinsock::_create() {
+
+ return memnew(PacketPeerUDPWinsock);
+};
+
+
+PacketPeerUDPWinsock::PacketPeerUDPWinsock() {
+
+ sockfd=-1;
+ packet_port=0;
+ queue_count=0;
+ peer_port=0;
+}
+
+PacketPeerUDPWinsock::~PacketPeerUDPWinsock() {
+
+ close();
+}
diff --git a/platform/windows/packet_peer_udp_winsock.h b/platform/windows/packet_peer_udp_winsock.h
new file mode 100644
index 0000000000..7806666b63
--- /dev/null
+++ b/platform/windows/packet_peer_udp_winsock.h
@@ -0,0 +1,51 @@
+#ifndef PACKET_PEER_UDP_WINSOCK_H
+#define PACKET_PEER_UDP_WINSOCK_H
+
+#include "io/packet_peer_udp.h"
+#include "ring_buffer.h"
+
+class PacketPeerUDPWinsock : public PacketPeerUDP {
+
+
+ enum {
+ PACKET_BUFFER_SIZE=65536
+ };
+
+ mutable RingBuffer<uint8_t> rb;
+ uint8_t recv_buffer[PACKET_BUFFER_SIZE];
+ mutable uint8_t packet_buffer[PACKET_BUFFER_SIZE];
+ IP_Address packet_ip;
+ int packet_port;
+ mutable int queue_count;
+ int sockfd;
+
+ IP_Address peer_addr;
+ int peer_port;
+
+ _FORCE_INLINE_ int _get_socket();
+
+ static PacketPeerUDP* _create();
+
+public:
+
+ virtual int get_available_packet_count() const;
+ virtual Error get_packet(const uint8_t **r_buffer,int &r_buffer_size) const;
+ virtual Error put_packet(const uint8_t *p_buffer,int p_buffer_size);
+
+ virtual int get_max_packet_size() const;
+
+ virtual Error listen(int p_port,int p_recv_buffer_size=65536);
+ virtual void close();
+ virtual Error poll();
+ virtual bool is_listening() const;
+
+ virtual IP_Address get_packet_address() const;
+ virtual int get_packet_port() const;
+
+ virtual void set_send_address(const IP_Address& p_address,int p_port);
+
+ static void make_default();
+ PacketPeerUDPWinsock();
+ ~PacketPeerUDPWinsock();
+};
+#endif // PACKET_PEER_UDP_WINSOCK_H
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 442fd286dd..cf3bef73ea 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -55,9 +55,9 @@ void BaseButton::_input_event(InputEvent p_event) {
if (b.pressed) {
if (!toggle_mode) { //mouse press attempt
-
- status.press_attempt=true;
- status.pressing_inside=true;
+
+ status.press_attempt=true;
+ status.pressing_inside=true;
pressed();
emit_signal("pressed");
@@ -74,13 +74,13 @@ void BaseButton::_input_event(InputEvent p_event) {
}
- } else {
-
- if (status.press_attempt &&status.pressing_inside) {
- pressed();
- emit_signal("pressed");
- }
- status.press_attempt=false;
+ } else {
+
+ if (status.press_attempt && status.pressing_inside) {
+// released();
+ emit_signal("released");
+ }
+ status.press_attempt=false;
}
update();
break;
@@ -95,14 +95,14 @@ void BaseButton::_input_event(InputEvent p_event) {
if (status.press_attempt &&status.pressing_inside) {
-
+
if (!toggle_mode) { //mouse press attempt
-
+
pressed();
- emit_signal("pressed");
+ emit_signal("pressed");
} else {
-
+
status.pressed=!status.pressed;
pressed();
@@ -110,11 +110,11 @@ void BaseButton::_input_event(InputEvent p_event) {
toggled(status.pressed);
emit_signal("toggled",status.pressed);
-
+
}
-
+
}
-
+
status.press_attempt=false;
}
@@ -363,6 +363,7 @@ void BaseButton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_draw_mode"),&BaseButton::get_draw_mode);
ADD_SIGNAL( MethodInfo("pressed" ) );
+ ADD_SIGNAL( MethodInfo("released" ) );
ADD_SIGNAL( MethodInfo("toggled", PropertyInfo( Variant::BOOL,"pressed") ) );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "disabled"), _SCS("set_disabled"), _SCS("is_disabled"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "toggle_mode"), _SCS("set_toggle_mode"), _SCS("is_toggle_mode"));
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 857ea25d0f..050fd890f4 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -192,7 +192,7 @@ String VideoPlayer::get_stream_name() const {
return stream->get_name();
};
-float VideoPlayer::get_pos() const {
+float VideoPlayer::get_stream_pos() const {
if (stream.is_null())
return 0;
@@ -231,7 +231,7 @@ void VideoPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_stream_name"),&VideoPlayer::get_stream_name);
- ObjectTypeDB::bind_method(_MD("get_pos"),&VideoPlayer::get_pos);
+ ObjectTypeDB::bind_method(_MD("get_stream_pos"),&VideoPlayer::get_stream_pos);
ObjectTypeDB::bind_method(_MD("set_autoplay","enabled"),&VideoPlayer::set_autoplay);
ObjectTypeDB::bind_method(_MD("has_autoplay"),&VideoPlayer::has_autoplay);
diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h
index db5f9a58a6..3eb629ced5 100644
--- a/scene/gui/video_player.h
+++ b/scene/gui/video_player.h
@@ -77,7 +77,7 @@ public:
float get_volume_db() const;
String get_stream_name() const;
- float get_pos() const;
+ float get_stream_pos() const;
void set_autoplay(bool p_vol);
bool has_autoplay() const;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 5561b5ef90..80993c7eaf 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1716,189 +1716,222 @@ void Animation::clear() {
}
-void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
- ERR_FAIL_INDEX(p_idx,tracks.size());
- ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM);
- TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]);
- for(int i=1;i<tt->transforms.size()-1;i++) {
- TKey<TransformKey> &t0 = tt->transforms[i-1];
- TKey<TransformKey> &t1 = tt->transforms[i];
- TKey<TransformKey> &t2 = tt->transforms[i+1];
+bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
- real_t c = (t1.time-t0.time)/(t2.time-t0.time);
- real_t t[3]={-1,-1,-1};
- { //translation
+ real_t c = (t1.time-t0.time)/(t2.time-t0.time);
+ real_t t[3]={-1,-1,-1};
- const Vector3 &v0=t0.value.loc;
- const Vector3 &v1=t1.value.loc;
- const Vector3 &v2=t2.value.loc;
+ { //translation
- if (v0.distance_to(v2)<CMP_EPSILON) {
- //0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1)>CMP_EPSILON) {
- //not close, not optimizable
- continue;
- }
+ const Vector3 &v0=t0.value.loc;
+ const Vector3 &v1=t1.value.loc;
+ const Vector3 &v2=t2.value.loc;
- } else {
+ if (v0.distance_to(v2)<CMP_EPSILON) {
+ //0 and 2 are close, let's see if 1 is close
+ if (v0.distance_to(v1)>CMP_EPSILON) {
+ //not close, not optimizable
+ return false;
+ }
- Vector3 pd = (v2-v0);
- float d0 = pd.dot(v0);
- float d1 = pd.dot(v1);
- float d2 = pd.dot(v2);
- if (d1<d0 || d1>d2) {
- continue; //beyond segment range
- }
+ } else {
- Vector3 s[2]={ v0, v2 };
- real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
+ Vector3 pd = (v2-v0);
+ float d0 = pd.dot(v0);
+ float d1 = pd.dot(v1);
+ float d2 = pd.dot(v2);
+ if (d1<d0 || d1>d2) {
+ return false;
+ }
- if (d>pd.length()*p_alowed_linear_err) {
- continue; //beyond allowed error for colinearity
- }
+ Vector3 s[2]={ v0, v2 };
+ real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
- t[0] = (d1-d0)/(d2-d0);
+ if (d>pd.length()*p_alowed_linear_err) {
+ return false; //beyond allowed error for colinearity
}
- }
- { //rotation
+ t[0] = (d1-d0)/(d2-d0);
+ }
+ }
- const Quat &q0=t0.value.rot;
- const Quat &q1=t1.value.rot;
- const Quat &q2=t2.value.rot;
+ { //rotation
- //localize both to rotation from q0
+ const Quat &q0=t0.value.rot;
+ const Quat &q1=t1.value.rot;
+ const Quat &q2=t2.value.rot;
- if ((q0-q2).length() < CMP_EPSILON) {
+ //localize both to rotation from q0
- if ((q0-q1).length() > CMP_EPSILON)
- continue;
+ if ((q0-q2).length() < CMP_EPSILON) {
- } else {
+ if ((q0-q1).length() > CMP_EPSILON)
+ return false;
+ } else {
- Quat r02 = (q0.inverse() * q2).normalized();
- Quat r01 = (q0.inverse() * q1).normalized();
- Vector3 v02,v01;
- real_t a02,a01;
+ Quat r02 = (q0.inverse() * q2).normalized();
+ Quat r01 = (q0.inverse() * q1).normalized();
- r02.get_axis_and_angle(v02,a02);
- r01.get_axis_and_angle(v01,a01);
+ Vector3 v02,v01;
+ real_t a02,a01;
- if (Math::abs(a02)>p_max_optimizable_angle)
- continue;
+ r02.get_axis_and_angle(v02,a02);
+ r01.get_axis_and_angle(v01,a01);
- if (v01.dot(v02)<0) {
- //make sure both rotations go the same way to compare
- v02=-v02;
- a02=-a02;
- }
+ if (Math::abs(a02)>p_max_optimizable_angle)
+ return false;
- real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI;
- if (err_01>p_alowed_angular_err) {
- //not rotating in the same axis
- continue;
- }
+ if (v01.dot(v02)<0) {
+ //make sure both rotations go the same way to compare
+ v02=-v02;
+ a02=-a02;
+ }
- if (a01*a02 < 0 ) {
- //not rotating in the same direction
- continue;
- }
+ real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI;
+ if (err_01>p_alowed_angular_err) {
+ //not rotating in the same axis
+ return false;
+ }
- real_t tr = a01/a02;
- if (tr<0 || tr>1)
- continue; //rotating too much or too less
+ if (a01*a02 < 0 ) {
+ //not rotating in the same direction
+ return false;
+ }
- t[1]=tr;
+ real_t tr = a01/a02;
+ if (tr<0 || tr>1)
+ return false; //rotating too much or too less
- }
+ t[1]=tr;
}
- { //scale
+ }
- const Vector3 &v0=t0.value.scale;
- const Vector3 &v1=t1.value.scale;
- const Vector3 &v2=t2.value.scale;
+ { //scale
- if (v0.distance_to(v2)<CMP_EPSILON) {
- //0 and 2 are close, let's see if 1 is close
- if (v0.distance_to(v1)>CMP_EPSILON) {
- //not close, not optimizable
- continue;
- }
+ const Vector3 &v0=t0.value.scale;
+ const Vector3 &v1=t1.value.scale;
+ const Vector3 &v2=t2.value.scale;
- } else {
+ if (v0.distance_to(v2)<CMP_EPSILON) {
+ //0 and 2 are close, let's see if 1 is close
+ if (v0.distance_to(v1)>CMP_EPSILON) {
+ //not close, not optimizable
+ return false;
+ }
- Vector3 pd = (v2-v0);
- float d0 = pd.dot(v0);
- float d1 = pd.dot(v1);
- float d2 = pd.dot(v2);
- if (d1<d0 || d1>d2) {
- continue; //beyond segment range
- }
+ } else {
- Vector3 s[2]={ v0, v2 };
- real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
+ Vector3 pd = (v2-v0);
+ float d0 = pd.dot(v0);
+ float d1 = pd.dot(v1);
+ float d2 = pd.dot(v2);
+ if (d1<d0 || d1>d2) {
+ return false; //beyond segment range
+ }
- if (d>pd.length()*p_alowed_linear_err) {
- continue; //beyond allowed error for colinearity
- }
+ Vector3 s[2]={ v0, v2 };
+ real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
- t[2] = (d1-d0)/(d2-d0);
+ if (d>pd.length()*p_alowed_linear_err) {
+ return false; //beyond allowed error for colinearity
}
+
+ t[2] = (d1-d0)/(d2-d0);
}
+ }
- bool erase=false;
- if (t[0]==-1 && t[1]==-1 && t[2]==-1) {
+ bool erase=false;
+ if (t[0]==-1 && t[1]==-1 && t[2]==-1) {
- erase=true;
- } else {
+ erase=true;
+ } else {
- erase=true;
- real_t lt=-1;
- for(int j=0;j<3;j++) {
- //search for t on first, one must be it
- if (t[j]!=-1) {
- lt=t[j]; //official t
- //validate rest
- for(int k=j+1;k<3;k++) {
- if (t[k]==-1)
- continue;
-
- if (Math::abs(lt-t[k])>p_alowed_linear_err) {
- erase=false;
- break;
- }
+ erase=true;
+ real_t lt=-1;
+ for(int j=0;j<3;j++) {
+ //search for t on first, one must be it
+ if (t[j]!=-1) {
+ lt=t[j]; //official t
+ //validate rest
+ for(int k=j+1;k<3;k++) {
+ if (t[k]==-1)
+ continue;
+
+ if (Math::abs(lt-t[k])>p_alowed_linear_err) {
+ erase=false;
+ break;
}
- break;
}
+ break;
}
+ }
- ERR_CONTINUE( lt==-1 );
+ ERR_FAIL_COND_V( lt==-1,false );
- if (erase) {
+ if (erase) {
- if (Math::abs(lt-c)>p_alowed_linear_err) {
- //todo, evaluate changing the transition if this fails?
- //this could be done as a second pass and would be
- //able to optimize more
- erase=false;
- } else {
+ if (Math::abs(lt-c)>p_alowed_linear_err) {
+ //todo, evaluate changing the transition if this fails?
+ //this could be done as a second pass and would be
+ //able to optimize more
+ erase=false;
+ } else {
- //print_line(itos(i)+"because of interp");
- }
+ //print_line(itos(i)+"because of interp");
}
+ }
+
+ }
+
+
+ return erase;
+
+
+}
+
+void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
+
+ ERR_FAIL_INDEX(p_idx,tracks.size());
+ ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM);
+ TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]);
+ bool prev_erased=false;
+ TKey<TransformKey> first_erased;
+
+ for(int i=1;i<tt->transforms.size()-1;i++) {
+
+ TKey<TransformKey> &t0 = tt->transforms[i-1];
+ TKey<TransformKey> &t1 = tt->transforms[i];
+ TKey<TransformKey> &t2 = tt->transforms[i+1];
+
+ bool erase = _transform_track_optimize_key(t0,t1,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle);
+
+
+ if (prev_erased && !_transform_track_optimize_key(t0,first_erased,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle)) {
+ //avoid error to go beyond first erased key
+ erase=false;
}
+
if (erase) {
+
+ if (!prev_erased) {
+ first_erased=t1;
+ prev_erased=true;
+ }
+
tt->transforms.remove(i);
i--;
+
+ } else {
+ prev_erased=false;
}
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 0c0290295a..bf87789e39 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -204,6 +204,7 @@ private:
return idxr;
}
+ bool _transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle);
void _transform_track_optimize(int p_idx, float p_allowed_err=0.05, float p_alowed_angular_err=0.01,float p_max_optimizable_angle=Math_PI*0.125);
protected:
diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp
index fffe1ad7fa..2bbae37510 100644
--- a/scene/resources/video_stream.cpp
+++ b/scene/resources/video_stream.cpp
@@ -33,6 +33,7 @@ void VideoStream::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_pending_frame_count"),&VideoStream::get_pending_frame_count);
ObjectTypeDB::bind_method(_MD("pop_frame"),&VideoStream::pop_frame);
ObjectTypeDB::bind_method(_MD("peek_frame"),&VideoStream::peek_frame);
+ ObjectTypeDB::bind_method(_MD("set_audio_track","idx"),&VideoStream::set_audio_track);
};
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index 1bc8a5e5bc..18f0cc3d05 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -62,6 +62,8 @@ public:
virtual void pop_frame(Ref<ImageTexture> p_tex)=0;
virtual Image peek_frame() const=0;
+ virtual void set_audio_track(int p_idx) =0;
+
virtual void update(float p_time)=0;
VideoStream();
diff --git a/servers/audio/audio_server_sw.cpp b/servers/audio/audio_server_sw.cpp
index f50813731e..55dde1b35b 100644
--- a/servers/audio/audio_server_sw.cpp
+++ b/servers/audio/audio_server_sw.cpp
@@ -332,6 +332,7 @@ void AudioServerSW::driver_process_chunk(int p_frames,int32_t *p_buffer) {
void AudioServerSW::driver_process(int p_frames,int32_t *p_buffer) {
+ _output_delay=p_frames/double(AudioDriverSW::get_singleton()->get_mix_rate());
//process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE
int todo=p_frames;
while(todo) {
@@ -795,6 +796,8 @@ void AudioServerSW::init() {
mixer = memnew( AudioMixerSW( sample_manager, latency, AudioDriverSW::get_singleton()->get_mix_rate(),mix_chans,mixer_use_fx,mixer_interp,_mixer_callback,this ) );
mixer_step_usecs=mixer->get_step_usecs();
+ _output_delay=0;
+
stream_volume=0.3;
// start the audio driver
if (AudioDriverSW::get_singleton())
@@ -911,6 +914,11 @@ float AudioServerSW::get_event_voice_global_volume_scale() const {
return event_voice_volume_scale;
}
+double AudioServerSW::get_output_delay() const {
+
+ return _output_delay;
+}
+
double AudioServerSW::get_mix_time() const {
return AudioDriverSW::get_singleton()->get_mix_time();
diff --git a/servers/audio/audio_server_sw.h b/servers/audio/audio_server_sw.h
index d137c15633..d47c1b4b3f 100644
--- a/servers/audio/audio_server_sw.h
+++ b/servers/audio/audio_server_sw.h
@@ -92,6 +92,8 @@ class AudioServerSW : public AudioServer {
float peak_left,peak_right;
uint32_t max_peak;
+ double _output_delay;
+
VoiceRBSW voice_rb;
bool exit_update_thread;
@@ -206,6 +208,9 @@ public:
virtual double get_mix_time() const; //useful for video -> audio sync
+ virtual double get_output_delay() const;
+
+
AudioServerSW(SampleManagerSW *p_sample_manager);
~AudioServerSW();
diff --git a/servers/audio_server.h b/servers/audio_server.h
index 85289de58a..511340678a 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -274,6 +274,7 @@ public:
static AudioServer *get_singleton();
virtual double get_mix_time() const=0; //useful for video -> audio sync
+ virtual double get_output_delay() const=0;
AudioServer();
virtual ~AudioServer();
diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp
index 2760f9bea6..22fb4fc0a8 100644
--- a/servers/physics_2d_server.cpp
+++ b/servers/physics_2d_server.cpp
@@ -514,7 +514,7 @@ void Physics2DServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("joint_get_type","joint"),&Physics2DServer::joint_get_type);
- ObjectTypeDB::bind_method(_MD("free","rid"),&Physics2DServer::free);
+ ObjectTypeDB::bind_method(_MD("free_rid","rid"),&Physics2DServer::free);
ObjectTypeDB::bind_method(_MD("set_active","active"),&Physics2DServer::set_active);
diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp
index e6b2927fb4..79de253d3b 100644
--- a/servers/physics_server.cpp
+++ b/servers/physics_server.cpp
@@ -655,7 +655,7 @@ void PhysicsServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("joint_get_type","joint"),&PhysicsServer::joint_get_type);
*/
- ObjectTypeDB::bind_method(_MD("free","rid"),&PhysicsServer::free);
+ ObjectTypeDB::bind_method(_MD("free_rid","rid"),&PhysicsServer::free);
ObjectTypeDB::bind_method(_MD("set_active","active"),&PhysicsServer::set_active);
diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp
index 68bd051ee9..0d4f5a7b74 100644
--- a/tools/editor/animation_editor.cpp
+++ b/tools/editor/animation_editor.cpp
@@ -687,9 +687,7 @@ void AnimationKeyEditor::_menu_track(int p_type) {
case TRACK_MENU_OPTIMIZE: {
- animation->optimize();
-
- track_editor->update();
+ optimize_dialog->popup_centered(Size2(250,180));
} break;
@@ -698,6 +696,18 @@ void AnimationKeyEditor::_menu_track(int p_type) {
}
+
+void AnimationKeyEditor::_animation_optimize() {
+
+
+ print_line("OPTIMIZE!");
+ animation->optimize(optimize_linear_error->get_val(),optimize_angular_error->get_val(),optimize_max_angle->get_val());
+ track_editor->update();
+ undo_redo->clear_history();
+
+}
+
+
float AnimationKeyEditor::_get_zoom_scale() const {
float zv = zoom->get_val();
@@ -2335,11 +2345,12 @@ void AnimationKeyEditor::_notification(int p_what) {
tpp->add_item("Out-In",TRACK_MENU_SET_ALL_TRANS_OUTIN);
tpp->set_name("Transitions");
tpp->connect("item_pressed",this,"_menu_track");
+ optimize_dialog->connect("confirmed",this,"_animation_optimize");
menu_track->get_popup()->add_child(tpp);
menu_track->get_popup()->add_submenu_item("Set Transitions..","Transitions");
- //menu_track->get_popup()->add_separator();
- //menu_track->get_popup()->add_item("Optimize Animation",TRACK_MENU_OPTIMIZE);
+ menu_track->get_popup()->add_separator();
+ menu_track->get_popup()->add_item("Optimize Animation",TRACK_MENU_OPTIMIZE);
@@ -3099,6 +3110,7 @@ void AnimationKeyEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_animation_len_update"),&AnimationKeyEditor::_animation_len_update);
ObjectTypeDB::bind_method(_MD("set_animation"),&AnimationKeyEditor::set_animation);
+ ObjectTypeDB::bind_method(_MD("_animation_optimize"),&AnimationKeyEditor::_animation_optimize);
ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) );
@@ -3224,6 +3236,37 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
remove_button->set_disabled(true);
remove_button->set_tooltip("Remove selected track.");
+
+ optimize_dialog = memnew( ConfirmationDialog );
+ add_child(optimize_dialog);
+ optimize_dialog->set_title("Anim. Optimizer");
+ VBoxContainer *optimize_vb = memnew( VBoxContainer );
+ optimize_dialog->add_child(optimize_vb);
+ optimize_dialog->set_child_rect(optimize_vb);
+ optimize_linear_error = memnew( SpinBox );
+ optimize_linear_error->set_max(1.0);
+ optimize_linear_error->set_min(0.001);
+ optimize_linear_error->set_step(0.001);
+ optimize_linear_error->set_val(0.05);
+ optimize_vb->add_margin_child("Max. Linear Error:",optimize_linear_error);
+ optimize_angular_error = memnew( SpinBox );
+ optimize_angular_error->set_max(1.0);
+ optimize_angular_error->set_min(0.001);
+ optimize_angular_error->set_step(0.001);
+ optimize_angular_error->set_val(0.01);
+
+ optimize_vb->add_margin_child("Max. Angular Error:",optimize_angular_error);
+ optimize_max_angle = memnew( SpinBox );
+ optimize_vb->add_margin_child("Max Optimizable Angle:",optimize_max_angle);
+ optimize_max_angle->set_max(360.0);
+ optimize_max_angle->set_min(0.0);
+ optimize_max_angle->set_step(0.1);
+ optimize_max_angle->set_val(22);
+
+ optimize_dialog->get_ok()->set_text("Optimize");
+
+
+
/*keying = memnew( Button );
keying->set_toggle_mode(true);
//keying->set_text("Keys");
diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h
index 01f6e294cc..9d3e692fad 100644
--- a/tools/editor/animation_editor.h
+++ b/tools/editor/animation_editor.h
@@ -169,6 +169,11 @@ class AnimationKeyEditor : public VBoxContainer {
ToolButton *move_down_button;
ToolButton *remove_button;
+ ConfirmationDialog *optimize_dialog;
+ SpinBox *optimize_linear_error;
+ SpinBox *optimize_angular_error;
+ SpinBox *optimize_max_angle;
+
SpinBox *step;
MenuButton *menu_track;
@@ -257,6 +262,7 @@ class AnimationKeyEditor : public VBoxContainer {
StringName alc;
void _animation_changed();
+ void _animation_optimize();
void _scroll_changed(double);
diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp
index e0b743a929..5d72928e9c 100644
--- a/tools/editor/editor_file_system.cpp
+++ b/tools/editor/editor_file_system.cpp
@@ -992,6 +992,35 @@ void EditorFileSystem::_resource_saved(const String& p_path){
EditorFileSystem::get_singleton()->update_file(p_path);
}
+String EditorFileSystem::_find_first_from_source(EditorFileSystemDirectory* p_dir,const String &p_src) const {
+
+ for(int i=0;i<p_dir->files.size();i++) {
+ for(int j=0;j<p_dir->files[i].meta.sources.size();j++) {
+
+ if (p_dir->files[i].meta.sources[j].path==p_src)
+ return p_dir->get_file_path(i);
+ }
+ }
+
+ for(int i=0;i<p_dir->subdirs.size();i++) {
+
+ String ret = _find_first_from_source(p_dir->subdirs[i],p_src);
+ if (ret.length()>0)
+ return ret;
+ }
+
+ return String();
+}
+
+
+String EditorFileSystem::find_resource_from_source(const String& p_path) const {
+
+
+ if (filesystem)
+ return _find_first_from_source(filesystem,p_path);
+ return String();
+}
+
void EditorFileSystem::update_file(const String& p_file) {
EditorFileSystemDirectory *fs=NULL;
diff --git a/tools/editor/editor_file_system.h b/tools/editor/editor_file_system.h
index c26fc02548..2d14f9012f 100644
--- a/tools/editor/editor_file_system.h
+++ b/tools/editor/editor_file_system.h
@@ -75,6 +75,7 @@ class EditorFileSystemDirectory : public Object {
static void _bind_methods();
+
friend class EditorFileSystem;
public:
@@ -180,6 +181,7 @@ class EditorFileSystem : public Node {
List<String> sources_changed;
static void _resource_saved(const String& p_path);
+ String _find_first_from_source(EditorFileSystemDirectory* p_dir,const String &p_src) const;
protected:
@@ -197,6 +199,7 @@ public:
void scan_sources();
void get_changed_sources(List<String> *r_changed);
void update_file(const String& p_file);
+ String find_resource_from_source(const String& p_path) const;
EditorFileSystemDirectory *get_path(const String& p_path);
String get_file_type(const String& p_file) const;
EditorFileSystem();
diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp
index 3fb45d1870..8fe7010760 100644
--- a/tools/editor/io_plugins/editor_import_collada.cpp
+++ b/tools/editor/io_plugins/editor_import_collada.cpp
@@ -1844,12 +1844,15 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
anim_length=collada.state.animation_clips[p_clip].end;
while(f<anim_length) {
- if (f>=anim_length)
- f=anim_length;
base_snapshots.push_back(f);
f+=snapshot_interval;
+
+ if (f>=anim_length) {
+ base_snapshots.push_back(anim_length);
+ }
}
+
//print_line("anim len: "+rtos(anim_length));
animation->set_length(anim_length);
@@ -1894,6 +1897,8 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
for(int i=0;i<at.keys.size();i++)
snapshots.push_back(at.keys[i].time);
+ print_line("using anim snapshots");
+
}
@@ -2185,8 +2190,6 @@ Node* EditorSceneImporterCollada::import_scene(const String& p_path, uint32_t p_
else
name=state.animations[i]->get_name();
- if (p_flags&IMPORT_ANIMATION_OPTIMIZE)
- state.animations[i]->optimize();
if (p_flags&IMPORT_ANIMATION_DETECT_LOOP) {
if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
@@ -2232,8 +2235,6 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String& p_path
}
}
- if (p_flags&IMPORT_ANIMATION_OPTIMIZE)
- anim->optimize();
return anim;
}
diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.cpp b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
index f305564622..06780e4d8a 100644
--- a/tools/editor/io_plugins/editor_scene_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
@@ -80,17 +80,25 @@ class EditorImportAnimationOptions : public VBoxContainer {
TreeItem *fps;
+ TreeItem* optimize_linear_error;
+ TreeItem* optimize_angular_error;
+ TreeItem* optimize_max_angle;
+
TreeItem *clips_base;
+
TextEdit *filters;
Vector<TreeItem*> clips;
Tree *flags;
Tree *clips_tree;
+ Tree *optimization_tree;
Vector<TreeItem*> items;
bool updating;
bool validating;
+
+
void _changed();
void _item_edited();
void _button_action(Object *p_obj,int p_col,int p_id);
@@ -107,6 +115,15 @@ public:
void set_fps(int p_fps);
int get_fps() const;
+ void set_optimize_linear_error(float p_error);
+ float get_optimize_linear_error() const;
+
+ void set_optimize_angular_error(float p_error);
+ float get_optimize_angular_error() const;
+
+ void set_optimize_max_angle(float p_error);
+ float get_optimize_max_angle() const;
+
void setup_clips(const Array& p_clips);
Array get_clips() const;
@@ -453,9 +470,41 @@ EditorImportAnimationOptions::EditorImportAnimationOptions() {
fps = flags->create_item(fps_base);
fps->set_cell_mode(0,TreeItem::CELL_MODE_RANGE);
fps->set_editable(0,true);
- fps->set_range(0,15);
fps->set_range_config(0,1,120,1);
+ fps->set_range(0,15);
+ optimization_tree = memnew( Tree );
+ optimization_tree->set_columns(2);
+ tab->add_child(optimization_tree);
+ optimization_tree->set_name("Optimizer");
+ optimization_tree->set_column_expand(0,true);
+ optimization_tree->set_column_expand(1,false);
+ optimization_tree->set_column_min_width(1,80);
+ optimization_tree->set_hide_root(true);
+
+
+ TreeItem *optimize_root = optimization_tree->create_item();
+
+ optimize_linear_error = optimization_tree->create_item(optimize_root);
+ optimize_linear_error->set_text(0,"Max Linear Error");
+ optimize_linear_error->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
+ optimize_linear_error->set_editable(1,true);
+ optimize_linear_error->set_range_config(1,0,1,0.001);
+ optimize_linear_error->set_range(1,0.05);
+
+ optimize_angular_error = optimization_tree->create_item(optimize_root);
+ optimize_angular_error->set_text(0,"Max Angular Error");
+ optimize_angular_error->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
+ optimize_angular_error->set_editable(1,true);
+ optimize_angular_error->set_range_config(1,0,1,0.001);
+ optimize_angular_error->set_range(1,0.01);
+
+ optimize_max_angle = optimization_tree->create_item(optimize_root);
+ optimize_max_angle->set_text(0,"Max Angle");
+ optimize_max_angle->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
+ optimize_max_angle->set_editable(1,true);
+ optimize_max_angle->set_range_config(1,0,360,0.001);
+ optimize_max_angle->set_range(1,int(180*0.125));
clips_tree = memnew( Tree );
clips_tree->set_hide_root(true);
@@ -498,6 +547,38 @@ int EditorImportAnimationOptions::get_fps() const {
return fps->get_range(0);
}
+
+void EditorImportAnimationOptions::set_optimize_linear_error(float p_optimize_linear_error) {
+
+ optimize_linear_error->set_range(1,p_optimize_linear_error);
+}
+
+float EditorImportAnimationOptions::get_optimize_linear_error() const {
+
+ return optimize_linear_error->get_range(1);
+}
+
+void EditorImportAnimationOptions::set_optimize_angular_error(float p_optimize_angular_error) {
+
+ optimize_angular_error->set_range(1,p_optimize_angular_error);
+}
+
+float EditorImportAnimationOptions::get_optimize_angular_error() const {
+
+ return optimize_angular_error->get_range(1);
+}
+
+void EditorImportAnimationOptions::set_optimize_max_angle(float p_optimize_max_angle) {
+
+ optimize_max_angle->set_range(1,p_optimize_max_angle);
+}
+
+float EditorImportAnimationOptions::get_optimize_max_angle() const {
+
+ return optimize_max_angle->get_range(1);
+}
+
+
void EditorImportAnimationOptions::set_filter(const String& p_filter) {
filters->set_text(p_filter);
@@ -544,6 +625,17 @@ void EditorSceneImportDialog::_choose_file(const String& p_path) {
}
#endif
+ if (p_path!=String()) {
+
+ String from_path = EditorFileSystem::get_singleton()->find_resource_from_source(EditorImportPlugin::validate_source_path(p_path));
+ print_line("from path.."+from_path);
+ if (from_path!=String()) {
+ popup_import(from_path);
+
+ }
+ }
+
+
import_path->set_text(p_path);
}
@@ -650,6 +742,9 @@ void EditorSceneImportDialog::_import(bool p_and_open) {
rim->set_option("texture_quality",texture_options->get_quality());
rim->set_option("animation_flags",animation_options->get_flags());
rim->set_option("animation_bake_fps",animation_options->get_fps());
+ rim->set_option("animation_optimizer_linear_error",animation_options->get_optimize_linear_error());
+ rim->set_option("animation_optimizer_angular_error",animation_options->get_optimize_angular_error());
+ rim->set_option("animation_optimizer_max_angle",animation_options->get_optimize_max_angle());
rim->set_option("animation_filters",animation_options->get_filter());
rim->set_option("animation_clips",animation_options->get_clips());
rim->set_option("post_import_script",script_path->get_text()!=String()?EditorImportPlugin::validate_source_path(script_path->get_text()):String());
@@ -791,6 +886,13 @@ void EditorSceneImportDialog::popup_import(const String &p_from) {
animation_options->set_filter(rimd->get_option("animation_filters"));
if (rimd->has_option("animation_bake_fps"))
animation_options->set_fps(rimd->get_option("animation_bake_fps"));
+ if (rimd->has_option("animation_optimizer_linear_error"))
+ animation_options->set_optimize_linear_error(rimd->get_option("animation_optimizer_linear_error"));
+ if (rimd->has_option("animation_optimizer_angular_error"))
+ animation_options->set_optimize_angular_error(rimd->get_option("animation_optimizer_angular_error"));
+ if (rimd->has_option("animation_optimizer_max_angle"))
+ animation_options->set_optimize_max_angle(rimd->get_option("animation_optimizer_max_angle"));
+
script_path->set_text(rimd->get_option("post_import_script"));
if (rimd->has_option("import_this_time"))
this_import->select(rimd->get_option("import_this_time"));
@@ -2223,6 +2325,8 @@ Error EditorSceneImportPlugin::import1(const Ref<ResourceImportMetadata>& p_from
int fps = 24;
if (from->has_option("animation_bake_fps"))
fps=from->get_option("animation_bake_fps");
+
+
Array clips;
if (from->has_option("animation_clips"))
clips=from->get_option("animation_clips");
@@ -2503,6 +2607,26 @@ void EditorSceneImportPlugin::_filter_tracks(Node *scene, const String& p_text)
}
+void EditorSceneImportPlugin::_optimize_animations(Node *scene, float p_max_lin_error,float p_max_ang_error,float p_max_angle) {
+
+ if (!scene->has_node(String("AnimationPlayer")))
+ return;
+ Node* n = scene->get_node(String("AnimationPlayer"));
+ ERR_FAIL_COND(!n);
+ AnimationPlayer *anim = n->cast_to<AnimationPlayer>();
+ ERR_FAIL_COND(!anim);
+
+
+ List<StringName> anim_names;
+ anim->get_animation_list(&anim_names);
+ for(List<StringName>::Element *E=anim_names.front();E;E=E->next()) {
+
+ Ref<Animation> a = anim->get_animation(E->get());
+ a->optimize(p_max_lin_error,p_max_ang_error,Math::deg2rad(p_max_angle));
+ }
+}
+
+
Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, const Ref<ResourceImportMetadata>& p_from) {
Error err=OK;
@@ -2512,6 +2636,16 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
Array animation_clips = p_from->get_option("animation_clips");
String animation_filter = p_from->get_option("animation_filters");
int scene_flags = from->get_option("flags");
+ float anim_optimizer_linerr=0.05;
+ float anim_optimizer_angerr=0.01;
+ float anim_optimizer_maxang=22;
+
+ if (from->has_option("animation_optimizer_linear_error"))
+ anim_optimizer_linerr=from->get_option("animation_optimizer_linear_error");
+ if (from->has_option("animation_optimizer_angular_error"))
+ anim_optimizer_angerr=from->get_option("animation_optimizer_angular_error");
+ if (from->has_option("animation_optimizer_max_angle"))
+ anim_optimizer_maxang=from->get_option("animation_optimizer_max_angle");
EditorProgress progress("import","Import Scene",104);
progress.step("Importing Scene..",2);
@@ -2536,6 +2670,8 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
Map< Ref<ImageTexture>,TextureRole > imagemap;
scene=_fix_node(scene,scene,collision_map,scene_flags,imagemap);
+ if (animation_flags&EditorSceneAnimationImportPlugin::ANIMATION_OPTIMIZE)
+ _optimize_animations(scene,anim_optimizer_linerr,anim_optimizer_angerr,anim_optimizer_maxang);
if (animation_clips.size())
_create_clips(scene,animation_clips,animation_flags&EditorSceneAnimationImportPlugin::ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.h b/tools/editor/io_plugins/editor_scene_import_plugin.h
index c56be57aed..fa4730f7ee 100644
--- a/tools/editor/io_plugins/editor_scene_import_plugin.h
+++ b/tools/editor/io_plugins/editor_scene_import_plugin.h
@@ -114,6 +114,7 @@ class EditorSceneImportPlugin : public EditorImportPlugin {
void _merge_existing_node(Node *p_node,Node *p_imported_scene,Set<Ref<Resource> >& checked_resources,Set<Node*> &checked_nodes);
void _add_new_nodes(Node *p_node,Node *p_imported,Node *p_imported_scene,Set<Node*> &checked_nodes);
+ void _optimize_animations(Node *scene, float p_max_lin_error,float p_max_ang_error,float p_max_angle);
void _merge_scenes(Node *p_node, Node *p_imported);
void _scan_materials(Node*p_base,Node *p_node,Map<String,Ref<Material> > &mesh_materials,Map<String,Ref<Material> >& override_materials);
diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py
index d3337033c8..2612e7e248 100644
--- a/tools/export/blender25/io_scene_dae/export_dae.py
+++ b/tools/export/blender25/io_scene_dae/export_dae.py
@@ -1457,7 +1457,7 @@ class DaeExporter:
print(str(x))
- tcn = self.export_animation(int(x.frame_range[0]),int(x.frame_range[1]),allowed_skeletons)
+ tcn = self.export_animation(int(x.frame_range[0]),int(x.frame_range[1]+0.5),allowed_skeletons)
framelen=(1.0/self.scene.render.fps)
start = x.frame_range[0]*framelen
end = x.frame_range[1]*framelen