3D Import Import & UDP

-=-=-=-=-=-=-=-=-=-=-

-Animation Import filter support
-Animation Clip import support
-Animation Optimizer Fixes, Improvements and Visibile Options
-Extremely Experimental UDP support.
This commit is contained in:
Juan Linietsky 2014-11-12 11:23:23 -03:00
parent c8cd5222a7
commit 6dd8768811
41 changed files with 1089 additions and 224 deletions

View file

@ -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);
};

View file

@ -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()
{
}

35
core/io/packet_peer_udp.h Normal file
View file

@ -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

View file

@ -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>();

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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

View file

@ -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;
};

View file

@ -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();

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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",
]

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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"));

View file

@ -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);

View file

@ -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;

View file

@ -1716,189 +1716,222 @@ void Animation::clear() {
}
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
const Vector3 &v0=t0.value.loc;
const Vector3 &v1=t1.value.loc;
const Vector3 &v2=t2.value.loc;
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;
}
} else {
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;
}
Vector3 s[2]={ v0, v2 };
real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
if (d>pd.length()*p_alowed_linear_err) {
return false; //beyond allowed error for colinearity
}
t[0] = (d1-d0)/(d2-d0);
}
}
{ //rotation
const Quat &q0=t0.value.rot;
const Quat &q1=t1.value.rot;
const Quat &q2=t2.value.rot;
//localize both to rotation from q0
if ((q0-q2).length() < CMP_EPSILON) {
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;
r02.get_axis_and_angle(v02,a02);
r01.get_axis_and_angle(v01,a01);
if (Math::abs(a02)>p_max_optimizable_angle)
return false;
if (v01.dot(v02)<0) {
//make sure both rotations go the same way to compare
v02=-v02;
a02=-a02;
}
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;
}
if (a01*a02 < 0 ) {
//not rotating in the same direction
return false;
}
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;
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;
}
} else {
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
}
Vector3 s[2]={ v0, v2 };
real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
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) {
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;
}
}
break;
}
}
ERR_FAIL_COND_V( lt==-1,false );
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 {
//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];
real_t c = (t1.time-t0.time)/(t2.time-t0.time);
real_t t[3]={-1,-1,-1};
bool erase = _transform_track_optimize_key(t0,t1,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle);
{ //translation
const Vector3 &v0=t0.value.loc;
const Vector3 &v1=t1.value.loc;
const Vector3 &v2=t2.value.loc;
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;
}
} else {
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
}
Vector3 s[2]={ v0, v2 };
real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
if (d>pd.length()*p_alowed_linear_err) {
continue; //beyond allowed error for colinearity
}
t[0] = (d1-d0)/(d2-d0);
}
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;
}
{ //rotation
const Quat &q0=t0.value.rot;
const Quat &q1=t1.value.rot;
const Quat &q2=t2.value.rot;
//localize both to rotation from q0
if ((q0-q2).length() < CMP_EPSILON) {
if ((q0-q1).length() > CMP_EPSILON)
continue;
} else {
Quat r02 = (q0.inverse() * q2).normalized();
Quat r01 = (q0.inverse() * q1).normalized();
Vector3 v02,v01;
real_t a02,a01;
r02.get_axis_and_angle(v02,a02);
r01.get_axis_and_angle(v01,a01);
if (Math::abs(a02)>p_max_optimizable_angle)
continue;
if (v01.dot(v02)<0) {
//make sure both rotations go the same way to compare
v02=-v02;
a02=-a02;
}
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 (a01*a02 < 0 ) {
//not rotating in the same direction
continue;
}
real_t tr = a01/a02;
if (tr<0 || tr>1)
continue; //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;
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;
}
} else {
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
}
Vector3 s[2]={ v0, v2 };
real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1);
if (d>pd.length()*p_alowed_linear_err) {
continue; //beyond allowed error for colinearity
}
t[2] = (d1-d0)/(d2-d0);
}
}
bool erase=false;
if (t[0]==-1 && t[1]==-1 && t[2]==-1) {
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;
}
}
break;
}
}
ERR_CONTINUE( lt==-1 );
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 {
//print_line(itos(i)+"because of interp");
}
}
}
if (erase) {
if (!prev_erased) {
first_erased=t1;
prev_erased=true;
}
tt->transforms.remove(i);
i--;
} else {
prev_erased=false;
}

View file

@ -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:

View file

@ -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);
};

View file

@ -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();

View file

@ -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();

View file

@ -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();

View file

@ -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();

View file

@ -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);

View file

@ -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);

View file

@ -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");

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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